Skip to content

Commit 84f231d

Browse files
SCANPY-237 Improved unit tests
1 parent 9f80487 commit 84f231d

File tree

1 file changed

+109
-63
lines changed

1 file changed

+109
-63
lines changed

tests/unit/test_dry_run.py

Lines changed: 109 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
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 unittest
21+
from unittest.mock import patch
2022

21-
from unittest.mock import patch, call
22-
from pyfakefs import fake_filesystem_unittest as pyfakefs
23+
import pyfakefs.fake_filesystem_unittest as pyfakefs
2324

2425
from pysonar_scanner.__main__ import run_dry_run
2526
from pysonar_scanner.configuration.properties import (
@@ -39,37 +40,43 @@
3940
)
4041

4142

42-
class TestValidationResult:
43+
class TestValidationResult(unittest.TestCase):
4344

4445
def test_valid_when_no_errors(self):
4546
result = ValidationResult()
46-
assert result.is_valid()
47-
assert len(result.errors) == 0
48-
assert len(result.warnings) == 0
47+
self.assertTrue(result.is_valid())
48+
self.assertEqual(len(result.errors), 0)
49+
self.assertEqual(len(result.warnings), 0)
4950

5051
def test_invalid_when_errors_present(self):
5152
result = ValidationResult()
5253
result.add_error("Test error")
53-
assert not result.is_valid()
54-
assert len(result.errors) == 1
54+
self.assertFalse(result.is_valid())
55+
self.assertEqual(len(result.errors), 1)
5556

5657
def test_can_add_warnings_without_becoming_invalid(self):
5758
result = ValidationResult()
5859
result.add_warning("Test warning")
59-
assert result.is_valid()
60-
assert len(result.warnings) == 1
60+
self.assertTrue(result.is_valid())
61+
self.assertEqual(len(result.warnings), 1)
62+
63+
def test_can_add_infos(self):
64+
result = ValidationResult()
65+
result.add_info("Test info")
66+
self.assertTrue(result.is_valid())
67+
self.assertEqual(len(result.infos), 1)
6168

6269
def test_multiple_errors_and_warnings(self):
6370
result = ValidationResult()
6471
result.add_error("Error 1")
6572
result.add_error("Error 2")
6673
result.add_warning("Warning 1")
67-
assert not result.is_valid()
68-
assert len(result.errors) == 2
69-
assert len(result.warnings) == 1
74+
self.assertFalse(result.is_valid())
75+
self.assertEqual(len(result.errors), 2)
76+
self.assertEqual(len(result.warnings), 1)
7077

7178

72-
class TestDryRunReporter:
79+
class TestDryRunReporter(unittest.TestCase):
7380

7481
@patch("pysonar_scanner.dry_run_reporter.logging")
7582
def test_report_configuration_logs_all_sections(self, mock_logging):
@@ -87,90 +94,109 @@ def test_report_configuration_logs_all_sections(self, mock_logging):
8794

8895
logged_messages = [str(c) for c in mock_logging.info.call_args_list]
8996
joined = " ".join(logged_messages)
90-
assert "DRY RUN MODE - Configuration Report" in joined
91-
assert "my-project" in joined
92-
assert "My Project" in joined
93-
assert "my-org" in joined
94-
assert "src" in joined
95-
assert "tests" in joined
96-
assert "coverage.xml" in joined
97-
assert "https://sonarqube.example.com" in joined
97+
self.assertIn("DRY RUN MODE - Configuration Report", joined)
98+
self.assertIn("my-project", joined)
99+
self.assertIn("My Project", joined)
100+
self.assertIn("my-org", joined)
101+
self.assertIn("src", joined)
102+
self.assertIn("tests", joined)
103+
self.assertIn("coverage.xml", joined)
104+
self.assertIn("https://sonarqube.example.com", joined)
98105

99106
@patch("pysonar_scanner.dry_run_reporter.logging")
100107
def test_report_configuration_shows_na_for_missing_values(self, mock_logging):
101-
config = {}
102-
103-
DryRunReporter.report_configuration(config)
108+
DryRunReporter.report_configuration({})
104109

105110
logged_messages = [str(c) for c in mock_logging.info.call_args_list]
106111
joined = " ".join(logged_messages)
107-
assert "N/A" in joined
112+
self.assertIn("N/A", joined)
108113

109114
@patch("pysonar_scanner.dry_run_reporter.logging")
110115
def test_report_validation_results_valid(self, mock_logging):
111116
result = ValidationResult()
112117
exit_code = DryRunReporter.report_validation_results(result)
113118

114-
assert exit_code == 0
119+
self.assertEqual(exit_code, 0)
115120
logged_messages = [str(c) for c in mock_logging.info.call_args_list]
116121
joined = " ".join(logged_messages)
117-
assert "PASSED" in joined
122+
self.assertIn("PASSED", joined)
123+
124+
@patch("pysonar_scanner.dry_run_reporter.logging")
125+
def test_report_validation_results_valid_with_infos_and_warnings(self, mock_logging):
126+
result = ValidationResult()
127+
result.add_info("Coverage report check passed: coverage.xml")
128+
result.add_warning("No tests directory specified")
129+
exit_code = DryRunReporter.report_validation_results(result)
130+
131+
self.assertEqual(exit_code, 0)
132+
logged_messages = [str(c) for c in mock_logging.info.call_args_list]
133+
self.assertIn("PASSED", " ".join(logged_messages))
134+
mock_logging.warning.assert_called()
118135

119136
@patch("pysonar_scanner.dry_run_reporter.logging")
120137
def test_report_validation_results_invalid(self, mock_logging):
121138
result = ValidationResult()
122139
result.add_error("Coverage file not found")
140+
result.add_warning("Unexpected root element")
123141
exit_code = DryRunReporter.report_validation_results(result)
124142

125-
assert exit_code == 1
143+
self.assertEqual(exit_code, 1)
126144
mock_logging.warning.assert_called()
127145
mock_logging.error.assert_called()
128146

129147
def test_format_key_handles_camel_case(self):
130-
assert DryRunReporter._format_key("sonar.projectKey") == "Project Key"
131-
assert DryRunReporter._format_key("sonar.projectName") == "Project Name"
148+
self.assertEqual(DryRunReporter._format_key("sonar.projectKey"), "Project Key")
149+
self.assertEqual(DryRunReporter._format_key("sonar.projectName"), "Project Name")
132150

133151
def test_format_key_handles_dotted_paths(self):
134-
assert DryRunReporter._format_key("sonar.host.url") == "Host Url"
135-
assert DryRunReporter._format_key("sonar.python.coverage.reportPaths") == "Python Coverage Report Paths"
152+
self.assertEqual(DryRunReporter._format_key("sonar.host.url"), "Host Url")
153+
self.assertEqual(
154+
DryRunReporter._format_key("sonar.python.coverage.reportPaths"), "Python Coverage Report Paths"
155+
)
136156

137157
def test_format_key_handles_simple_keys(self):
138-
assert DryRunReporter._format_key("sonar.sources") == "Sources"
139-
assert DryRunReporter._format_key("sonar.organization") == "Organization"
158+
self.assertEqual(DryRunReporter._format_key("sonar.sources"), "Sources")
159+
self.assertEqual(DryRunReporter._format_key("sonar.organization"), "Organization")
140160

141161

142162
class TestCoverageReportValidator(pyfakefs.TestCase):
143163

144164
def setUp(self):
145165
self.setUpPyfakefs()
146166

147-
def test_validate_coverage_reports_no_paths(self):
167+
def test_validate_no_paths(self):
148168
result = CoverageReportValidator.validate_coverage_reports(None, ".")
149169

150-
assert result.is_valid()
151-
assert len(result.warnings) == 1
152-
assert "No coverage report paths specified" in result.warnings[0]
170+
self.assertTrue(result.is_valid())
171+
self.assertEqual(len(result.warnings), 1)
172+
self.assertIn("No coverage report paths specified", result.warnings[0])
173+
174+
def test_validate_empty_string_paths(self):
175+
result = CoverageReportValidator.validate_coverage_reports("", ".")
176+
177+
self.assertTrue(result.is_valid())
178+
self.assertEqual(len(result.warnings), 1)
179+
self.assertIn("No coverage report paths specified", result.warnings[0])
153180

154181
def test_validate_single_report_file_not_found(self):
155182
self.fs.create_dir("/project")
156183

157184
result = CoverageReportValidator.validate_coverage_reports("coverage.xml", "/project")
158185

159-
assert not result.is_valid()
160-
assert len(result.errors) == 1
161-
assert "not found" in result.errors[0]
186+
self.assertFalse(result.is_valid())
187+
self.assertEqual(len(result.errors), 1)
188+
self.assertIn("not found", result.errors[0])
162189

163-
@patch("pysonar_scanner.dry_run_reporter.logging")
164-
def test_validate_single_report_valid_cobertura(self, mock_logging):
190+
def test_validate_single_report_valid_cobertura(self):
165191
self.fs.create_dir("/project")
166192
self.fs.create_file("/project/coverage.xml", contents='<?xml version="1.0"?>\n<coverage></coverage>')
167193

168194
result = CoverageReportValidator.validate_coverage_reports("coverage.xml", "/project")
169195

170-
assert result.is_valid()
171-
assert len(result.warnings) == 0
172-
assert len(result.infos) == 1
173-
assert "Coverage report check passed" in result.infos[0]
196+
self.assertTrue(result.is_valid())
197+
self.assertEqual(len(result.warnings), 0)
198+
self.assertEqual(len(result.infos), 1)
199+
self.assertIn("Coverage report check passed", result.infos[0])
174200

175201
def test_validate_multiple_coverage_reports(self):
176202
self.fs.create_dir("/project")
@@ -179,46 +205,66 @@ def test_validate_multiple_coverage_reports(self):
179205

180206
result = CoverageReportValidator.validate_coverage_reports("coverage1.xml, coverage2.xml", "/project")
181207

182-
assert result.is_valid()
208+
self.assertTrue(result.is_valid())
183209

184210
def test_validate_report_not_a_file(self):
185211
self.fs.create_dir("/project")
186212
self.fs.create_dir("/project/coverage.xml")
187213

188214
result = CoverageReportValidator.validate_coverage_reports("coverage.xml", "/project")
189215

190-
assert not result.is_valid()
191-
assert "not a file" in result.errors[0]
216+
self.assertFalse(result.is_valid())
217+
self.assertIn("not a file", result.errors[0])
192218

193219
def test_validate_report_invalid_xml(self):
194220
self.fs.create_dir("/project")
195221
self.fs.create_file("/project/coverage.xml", contents="not valid xml")
196222

197223
result = CoverageReportValidator.validate_coverage_reports("coverage.xml", "/project")
198224

199-
assert not result.is_valid()
200-
assert "not valid XML" in result.errors[0]
225+
self.assertFalse(result.is_valid())
226+
self.assertIn("not valid XML", result.errors[0])
201227

202228
def test_validate_report_wrong_root_element(self):
203229
self.fs.create_dir("/project")
204230
self.fs.create_file("/project/coverage.xml", contents='<?xml version="1.0"?>\n<report></report>')
205231

206232
result = CoverageReportValidator.validate_coverage_reports("coverage.xml", "/project")
207233

208-
assert result.is_valid()
209-
assert len(result.warnings) == 1
210-
assert "report" in result.warnings[0]
211-
assert "expected 'coverage'" in result.warnings[0]
234+
self.assertTrue(result.is_valid())
235+
self.assertEqual(len(result.warnings), 1)
236+
self.assertIn("report", result.warnings[0])
237+
self.assertIn("expected 'coverage'", result.warnings[0])
238+
239+
def test_validate_report_permission_denied(self):
240+
self.fs.create_dir("/project")
241+
self.fs.create_file("/project/coverage.xml", contents='<?xml version="1.0"?>\n<coverage></coverage>')
242+
self.fs.chmod("/project/coverage.xml", mode=0o000, force_unix_mode=True)
243+
244+
result = CoverageReportValidator.validate_coverage_reports("coverage.xml", "/project")
245+
246+
self.assertFalse(result.is_valid())
247+
self.assertIn("permission denied", result.errors[0])
248+
249+
def test_validate_report_binary_content(self):
250+
self.fs.create_dir("/project")
251+
self.fs.create_file("/project/coverage.xml", contents=b"\x80\x81\x82\x83\xff\xfe")
252+
253+
result = CoverageReportValidator.validate_coverage_reports("coverage.xml", "/project")
254+
255+
has_unicode_warning = any("binary format" in w for w in result.warnings)
256+
has_xml_error = any("not valid XML" in e for e in result.errors)
257+
self.assertTrue(has_unicode_warning or has_xml_error)
212258

213259
def test_validate_mixed_valid_and_missing_reports(self):
214260
self.fs.create_dir("/project")
215261
self.fs.create_file("/project/exists.xml", contents='<?xml version="1.0"?>\n<coverage></coverage>')
216262

217263
result = CoverageReportValidator.validate_coverage_reports("exists.xml, missing.xml", "/project")
218264

219-
assert not result.is_valid()
220-
assert len(result.errors) == 1
221-
assert "missing.xml" in result.errors[0]
265+
self.assertFalse(result.is_valid())
266+
self.assertEqual(len(result.errors), 1)
267+
self.assertIn("missing.xml", result.errors[0])
222268

223269

224270
class TestRunDryRun(pyfakefs.TestCase):
@@ -236,7 +282,7 @@ def test_run_dry_run_no_coverage_reports(self, mock_logging):
236282

237283
exit_code = run_dry_run(config)
238284

239-
assert exit_code == 0
285+
self.assertEqual(exit_code, 0)
240286

241287
@patch("pysonar_scanner.__main__.logging")
242288
def test_run_dry_run_with_valid_coverage_reports(self, mock_logging):
@@ -250,7 +296,7 @@ def test_run_dry_run_with_valid_coverage_reports(self, mock_logging):
250296

251297
exit_code = run_dry_run(config)
252298

253-
assert exit_code == 0
299+
self.assertEqual(exit_code, 0)
254300

255301
@patch("pysonar_scanner.__main__.logging")
256302
def test_run_dry_run_with_missing_coverage_reports(self, mock_logging):
@@ -263,7 +309,7 @@ def test_run_dry_run_with_missing_coverage_reports(self, mock_logging):
263309

264310
exit_code = run_dry_run(config)
265311

266-
assert exit_code == 1
312+
self.assertEqual(exit_code, 1)
267313

268314
@patch("pysonar_scanner.__main__.logging")
269315
def test_run_dry_run_logs_dry_run_mode(self, mock_logging):

0 commit comments

Comments
 (0)