feat(daemon): classify test vs production files per SonarQube convention#3
Merged
Conversation
Adds the test/main code split SonarQube proper supports. Each input file
is now classified as test or main, and that classification flows to the
engine via ClientInputFile.isTest(). SonarSource rules carry a scope
(Main, Test, All); Main-only rules (java:S100 method naming, java:S106
System.out, java:S1118 utility-class ctor, ...) now correctly skip test
files. We are not overriding any rule — only classifying files correctly
so the analyzer's own scope metadata can do its job.
Classification rules (industry-standard per language):
Java/Kotlin: src/test/**, *Test.java, *Tests.java, *IT.java (and .kt)
Scala: src/test/**, *Test.scala
Go: *_test.go
Python: tests/**, test/**, test_*.py, *_test.py
JS/TS: tests/**, __tests__/**, *.{test,spec}.{js,jsx,ts,tsx}
PHP: tests/**, *Test.php
Ruby: spec/**, test/**, *_spec.rb, *_test.rb
HTML/XML/CSS: no convention; classified as MAIN
Cross-language paths like src/test/, tests/, __tests__/, spec/ also count.
Files:
daemon: new TestPathDetector + 21-case unit test
daemon: FileInputFile gains an isTest field (4-arg ctor; old 3-arg
ctor delegates with isTest=false for backward compatibility)
daemon: AnalysisService classifies each file before constructing
its FileInputFile
protocol: AnalyzeRequest gains an additionalTestPaths field for
agent/skill overrides; a backward-compat 5-arg constructor
keeps all existing call sites compiling
daemon: AnalysisService glob-matches additionalTestPaths against
each file (additive to the built-in detector)
cli: global --test-path GLOB option (repeatable) plumbed into the
AnalyzeRequest
Skills and agents that know a project's layout (e.g. integration tests
under src/integration/) pass --test-path 'src/integration/**'. Standalone
invocations without an agent fall back to the built-in detector.
Verified end to end (self-scan of this repo):
Before After
───────── ─────────
263 issues -> 77 issues (-186; -70%)
java:S100: 70 -> 0 (all 70 were test method naming)
java:S106: 13 -> 11 main, 0 test (System.out — tests get a pass)
java:S1118: ? -> 1 main, 0 test (utility-class ctor)
All 21 detector unit tests pass; full daemon test suite green; full
reactor build (protocol, daemon, cli, dist) green.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
8d84b3c to
3e19e3e
Compare
Layers the test/main classification feature into the user-facing docs that PR #3 left untouched: - SKILL.md now states the daemon applies SonarSource's Main/Test rule scope (java:S100, S106, S1118, ... skip test files), lists the auto-detected language-conventional paths, and documents --test-path GLOB as the agent escape hatch for non-standard layouts. - sonar-scanner-claude (haiku) and sonar-scanner-copilot (gpt-5-mini) both gain a 'Non-standard test layouts' section instructing the agent to inspect the project layout before scanning and pass --test-path globs for non-conventional directories. Worded to discourage over-classification — the goal is to not flag intentional test conventions, not to silence rules. No code change in this commit; doc/skill updates only. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced May 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the test/main code split SonarQube proper supports. Each input file gets an
isTestflag based on language-conventional paths;sonarlint-analysis-enginethen skipsMain-only rules on test files (java:S100 method naming, java:S106 System.out, java:S1118 utility-class ctor, ...). We override no rules — only classify files correctly so the analyzer's own scope metadata does its job.Verified self-scan result
java:S100(method naming)java:S106(System.out)java:S1118(utility-class ctor)The 70
java:S100hits the previous self-scan flagged ondaemon/src/test/java/...test methods are gone — same code, same rules, same analyzer; the classifier just tells the engine what's a test.Classification (industry-standard per language)
src/test/**,**/*Test.java,**/*Tests.java,**/*IT.java(and.kt)src/test/**,**/*Test.scala**/*_test.gotests/**,test/**,**/test_*.py,**/*_test.pytests/**,__tests__/**,**/*.{test,spec}.{js,jsx,ts,tsx}tests/**,**/*Test.phpspec/**,test/**,**/*_spec.rb,**/*_test.rbCross-language paths like
src/test/,tests/,__tests__/,spec/count regardless of language.Agent / skill override
A new global CLI option
--test-path GLOB(repeatable) augments the built-in detection for non-standard layouts:Plumbed through
AnalyzeRequest.additionalTestPaths(new field, with a 5-arg backward-compat constructor so existing call sites keep compiling). Standalone runs without an agent fall back to the detector defaults.Tested
TestPathDetector(cross-language paths, per-language filenames, negatives, Windows backslashes, null/empty edge cases) — all pass.protocol,daemon,cli,dist) green.java:S100(verified against a fresh daemon running this branch's code).🤖 Generated with Claude Code