Coverage for tests / test_xml.py: 100.000%

309 statements  

« prev     ^ index     » next       coverage.py v7.12.1a0.dev1, created at 2025-11-30 17:57 +0000

1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 

2# For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt 

3 

4"""Tests for XML reports from coverage.py.""" 

5 

6from __future__ import annotations 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

7 

8import os 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

9import os.path 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

10import re 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

11 

12from typing import Any 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

13from collections.abc import Iterable 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

14from xml.etree import ElementTree 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

15 

16import pytest 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

17 

18import coverage 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

19from coverage import Coverage, env 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

20from coverage.exceptions import NoDataError 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

21from coverage.files import abs_file 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

22from coverage.misc import import_local_file 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

23 

24from tests.coveragetest import CoverageTest 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

25from tests.goldtest import compare, gold_path 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

26from tests.helpers import assert_coverage_warnings, change_dir 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

27 

28 

29class XmlTestHelpers(CoverageTest): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

30 """Methods to use from XML tests.""" 

31 

32 def run_doit(self) -> Coverage: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

33 """Construct a simple sub-package.""" 

34 self.make_file("sub/__init__.py") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

35 self.make_file("sub/doit.py", "print('doit!')") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

36 self.make_file("main.py", "import sub.doit") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

37 cov = coverage.Coverage(source=["."]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

38 self.start_import_stop(cov, "main") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

39 return cov 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

40 

41 def make_tree(self, width: int, depth: int, curdir: str = ".") -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

42 """Make a tree of packages. 

43 

44 Makes `width` directories, named d0 .. d{width-1}. Each directory has 

45 __init__.py, and `width` files, named f0.py .. f{width-1}.py. Each 

46 directory also has `width` sub-directories, in the same fashion, until 

47 a depth of `depth` is reached. 

48 

49 """ 

50 if depth == 0: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

51 return 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

52 

53 def here(p: str) -> str: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

54 """A path for `p` in our currently interesting directory.""" 

55 return os.path.join(curdir, p) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

56 

57 for i in range(width): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

58 next_dir = here(f"d{i}") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

59 self.make_tree(width, depth - 1, next_dir) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

60 if curdir != ".": 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

61 self.make_file(here("__init__.py"), "") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

62 for i in range(width): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

63 filename = here(f"f{i}.py") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

64 self.make_file(filename, f"# {filename}\n") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

65 

66 def assert_source( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

67 self, 

68 xmldom: ElementTree.Element | ElementTree.ElementTree, 

69 src: str, 

70 ) -> None: 

71 """Assert that the XML has a <source> element with `src`.""" 

72 src = abs_file(src) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

73 elts = xmldom.findall(".//sources/source") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

74 assert any(elt.text == src for elt in elts) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

75 

76 

77class XmlTestHelpersTest(XmlTestHelpers, CoverageTest): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

78 """Tests of methods in XmlTestHelpers.""" 

79 

80 run_in_temp_dir = False 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

81 

82 def test_assert_source(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

83 dom = ElementTree.fromstring( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

84 """\ 

85 <doc> 

86 <src>foo</src> 

87 <sources> 

88 <source>{cwd}something</source> 

89 <source>{cwd}another</source> 

90 </sources> 

91 </doc> 

92 """.format(cwd=abs_file(".") + os.sep) 

93 ) 

94 

95 self.assert_source(dom, "something") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

96 self.assert_source(dom, "another") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

97 

98 with pytest.raises(AssertionError): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

99 self.assert_source(dom, "hello") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

100 with pytest.raises(AssertionError): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

101 self.assert_source(dom, "foo") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

102 with pytest.raises(AssertionError): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

103 self.assert_source(dom, "thing") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

104 

105 

106class XmlReportTest(XmlTestHelpers, CoverageTest): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

107 """Tests of the XML reports from coverage.py.""" 

108 

109 def make_mycode_data(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

110 """Pretend that we ran mycode.py, so we can report on it.""" 

111 self.make_file("mycode.py", "print('hello')\n") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

112 self.make_data_file(lines={abs_file("mycode.py"): [1]}) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

113 

114 def run_xml_report(self, **kwargs: Any) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

115 """Run xml_report()""" 

116 cov = coverage.Coverage() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

117 cov.load() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

118 cov.xml_report(**kwargs) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

119 

120 def test_default_file_placement(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

121 self.make_mycode_data() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

122 self.run_xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

123 self.assert_exists("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

124 assert self.stdout() == "" 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

125 

126 def test_argument_affects_xml_placement(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

127 self.make_mycode_data() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

128 cov = coverage.Coverage(messages=True) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

129 cov.load() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

130 cov.xml_report(outfile="put_it_there.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

131 assert self.stdout() == "Wrote XML report to put_it_there.xml\n" 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

132 self.assert_doesnt_exist("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

133 self.assert_exists("put_it_there.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

134 

135 def test_output_directory_does_not_exist(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

136 self.make_mycode_data() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

137 self.run_xml_report(outfile="nonexistent/put_it_there.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

138 self.assert_doesnt_exist("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

139 self.assert_doesnt_exist("put_it_there.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

140 self.assert_exists("nonexistent/put_it_there.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

141 

142 def test_config_affects_xml_placement(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

143 self.make_mycode_data() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

144 self.make_file(".coveragerc", "[xml]\noutput = xml.out\n") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

145 self.run_xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

146 self.assert_doesnt_exist("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

147 self.assert_exists("xml.out") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

148 

149 def test_no_data(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

150 # https://github.com/coveragepy/coveragepy/issues/210 

151 with pytest.raises(NoDataError, match="No data to report."): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

152 self.run_xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

153 self.assert_doesnt_exist("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

154 self.assert_doesnt_exist(".coverage") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

155 

156 def test_no_source(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

157 # Written while investigating a bug, might as well keep it. 

158 # https://github.com/coveragepy/coveragepy/issues/208 

159 self.make_file("innocuous.py", "a = 4") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

160 cov = coverage.Coverage() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

161 self.start_import_stop(cov, "innocuous") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

162 os.remove("innocuous.py") 1EaFbuGcHdWvIeJf2wKgLhXxMiNjyOkPlYzQmRn4ASoTpZBUqVr0CstD

163 with pytest.warns(Warning) as warns: 1EaFbuGcHdWvIeJf2wKgLhXxMiNjyOkPlYzQmRn4ASoTpZBUqVr0CstD

164 cov.xml_report(ignore_errors=True) 1EaFbuGcHdWvIeJf2wKgLhXxMiNjyOkPlYzQmRn4ASoTpZBUqVr0CstD

165 assert_coverage_warnings( 1EaFbuGcHdWvIeJf2wKgLhXxMiNjyOkPlYzQmRn4ASoTpZBUqVr0CstD

166 warns, 

167 re.compile(r"Couldn't parse '.*innocuous.py'. \(couldnt-parse\)"), 

168 ) 

169 self.assert_exists("coverage.xml") 1EaFbuGcHdWvIeJf2wKgLhXxMiNjyOkPlYzQmRn4ASoTpZBUqVr0CstD

170 

171 def test_filename_format_showing_everything(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

172 cov = self.run_doit() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

173 cov.xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

174 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

175 elts = dom.findall(".//class[@name='doit.py']") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

176 assert len(elts) == 1 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

177 assert elts[0].get("filename") == "sub/doit.py" 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

178 

179 def test_filename_format_including_filename(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

180 cov = self.run_doit() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

181 cov.xml_report(["sub/doit.py"]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

182 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

183 elts = dom.findall(".//class[@name='doit.py']") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

184 assert len(elts) == 1 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

185 assert elts[0].get("filename") == "sub/doit.py" 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

186 

187 def test_filename_format_including_module(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

188 cov = self.run_doit() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

189 import sub.doit # pylint: disable=import-error 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

190 

191 cov.xml_report([sub.doit]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

192 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

193 elts = dom.findall(".//class[@name='doit.py']") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

194 assert len(elts) == 1 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

195 assert elts[0].get("filename") == "sub/doit.py" 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

196 

197 def test_reporting_on_nothing(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

198 # Used to raise a zero division error: 

199 # https://github.com/coveragepy/coveragepy/issues/250 

200 self.make_file("empty.py", "") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

201 cov = coverage.Coverage() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

202 empty = self.start_import_stop(cov, "empty") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

203 cov.xml_report([empty]) 1EaFb1uGcHdWvIeJfwKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

204 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJfwKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

205 elts = dom.findall(".//class[@name='empty.py']") 1EaFb1uGcHdWvIeJfwKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

206 assert len(elts) == 1 1EaFb1uGcHdWvIeJfwKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

207 assert elts[0].get("filename") == "empty.py" 1EaFb1uGcHdWvIeJfwKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

208 assert elts[0].get("line-rate") == "1" 1EaFb1uGcHdWvIeJfwKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

209 

210 def test_empty_file_is_100_not_0(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

211 # https://github.com/coveragepy/coveragepy/issues/345 

212 cov = self.run_doit() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

213 cov.xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

214 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

215 elts = dom.findall(".//class[@name='__init__.py']") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

216 assert len(elts) == 1 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

217 assert elts[0].get("line-rate") == "1" 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

218 

219 def test_empty_file_is_skipped(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

220 cov = self.run_doit() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

221 cov.xml_report(skip_empty=True) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

222 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

223 elts = dom.findall(".//class[@name='__init__.py']") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

224 assert len(elts) == 0 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

225 

226 def test_curdir_source(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

227 # With no source= option, the XML report should explain that the source 

228 # is in the current directory. 

229 cov = self.run_doit() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

230 cov.xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

231 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

232 self.assert_source(dom, ".") # type: ignore[arg-type] 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

233 sources = dom.findall(".//source") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

234 assert len(sources) == 1 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

235 

236 def test_deep_source(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

237 # When using source=, the XML report needs to mention those directories 

238 # in the <source> elements. 

239 # https://github.com/coveragepy/coveragepy/issues/439 

240 self.make_file("src/main/foo.py", "a = 1") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

241 self.make_file("also/over/there/bar.py", "b = 2") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

242 

243 cov = coverage.Coverage(source=["src/main", "also/over/there", "not/really"]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

244 with cov.collect(): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

245 mod_foo = import_local_file("foo", "src/main/foo.py") 1abucdvefwghxijyklzmnAopBqrCstD

246 mod_bar = import_local_file("bar", "also/over/there/bar.py") 1abucdvefwghxijyklzmnAopBqrCstD

247 

248 with pytest.warns(Warning) as warns: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

249 cov.xml_report([mod_foo, mod_bar]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

250 assert_coverage_warnings( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

251 warns, 

252 "Module not/really was never imported. (module-not-imported)", 

253 ) 

254 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

255 

256 self.assert_source(dom, "src/main") # type: ignore[arg-type] 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

257 self.assert_source(dom, "also/over/there") # type: ignore[arg-type] 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

258 sources = dom.findall(".//source") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

259 assert len(sources) == 2 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

260 

261 foo_class = dom.findall(".//class[@name='foo.py']") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

262 assert len(foo_class) == 1 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

263 assert foo_class[0].attrib == { 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

264 "branch-rate": "0", 

265 "complexity": "0", 

266 "filename": "foo.py", 

267 "line-rate": "1", 

268 "name": "foo.py", 

269 } 

270 

271 bar_class = dom.findall(".//class[@name='bar.py']") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

272 assert len(bar_class) == 1 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

273 assert bar_class[0].attrib == { 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRnASoTpZBUqVr0CstD

274 "branch-rate": "0", 

275 "complexity": "0", 

276 "filename": "bar.py", 

277 "line-rate": "1", 

278 "name": "bar.py", 

279 } 

280 

281 def test_nonascii_directory(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

282 # https://github.com/coveragepy/coveragepy/issues/573 

283 self.make_file("테스트/program.py", "a = 1") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

284 with change_dir("테스트"): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

285 cov = coverage.Coverage() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

286 self.start_import_stop(cov, "program") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

287 cov.xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNjyOkPlYzQmRn4ASoTpZBUqVr0CstD

288 

289 def test_accented_dot_py(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

290 # Make a file with a non-ascii character in the filename. 

291 self.make_file("h\xe2t.py", "print('accented')") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

292 self.make_data_file(lines={abs_file("h\xe2t.py"): [1]}) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

293 cov = coverage.Coverage() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

294 cov.load() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

295 cov.xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

296 # The XML report is always UTF8-encoded. 

297 with open("coverage.xml", "rb") as xmlf: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

298 xml = xmlf.read() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

299 assert ' filename="h\xe2t.py"'.encode() in xml 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

300 assert ' name="h\xe2t.py"'.encode() in xml 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

301 

302 def test_accented_directory(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

303 # Make a file with a non-ascii character in the directory name. 

304 self.make_file("\xe2/accented.py", "print('accented')") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

305 self.make_data_file(lines={abs_file("\xe2/accented.py"): [1]}) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

306 

307 # The XML report is always UTF8-encoded. 

308 cov = coverage.Coverage() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

309 cov.load() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

310 cov.xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

311 with open("coverage.xml", "rb") as xmlf: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

312 xml = xmlf.read() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

313 assert b' filename="\xc3\xa2/accented.py"' in xml 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

314 assert b' name="accented.py"' in xml 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

315 

316 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

317 elts = dom.findall(".//package[@name='â']") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

318 assert len(elts) == 1 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

319 assert elts[0].attrib == { 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

320 "branch-rate": "0", 

321 "complexity": "0", 

322 "line-rate": "1", 

323 "name": "â", 

324 } 

325 

326 def test_no_duplicate_packages(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

327 self.make_file( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

328 "namespace/package/__init__.py", 

329 "from . import sample; from . import test; from .subpackage import test", 

330 ) 

331 self.make_file("namespace/package/sample.py", "print('package.sample')") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

332 self.make_file("namespace/package/test.py", "print('package.test')") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

333 self.make_file("namespace/package/subpackage/test.py", "print('package.subpackage.test')") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

334 

335 # no source path passed to coverage! 

336 # problem occurs when they are dynamically generated during xml report 

337 cov = coverage.Coverage() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

338 with cov.collect(): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

339 import_local_file("namespace.package", "namespace/package/__init__.py") 1abucdvefwghxijyklzmnAopBqrCstD

340 

341 cov.xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

342 

343 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

344 

345 # only two packages should be present 

346 packages = dom.findall(".//package") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

347 assert len(packages) == 2 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

348 

349 # one of them is namespace.package 

350 named_package = dom.findall(".//package[@name='namespace.package']") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

351 assert len(named_package) == 1 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

352 

353 # the other one namespace.package.subpackage 

354 named_sub_package = dom.findall(".//package[@name='namespace.package.subpackage']") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

355 assert len(named_sub_package) == 1 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

356 

357 def test_bug_1709(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

358 # https://github.com/coveragepy/coveragepy/issues/1709 

359 self.make_file("main.py", "import x1y, x01y, x001y") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

360 self.make_file("x1y.py", "print('x1y')") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

361 self.make_file("x01y.py", "print('x01y')") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

362 self.make_file("x001y.py", "print('x001y')") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

363 

364 cov = coverage.Coverage() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

365 self.start_import_stop(cov, "main") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

366 assert self.stdout() == "x1y\nx01y\nx001y\n" 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

367 # This used to raise: 

368 # TypeError: '<' not supported between instances of 'Element' and 'Element' 

369 cov.xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

370 

371 

372def unbackslash(v: Any) -> Any: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

373 """Find strings in `v`, and replace backslashes with slashes throughout.""" 

374 if isinstance(v, (tuple, list)): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

375 return [unbackslash(vv) for vv in v] 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

376 elif isinstance(v, dict): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

377 return {k: unbackslash(vv) for k, vv in v.items()} 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

378 else: 

379 assert isinstance(v, str) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

380 return v.replace("\\", "/") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

381 

382 

383class XmlPackageStructureTest(XmlTestHelpers, CoverageTest): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

384 """Tests about the package structure reported in the coverage.xml file.""" 

385 

386 def package_and_class_tags(self, cov: Coverage) -> Iterable[tuple[str, dict[str, Any]]]: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

387 """Run an XML report on `cov`, and get the package and class tags.""" 

388 cov.xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

389 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

390 for node in dom.iter(): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

391 if node.tag in ["package", "class"]: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

392 yield (node.tag, {a: v for a, v in node.items() if a in ["name", "filename"]}) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

393 

394 def assert_package_and_class_tags(self, cov: Coverage, result: Any) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

395 """Check the XML package and class tags from `cov` match `result`.""" 

396 assert unbackslash(list(self.package_and_class_tags(cov))) == unbackslash(result) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

397 

398 def test_package_names(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

399 self.make_tree(width=1, depth=3) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

400 self.make_file( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

401 "main.py", 

402 """\ 

403 from d0.d0 import f0 

404 """, 

405 ) 

406 cov = coverage.Coverage(source=["."]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

407 self.start_import_stop(cov, "main") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

408 self.assert_package_and_class_tags( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

409 cov, 

410 [ 

411 ("package", {"name": "."}), 

412 ("class", {"filename": "main.py", "name": "main.py"}), 

413 ("package", {"name": "d0"}), 

414 ("class", {"filename": "d0/__init__.py", "name": "__init__.py"}), 

415 ("class", {"filename": "d0/f0.py", "name": "f0.py"}), 

416 ("package", {"name": "d0.d0"}), 

417 ("class", {"filename": "d0/d0/__init__.py", "name": "__init__.py"}), 

418 ("class", {"filename": "d0/d0/f0.py", "name": "f0.py"}), 

419 ], 

420 ) 

421 

422 def test_package_depth_1(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

423 self.make_tree(width=1, depth=4) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

424 self.make_file( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

425 "main.py", 

426 """\ 

427 from d0.d0 import f0 

428 """, 

429 ) 

430 cov = coverage.Coverage(source=["."]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

431 self.start_import_stop(cov, "main") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

432 

433 cov.set_option("xml:package_depth", 1) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

434 self.assert_package_and_class_tags( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

435 cov, 

436 [ 

437 ("package", {"name": "."}), 

438 ("class", {"filename": "main.py", "name": "main.py"}), 

439 ("package", {"name": "d0"}), 

440 ("class", {"filename": "d0/__init__.py", "name": "__init__.py"}), 

441 ("class", {"filename": "d0/d0/__init__.py", "name": "d0/__init__.py"}), 

442 ("class", {"filename": "d0/d0/d0/__init__.py", "name": "d0/d0/__init__.py"}), 

443 ("class", {"filename": "d0/d0/d0/f0.py", "name": "d0/d0/f0.py"}), 

444 ("class", {"filename": "d0/d0/f0.py", "name": "d0/f0.py"}), 

445 ("class", {"filename": "d0/f0.py", "name": "f0.py"}), 

446 ], 

447 ) 

448 

449 def test_package_depth_2(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

450 self.make_tree(width=1, depth=4) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

451 self.make_file( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

452 "main.py", 

453 """\ 

454 from d0.d0 import f0 

455 """, 

456 ) 

457 cov = coverage.Coverage(source=["."]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

458 self.start_import_stop(cov, "main") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

459 

460 cov.set_option("xml:package_depth", 2) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

461 self.assert_package_and_class_tags( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

462 cov, 

463 [ 

464 ("package", {"name": "."}), 

465 ("class", {"filename": "main.py", "name": "main.py"}), 

466 ("package", {"name": "d0"}), 

467 ("class", {"filename": "d0/__init__.py", "name": "__init__.py"}), 

468 ("class", {"filename": "d0/f0.py", "name": "f0.py"}), 

469 ("package", {"name": "d0.d0"}), 

470 ("class", {"filename": "d0/d0/__init__.py", "name": "__init__.py"}), 

471 ("class", {"filename": "d0/d0/d0/__init__.py", "name": "d0/__init__.py"}), 

472 ("class", {"filename": "d0/d0/d0/f0.py", "name": "d0/f0.py"}), 

473 ("class", {"filename": "d0/d0/f0.py", "name": "f0.py"}), 

474 ], 

475 ) 

476 

477 def test_package_depth_3(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

478 self.make_tree(width=1, depth=4) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

479 self.make_file( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

480 "main.py", 

481 """\ 

482 from d0.d0 import f0 

483 """, 

484 ) 

485 cov = coverage.Coverage(source=["."]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

486 self.start_import_stop(cov, "main") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

487 

488 cov.set_option("xml:package_depth", 3) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

489 self.assert_package_and_class_tags( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

490 cov, 

491 [ 

492 ("package", {"name": "."}), 

493 ("class", {"filename": "main.py", "name": "main.py"}), 

494 ("package", {"name": "d0"}), 

495 ("class", {"filename": "d0/__init__.py", "name": "__init__.py"}), 

496 ("class", {"filename": "d0/f0.py", "name": "f0.py"}), 

497 ("package", {"name": "d0.d0"}), 

498 ("class", {"filename": "d0/d0/__init__.py", "name": "__init__.py"}), 

499 ("class", {"filename": "d0/d0/f0.py", "name": "f0.py"}), 

500 ("package", {"name": "d0.d0.d0"}), 

501 ("class", {"filename": "d0/d0/d0/__init__.py", "name": "__init__.py"}), 

502 ("class", {"filename": "d0/d0/d0/f0.py", "name": "f0.py"}), 

503 ], 

504 ) 

505 

506 def test_source_prefix(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

507 # https://github.com/coveragepy/coveragepy/issues/465 

508 # https://github.com/coveragepy/coveragepy/issues/526 

509 self.make_file("src/mod.py", "print(17)") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

510 cov = coverage.Coverage(source=["src"]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

511 self.start_import_stop(cov, "mod", modfile="src/mod.py") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

512 

513 self.assert_package_and_class_tags( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

514 cov, 

515 [ 

516 ("package", {"name": "."}), 

517 ("class", {"filename": "mod.py", "name": "mod.py"}), 

518 ], 

519 ) 

520 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

521 self.assert_source(dom, "src") # type: ignore[arg-type] 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

522 

523 @pytest.mark.parametrize("trail", ["", "/", "\\"]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

524 def test_relative_source(self, trail: str) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

525 if trail == "\\" and not env.WINDOWS: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

526 pytest.skip("trailing backslash is only for Windows") 1EaFbGcHdIeJfKgLhMiNjOkPlQmRn5SoTp6UqVrst

527 self.make_file("src/mod.py", "print(17)") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

528 cov = coverage.Coverage(source=[f"src{trail}"]) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

529 cov.set_option("run:relative_files", True) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

530 self.start_import_stop(cov, "mod", modfile="src/mod.py") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

531 cov.xml_report() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

532 

533 dom = ElementTree.parse("coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

534 elts = dom.findall(".//sources/source") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

535 assert [elt.text for elt in elts] == ["src"] 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

536 

537 

538def compare_xml(expected: str, actual: str, actual_extra: bool = False) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

539 """Specialized compare function for our XML files.""" 

540 source_path = coverage.files.relative_directory().rstrip(r"\/") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

541 

542 scrubs = [ 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

543 (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'), 

544 (r' version="[-.\w]+"', ' version="VERSION"'), 

545 (r"<source>\s*.*?\s*</source>", "<source>%s</source>" % re.escape(source_path)), 

546 (r"/coverage\.readthedocs\.io/?[-.\w/]*", "/coverage.readthedocs.io/VER"), 

547 ] 

548 compare(expected, actual, scrubs=scrubs, actual_extra=actual_extra) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

549 

550 

551class XmlGoldTest(CoverageTest): 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

552 """Tests of XML reporting that use gold files.""" 

553 

554 def test_a_xml_1(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

555 self.make_file( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

556 "a.py", 

557 """\ 

558 if 1 < 2: 

559 # Needed a < to look at HTML entities. 

560 a = 3 

561 else: 

562 a = 4 

563 """, 

564 ) 

565 

566 cov = coverage.Coverage() 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

567 a = self.start_import_stop(cov, "a") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

568 cov.xml_report(a, outfile="coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

569 compare_xml(gold_path("xml/x_xml"), ".", actual_extra=True) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

570 

571 def test_a_xml_2(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

572 self.make_file( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

573 "a.py", 

574 """\ 

575 if 1 < 2: 

576 # Needed a < to look at HTML entities. 

577 a = 3 

578 else: 

579 a = 4 

580 """, 

581 ) 

582 

583 self.make_file( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

584 "run_a_xml_2.ini", 

585 """\ 

586 # Put all the XML output in xml_2 

587 [xml] 

588 output = xml_2/coverage.xml 

589 """, 

590 ) 

591 

592 cov = coverage.Coverage(config_file="run_a_xml_2.ini") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

593 a = self.start_import_stop(cov, "a") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

594 cov.xml_report(a) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

595 compare_xml(gold_path("xml/x_xml"), "xml_2") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

596 

597 def test_y_xml_branch(self) -> None: 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

598 self.make_file( 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

599 "y.py", 

600 """\ 

601 def choice(x): 

602 if x < 2: 

603 return 3 

604 else: 

605 return 4 

606 

607 assert choice(1) == 3 

608 """, 

609 ) 

610 

611 cov = coverage.Coverage(branch=True) 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

612 y = self.start_import_stop(cov, "y") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOk7Pl8Yz9Qm!Rn54A#So$Tp6ZB%Uq'Vr(0C)stD

613 cov.xml_report(y, outfile="y_xml_branch/coverage.xml") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD

614 compare_xml(gold_path("xml/y_xml_branch"), "y_xml_branch") 1EaFb1uGcHdWvIeJf2wKgLhXxMiNj3yOkPlYzQmRn4ASoTpZBUqVr0CstD