Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Differentiate parsing errors in a parent class from the ones in the test class #6684

Open
wants to merge 1 commit into
base: 5.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions composer.json
Expand Up @@ -90,6 +90,8 @@
"tests/data/register_command/examples",
"tests/data/DummyClass.php",
"tests/data/DummyOverloadableClass.php",
"tests/data/InvalidClass.php",
"tests/data/InvalidChildClass.php",
"tests/data/services/UserModel.php",
"tests/data/services/UserService.php",
"tests/unit/Codeception/Command/BaseCommandRunner.php",
Expand Down
13 changes: 11 additions & 2 deletions src/Codeception/Exception/TestParseException.php
Expand Up @@ -8,14 +8,23 @@

class TestParseException extends Exception
{
public function __construct(string $fileName, string $errors = null, int $line = null)
public function __construct(string $fileName, string $errors = null, int $line = null, string $testFile = null)
{
$fileName = self::normalizePathSeparators($fileName);
$this->message = "Couldn't parse test '{$fileName}'";
if ($line !== null) {
$this->message .= " on line {$line}";
}
if ($errors) {
$this->message .= PHP_EOL . $errors;
$this->message .= ":" . PHP_EOL . $errors;
}
if (($testFile = self::normalizePathSeparators($testFile)) && realpath($fileName) !== realpath($testFile)) {
$this->message .= PHP_EOL . "(Error occurred while parsing Test '{$testFile}')";
}
}

public static function normalizePathSeparators(?string $testFile): ?string
{
return str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $testFile ?? '');
}
}
2 changes: 1 addition & 1 deletion src/Codeception/Lib/Parser.php
Expand Up @@ -100,7 +100,7 @@ public static function load(string $file): void
try {
self::includeFile($file);
} catch (ParseError $e) {
throw new TestParseException($file, $e->getMessage(), $e->getLine());
throw new TestParseException($e->getFile(), $e->getMessage(), $e->getLine(), $file);
} catch (Exception) {
// file is valid otherwise
}
Expand Down
5 changes: 5 additions & 0 deletions tests/data/InvalidChildClass.php
@@ -0,0 +1,5 @@
<?php

class InvalidChildClass extends InvalidClass
{
}
6 changes: 6 additions & 0 deletions tests/data/InvalidClass.php
@@ -0,0 +1,6 @@
<?php

class InvalidClass
{
foo
}
76 changes: 75 additions & 1 deletion tests/unit/Codeception/Lib/ParserTest.php
Expand Up @@ -3,6 +3,7 @@
declare(strict_types=1);

use Codeception\Attribute\Group;
use Codeception\Exception\TestParseException;
use Codeception\Lib\Parser;
use Codeception\Scenario;
use Codeception\Test\Cept;
Expand Down Expand Up @@ -146,13 +147,86 @@ public function testParseFileWhichUnsetsFileVariable()
$this->assertSame([], $classes);
}

#[Group('core')]
public function testParseExceptionWithFileNameOnly()
{
$this->expectException(TestParseException::class);
$this->expectExceptionMessage("Couldn't parse test 'test.file'");
throw new TestParseException('test.file');
}

#[Group('core')]
public function testParseExceptionWithErrors()
{
$this->expectException(TestParseException::class);
$this->expectExceptionMessage("Couldn't parse test 'test.file':" . PHP_EOL . "Funny error");
throw new TestParseException('test.file', 'Funny error');
}

#[Group('core')]
public function testParseExceptionWithLineNumber()
{
$this->expectException(TestParseException::class);
$this->expectExceptionMessage("Couldn't parse test 'test.file' on line 27:" . PHP_EOL . "Funny error");
throw new TestParseException('test.file', 'Funny error', 27);
}

#[Group('core')]
public function testParseExceptionWithTestFile()
{
$this->expectException(TestParseException::class);
$this->expectExceptionMessage("Couldn't parse test 'test.file' on line 27:" . PHP_EOL . "Funny error" . PHP_EOL . "(Error occurred while parsing Test 'test.file')");
throw new TestParseException('test.file', 'Funny error', 27, 'test.file');
}

#[Group('core')]
public function testParseExceptionWithDifferentTestFile()
{
$this->expectException(TestParseException::class);
$this->expectExceptionMessage(sprintf(
"Couldn't parse test '%s' on line %d:" . PHP_EOL . "%s" . PHP_EOL . "(Error occurred while parsing Test '%s')",
'parent.file',
27,
'Funny error',
'test.file'
));
throw new TestParseException('parent.file', 'Funny error', 27, 'test.file');
}

#[Group('core')]
public function testModernValidation()
{
$this->expectException(\Codeception\Exception\TestParseException::class);
$this->expectException(TestParseException::class);
Parser::load(codecept_data_dir('Invalid.php'));
}

#[Group('core')]
public function testModernClassValidation()
{
$this->expectException(TestParseException::class);
$this->expectExceptionMessage(sprintf(
"Couldn't parse test '%s' on line %d:" . PHP_EOL . "%s",
TestParseException::normalizePathSeparators(codecept_data_dir('InvalidClass.php')),
5,
'syntax error, unexpected identifier "foo", expecting "function" or "const"'
));
Parser::load(codecept_data_dir('InvalidClass.php'));
}

#[Group('core')]
public function testModernChildClassValidation()
{
$this->expectException(TestParseException::class);
$this->expectExceptionMessage(sprintf(
"Couldn't parse test '%s' on line %d:" . PHP_EOL . "%s" . PHP_EOL . "(Error occurred while parsing Test '%s')",
TestParseException::normalizePathSeparators(codecept_data_dir('InvalidClass.php')),
5,
'syntax error, unexpected identifier "foo", expecting "function" or "const"',
TestParseException::normalizePathSeparators(codecept_data_dir('InvalidChildClass.php'))
));
Parser::load(codecept_data_dir('InvalidChildClass.php'));
}

#[Group('core')]
public function testClassesFromFile()
{
Expand Down