def test_styled(self): self.make_file("a.py", """\ if 1 < 2: # Needed a < to look at HTML entities. a = 3 else: a = 4 """) self.make_file("extra.css", "/* Doesn't matter what goes in here, it gets copied. */\n") cov = coverage.Coverage() a = self.start_import_stop(cov, "a") cov.html_report(a, directory="out", extra_css="extra.css") compare_html(gold_path("html/styled"), "out") compare(gold_path("html/styled"), "out", file_pattern="*.css") contains( "out/a_py.html", '<link rel="stylesheet" href="extra.css" type="text/css">', ('<span class="key">if</span> <span class="num">1</span> ' '<span class="op"><</span> <span class="num">2</span>'), (' <span class="nam">a</span> <span class="op">=</span> ' '<span class="num">3</span>'), '<span class="pc_cov">67%</span>' ) contains( "out/index.html", '<link rel="stylesheet" href="extra.css" type="text/css">', '<a href="a_py.html">a.py</a>', '<span class="pc_cov">67%</span>' )
def test_other(self): self.make_file("src/here.py", """\ import other if 1 < 2: h = 3 else: h = 4 """) self.make_file("othersrc/other.py", """\ # A file in another directory. We're checking that it ends up in the # HTML report. print("This is the other src!") """) with change_dir("src"): sys.path.insert(0, "") # pytest sometimes has this, sometimes not!? sys.path.insert(0, "../othersrc") cov = coverage.Coverage(include=["./*", "../othersrc/*"]) self.start_import_stop(cov, "here") cov.html_report(directory="../out") # Different platforms will name the "other" file differently. Rename it for p in glob.glob("out/*_other_py.html"): os.rename(p, "out/blah_blah_other_py.html") compare_html(gold_path("html/other"), "out") contains( "out/index.html", '<a href="here_py.html">here.py</a>', 'other_py.html">', 'other.py</a>', )
def test_bom(self): self.make_file("bom.py", bytes=b"""\ \xef\xbb\xbf# A Python source file in utf-8, with BOM. math = "3\xc3\x974 = 12, \xc3\xb72 = 6\xc2\xb10" import sys if sys.version_info >= (3, 0): assert len(math) == 18 assert len(math.encode('utf-8')) == 21 else: assert len(math) == 21 assert len(math.decode('utf-8')) == 18 """.replace(b"\n", b"\r\n")) # It's important that the source file really have a BOM, which can # get lost, so check that it's really there, and that we have \r\n # line endings. with open("bom.py", "rb") as f: data = f.read() assert data[:3] == b"\xef\xbb\xbf" assert data.count(b"\r\n") == 11 cov = coverage.Coverage() bom = self.start_import_stop(cov, "bom") cov.html_report(bom, directory="out") compare_html(gold_path("html/bom"), "out") contains( "out/bom_py.html", '<span class="str">"3×4 = 12, ÷2 = 6±0"</span>', )
def test_a(self): self.make_file("a.py", """\ if 1 < 2: # Needed a < to look at HTML entities. a = 3 else: a = 4 """) cov = coverage.Coverage() a = self.start_import_stop(cov, "a") cov.html_report(a, directory='out') compare_html(gold_path("html/a"), "out") contains( "out/a_py.html", ('<span class="key">if</span> <span class="num">1</span> ' '<span class="op"><</span> <span class="num">2</span>'), (' <span class="nam">a</span> ' '<span class="op">=</span> <span class="num">3</span>'), '<span class="pc_cov">67%</span>', ) contains( "out/index.html", '<a href="a_py.html">a.py</a>', '<span class="pc_cov">67%</span>', '<td class="right" data-ratio="2 3">67%</td>', )
def test_annotate_dir(self): self.make_multi() cov = coverage.Coverage(source=["."]) self.start_import_stop(cov, "multi") cov.annotate(directory="out_anno_dir") compare(gold_path("annotate/anno_dir"), "out_anno_dir", "*,cover")
def test_multi(self): self.make_multi() cov = coverage.Coverage() self.start_import_stop(cov, "multi") cov.annotate() compare(gold_path("annotate/multi"), ".", "*,cover")
def test_encoding(self): self.make_file("utf8.py", """\ # -*- coding: utf-8 -*- # This comment has an accent: é print("spam eggs") """) cov = coverage.Coverage() self.start_import_stop(cov, "utf8") cov.annotate() compare(gold_path("annotate/encodings"), ".", "*,cover")
def test_omit_4(self): self.make_main_etc() self.make_file("omit4.ini", """\ [report] omit = m2.py """) cov = coverage.Coverage(config_file="omit4.ini", include=["./*"]) self.start_import_stop(cov, "main") cov.html_report(directory="out") compare_html(gold_path("html/omit_4"), "out")
def test_a_xml_1(self): self.make_file("a.py", """\ if 1 < 2: # Needed a < to look at HTML entities. a = 3 else: a = 4 """) cov = coverage.Coverage() a = self.start_import_stop(cov, "a") cov.xml_report(a, outfile="coverage.xml") compare_xml(gold_path("xml/x_xml"), ".", actual_extra=True)
def test_partial(self): self.make_file("partial.py", """\ # partial branches and excluded lines a = 6 while "no peephole".upper(): # t4 break while a: # pragma: no branch break if 0: never_happen() if 1: a = 21 if a == 23: raise AssertionError("Can't") """) self.make_file("partial.ini", """\ [run] branch = True [report] exclude_lines = raise AssertionError """) cov = coverage.Coverage(config_file="partial.ini") partial = self.start_import_stop(cov, "partial") cov.html_report(partial, directory="out") compare_html(gold_path("html/partial"), "out") contains( "out/partial_py.html", '<p id="t4" class="stm par run hide_run">', '<p id="t7" class="stm run hide_run">', # The "if 0" and "if 1" statements are optimized away. '<p id="t10" class="pln">', # The "raise AssertionError" is excluded by regex in the .ini. '<p id="t17" class="exc">', ) contains( "out/index.html", '<a href="partial_py.html">partial.py</a>', ) contains( "out/index.html", '<span class="pc_cov">91%</span>' )
def test_y_xml_branch(self): self.make_file("y.py", """\ def choice(x): if x < 2: return 3 else: return 4 assert choice(1) == 3 """) cov = coverage.Coverage(branch=True) y = self.start_import_stop(cov, "y") cov.xml_report(y, outfile="y_xml_branch/coverage.xml") compare_xml(gold_path("xml/y_xml_branch"), "y_xml_branch")
def test_omit_4(self): self.make_main_etc() self.make_file( "omit4.ini", """\ [report] omit = m2.py """) cov = coverage.Coverage(config_file="omit4.ini", include=["./*"]) cov.start() import main # pragma: nested # pylint: disable=unused-variable, import-error cov.stop() # pragma: nested cov.html_report(directory="out") compare_html("out", gold_path("html/gold_omit_4"))
def test_styled(self): self.make_file( "a.py", """\ if 1 < 2: # Needed a < to look at HTML entities. a = 3 else: a = 4 """) self.make_file( "extra.css", "/* Doesn't matter what goes in here, it gets copied. */") cov = coverage.Coverage() cov.start() import a # pragma: nested # pylint: disable=import-error cov.stop() # pragma: nested cov.html_report(a, directory="out", extra_css="extra.css") compare_html(gold_path("html/gold_styled"), "out") compare(gold_path("html/gold_styled"), "out", size_within=10, file_pattern="*.css") contains("out/a_py.html", '<link rel="stylesheet" href="extra.css" type="text/css">', ('<span class="key">if</span> <span class="num">1</span> ' '<span class="op"><</span> <span class="num">2</span>'), (' <span class="nam">a</span> <span class="op">=</span> ' '<span class="num">3</span>'), '<span class="pc_cov">67%</span>') contains("out/index.html", '<link rel="stylesheet" href="extra.css" type="text/css">', '<a href="a_py.html">a.py</a>', '<span class="pc_cov">67%</span>')
def test_partial(self): self.make_file("partial.py", """\ # partial branches and excluded lines a = 2 while "no peephole".upper(): # t4 break while a: # pragma: no branch break if 0: never_happen() if 13: a = 14 if a == 16: raise ZeroDivisionError("17") """) self.make_file("partial.ini", """\ [run] branch = True [report] exclude_lines = raise ZeroDivisionError """) cov = coverage.Coverage(config_file="partial.ini") partial = self.start_import_stop(cov, "partial") cov.html_report(partial, directory="out/partial") compare_html(gold_path("html/partial"), "out/partial") contains( "out/partial/partial_py.html", '<p id="t4" class="par run show_par">', '<p id="t7" class="run">', # The "if 0" and "if 1" statements are optimized away. '<p id="t10" class="pln">', # The "raise ZeroDivisionError" is excluded by regex in the .ini. '<p id="t17" class="exc show_exc">', ) contains( "out/partial/index.html", '<a href="partial_py.html">partial.py</a>', '<span class="pc_cov">91%</span>' )
def test_y_xml_branch(self): self.make_file( "y.py", """\ def choice(x): if x < 2: return 3 else: return 4 assert choice(1) == 3 """) cov = coverage.Coverage(branch=True) y = self.start_import_stop(cov, "y") cov.xml_report(y, outfile="y_xml_branch/coverage.xml") compare_xml(gold_path("xml/y_xml_branch"), "y_xml_branch")
def test_a_xml_1(self): self.make_file( "a.py", """\ if 1 < 2: # Needed a < to look at HTML entities. a = 3 else: a = 4 """) cov = coverage.Coverage() cov.start() import a # pragma: nested # pylint: disable=import-error cov.stop() # pragma: nested cov.xml_report(a, outfile="coverage.xml") compare_xml(gold_path("html/gold_x_xml"), ".", actual_extra=True)
def test_omit_5(self): self.make_main_etc() self.make_file("omit5.ini", """\ [report] omit = fooey gooey, m[23]*, kablooey helloworld [html] directory = out/omit_5 """) cov = coverage.Coverage(config_file="omit5.ini", include=["./*"]) self.start_import_stop(cov, "main") cov.html_report() compare_html(gold_path("html/omit_5"), "out/omit_5")
def test_y_xml_branch(self): self.make_file( "y.py", """\ def choice(x): if x < 2: return 3 else: return 4 assert choice(1) == 3 """) cov = coverage.Coverage(branch=True) cov.start() import y # pragma: nested # pylint: disable=import-error cov.stop() # pragma: nested cov.xml_report(y, outfile="y_xml_branch/coverage.xml") compare_xml(gold_path("html/gold_y_xml_branch"), "y_xml_branch")
def test_isolatin1(self): self.make_file("isolatin1.py", bytes=b"""\ # -*- coding: iso8859-1 -*- # A Python source file in another encoding. math = "3\xd74 = 12, \xf72 = 6\xb10" assert len(math) == 18 """) cov = coverage.Coverage() isolatin1 = self.start_import_stop(cov, "isolatin1") cov.html_report(isolatin1, directory="out/isolatin1") compare_html(gold_path("html/isolatin1"), "out/isolatin1") contains( "out/isolatin1/isolatin1_py.html", '<span class="str">"3×4 = 12, ÷2 = 6±0"</span>', )
def test_isolatin1(self): self.make_file("isolatin1.py", bytes=b"""\ # -*- coding: iso8859-1 -*- # A Python source file in another encoding. math = "3\xd74 = 12, \xf72 = 6\xb10" assert len(math) == 18 """) cov = coverage.Coverage() isolatin1 = self.start_import_stop(cov, "isolatin1") cov.html_report(isolatin1, directory="out") compare_html(gold_path("html/isolatin1"), "out") contains( "out/isolatin1_py.html", '<span class="str">"3×4 = 12, ÷2 = 6±0"</span>', )
def test_a_xml_2(self): self.make_file("a.py", """\ if 1 < 2: # Needed a < to look at HTML entities. a = 3 else: a = 4 """) self.make_file("run_a_xml_2.ini", """\ # Put all the XML output in xml_2 [xml] output = xml_2/coverage.xml """) cov = coverage.Coverage(config_file="run_a_xml_2.ini") a = self.start_import_stop(cov, "a") cov.xml_report(a) compare_xml(gold_path("xml/x_xml"), "xml_2")
def test_other(self): self.make_file( "src/here.py", """\ import other if 1 < 2: h = 3 else: h = 4 """) self.make_file( "othersrc/other.py", """\ # A file in another directory. We're checking that it ends up in the # HTML report. print("This is the other src!") """) with change_dir("src"): sys.path.insert(0, "../othersrc") cov = coverage.Coverage(include=["./*", "../othersrc/*"]) self.start_import_stop(cov, "here") cov.html_report(directory="../out/other") # Different platforms will name the "other" file differently. Rename it actual_file = list(glob.glob("out/other/*_other_py.html")) assert len(actual_file) == 1 os.rename(actual_file[0], "out/other/blah_blah_other_py.html") compare_html( gold_path("html/other"), "out/other", extra_scrubs=[ (r'href="d_[0-9a-z]{16}_', 'href="_TEST_TMPDIR_othersrc_'), ], ) contains( 'out/other/index.html', '<a href="here_py.html">here.py</a>', 'other_py.html">', 'other.py</a>', )
def test_white(self): self.make_file( "white.py", """\ # A test case sent to me by Steve White def f(self): if self==1: pass elif self.m('fred'): pass elif (g==1) and (b==2): pass elif self.m('fred')==True: pass elif ((g==1) and (b==2))==True: pass else: pass def g(x): if x == 1: a = 1 else: a = 2 g(1) def h(x): if 0: #pragma: no cover pass if x == 1: a = 1 else: a = 2 h(2) """) cov = coverage.Coverage() self.start_import_stop(cov, "white") cov.annotate() compare(gold_path("annotate/white"), ".", "*,cover")
def test_isolatin1(self): self.make_file("isolatin1.py", bytes=b"""\ # -*- coding: iso8859-1 -*- # A Python source file in another encoding. math = "3\xd74 = 12, \xf72 = 6\xb10" assert len(math) == 18 """) cov = coverage.Coverage() cov.start() import isolatin1 # pragma: nested # pylint: disable=import-error cov.stop() # pragma: nested cov.html_report(isolatin1, directory="out") compare_html("out", gold_path("html/gold_isolatin1")) contains( "out/isolatin1_py.html", '<span class="str">"3×4 = 12, ÷2 = 6±0"</span>', )
def test_omit_5(self): self.make_main_etc() self.make_file("omit5.ini", """\ [report] omit = fooey gooey, m[23]*, kablooey helloworld [html] directory = out/omit_5 """) cov = coverage.Coverage(config_file="omit5.ini", include=["./*"]) cov.start() import main # pragma: nested # pylint: disable=unused-variable, import-error cov.stop() # pragma: nested cov.html_report() compare_html("out/omit_5", gold_path("html/gold_omit_5"))
def test_white(self): self.make_file("white.py", """\ # A test case sent to me by Steve White def f(self): if self==1: pass elif self.m('fred'): pass elif (g==1) and (b==2): pass elif self.m('fred')==True: pass elif ((g==1) and (b==2))==True: pass else: pass def g(x): if x == 1: a = 1 else: a = 2 g(1) def h(x): if 0: #pragma: no cover pass if x == 1: a = 1 else: a = 2 h(2) """) cov = coverage.Coverage() self.start_import_stop(cov, "white") cov.annotate() compare(gold_path("annotate/annotate"), ".", "*,cover")
def test_a_xml_2(self): self.make_file( "a.py", """\ if 1 < 2: # Needed a < to look at HTML entities. a = 3 else: a = 4 """) self.make_file( "run_a_xml_2.ini", """\ # Put all the XML output in xml_2 [xml] output = xml_2/coverage.xml """) cov = coverage.Coverage(config_file="run_a_xml_2.ini") a = self.start_import_stop(cov, "a") cov.xml_report(a) compare_xml(gold_path("xml/x_xml"), "xml_2")
def test_other(self): self.make_file( "src/here.py", """\ import other if 1 < 2: h = 3 else: h = 4 """) self.make_file( "othersrc/other.py", """\ # A file in another directory. We're checking that it ends up in the # HTML report. print("This is the other src!") """) with change_dir("src"): sys.path.insert(0, "") # pytest sometimes has this, sometimes not!? sys.path.insert(0, "../othersrc") cov = coverage.Coverage(include=["./*", "../othersrc/*"]) cov.start() import here # pragma: nested # pylint: disable=unused-variable, import-error cov.stop() # pragma: nested cov.html_report(directory="../out") # Different platforms will name the "other" file differently. Rename it for p in glob.glob("out/*_other_py.html"): os.rename(p, "out/blah_blah_other_py.html") compare_html("out", gold_path("html/gold_other")) contains( "out/index.html", '<a href="here_py.html">here.py</a>', 'other_py.html">', 'other.py</a>', )
def test_a_xml_1(self): self.make_file("a.py", """\ if 1 < 2: # Needed a < to look at HTML entities. a = 3 else: a = 4 """) cov = coverage.Coverage() cov.start() import a # pragma: nested # pylint: disable=import-error cov.stop() # pragma: nested cov.xml_report(a, outfile="coverage.xml") source_path = coverage.files.relative_directory().rstrip(r"\/") compare(".", gold_path("html/gold_x_xml"), left_extra=True, scrubs=[ (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'), (r' version="[-.\w]+"', ' version="VERSION"'), (r'<source>\s*.*?\s*</source>', '<source>%s</source>' % re.escape(source_path)), (r'/coverage.readthedocs.io/?[-.\w/]*', '/coverage.readthedocs.io/VER'), ])
def test_bad(self): self.make_file("out/gettysburg.txt", BAD_GETTY) # compare() raises an assertion. msg = rf"Files differ: .*{GOLD_PATH_RX} != {OUT_PATH_RX}" with pytest.raises(AssertionError, match=msg): compare(gold_path("testing/getty"), "out", scrubs=SCRUBS) # Stdout has a description of the diff. The diff shows the scrubbed content. stdout = self.stdout() assert "- Four score" in stdout assert "+ Five score" in stdout assert re_line(rf"^:::: diff '.*{GOLD_PATH_RX}' and '{OUT_PATH_RX}'", stdout) assert re_line( rf"^:::: end diff '.*{GOLD_PATH_RX}' and '{OUT_PATH_RX}'", stdout) assert " D/D/D, Gxxx, Pennsylvania" in stdout # The actual file was saved. with open(ACTUAL_GETTY_FILE) as f: saved = f.read() assert saved == BAD_GETTY
def test_a_xml_2(self): self.make_file( "a.py", """\ if 1 < 2: # Needed a < to look at HTML entities. a = 3 else: a = 4 """) self.make_file( "run_a_xml_2.ini", """\ # Put all the XML output in xml_2 [xml] output = xml_2/coverage.xml """) cov = coverage.Coverage(config_file="run_a_xml_2.ini") cov.start() import a # pragma: nested # pylint: disable=import-error cov.stop() # pragma: nested cov.xml_report(a) compare_xml(gold_path("html/gold_x_xml"), "xml_2")
def test_missing_after_else(self): self.make_file( "mae.py", """\ def f(x): if x == 1: print("1") else: print("2") if f(1): print("nope") if f(2): print("nope") """) cov = coverage.Coverage() self.start_import_stop(cov, "mae") cov.annotate() assert self.stdout() == ( "1\n" + "2\n" + "The annotate command will be removed in a future version.\n" + "Get in touch if you still use it: [email protected]\n") compare(gold_path("annotate/mae"), ".", "*,cover")
def test_unicode(self): self.make_file("unicode.py", """\ # -*- coding: utf-8 -*- # A Python source file with exotic characters. upside_down = "ʎd˙ǝbɐɹǝʌoɔ" surrogate = "db40,dd00: x󠄀" """) cov = coverage.Coverage() unimod = self.start_import_stop(cov, "unicode") cov.html_report(unimod, directory="out") compare_html(gold_path("html/unicode"), "out") contains( "out/unicode_py.html", '<span class="str">"ʎd˙ǝbɐɹǝʌoɔ"</span>', ) contains_any( "out/unicode_py.html", '<span class="str">"db40,dd00: x��"</span>', '<span class="str">"db40,dd00: x󠄀"</span>', )
def test_y_xml_branch(self): self.make_file("y.py", """\ def choice(x): if x < 2: return 3 else: return 4 assert choice(1) == 3 """) cov = coverage.Coverage(branch=True) cov.start() import y # pragma: nested # pylint: disable=import-error cov.stop() # pragma: nested cov.xml_report(y, outfile="y_xml_branch/coverage.xml") source_path = coverage.files.relative_directory().rstrip(r"\/") compare("y_xml_branch", gold_path("html/gold_y_xml_branch"), scrubs=[ (r' timestamp="\d+"', ' timestamp="TIMESTAMP"'), (r' version="[-.\w]+"', ' version="VERSION"'), (r'<source>\s*.*?\s*</source>', '<source>%s</source>' % re.escape(source_path)), (r'/coverage.readthedocs.io/?[-.\w/]*', '/coverage.readthedocs.io/VER'), ])
def test_omit_3(self): self.make_main_etc() cov = coverage.Coverage(include=["./*"]) self.start_import_stop(cov, "main") cov.html_report(directory="out", omit=["m1.py", "m2.py"]) compare_html(gold_path("html/omit_3"), "out")
def test_good(self): self.make_file("out/gettysburg.txt", GOOD_GETTY) compare(gold_path("testing/getty"), "out", scrubs=SCRUBS) self.assert_doesnt_exist(ACTUAL_GETTY_FILE)
def test_b_branch(self): self.make_file("b.py", """\ def one(x): # This will be a branch that misses the else. if x < 2: a = 3 else: a = 4 one(1) def two(x): # A missed else that branches to "exit" if x: a = 5 two(1) def three(): try: # This if has two branches, *neither* one taken. if name_error_this_variable_doesnt_exist: a = 1 else: a = 2 except: pass three() """) cov = coverage.Coverage(branch=True) b = self.start_import_stop(cov, "b") cov.html_report(b, directory="out") compare_html(gold_path("html/b_branch"), "out") contains( "out/b_py.html", ('<span class="key">if</span> <span class="nam">x</span> ' '<span class="op"><</span> <span class="num">2</span>'), (' <span class="nam">a</span> <span class="op">=</span> ' '<span class="num">3</span>'), '<span class="pc_cov">70%</span>', ('<span class="annotate short">3 ↛ 6</span>' '<span class="annotate long">line 3 didn\'t jump to line 6, ' 'because the condition on line 3 was never false</span>'), ('<span class="annotate short">12 ↛ exit</span>' '<span class="annotate long">line 12 didn\'t return from function \'two\', ' 'because the condition on line 12 was never false</span>'), ('<span class="annotate short">20 ↛ 21, ' '20 ↛ 23</span>' '<span class="annotate long">2 missed branches: ' '1) line 20 didn\'t jump to line 21, ' 'because the condition on line 20 was never true, ' '2) line 20 didn\'t jump to line 23, ' 'because the condition on line 20 was never false</span>'), ) contains( "out/index.html", '<a href="b_py.html">b.py</a>', '<span class="pc_cov">70%</span>', '<td class="right" data-ratio="16 23">70%</td>', )
def test_omit_1(self): self.make_main_etc() cov = coverage.Coverage(include=["./*"]) self.start_import_stop(cov, "main") cov.html_report(directory="out") compare_html(gold_path("html/gold_omit_1"), "out")
def test_omit_3(self): self.make_main_etc() cov = coverage.Coverage(include=["./*"]) self.start_import_stop(cov, "main") cov.html_report(directory="out/omit_3", omit=["m1.py", "m2.py"]) compare_html(gold_path("html/omit_3"), "out/omit_3")
def test_b_branch(self): self.make_file("b.py", """\ def one(x): # This will be a branch that misses the else. if x < 2: a = 3 else: a = 4 one(1) def two(x): # A missed else that branches to "exit" if x: a = 5 two(1) def three(): try: # This if has two branches, *neither* one taken. if name_error_this_variable_doesnt_exist: a = 1 else: a = 2 except: pass three() """) cov = coverage.Coverage(branch=True) b = self.start_import_stop(cov, "b") cov.html_report(b, directory="out/b_branch") compare_html(gold_path("html/b_branch"), "out/b_branch") contains( "out/b_branch/b_py.html", ('<span class="key">if</span> <span class="nam">x</span> ' '<span class="op"><</span> <span class="num">2</span>'), (' <span class="nam">a</span> <span class="op">=</span> ' '<span class="num">3</span>'), '<span class="pc_cov">70%</span>', ('<span class="annotate short">3 ↛ 6</span>' '<span class="annotate long">line 3 didn\'t jump to line 6, ' 'because the condition on line 3 was never false</span>'), ('<span class="annotate short">12 ↛ exit</span>' '<span class="annotate long">line 12 didn\'t return from function \'two\', ' 'because the condition on line 12 was never false</span>'), ('<span class="annotate short">20 ↛ 21, ' '20 ↛ 23</span>' '<span class="annotate long">2 missed branches: ' '1) line 20 didn\'t jump to line 21, ' 'because the condition on line 20 was never true, ' '2) line 20 didn\'t jump to line 23, ' 'because the condition on line 20 was never false</span>'), ) contains( "out/b_branch/index.html", '<a href="b_py.html">b.py</a>', '<span class="pc_cov">70%</span>', '<td class="right" data-ratio="16 23">70%</td>', )