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

pantsbuild / pants / 20632486505

01 Jan 2026 04:21AM UTC coverage: 43.231% (-37.1%) from 80.281%
20632486505

Pull #22962

github

web-flow
Merge 08d5c63b0 into f52ab6675
Pull Request #22962: Bump the gha-deps group across 1 directory with 6 updates

26122 of 60424 relevant lines covered (43.23%)

0.86 hits per line

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

72.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
2✔
5

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

14

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

18

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

23

24
@pytest.fixture
2✔
25
def rule_runner() -> RuleRunner:
2✔
26
    return RuleRunner(
2✔
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(
2✔
37
    stdout: str, lang: str, *, num_files: int = 1, blank: int = 0, comment: int = 0, code: int = 0
38
) -> None:
39
    summary_line = next(
2✔
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}"
2✔
48
    fields = summary_line.split()
2✔
49
    assert num_files == int(fields[1])
2✔
50
    assert blank == int(fields[3])
2✔
51
    assert comment == int(fields[4])
2✔
52
    assert code == int(fields[5])
2✔
53

54

55
@pytest.mark.platform_specific_behavior
2✔
56
def test_count_loc(rule_runner: RuleRunner) -> None:
2✔
57
    py_dir = "src/py/foo"
2✔
58
    elixir_dir = "src/elixir/foo"
2✔
59
    rule_runner.write_files(
2✔
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(
2✔
70
        CountLinesOfCode, args=[f"{py_dir}:lib", f"{elixir_dir}:lib"]
71
    )
72
    assert result.exit_code == 0
2✔
73
    assert_counts(result.stdout, "Python", num_files=2, blank=2, comment=3, code=2)
2✔
74
    assert_counts(result.stdout, "Elixir", comment=1, code=1)
2✔
75

76

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

86

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

101

102
def test_no_sources_exits_gracefully(rule_runner: RuleRunner) -> None:
2✔
103
    py_dir = "src/py/foo"
×
104
    rule_runner.write_files({f"{py_dir}/BUILD": "python_sources(name='lib')"})
×
105
    result = rule_runner.run_goal_rule(CountLinesOfCode, args=[f"{py_dir}:lib"])
×
106
    assert result == GoalRuleResult.noop()
×
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