S128 — PSR-12 for tests/, minus two sniffs that PSR-12 does not actually
require of test code. This file is DELIBERATELY separate from the src/ gate
(`phpcs --standard=PSR12 src/`), which stays untouched: src/ keeps full PSR-12
with zero exclusions.
THE MEASUREMENT THAT CHOSE THESE TWO EXCLUSIONS (origin/master @ 12bdea6c,
phpcs 3.13.5, one-off `--standard=PSR12 tests/ --report=summary` run — the
totals footer and the per-sniff table quoted below are `summary`-report
output, not what the CI gate's default `full` report prints):
A TOTAL OF 2155 ERRORS AND 288 WARNINGS WERE FOUND IN 293 FILES
PSR1.Methods.CamelCapsMethodName ............... 2065 (95.8% of errors)
PSR1.Classes.ClassDeclaration.MultipleClasses .. 63
everything else ................................ 27
(+ 288 warnings: 286 Generic.Files.LineLength, 2 PSR1.Files.SideEffects)
Only 23 of the 2443 violations were auto-fixable by phpcbf, so "run phpcbf and
commit" was never on the table. The two sniff exclusions below account for 2128
of the 2155 errors; of the 27 that remained, 25 were FIXED (22 by phpcbf — call
signatures, control-structure spacing, an anonymous-class brace — and 3 file-level
docblocks moved above their `declare(strict_types=1);` by hand, per PSR-12 §3) and
2 are carved out per-file below. There is no baseline and no ignore list.
1. PSR1.Methods.CamelCapsMethodName — 2065 errors, and all 2065 were classified
rather than assumed: every one is a snake_case test method name
(`test_playback_started_dispatch_reaches_listener`, 1980 distinct names).
ZERO were acronym cases and ZERO were leading-uppercase, so this is one
deliberate naming convention, not accumulated sloppiness. PSR-12 §4.3
governs the declared API of production classes; PHPUnit test methods are
discovered by the `test` prefix and read as sentences, and snake_case is a
mainstream PHPUnit style. Renaming 1980 methods would be the largest
behaviour-free diff in the repo's history, would break every `--filter`
expression and `@depends` reference pointing at them, and would buy nothing.
src/ is unaffected: it passes this sniff today with 0 errors.
2. PSR1.Classes.ClassDeclaration.MultipleClasses — 63 errors. These are test
doubles declared in the same file as the test that uses them, which keeps a
double next to its only consumer and out of the autoloadable namespace.
Splitting 63 files' doubles into 63+ new files makes the suite harder to
read, not more correct.
WARNINGS ARE REPORTED AND DO NOT BLOCK — and the difference from `-n` matters.
phpcs exits non-zero on WARNINGS ALONE, so a gate that trusts its exit code
would be permanently red here over 288 pre-existing warnings, and the next
person would silence it with `-n`. That is precisely how S109's defect happened:
`-n` on the src/ gate SUPPRESSED 8 real PSR-12 warnings for months. So the
`ignore_warnings_on_exit` config below is set instead — it changes only the exit
code. Every warning is still counted and still printed in the job log, and the
per-file "FOUND n ERRORS … AFFECTING m LINES" footers of the default `full`
report are the lines to read there. No "A TOTAL OF" line ever appears in this
job's log — that footer belongs to the `summary` report, which the CI invocation
(`--standard=phpcs-tests.xml --colors`) never requests; a grep for it could
never fire. The gate is phpcs's nonzero exit code, read directly by the runner,
not a log line (see the corrected step comment in
.github/workflows/coding-standards.yml @ 4c96f085). Do NOT add `-n` and do NOT
exclude Generic.Files.LineLength; src/ keeps both, and so does this.
The two remaining errors are carved out per-file below, each naming the thing
that makes fixing it wrong rather than merely inconvenient. The 2 SideEffects
warnings are deliberately NOT excluded: they cost nothing to leave visible, and
an exclusion that buys no green is just a narrower gate.
Anything added to the exclude list needs the same treatment: a count, a
classification of what the violations actually ARE, and a reason PSR-12 does not
require it of test code. tests/Unit/Support/StaticAnalysisScopeTest.php asserts
this file exists, targets tests/, and carries EXACTLY the exclusions below — so
the list cannot grow quietly, which is how an exclusion list becomes a baseline.
tests
tests/codeception/Helper/SyncPlay.php
tests/Unit/Server/Http/Controllers/Admin/AdminSettingsControllerTest.php