| 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. | | | |