1+ import pathlib
2+ from unittest .mock import MagicMock
3+
14import pytest
25
6+ from codecov_cli .helpers .folder_searcher import globs_to_regex
37from codecov_cli .plugins .pycoverage import Pycoverage
48
59
@@ -15,6 +19,18 @@ def xml_subprocess_side_effect(*args, cwd, **kwargs):
1519 )
1620
1721
22+ @pytest .fixture
23+ def json_subprocess_mock (mocker ):
24+ def json_subprocess_side_effect (* args , cwd , ** kwargs ):
25+ (cwd / "coverage.json" ).touch ()
26+ return mocker .MagicMock (stdout = b"Wrote JSON report to coverage.json\n " )
27+
28+ yield mocker .patch (
29+ "codecov_cli.plugins.pycoverage.subprocess.run" ,
30+ side_effect = json_subprocess_side_effect ,
31+ )
32+
33+
1834@pytest .fixture
1935def combine_subprocess_mock (mocker ):
2036 def combine_subprocess_side_effect (first_arg , * args , cwd , ** kwargs ):
@@ -40,11 +56,49 @@ def generate_XML_report_side_effect(working_dir, *args, **kwargs):
4056 )
4157
4258
43- class TestPycoverage (object ):
59+ class TestPycoveragePathToCoverage (object ):
60+ def test_path_from_config (self , tmp_path , mocker ):
61+ (tmp_path / ".coverage" ).touch ()
62+ config = {
63+ "project_root" : tmp_path ,
64+ "path_to_coverage_file" : pathlib .Path .joinpath (tmp_path , ".coverage" ),
65+ }
66+ plugin = Pycoverage (config )
67+
68+ mock_search_path = mocker .patch ("codecov_cli.plugins.pycoverage.search_files" )
69+ path = plugin ._get_path_to_coverage ()
70+ assert path == pathlib .Path .joinpath (tmp_path , ".coverage" )
71+ assert path .parent == tmp_path
72+ mock_search_path .assert_not_called ()
73+
74+ def test_path_from_config_fallback (self , tmp_path , mocker ):
75+ config = {
76+ "project_root" : tmp_path ,
77+ "path_to_coverage_file" : pathlib .Path .joinpath (tmp_path , ".coverage" ),
78+ }
79+ plugin = Pycoverage (config )
80+
81+ mock_search_path_return = MagicMock ()
82+ mock_search_path = mocker .patch (
83+ "codecov_cli.plugins.pycoverage.search_files" ,
84+ return_value = mock_search_path_return ,
85+ )
86+ path = plugin ._get_path_to_coverage ()
87+ mock_search_path .assert_called_with (
88+ tmp_path ,
89+ [],
90+ filename_include_regex = globs_to_regex ([".coverage" , ".coverage.*" ]),
91+ filename_exclude_regex = None ,
92+ )
93+ assert path == mock_search_path_return .__next__ .return_value
94+
95+
96+ class TestPycoverageXMLReportGeneration (object ):
4497 def test_coverage_combine_called_if_coverage_data_exist (
4598 self , tmp_path , mocker , combine_subprocess_mock
4699 ):
47- Pycoverage (tmp_path )._generate_XML_report (tmp_path )
100+ config = {"project_root" : tmp_path }
101+ Pycoverage (config )._generate_XML_report (tmp_path )
48102 assert not combine_subprocess_mock .called
49103
50104 combine_subprocess_mock .reset_mock ()
@@ -54,7 +108,7 @@ def test_coverage_combine_called_if_coverage_data_exist(
54108 p = tmp_path / name
55109 p .touch ()
56110
57- Pycoverage (tmp_path )._generate_XML_report (tmp_path )
111+ Pycoverage (config )._generate_XML_report (tmp_path )
58112
59113 combine_subprocess_mock .assert_any_call (
60114 ["coverage" , "combine" , "-a" ], cwd = tmp_path
@@ -64,29 +118,56 @@ def test_coverage_combine_called_if_coverage_data_exist(
64118 def test_xml_reports_generated_if_coverage_file_exists (
65119 self , tmp_path , mocker , xml_subprocess_mock
66120 ):
67-
68- Pycoverage (tmp_path )._generate_XML_report (tmp_path )
121+ config = { "project_root" : tmp_path }
122+ Pycoverage (config )._generate_XML_report (tmp_path )
69123 xml_subprocess_mock .assert_not_called ()
70124
125+ config = {"project_root" : tmp_path }
71126 (tmp_path / ".coverage" ).touch ()
72- Pycoverage (tmp_path )._generate_XML_report (tmp_path )
127+ Pycoverage (config )._generate_XML_report (tmp_path )
73128 xml_subprocess_mock .assert_called_with (
74129 ["coverage" , "xml" , "-i" ], cwd = tmp_path , capture_output = True
75130 )
76131 assert (tmp_path / ".coverage" ).exists ()
77132
78- def test_run_preparation_creates_nothing_if_nothing (
79- self , mocked_generator , tmp_path , mocker
133+
134+ class TestPycoverageJSONReportGeneration (object ):
135+ def test_report_not_generated_if_coverage_not_there (
136+ self , tmp_path , mocker , json_subprocess_mock
80137 ):
81- Pycoverage ( tmp_path ). run_preparation ( None )
82- assert not ( tmp_path / "coverage.xml" ). exists ( )
83- assert not mocked_generator . called
138+ config = { "project_root" : tmp_path }
139+ Pycoverage ( config ). _generate_JSON_report ( tmp_path )
140+ json_subprocess_mock . assert_not_called ()
84141
142+ def test_reports_generated_if_coverage_file_exists (
143+ self , tmp_path , mocker , json_subprocess_mock
144+ ):
145+ config = {"project_root" : tmp_path }
146+ (tmp_path / ".coverage" ).touch ()
147+ Pycoverage (config )._generate_JSON_report (tmp_path )
148+ json_subprocess_mock .assert_called_with (
149+ ["coverage" , "json" , "--show-contexts" ], cwd = tmp_path , capture_output = True
150+ )
151+ assert (tmp_path / ".coverage" ).exists ()
152+
153+ def test_reports_generated_with_no_context_if_option (
154+ self , tmp_path , mocker , json_subprocess_mock
155+ ):
156+ config = {"project_root" : tmp_path , "include_contexts" : False }
157+ (tmp_path / ".coverage" ).touch ()
158+ Pycoverage (config )._generate_JSON_report (tmp_path )
159+ json_subprocess_mock .assert_called_with (
160+ ["coverage" , "json" ], cwd = tmp_path , capture_output = True
161+ )
162+
163+
164+ class TestPycoverageRunPreparation (object ):
85165 def test_run_preparation_creates_reports_in_root_dir (
86166 self , mocked_generator , tmp_path , mocker
87167 ):
88168 (tmp_path / ".coverage" ).touch ()
89- Pycoverage (tmp_path ).run_preparation (None )
169+ config = {"project_root" : tmp_path }
170+ Pycoverage (config ).run_preparation (None )
90171 assert (tmp_path / "coverage.xml" ).exists ()
91172 mocked_generator .assert_called_with (tmp_path )
92173
@@ -95,7 +176,8 @@ def test_run_preparation_creates_reports_in_sub_dirs(
95176 ):
96177 (tmp_path / "sub" ).mkdir ()
97178 (tmp_path / "sub" / ".coverage" ).touch ()
98- Pycoverage (tmp_path ).run_preparation (None )
179+ config = {"project_root" : tmp_path }
180+ Pycoverage (config ).run_preparation (None )
99181
100182 assert (tmp_path / "sub" / "coverage.xml" ).exists ()
101183 mocked_generator .assert_called_with (tmp_path / "sub" )
@@ -104,5 +186,14 @@ def test_aborts_plugin_if_coverage_is_not_installed(
104186 self , tmp_path , mocker , mocked_generator
105187 ):
106188 mocker .patch ("codecov_cli.plugins.pycoverage.shutil.which" , return_value = None )
107- Pycoverage (tmp_path ).run_preparation (None )
189+ config = {"project_root" : tmp_path }
190+ Pycoverage (config ).run_preparation (None )
191+ assert not mocked_generator .called
192+
193+ def test_run_preparation_creates_nothing_if_nothing (
194+ self , mocked_generator , tmp_path , mocker
195+ ):
196+ config = {"project_root" : tmp_path }
197+ Pycoverage (config ).run_preparation (None )
198+ assert not (tmp_path / "coverage.xml" ).exists ()
108199 assert not mocked_generator .called
0 commit comments