Skip to content

Commit 83c7b37

Browse files
PYSCAN-41 Implement and test handling of duplicate arguments (#26)
1 parent e009f69 commit 83c7b37

File tree

2 files changed

+38
-17
lines changed

2 files changed

+38
-17
lines changed

src/py_sonar_scanner/configuration.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ def setup(self) -> None:
5050
"""This is executed when run from the command line"""
5151
self._read_wrapper_arguments()
5252
ApplicationLogger.set_debug(self.is_debug())
53-
self.scan_arguments = sys.argv[1:]
54-
self.scan_arguments.extend(self._read_toml_args())
53+
self.scan_arguments = self._read_toml_args()
54+
# If duplicate properties are provided, newer values will override older ones.
55+
# We therefore read CLI arguments last so that they have priority over toml configuration.
56+
self.scan_arguments.extend(sys.argv[1:])
5557

5658
def _read_wrapper_arguments(self):
5759
argument_parser = argparse.ArgumentParser()

tests/test_configuration.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
from py_sonar_scanner.logger import ApplicationLogger
2525

2626
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
27+
TEST_TOML_FILE = "test_toml_file.toml"
28+
SAMPLE_SCANNER_PATH = "path/to/scanner/py-sonar-scanner"
2729

2830

2931
class TestConfiguration(unittest.TestCase):
@@ -32,16 +34,16 @@ def test_argument_parsing(self, mock_sys):
3234
configuration = Configuration()
3335
self.assertFalse(configuration.is_debug())
3436

35-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner"]
37+
mock_sys.argv = [SAMPLE_SCANNER_PATH]
3638
configuration.setup()
3739
self.assertListEqual(configuration.scan_arguments, [])
3840

39-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", "-DSomeJVMArg"]
41+
mock_sys.argv = [SAMPLE_SCANNER_PATH, "-DSomeJVMArg"]
4042
configuration.setup()
4143
self.assertListEqual(configuration.scan_arguments, ["-DSomeJVMArg"])
4244

4345
mock_sys.argv = [
44-
"path/to/scanner/py-sonar-scanner",
46+
SAMPLE_SCANNER_PATH,
4547
"-DSomeJVMArg",
4648
"-DAnotherJVMArg",
4749
"-dNotAJVMArg",
@@ -52,35 +54,35 @@ def test_argument_parsing(self, mock_sys):
5254
configuration.scan_arguments, ["-DSomeJVMArg", "-DAnotherJVMArg", "-dNotAJVMArg", "-SomeNonsense"]
5355
)
5456

55-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", f"-Dtoml.path={CURRENT_DIR}/resources/pyproject.toml"]
57+
mock_sys.argv = [SAMPLE_SCANNER_PATH, f"-Dtoml.path={CURRENT_DIR}/resources/pyproject.toml"]
5658
configuration.setup()
5759
self.assertListEqual(
5860
configuration.scan_arguments,
59-
[f"-Dtoml.path={CURRENT_DIR}/resources/pyproject.toml", "-Dsonar.a=b", "-Dsonar.c=d"],
61+
["-Dsonar.a=b", "-Dsonar.c=d", f"-Dtoml.path={CURRENT_DIR}/resources/pyproject.toml"],
6062
)
6163

62-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", f"-Dproject.home={CURRENT_DIR}/resources/"]
64+
mock_sys.argv = [SAMPLE_SCANNER_PATH, f"-Dproject.home={CURRENT_DIR}/resources/"]
6365
configuration.setup()
6466
self.assertListEqual(
65-
configuration.scan_arguments, [f"-Dproject.home={CURRENT_DIR}/resources/", "-Dsonar.a=b", "-Dsonar.c=d"]
67+
configuration.scan_arguments, ["-Dsonar.a=b", "-Dsonar.c=d", f"-Dproject.home={CURRENT_DIR}/resources/"]
6668
)
6769

68-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", "-Dproject.home=tests2"]
70+
mock_sys.argv = [SAMPLE_SCANNER_PATH, "-Dproject.home=tests2"]
6971
configuration.setup()
7072
self.assertListEqual(configuration.scan_arguments, ["-Dproject.home=tests2"])
7173

72-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", "-Dproject.home=tests=2"]
74+
mock_sys.argv = [SAMPLE_SCANNER_PATH, "-Dproject.home=tests=2"]
7375
configuration.setup()
7476
self.assertListEqual(configuration.scan_arguments, ["-Dproject.home=tests=2"])
7577

76-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", "-X"]
78+
mock_sys.argv = [SAMPLE_SCANNER_PATH, "-X"]
7779
configuration.setup()
7880
self.assertTrue(configuration.is_debug())
7981

8082
@patch("py_sonar_scanner.configuration.sys")
8183
def test_dict_with_no_valid_values(self, mock_sys):
8284
configuration = Configuration()
83-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner"]
85+
mock_sys.argv = [SAMPLE_SCANNER_PATH]
8486

8587
test_dict = {}
8688
configuration._read_toml_file = Mock(return_value=test_dict)
@@ -100,7 +102,7 @@ def test_dict_with_no_valid_values(self, mock_sys):
100102
@patch("py_sonar_scanner.configuration.sys")
101103
def test_dict_with_valid_values(self, mock_sys):
102104
configuration = Configuration()
103-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner"]
105+
mock_sys.argv = [SAMPLE_SCANNER_PATH]
104106

105107
test_dict = {"tool": {"sonar": {"property1": "value1"}}}
106108
configuration._read_toml_file = Mock(return_value=test_dict)
@@ -127,23 +129,40 @@ def test_dict_with_valid_values(self, mock_sys):
127129
@patch("py_sonar_scanner.configuration.sys")
128130
def test_toml_with_valid_values(self, mock_sys):
129131
configuration = Configuration()
130-
toml_file_path = os.path.join(CURRENT_DIR, "resources", "test_toml_file.toml")
131-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", f"-Dtoml.path={toml_file_path}"]
132+
toml_file_path = os.path.join(CURRENT_DIR, "resources", TEST_TOML_FILE)
133+
mock_sys.argv = [SAMPLE_SCANNER_PATH, f"-Dtoml.path={toml_file_path}"]
132134
configuration.setup()
133135
self.assertListEqual(
134136
configuration.scan_arguments,
135137
[
138+
"-Dsonar.property1=value1",
139+
"-Dsonar.property2=value2",
140+
"-Dsonar.property_class.property1=value1",
136141
f"-Dtoml.path={CURRENT_DIR}/resources/test_toml_file.toml",
142+
],
143+
)
144+
145+
@patch("py_sonar_scanner.configuration.sys")
146+
def test_duplicate_values_toml_cli(self, mock_sys):
147+
configuration = Configuration()
148+
toml_file_path = os.path.join(CURRENT_DIR, "resources", TEST_TOML_FILE)
149+
mock_sys.argv = [SAMPLE_SCANNER_PATH, f"-Dtoml.path={toml_file_path}", "-Dsonar.property1=value1"]
150+
configuration.setup()
151+
self.assertListEqual(
152+
configuration.scan_arguments,
153+
[
137154
"-Dsonar.property1=value1",
138155
"-Dsonar.property2=value2",
139156
"-Dsonar.property_class.property1=value1",
157+
f"-Dtoml.path={CURRENT_DIR}/resources/test_toml_file.toml",
158+
"-Dsonar.property1=value1",
140159
],
141160
)
142161

143162
@patch("builtins.open")
144163
@patch("py_sonar_scanner.configuration.sys")
145164
def test_error_while_reading_toml_file(self, mock_sys, mock_open):
146-
toml_file_path = os.path.join(CURRENT_DIR, "resources", "test_toml_file.toml")
165+
toml_file_path = os.path.join(CURRENT_DIR, "resources", TEST_TOML_FILE)
147166
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", f"-Dtoml.path={toml_file_path}"]
148167

149168
mock_open.side_effect = OSError("Test error while opening file.")

0 commit comments

Comments
 (0)