-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathphpunit.xml
More file actions
147 lines (135 loc) · 7.73 KB
/
Copy pathphpunit.xml
File metadata and controls
147 lines (135 loc) · 7.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" bootstrap="tests/bootstrap.php" colors="true" cacheDirectory=".phpunit.cache" executionOrder="random" failOnRisky="true" failOnWarning="true" beStrictAboutOutputDuringTests="true" displayDetailsOnTestsThatTriggerDeprecations="true" displayDetailsOnTestsThatTriggerWarnings="true" displayDetailsOnTestsThatTriggerErrors="true">
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">tests/Unit</directory>
</testsuite>
<testsuite name="Integration">
<directory suffix="Test.php">tests/Integration</directory>
</testsuite>
<testsuite name="E2E">
<directory suffix="Test.php">tests/E2E</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>network</group>
</exclude>
</groups>
<!--
============================================================================
S141 — HOW TO READ THIS REPO'S COVERAGE NUMBERS. This is the ONE
authoritative statement; nothing else in the repo gets to contradict it.
============================================================================
THE POLICY (decided 2026-08-03, on the measurement below):
**This repo carries NO PHPUnit coverage metadata in tests/.** No `@covers`,
no `@coversNothing`, no `#[CoversClass]` / `#[CoversMethod]` /
`#[CoversFunction]` / `#[CoversNothing]`. Coverage is read WHOLE-RUN: a
file's figure is everything the suite executed in it.
THEREFORE:
* A 0.00% file is a file the suite NEVER EXECUTES. That reading is now
sound, and it was not before.
* A non-zero figure is what the suite executed. It is NOT a claim that
every executed line is asserted — see "the cost", below.
* The headline statement percentage, and the MIN_COVERAGE floor in
scripts/coverage-threshold-check.php, are a ratchet over that figure.
tests/Unit/Support/CoverageMetadataPolicyTest.php enforces all of it and
fails if metadata reappears, if this comment is deleted, or if
phpunit.xml starts requiring coverage metadata. Do NOT re-add an annotation
to silence it.
WHY — measured, not assumed. PHP 8.3.6 + PCOV 1.0.11, the CI invocation
(`php -d max_execution_time=0 vendor/bin/phpunit` with the clover report),
real MySQL 8.0, one identical random seed, the SAME tree twice with only the
603 annotation lines removed on the second pass. Both runs: Tests 8971,
Skipped 7, same failures.
metric (Clover /coverage/project/metrics) with @covers without
statements 65.49% 67.22%
41939/64039 43045/64039
methods 3110/6057 3231/6057
classes 160/672 175/672
files reporting 0.00% .................... 143 101
of which FALSE zeros (executed anyway) .. 42 0
of which reach 100% once un-narrowed .... 6 -
files that LOST coverage ................. - 0
So 42 of the 143 zeros — 29% of them — were files the suite runs and the
report called untested; six of those are executed in FULL. That is the
defect: "untested" and "attributed elsewhere by an annotation" were
indistinguishable, silently, and the natural reaction to a 0% file is to
write duplicate tests for behaviour that is already covered. (S96 and S121
each came within one step of doing exactly that.)
The mechanism, for the record: PHPUnit 10.5
`Framework/TestRunner.php:163` asks `Metadata/Api/CodeCoverage.php` for the
lines to be covered, and php-code-coverage
`CodeCoverage::applyCoversAndUsesFilter()` then does one of three things —
`false` (@coversNothing) CLEARS the whole run's data for that test, a
NON-EMPTY list keeps only the named units' listed lines and DELETES every
other file, and `[]` (no metadata) keeps everything. No warning is emitted
in any of the three cases.
Two further reasons the annotations had to go rather than be completed:
* The report was not one measurement but two incompatible ones mixed —
369 of 707 test files narrowed, 338 did not. An aggregate over that
mixture is not a measurement of anything.
* The annotations were inert as documentation and destructive as
configuration: this file sets neither `requireCoverageMetadata` nor
`beStrictAboutCoverageMetadata`, which are the only two settings that
make coverage metadata load-bearing. Nothing checked that a `@covers`
was correct, complete, or even resolvable.
THE COST, stated rather than hidden: whole-run coverage counts a line that
was merely EXECUTED, not necessarily asserted. 67.22% is therefore an upper
bound on "behaviour pinned by an assertion" in exactly the way 65.49% was a
lower bound on "code the suite runs". The defences against vacuous
execution are separate and already in place — the S120 assertion-escape
extension registered below, scripts/assertion-escape-audit.php in probe mode, and
per-step mutation testing. Coverage is not, and was never, that defence.
ONE DOCUMENTED EXCEPTION.
tests/Unit/Server/Http/Controllers/Admin/AdminSettingsControllerTest.php
still carries a `@covers`. A concurrent writer owned that file (uncommitted)
when this policy landed, so it was deliberately left alone rather than have
two writers edit one file. It is named explicitly in
CoverageMetadataPolicyTest's allow-list, and that test FAILS once the
annotation is gone, so the exception cannot rot into a permanent hole.
-->
<coverage>
<report>
<html outputDirectory="coverage-report"/>
<clover outputFile="coverage.xml"/>
<text outputFile="php://stdout" showUncoveredFiles="true" showOnlySummary="true"/>
</report>
</coverage>
<extensions>
<!--
S120 — reports any test where a failed assertion did not decide the test's
outcome (an assertion swallowed between the assertion and PHPUnit — by
`catch (\Throwable)`, `catch (\Exception)` or `catch (\RuntimeException)`, or by
a `return` inside a `finally` with no catch at all). See
tests/Support/AssertionEscape/EscapeCollector.php for the mechanism, for the four
blind spots (Assert::fail(), mock parameter/invocation rules,
markTestSkipped/Incomplete, and the failed-outcome budget itself), and for the
known false-positive class (a test that deliberately catches its own assertion
failure) together with the reasoning for providing no opt-out.
scripts/assertion-escape-check.php turns a report into a non-zero exit for CI.
DO NOT DELETE THE LINE BELOW. Removing this registration is silent: the guard
loads nothing, writes no report, and the CI check script exits 0 on a run full of
swallowed assertions. tests/Unit/Support/AssertionEscapeGuardWiringTest.php fails
if it goes missing — or is commented out, which it checks against the parsed
document rather than the file's text.
-->
<bootstrap class="Phlix\Tests\Support\AssertionEscape\AssertionEscapeGuardExtension"/>
</extensions>
<php>
<env name="APP_ENV" value="testing"/>
<env name="DB_HOST" value="127.0.0.1"/>
<env name="DB_PORT" value="3306"/>
<env name="DB_DATABASE" value="phlix_test"/>
<env name="DB_USER" value="root"/>
<env name="DB_PASSWORD" value="root"/>
</php>
<source>
<include>
<directory suffix=".php">src</directory>
</include>
<exclude>
<directory suffix=".php">src/vendor</directory>
</exclude>
</source>
</phpunit>