Skip to content

Commit d2e6eb9

Browse files
author
Jeremi Do Dinh
authored
PYSCAN-3 Add tests for pyproject.toml file parsing. (#19)
1 parent 06d004d commit d2e6eb9

File tree

3 files changed

+128
-14
lines changed

3 files changed

+128
-14
lines changed

src/py_sonar_scanner/configuration.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,26 @@
2020
from __future__ import annotations
2121
import os
2222
import sys
23+
from logging import Logger
24+
2325
import toml
2426

27+
from py_sonar_scanner.logger import ApplicationLogger
28+
2529

2630
class Configuration:
2731
sonar_scanner_executable_path: str
2832
sonar_scanner_path: str
2933
sonar_scanner_version: str
3034
scan_arguments: list[str]
35+
log: Logger
3136

3237
def __init__(self):
3338
self.sonar_scanner_path = ".scanner"
3439
self.sonar_scanner_version = "4.6.2.2472"
3540
self.sonar_scanner_executable_path = ""
3641
self.scan_arguments = []
42+
self.log = ApplicationLogger.get_logger()
3743

3844
def setup(self) -> None:
3945
"""This is executed when run from the command line"""
@@ -42,18 +48,25 @@ def setup(self) -> None:
4248

4349
def _read_toml_args(self) -> list[str]:
4450
scan_arguments: list[str] = []
51+
toml_data: dict = {}
4552
try:
46-
parsed_data = self._read_toml_file()
47-
if ("tool" not in parsed_data) or ("sonar" not in parsed_data["tool"]):
48-
return scan_arguments
49-
sonar_properties = parsed_data["tool"]["sonar"]
50-
for key, value in sonar_properties.items():
51-
self._add_parameter_to_scanner_args(scan_arguments, key, value)
52-
except BaseException as e:
53-
print(e)
54-
raise e
53+
toml_data = self._read_toml_file()
54+
except OSError:
55+
self.log.error("Test error while opening file.")
56+
sonar_properties = self._extract_sonar_properties(toml_data)
57+
for key, value in sonar_properties.items():
58+
self._add_parameter_to_scanner_args(scan_arguments, key, value)
5559
return scan_arguments
5660

61+
def _extract_sonar_properties(self, toml_properties):
62+
if "tool" not in toml_properties.keys():
63+
return {}
64+
tool_data = toml_properties["tool"]
65+
if not isinstance(tool_data, dict) or "sonar" not in tool_data.keys():
66+
return {}
67+
sonar_properties = tool_data["sonar"]
68+
return sonar_properties if isinstance(sonar_properties, dict) else {}
69+
5770
def _add_parameter_to_scanner_args(self, scan_arguments: list[str], key: str, value: Union[str, dict]):
5871
if isinstance(value, str):
5972
scan_arguments.append(f"-Dsonar.{key}={value}")

tests/resources/test_toml_file.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[tool]
2+
ignored_property="something"
3+
4+
[tool.sonar]
5+
property1="value1"
6+
property2="value2"
7+
8+
[tool.sonar.property_class]
9+
property1="value1"
10+

tests/test_configuration.py

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
# along with this program; if not, write to the Free Software Foundation,
1818
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1919
#
20+
import os
2021
import unittest
21-
from unittest.mock import patch
22+
from unittest.mock import patch, Mock
2223
from py_sonar_scanner.configuration import Configuration
2324

25+
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
26+
2427

2528
class TestConfiguration(unittest.TestCase):
2629
@patch("py_sonar_scanner.configuration.sys")
@@ -47,16 +50,17 @@ def test_argument_parsing(self, mock_sys):
4750
configuration.scan_arguments, ["-DSomeJVMArg", "-DAnotherJVMArg", "-dNotAJVMArg", "-SomeNonsense"]
4851
)
4952

50-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", "-Dtoml.path=tests/resources/pyproject.toml"]
53+
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", f"-Dtoml.path={CURRENT_DIR}/resources/pyproject.toml"]
5154
configuration.setup()
5255
self.assertListEqual(
53-
configuration.scan_arguments, ["-Dtoml.path=tests/resources/pyproject.toml", "-Dsonar.a=b", "-Dsonar.c=d"]
56+
configuration.scan_arguments,
57+
[f"-Dtoml.path={CURRENT_DIR}/resources/pyproject.toml", "-Dsonar.a=b", "-Dsonar.c=d"],
5458
)
5559

56-
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", "-Dproject.home=tests/resources/"]
60+
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", f"-Dproject.home={CURRENT_DIR}/resources/"]
5761
configuration.setup()
5862
self.assertListEqual(
59-
configuration.scan_arguments, ["-Dproject.home=tests/resources/", "-Dsonar.a=b", "-Dsonar.c=d"]
63+
configuration.scan_arguments, [f"-Dproject.home={CURRENT_DIR}/resources/", "-Dsonar.a=b", "-Dsonar.c=d"]
6064
)
6165

6266
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", "-Dproject.home=tests2"]
@@ -66,3 +70,90 @@ def test_argument_parsing(self, mock_sys):
6670
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", "-Dproject.home=tests=2"]
6771
configuration.setup()
6872
self.assertListEqual(configuration.scan_arguments, ["-Dproject.home=tests=2"])
73+
74+
@patch("py_sonar_scanner.configuration.sys")
75+
def test_dict_with_no_valid_values(self, mock_sys):
76+
configuration = Configuration()
77+
mock_sys.argv = ["path/to/scanner/py-sonar-scanner"]
78+
79+
test_dict = {}
80+
configuration._read_toml_file = Mock(return_value=test_dict)
81+
configuration.setup()
82+
self.assertListEqual(configuration.scan_arguments, [])
83+
84+
test_dict = {"tool": "some_property"}
85+
configuration._read_toml_file = Mock(return_value=test_dict)
86+
configuration.setup()
87+
self.assertListEqual(configuration.scan_arguments, [])
88+
89+
test_dict = {"tool": {"sonar": "some_property"}}
90+
configuration._read_toml_file = Mock(return_value=test_dict)
91+
configuration.setup()
92+
self.assertListEqual(configuration.scan_arguments, [])
93+
94+
@patch("py_sonar_scanner.configuration.sys")
95+
def test_dict_with_valid_values(self, mock_sys):
96+
configuration = Configuration()
97+
mock_sys.argv = ["path/to/scanner/py-sonar-scanner"]
98+
99+
test_dict = {"tool": {"sonar": {"property1": "value1"}}}
100+
configuration._read_toml_file = Mock(return_value=test_dict)
101+
configuration.setup()
102+
self.assertListEqual(configuration.scan_arguments, ["-Dsonar.property1=value1"])
103+
104+
test_dict = {"tool": {"sonar": {"property1": "value1", "property2": "value2"}}}
105+
configuration._read_toml_file = Mock(return_value=test_dict)
106+
configuration.setup()
107+
self.assertListEqual(configuration.scan_arguments, ["-Dsonar.property1=value1", "-Dsonar.property2=value2"])
108+
109+
test_dict = {"tool": {"sonar": {"property_class": {"property1": "value1"}}}}
110+
configuration._read_toml_file = Mock(return_value=test_dict)
111+
configuration.setup()
112+
self.assertListEqual(configuration.scan_arguments, ["-Dsonar.property_class.property1=value1"])
113+
114+
test_dict = {"tool": {"sonar": {"property1": "value1", "property_class": {"sub_property": "sub_value"}}}}
115+
configuration._read_toml_file = Mock(return_value=test_dict)
116+
configuration.setup()
117+
self.assertListEqual(
118+
configuration.scan_arguments, ["-Dsonar.property1=value1", "-Dsonar.property_class.sub_property=sub_value"]
119+
)
120+
121+
@patch("py_sonar_scanner.configuration.sys")
122+
def test_toml_with_valid_values(self, mock_sys):
123+
configuration = Configuration()
124+
toml_file_path = os.path.join(CURRENT_DIR, "resources", "test_toml_file.toml")
125+
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", f"-Dtoml.path={toml_file_path}"]
126+
configuration.setup()
127+
self.assertListEqual(
128+
configuration.scan_arguments,
129+
[
130+
f"-Dtoml.path={CURRENT_DIR}/resources/test_toml_file.toml",
131+
"-Dsonar.property1=value1",
132+
"-Dsonar.property2=value2",
133+
"-Dsonar.property_class.property1=value1",
134+
],
135+
)
136+
137+
@patch("py_sonar_scanner.configuration.ApplicationLogger.get_logger")
138+
@patch("builtins.open")
139+
@patch("py_sonar_scanner.configuration.sys")
140+
def test_error_while_reading_toml_file(self, mock_sys, mock_open, mock_logger):
141+
toml_file_path = os.path.join(CURRENT_DIR, "resources", "test_toml_file.toml")
142+
mock_sys.argv = ["path/to/scanner/py-sonar-scanner", f"-Dtoml.path={toml_file_path}"]
143+
144+
mock_open.side_effect = OSError("Test error while opening file.")
145+
146+
mock_logger_instance = Mock()
147+
mock_logger_instance.error = Mock()
148+
mock_logger.return_value = mock_logger_instance
149+
150+
configuration = Configuration()
151+
configuration.setup()
152+
153+
self.assertListEqual(
154+
configuration.scan_arguments,
155+
[
156+
f"-Dtoml.path={CURRENT_DIR}/resources/test_toml_file.toml",
157+
],
158+
)
159+
mock_logger_instance.error.assert_called_once_with("Test error while opening file.")

0 commit comments

Comments
 (0)