• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pantsbuild / pants / 18812500213

26 Oct 2025 03:42AM UTC coverage: 80.284% (+0.005%) from 80.279%
18812500213

Pull #22804

github

web-flow
Merge 2a56fdb46 into 4834308dc
Pull Request #22804: test_shell_command: use correct default cache scope for a test's environment

29 of 31 new or added lines in 2 files covered. (93.55%)

1314 existing lines in 64 files now uncovered.

77900 of 97030 relevant lines covered (80.28%)

3.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/python/pants/backend/project_info/count_loc_test.py
1
# Copyright 2019 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
import pytest
3✔
5

6
from pants.backend.project_info import count_loc
3✔
7
from pants.backend.project_info.count_loc import CountLinesOfCode
3✔
8
from pants.backend.python import target_types_rules
3✔
9
from pants.backend.python.target_types import PythonSourcesGeneratorTarget
3✔
10
from pants.core.util_rules import external_tool
3✔
11
from pants.engine.target import MultipleSourcesField, Target
3✔
12
from pants.testutil.rule_runner import GoalRuleResult, RuleRunner
3✔
13

14

15
class ElixirSources(MultipleSourcesField):
3✔
16
    default = ("*.ex",)
3✔
17

18

19
class ElixirTarget(Target):
3✔
20
    alias = "elixir"
3✔
21
    core_fields = (ElixirSources,)
3✔
22

23

24
@pytest.fixture
3✔
25
def rule_runner() -> RuleRunner:
3✔
26
    return RuleRunner(
3✔
27
        rules=[
28
            *count_loc.rules(),
29
            *external_tool.rules(),
30
            *target_types_rules.rules(),
31
        ],
32
        target_types=[PythonSourcesGeneratorTarget, ElixirTarget],
33
    )
34

35

36
def assert_counts(
3✔
37
    stdout: str, lang: str, *, num_files: int = 1, blank: int = 0, comment: int = 0, code: int = 0
38
) -> None:
39
    summary_line = next(
3✔
40
        (
41
            line
42
            for line in stdout.splitlines()
43
            if len(line.split()) in (6, 7) and line.split()[0] == lang
44
        ),
45
        None,
46
    )
47
    assert summary_line is not None, f"Found no output line for {lang} given stdout:\n {stdout}"
3✔
48
    fields = summary_line.split()
3✔
49
    assert num_files == int(fields[1])
3✔
50
    assert blank == int(fields[3])
3✔
51
    assert comment == int(fields[4])
3✔
52
    assert code == int(fields[5])
3✔
53

54

55
@pytest.mark.platform_specific_behavior
3✔
56
def test_count_loc(rule_runner: RuleRunner) -> None:
3✔
57
    py_dir = "src/py/foo"
3✔
58
    elixir_dir = "src/elixir/foo"
3✔
59
    rule_runner.write_files(
3✔
60
        {
61
            f"{py_dir}/foo.py": '# A comment.\n\nprint("some code")\n# Another comment.',
62
            f"{py_dir}/bar.py": '# A comment.\n\nprint("some more code")',
63
            f"{py_dir}/BUILD": "python_sources(name='lib')",
64
            f"{elixir_dir}/foo.ex": 'IO.puts("Some elixir")\n# A comment',
65
            f"{elixir_dir}/ignored.ex": "# We do not expect this file to appear in counts.",
66
            f"{elixir_dir}/BUILD": "elixir(name='lib', sources=['foo.ex'])",
67
        }
68
    )
69
    result = rule_runner.run_goal_rule(
3✔
70
        CountLinesOfCode, args=[f"{py_dir}:lib", f"{elixir_dir}:lib"]
71
    )
72
    assert result.exit_code == 0
3✔
73
    assert_counts(result.stdout, "Python", num_files=2, blank=2, comment=3, code=2)
3✔
74
    assert_counts(result.stdout, "Elixir", comment=1, code=1)
3✔
75

76

77
def test_passthrough_args(rule_runner: RuleRunner) -> None:
3✔
UNCOV
78
    rule_runner.write_files(
1✔
79
        {"foo.py": "print('hello world!')\n", "BUILD": "python_sources(name='foo')"}
80
    )
UNCOV
81
    result = rule_runner.run_goal_rule(CountLinesOfCode, args=["//:foo", "--", "--no-cocomo"])
1✔
UNCOV
82
    assert result.exit_code == 0
1✔
UNCOV
83
    assert_counts(result.stdout, "Python", code=1)
1✔
UNCOV
84
    assert "Estimated Cost to Develop" not in result.stdout
1✔
85

86

87
def test_files_without_owners(rule_runner: RuleRunner) -> None:
3✔
88
    """cloc works on any readable file in the build root, regardless of whether it's declared in a
89
    BUILD file."""
UNCOV
90
    rule_runner.write_files(
1✔
91
        {
92
            "test/foo.ex": 'IO.puts("im a free thinker!")',
93
            "test/foo.hs": 'main = putStrLn "Whats Pants, precious?"',
94
        }
95
    )
UNCOV
96
    result = rule_runner.run_goal_rule(CountLinesOfCode, args=["test/foo.*"])
1✔
UNCOV
97
    assert result.exit_code == 0
1✔
UNCOV
98
    assert_counts(result.stdout, "Elixir", code=1)
1✔
UNCOV
99
    assert_counts(result.stdout, "Haskell", code=1)
1✔
100

101

102
def test_no_sources_exits_gracefully(rule_runner: RuleRunner) -> None:
3✔
UNCOV
103
    py_dir = "src/py/foo"
1✔
UNCOV
104
    rule_runner.write_files({f"{py_dir}/BUILD": "python_sources(name='lib')"})
1✔
UNCOV
105
    result = rule_runner.run_goal_rule(CountLinesOfCode, args=[f"{py_dir}:lib"])
1✔
UNCOV
106
    assert result == GoalRuleResult.noop()
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc