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+ print (f"{ input_path } => { output } " )
66+
67+ assert (
68+ scripts_bazel .generate_sourcelinks_cli .clean_external_prefix (input_path )
69+ == expected_output
70+ )
71+
72+
73+ def test_generate_sourcelinks_cli_basic (
74+ tmp_path : Path , monkeypatch : pytest .MonkeyPatch
75+ ) -> None :
2576 """Test basic functionality of generate_sourcelinks_cli."""
2677 # Create a test source file with a traceability tag
2778 test_file = tmp_path / "test_source.py"
@@ -36,39 +87,116 @@ def some_function():
3687
3788 output_file = tmp_path / "output.json"
3889
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 ()
90+ test_args : list [Path | str ] = [
91+ _MY_PATH .parent
92+ / "generate_sourcelinks_cli.py" , # sys.argv[0] is always the script name
93+ "--output" ,
94+ str (output_file ),
95+ str (test_file ),
96+ ]
97+ monkeypatch .setattr (sys , "argv" , test_args )
98+ result = scripts_bazel .generate_sourcelinks_cli .main ()
99+ assert result == 0
52100
53101 # Check the output content
54102 with open (output_file ) as f :
55103 data : list [dict [str , str | int ]] = json .load (f )
56104 assert isinstance (data , list )
57- assert len (data ) > 0
105+ # The first dictionary has to be metadata
106+ assert len (data ) == 2
107+ assert is_metadata (data [0 ])
108+ assert data [0 ]["repo_name" ] == "local_repo"
109+ # hash & url can not be set in this script therefore HAVE to be empty
110+ assert data [0 ]["hash" ] == ""
111+ assert data [0 ]["url" ] == ""
58112
59113 # 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
114+ assert_json_internal_types (data [1 :])
66115
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 )
116+ assert data [1 ]["need" ] == "tool_req__docs_arch_types"
117+
118+
119+ def test_generate_sourcelinks_cli_parse_external_module (
120+ tmp_path : Path , monkeypatch : pytest .MonkeyPatch
121+ ):
122+ # 1. Create the 'external' directory inside the temp path
123+ external_root = tmp_path / "external"
124+ external_root .mkdir ()
125+
126+ # 2. Create your file inside that 'external' directory
127+ test_file = external_root / "score_baselibs+" / "src" / "source_file1.py"
128+ test_file .parent .mkdir (parents = True )
129+ test_file .write_text ("content" )
73130
74- assert any (entry ["need" ] == "tool_req__docs_arch_types" for entry in data )
131+ # 3. Create the path relative to tmp_path so it starts with 'external/'
132+ # Use .relative_to(tmp_path) to get 'external/score_docs_as_code+/...'
133+ test_file .write_text (
134+ """
135+ # Some code here
136+ # req-Id: tool_req__docs_arch_types
137+ def some_function():
138+ pass
139+ """
140+ )
141+ output_file = tmp_path / "output.json"
142+ monkeypatch .chdir (tmp_path )
143+ relative_test_file = test_file .relative_to (tmp_path )
144+ test_args : list [Path | str ] = [
145+ _MY_PATH .parent
146+ / "generate_sourcelinks_cli.py" , # sys.argv[0] is always the script name
147+ "--output" ,
148+ str (output_file ),
149+ str (relative_test_file ),
150+ ]
151+ monkeypatch .setattr (sys , "argv" , test_args )
152+ result = scripts_bazel .generate_sourcelinks_cli .main ()
153+ assert result == 0
154+ with open (output_file ) as f :
155+ data : list [dict [str , str | int ]] = json .load (f )
156+ assert isinstance (data , list )
157+ assert len (data ) == 2
158+ # The first dictionary has to be metadata
159+ assert is_metadata (data [0 ])
160+ assert data [0 ]["repo_name" ] == "score_baselibs"
161+ # hash & url can not be set in this script therefore HAVE to be empty
162+ assert data [0 ]["hash" ] == ""
163+ assert data [0 ]["url" ] == ""
164+
165+ # Verify schema of each entry
166+ assert_json_internal_types (data [1 :])
167+
168+
169+ def test_generate_sourcelinks_cli_file_not_exists (
170+ tmp_path : Path , monkeypatch : pytest .MonkeyPatch
171+ ):
172+ external_root = tmp_path / "external"
173+ external_root .mkdir ()
174+
175+ # 2. Create your file inside that 'external' directory
176+ test_file = external_root / "score_baselibs+" / "src" / "source_file1.py"
177+ test_file .parent .mkdir (parents = True )
178+ test_file .write_text ("content" )
179+
180+ # 3. Create the path relative to tmp_path so it starts with 'external/'
181+ # Use .relative_to(tmp_path) to get 'external/score_docs_as_code+/...'
182+ test_file .write_text (
183+ """
184+ # Some code here
185+ # req-Id: tool_req__docs_arch_types
186+ def some_function():
187+ pass
188+ """
189+ )
190+ output_file = tmp_path / "output.json"
191+ # BY not changing directory (like above) we can FORCE the file to not exists
192+ relative_test_file = test_file .relative_to (tmp_path )
193+ test_args : list [Path | str ] = [
194+ _MY_PATH .parent
195+ / "generate_sourcelinks_cli.py" , # sys.argv[0] is always the script name
196+ "--output" ,
197+ str (output_file ),
198+ str (relative_test_file ),
199+ ]
200+ monkeypatch .setattr (sys , "argv" , test_args )
201+ with pytest .raises (AssertionError ):
202+ scripts_bazel .generate_sourcelinks_cli .main ()
0 commit comments