mirror of
https://github.com/unclebob/crapper.git
synced 2026-11-06 18:13:50 +00:00
Add a multi-language CRAP tool that writes .metrics/crap.edn for uml-viewer.
Score Clojure, Java, Go, TypeScript, Rust, and Python with each language's complexity rules and coverage report.
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
from crapper.coverage import (
|
||||
CoverageBundle,
|
||||
go_percent,
|
||||
load_bundle,
|
||||
parse_form_coverage,
|
||||
parse_go_profile,
|
||||
parse_jacoco_index,
|
||||
parse_lcov,
|
||||
)
|
||||
from crapper.model import Function
|
||||
|
||||
|
||||
def function(**kwargs):
|
||||
defaults = dict(
|
||||
name="choose",
|
||||
namespace="demo.core",
|
||||
complexity=2,
|
||||
start_line=3,
|
||||
end_line=5,
|
||||
path="src/demo/core.clj",
|
||||
language="clojure",
|
||||
jacoco_class=None,
|
||||
)
|
||||
defaults.update(kwargs)
|
||||
return Function(**defaults)
|
||||
|
||||
|
||||
def test_cloverage_form_counts_and_lcov_lines():
|
||||
html = '<span class="pc" title="1 out of 2 forms covered"> 4 (if x 1)</span>'
|
||||
assert parse_form_coverage(html) == {4: (1, 2)}
|
||||
lcov = "SF:src/demo/core.clj\nDA:3,1\nDA:4,0\nDA:9,3\nend_of_record\n"
|
||||
parsed = parse_lcov(lcov)
|
||||
bundle = CoverageBundle(lcov=parsed, form_html={"src/demo/core.clj": {4: (1, 2)}})
|
||||
# Form HTML wins over LCOV for Clojure, matching crap4clj.
|
||||
assert bundle.percent_for(function(start_line=3, end_line=5)) == 50.0
|
||||
|
||||
|
||||
def test_lcov_percentage_when_there_is_no_html():
|
||||
lcov = parse_lcov("SF:src/demo/core.clj\nDA:3,1\nDA:4,0\nend_of_record\n")
|
||||
bundle = CoverageBundle(lcov=lcov)
|
||||
assert bundle.percent_for(function(start_line=3, end_line=4)) == 50.0
|
||||
assert bundle.percent_for(function(path="src/missing.clj")) is None
|
||||
|
||||
|
||||
def test_go_profile_matches_crap4go_statement_ranges():
|
||||
profile = parse_go_profile(
|
||||
"mode: set\ngithub.com/acme/demo/board.go:4.1,6.2 2 1\ngithub.com/acme/demo/board.go:8.1,9.2 1 0\n"
|
||||
)
|
||||
assert go_percent(profile, "board.go", 4, 6) == 100.0
|
||||
assert go_percent(profile, "board.go", 8, 9) == 0.0
|
||||
assert go_percent(profile, "other.go", 1, 3) is None
|
||||
|
||||
|
||||
def test_jacoco_instruction_coverage_joins_on_class_and_method():
|
||||
xml = """<?xml version="1.0"?>
|
||||
<report>
|
||||
<package>
|
||||
<class name="demo/pkg/Board">
|
||||
<method name="place" line="4">
|
||||
<counter type="INSTRUCTION" missed="1" covered="3"/>
|
||||
</method>
|
||||
</class>
|
||||
<class name="demo/pkg/Board$Inner">
|
||||
<method name="tick" line="9">
|
||||
<counter type="INSTRUCTION" missed="0" covered="2"/>
|
||||
</method>
|
||||
</class>
|
||||
</package>
|
||||
</report>
|
||||
"""
|
||||
bundle = CoverageBundle(jacoco=parse_jacoco_index(xml))
|
||||
outer = function(
|
||||
name="place",
|
||||
namespace="demo.pkg.Board",
|
||||
language="java",
|
||||
jacoco_class="demo.pkg.Board",
|
||||
start_line=4,
|
||||
path="src/demo/pkg/Board.java",
|
||||
)
|
||||
inner = function(
|
||||
name="tick",
|
||||
namespace="demo.pkg.Board.Inner",
|
||||
language="java",
|
||||
jacoco_class="demo.pkg.Board$Inner",
|
||||
start_line=9,
|
||||
path="src/demo/pkg/Board.java",
|
||||
)
|
||||
assert bundle.percent_for(outer) == 75.0
|
||||
assert bundle.percent_for(inner) == 100.0
|
||||
|
||||
|
||||
def test_jacoco_skips_methods_without_an_instruction_counter():
|
||||
xml = """<report>
|
||||
<class name="demo/pkg/Board">
|
||||
<method name="skip" line="2">
|
||||
<counter type="LINE" missed="1" covered="0"/>
|
||||
</method>
|
||||
<method name="bad" line="nope">
|
||||
<counter type="INSTRUCTION" missed="1" covered="1"/>
|
||||
</method>
|
||||
<counter type="INSTRUCTION" missed="0" covered="1"/>
|
||||
</class>
|
||||
</report>"""
|
||||
found = parse_jacoco_index(xml)
|
||||
assert list(found) == ["demo.pkg.Board#bad"]
|
||||
assert found["demo.pkg.Board#bad"][0].line == 0
|
||||
|
||||
|
||||
def test_missing_go_profile_is_na():
|
||||
assert go_percent(None, "board.go", 1, 3) is None
|
||||
|
||||
|
||||
def test_load_bundle_merges_each_report(tmp_path):
|
||||
lcov = tmp_path / "target" / "coverage" / "lcov.info"
|
||||
lcov.parent.mkdir(parents=True)
|
||||
lcov.write_text("SF:src/demo/core.clj\nDA:3,1\nDA:4,0\nend_of_record\n", encoding="utf-8")
|
||||
go = tmp_path / "target" / "coverage" / "go" / "coverage.out"
|
||||
go.parent.mkdir(parents=True)
|
||||
go.write_text("mode: set\nboard.go:1.1,2.2 1 1\n", encoding="utf-8")
|
||||
jacoco = tmp_path / "target" / "site" / "jacoco" / "jacoco.xml"
|
||||
jacoco.parent.mkdir(parents=True)
|
||||
jacoco.write_text(
|
||||
'<report><class name="demo/Board"><method name="place" line="4">'
|
||||
'<counter type="INSTRUCTION" missed="0" covered="1"/></method></class></report>',
|
||||
encoding="utf-8",
|
||||
)
|
||||
html = tmp_path / "target" / "coverage" / "src" / "demo" / "core.clj.html"
|
||||
html.parent.mkdir(parents=True)
|
||||
html.write_text(
|
||||
'<span title="1 out of 2 forms covered"> 4 (if x 1)</span>',
|
||||
encoding="utf-8",
|
||||
)
|
||||
(tmp_path / "target" / "coverage" / "index.html").write_text("<html></html>", encoding="utf-8")
|
||||
bundle = load_bundle(tmp_path)
|
||||
assert bundle.percent_for(function(start_line=3, end_line=4)) == 50.0
|
||||
assert bundle.go_profile is not None
|
||||
assert bundle.jacoco is not None
|
||||
Reference in New Issue
Block a user