Author Commit message Committed SHA  
 
by dg TestCase: data provider returning no data sets is an error

A method-level data provider returning an empty array or an empty
Traversable made runTest() return without calling the test method, and
run() printed a passing mark. It now throws TestCaseException, the same
way as an empty file-level data provider fails the test.

by dg TestCase: added #[Throws] and #[DataProvider] attributes as an alternative to annotations

Method-level annotations only; attributes take precedence over the docblock,
which stays fully functional. File-level .phpt annotations cannot be replaced
(no file-level attributes in PHP, runner reads them statically before spawn).

by dg improved --cider mode (thx Claude)
by dg Assert: type 'integer' deprecated, use 'int'
by dg uses nette/phpstan-rules
by dg uses dresscode

DressCode replaces Nette Coding Standard in CI, which now runs on PHP 8.4.
It is installed from dev-master, as it has no tagged release yet.
.gitattributes normalizes line endings of all text files (text=auto).

by dg requires PHP 8.1
by dg opened 2.7-dev
by dg Released version 2.6.2
by dg improved error messages, updated readme and agent documentation

Changed messages:
- "This test forgets to execute an assertion." is now "No assertions were
executed in this test."
- a test method with arguments but without a data provider reports "no data
provider is configured" instead of "@dataProvider is missing"
- an empty data provider file reports the data file, not the test file
- DomQuery names the unsupported pseudo-class or combinator instead of
"Not implemented."
- Helpers::prepareTempDir() shows the given path instead of an empty one
- fixed wording of CLI option errors ("does not accept an argument",
"more than once") and a stray apostrophe
- Assert::contains() and notContains() keep the custom description when the
needle is not a string

Assert::throws() declares the same type of $code as exception(). Expect
lists all supported constraints. The readme example is runnable, lists all
assertions and matches the current output and options.

by dg added support for PHP 8.6

Dumper: replaced spl_object_hash() with spl_object_id(), the former is
deprecated. TestCase: ReflectionMethod::invoke() no longer receives an
object for a static test method. Assert::type() maps the 'integer' alias
to is_int(), because is_integer() is deprecated. FileMock.phpt: PHP 8.6
no longer shows the path in the warning about a failed stream_open().

by dg HtmlGenerator: last line of a file without trailing newline has its line number

The number of lines was the count of newlines plus one, and the code
view listed the numbers up to that count exclusively, so the last line of
a file not ending with a newline had no line number and coverage mark.
The number of lines is now counted correctly, which also fixes the total
shown in the report header.

by dg HtmlGenerator: report can be rendered repeatedly in one process

The template declared a global function, so rendering a second report in
the same process failed on its redeclaration.

by dg HtmlGenerator: file and directory names are escaped in the report

Names were inserted into the page as HTML, so a path containing HTML
special characters broke the report and could inject active content when
opening a report generated from a foreign source tree. Directories in
the tree view use generated element ids, as a path may contain
characters like # that break the links.

Not covered by a test, as the names are inserted by JavaScript of the
report template.

by dg CliTester: coverage report does not pollute machine-readable output, failure to generate it is an error

With -o tap, junit or none on stdout, the final "% covered" line was
still printed into the TAP or XML output; the error about an empty
coverage file goes to stderr in that case. When the requested report
cannot be generated, tester now exits with code 1.

by dg CloverXMLGenerator: file and project metrics include functions and code outside classes

Metrics of a file were the sum of its classes and traits only, so free
functions and top-level statements were missing although their <line>
elements were reported. Functions are now counted among methods, and the
statements of a loaded file are all its executable lines. For a never
loaded file the statements are still estimated from methods and
functions.

by dg PhpParser: recognizes enums and functions returning by reference

Methods of an enum were reported as free functions, and a function or
method declared as function &name() was not reported at all. Enums are
listed among classes, so they are included in Clover metrics.

by dg HtmlGenerator: file containing only dead code no longer causes division by zero

Such a file has nothing left uncovered and is shown with 100 % coverage.

by dg Helpers: purge() refuses also paths resolving to a root directory

The guard checked only the literal form of the path, so e.g. a path
ending with '..' or a symbolic link pointing to the root passed.

by dg JUnitPrinter: failed tests are counted in the failures attribute

Failed tests are reported as <failure> elements, but the summary counted
them in the errors attribute and failures was missing. The testsuite
element now has failures with their number and errors="0". Consumers
reading only the errors attribute will see 0 now.

by dg JUnitPrinter: report is well-formed XML regardless of the test output

A failure message comes from the output of the test process, and control
characters or invalid UTF-8 in it made the whole report unparsable.
They are now replaced by U+FFFD, in test names as well.

by dg TestHandler: invalid @multiple value is an error

@multiple 0 or a non-numeric value ran the test twice, because the
value was cast to int and used as range(0, $count - 1). It now fails
with a message that a positive integer is expected.

by dg DomQuery: fixed attribute suffix selector, quotes in attribute values and scope of selector lists on PHP < 8.4

css2xpath() converted [attr$="val"] to an expression that never matched
a longer value. An attribute value containing an apostrophe produced an
invalid XPath expression, and a quoted value lost all its surrounding
quotes instead of one pair.

On PHP < 8.4, find() and matches() with a selector list like 'a, b'
applied the axis only to the first alternative, so find() returned
elements from the whole document. The output format of css2xpath() for
selector lists is unchanged.

by dg FileMock: fixed append through multiple handles, mode flags and touch()

Appending remembered the end of the file at open time, so two handles
opened in 'a' mode overwrote each other's data. A mode like 'rb+' was
treated as read-only, because the parser did not reach the '+' after a
flag; like PHP, only the first character and the presence of '+' matter
now. touch() creates a missing file.

by dg Assert: fixed UTF-8 matching and %f% in masks, pcre.backtrack_limit is restored on error

The detection of a UTF-8 mask was broken, so characters were always
matched as bytes and e.g. %c% could not match a multibyte character.
A mask containing non-ASCII characters is now matched as UTF-8 when the
actual value is valid UTF-8 as well; binary values are still matched as
bytes.

%f% no longer accepts invalid numbers like '.1.2'.

isMatching() left the raised pcre.backtrack_limit set when the regular
expression threw (e.g. a warning escalated to an exception).

by dg Job: works without setTempDirectory() and captures stderr without a temp directory

run() without a previous setTempDirectory() call failed on an
uninitialized property, as did getDuration() before run(). Without a temp
directory, stderr was connected to a pipe that was closed immediately,
so the output was lost; it is now captured to a tmpfile().

by dg Job: environment variables of the runner process are restored after start

Variables passed to the test process were removed from the runner's
environment after proc_open() instead of being restored, so a variable
the runner itself had (e.g. set by --setup) was lost. They are restored
even when the process fails to start.

by dg Runner: no test process outlives run()

With --stop-on-fail and parallel jobs, run() returned while the other
jobs were still running, after end() had been called on output
handlers, so they could write files or coverage data late or overlap
with the next run in watch mode. Now no new job is started after the
failure, but the running ones are finished and their results reported.

When an exception leaves the loop (Ctrl+C, a failing output handler),
running processes are terminated. Test discovery is inside the
try/finally block too, and end() is called on all output handlers even
if one of them throws.

by dg HttpAssert: headers are taken from the final response only

With follow: true, curl returns header blocks of all responses in the
redirect chain (and interim responses like 100 Continue), and they were
merged into one array, so e.g. Location of the 302 response was visible
after following it. Now each status line resets the parsed headers.

A header sent multiple times (e.g. Set-Cookie) is combined into one
comma-separated value instead of keeping only the last one.

by dg HttpAssert: header existence checks are counted as assertions

expectHeader() without an expected value and denyHeader() for a missing
header did not increment Assert::$counter, so a test consisting only of
such checks failed with "This test forgets to execute an assertion".

by dg Dumper: toPhp() no longer modifies dumped data containing references

A float reachable through a PHP reference (array item, object property)
was converted to a string in the original variable, so a failed
assertion could change data used later by the test or its teardown.
INF, -INF and NAN are now dumped as valid PHP instead of INF.0 etc.

by dg Assert: exception() and error() verify also an empty or '0' message

A message pattern '' or '0' was treated as "do not check", so any
message passed. Now only null skips the check. Tests that used '' to
disable the message check must pass null instead. The failure message
also shows an exception or error message '0' instead of omitting it.

Last synchronization: 2026-09-13 22:02:52