1111# SPDX-License-Identifier: Apache-2.0
1212# *******************************************************************************
1313
14+ # ╓ ╖
15+ # ║ Some parts are generated by Gemini ║
16+ # ╙ ╜
17+
1418"""Tests for generate_sourcelinks_cli.py"""
1519
1620import json
17- import subprocess
1821import sys
1922from pathlib import Path
2023
24+ import pytest
25+
26+ import scripts_bazel .generate_sourcelinks_cli
27+ from src .extensions .score_source_code_linker .needlinks import is_metadata
28+
2129_MY_PATH = Path (__file__ ).parent
2230
2331
24- def test_generate_sourcelinks_cli_basic (tmp_path : Path ) -> None :
32+ def assert_json_internal_types (input : list [dict [str , str | int ]]):
33+ for entry in input :
34+ assert "file" in entry
35+ assert "line" in entry
36+ assert "tag" in entry
37+ assert "need" in entry
38+ assert "full_line" in entry
39+
40+ assert isinstance (entry ["file" ], str )
41+ assert isinstance (entry ["line" ], int )
42+ assert isinstance (entry ["tag" ], str )
43+ assert isinstance (entry ["need" ], str )
44+ assert isinstance (entry ["full_line" ], str )
45+
46+
47+ # Unit test generated by Gemini.
48+ @pytest .mark .parametrize (
49+ "input_path, expected_output" ,
50+ [
51+ # Case 1: Path starts with "external/" and has a project name
52+ (Path ("external/score_docs_as_code+/docs/index.md" ), Path ("docs/index.md" )),
53+ # Case 2: Path does NOT start with "external/"
54+ (Path ("src/main.py" ), Path ("src/main.py" )),
55+ # Case 3: Path has "external" elsewhere in the string (should not be removed)
56+ (Path ("my_external_data/file.txt" ), Path ("my_external_data/file.txt" )),
57+ # Case 4: Deeply nested path inside an external prefix
58+ (Path ("external/repo/subfolder/file.py" ), Path ("subfolder/file.py" )),
59+ # Case 5: Path is exactly "external/" (edge case, returns empty path based on split logic)
60+ (Path ("external/" ), Path ("external" )),
61+ ],
62+ )
63+ def test_clean_external_prefix (input_path : Path , expected_output : Path ):
64+ output = scripts_bazel .generate_sourcelinks_cli .clean_external_prefix (input_path )
65+ assert output == expected_output
66+
67+
68+ def test_generate_sourcelinks_cli_basic (
69+ tmp_path : Path , monkeypatch : pytest .MonkeyPatch
70+ ) -> None :
2571 """Test basic functionality of generate_sourcelinks_cli."""
2672 # Create a test source file with a traceability tag
2773 test_file = tmp_path / "test_source.py"
@@ -36,39 +82,116 @@ def some_function():
3682
3783 output_file = tmp_path / "output.json"
3884
39- # Execute the script
40- result = subprocess .run (
41- [
42- sys .executable ,
43- _MY_PATH .parent / "generate_sourcelinks_cli.py" ,
44- "--output" ,
45- str (output_file ),
46- str (test_file ),
47- ],
48- )
49-
50- assert result .returncode == 0
51- assert output_file .exists ()
85+ test_args : list [Path | str ] = [
86+ _MY_PATH .parent
87+ / "generate_sourcelinks_cli.py" , # sys.argv[0] is always the script name
88+ "--output" ,
89+ str (output_file ),
90+ str (test_file ),
91+ ]
92+ monkeypatch .setattr (sys , "argv" , test_args )
93+ result = scripts_bazel .generate_sourcelinks_cli .main ()
94+ assert result == 0
5295
5396 # Check the output content
5497 with open (output_file ) as f :
5598 data : list [dict [str , str | int ]] = json .load (f )
5699 assert isinstance (data , list )
57- assert len (data ) > 0
100+ # The first dictionary has to be metadata
101+ assert len (data ) == 2
102+ assert is_metadata (data [0 ])
103+ assert data [0 ]["repo_name" ] == "local_repo"
104+ # hash & url can not be set in this script therefore HAVE to be empty
105+ assert data [0 ]["hash" ] == ""
106+ assert data [0 ]["url" ] == ""
58107
59108 # Verify schema of each entry
60- for entry in data :
61- assert "file" in entry
62- assert "line" in entry
63- assert "tag" in entry
64- assert "need" in entry
65- assert "full_line" in entry
109+ assert_json_internal_types (data [1 :])
66110
67- # Verify types
68- assert isinstance (entry ["file" ], str )
69- assert isinstance (entry ["line" ], int )
70- assert isinstance (entry ["tag" ], str )
71- assert isinstance (entry ["need" ], str )
72- assert isinstance (entry ["full_line" ], str )
111+ assert data [1 ]["need" ] == "tool_req__docs_arch_types"
73112
74- assert any (entry ["need" ] == "tool_req__docs_arch_types" for entry in data )
113+
114+ def test_generate_sourcelinks_cli_parse_external_module (
115+ tmp_path : Path , monkeypatch : pytest .MonkeyPatch
116+ ):
117+ # 1. Create the 'external' directory inside the temp path
118+ external_root = tmp_path / "external"
119+ external_root .mkdir ()
120+
121+ # 2. Create your file inside that 'external' directory
122+ test_file = external_root / "score_baselibs+" / "src" / "source_file1.py"
123+ test_file .parent .mkdir (parents = True )
124+ test_file .write_text ("content" )
125+
126+ # 3. Create the path relative to tmp_path so it starts with 'external/'
127+ # Use .relative_to(tmp_path) to get 'external/score_docs_as_code+/...'
128+ test_file .write_text (
129+ """
130+ # Some code here
131+ # req-Id: tool_req__docs_arch_types
132+ def some_function():
133+ pass
134+ """
135+ )
136+ output_file = tmp_path / "output.json"
137+ monkeypatch .chdir (tmp_path )
138+ relative_test_file = test_file .relative_to (tmp_path )
139+ test_args : list [Path | str ] = [
140+ _MY_PATH .parent
141+ / "generate_sourcelinks_cli.py" , # sys.argv[0] is always the script name
142+ "--output" ,
143+ str (output_file ),
144+ str (relative_test_file ),
145+ ]
146+ monkeypatch .setattr (sys , "argv" , test_args )
147+ result = scripts_bazel .generate_sourcelinks_cli .main ()
148+ assert result == 0
149+ with open (output_file ) as f :
150+ data : list [dict [str , str | int ]] = json .load (f )
151+ assert isinstance (data , list )
152+ assert len (data ) == 2
153+ # The first dictionary has to be metadata
154+ assert is_metadata (data [0 ])
155+ assert data [0 ]["repo_name" ] == "score_baselibs"
156+ # hash & url can not be set in this script therefore HAVE to be empty
157+ assert data [0 ]["hash" ] == ""
158+ assert data [0 ]["url" ] == ""
159+
160+ # Verify schema of each entry
161+ assert_json_internal_types (data [1 :])
162+
163+
164+ def test_generate_sourcelinks_cli_file_not_exists (
165+ tmp_path : Path , monkeypatch : pytest .MonkeyPatch
166+ ):
167+ external_root = tmp_path / "external"
168+ external_root .mkdir ()
169+
170+ # 2. Create your file inside that 'external' directory
171+ test_file = external_root / "score_baselibs+" / "src" / "source_file1.py"
172+ test_file .parent .mkdir (parents = True )
173+ test_file .write_text ("content" )
174+
175+ # 3. Create the path relative to tmp_path so it starts with 'external/'
176+ # Use .relative_to(tmp_path) to get 'external/score_docs_as_code+/...'
177+ test_file .write_text (
178+ """
179+ # Some code here
180+ # req-Id: tool_req__docs_arch_types
181+ def some_function():
182+ pass
183+ """
184+ )
185+ output_file = tmp_path / "output.json"
186+ # BY not changing directory (like above) we can FORCE the file to not exists
187+ relative_test_file = test_file .relative_to (tmp_path )
188+ test_args : list [Path | str ] = [
189+ _MY_PATH .parent
190+ / "generate_sourcelinks_cli.py" , # sys.argv[0] is always the script name
191+ "--output" ,
192+ str (output_file ),
193+ str (relative_test_file ),
194+ ]
195+ monkeypatch .setattr (sys , "argv" , test_args )
196+ with pytest .raises (AssertionError ):
197+ scripts_bazel .generate_sourcelinks_cli .main ()
0 commit comments