Skip to content

Commit

Permalink
compiler exception tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubkulhan committed May 28, 2024
1 parent 2da02ff commit 91d761b
Show file tree
Hide file tree
Showing 44 changed files with 340 additions and 24 deletions.
8 changes: 4 additions & 4 deletions data-access-kit/src/Repository/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ public function prepare(ReflectionClass|string $repositoryInterface): Result

if (!$repositoryInterface->isInterface()) {
throw new CompilerException(sprintf(
"The provided class name must be an interface, %s is not an interface.",
$repositoryInterface,
"The provided class name must be an interface, [%s] is not an interface.",
$repositoryInterface->getName(),
));
}

Expand Down Expand Up @@ -147,7 +147,7 @@ public function compile(Result $result): Result
$returnType = $rm->getReturnType();
if (!$returnType instanceof ReflectionNamedType || !in_array($returnType->getName(), ["array", "iterable", $result->repository->class], true)) {
throw new CompilerException(sprintf(
"Method [%s::%s] must return array, iterable, or [%s] to able to be generated. Either change the return type, add an attribute, or remove the method.",
"Find method [%s::%s] must return array, iterable, or [%s] to able to be generated. Either change the return type, add an attribute, or remove the method.",
$result->reflection->getName(),
$rm->getName(),
$result->repository->class,
Expand All @@ -161,7 +161,7 @@ public function compile(Result $result): Result
$returnType = $rm->getReturnType();
if (!$returnType instanceof ReflectionNamedType || $returnType->getName() !== "int") {
throw new CompilerException(sprintf(
"Method [%s::%s] must return int to able to be generated. Either change the return type, add an attribute, or remove the method.",
"Count method [%s::%s] must return int to able to be generated. Either change the return type, add an attribute, or remove the method.",
$result->reflection->getName(),
$rm->getName(),
));
Expand Down
4 changes: 2 additions & 2 deletions data-access-kit/src/Repository/Method/BuildWhereTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ private function buildWhere(ResultMethod $method, Table $table, Result $result,
}
if ($column === null) {
throw new CompilerException(sprintf(
"Method [%s::%s] parameter [%s] does not match any property of [%s], and therefore cannot be used as a query condition.",
"Parameter [%s] of method [%s::%s] does not match any property of [%s], and therefore cannot be used as a query condition.",
$parameter->getName(),
$result->reflection->getName(),
$method->reflection->getName(),
$parameter->getName(),
$result->repository->class,
));
}
Expand Down
31 changes: 30 additions & 1 deletion data-access-kit/src/Repository/Method/DelegateMethodCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@

use DataAccessKit\Repository\Attribute\Delegate;
use DataAccessKit\Repository\Compiler;
use DataAccessKit\Repository\Exception\CompilerException;
use DataAccessKit\Repository\MethodCompilerInterface;
use DataAccessKit\Repository\Result;
use DataAccessKit\Repository\ResultMethod;
use ReflectionClass;
use ReflectionException;
use ReflectionNamedType;
use function class_exists;
use function lcfirst;
use function sprintf;
use function ucfirst;

/**
Expand All @@ -19,7 +23,21 @@ class DelegateMethodCompiler implements MethodCompilerInterface
{
public function compile(Result $result, ResultMethod $method, $attribute): void
{
$delegateRC = new ReflectionClass($attribute->class);
try {
$delegateRC = new ReflectionClass($attribute->class);
} catch (ReflectionException $e) {
throw new CompilerException(
sprintf(
"Delegate class [%s] referenced by method [%s::%s] does not exist. Please fix the class, interface, or trait reference.",
$attribute->class,
$result->reflection->getName(),
$method->reflection->getName(),
),
0,
$e,
);
}

$alias = $result->use($delegateRC->getName());
$propertyName = lcfirst($alias);

Expand Down Expand Up @@ -54,6 +72,17 @@ public function compile(Result $result, ResultMethod $method, $attribute): void
}

$delegateMethodName = $attribute->method ?? $method->name;
if (!$delegateRC->hasMethod($delegateMethodName)) {
throw new CompilerException(
sprintf(
"Delegate method [%s::%s] referenced by method [%s::%s] does not exist. Please fix the method name.",
$delegateRC->getName(),
$delegateMethodName,
$result->reflection->getName(),
$method->reflection->getName(),
),
);
}
$returnType = $method->reflection->getReturnType();
$void = $returnType instanceof ReflectionNamedType && $returnType->getName() === "void";
$method->line((!$void ? "return " : "") . "\$this->{$propertyName}->{$delegateMethodName}(...func_get_args());");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function compile(Result $result, ResultMethod $method, $attribute): void
$file = dirname($result->reflection->getFileName()) . DIRECTORY_SEPARATOR . $file;
}

$contents = file_get_contents($file);
$contents = @file_get_contents($file);
if ($contents === false) {
throw new CompilerException(sprintf(
"SQL file for method [%s::%s] does not exist or is not readable.",
Expand Down
52 changes: 37 additions & 15 deletions data-access-kit/test/Repository/CompilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,21 @@
use DataAccessKit\Registry;
use DataAccessKit\Repository\Exception\CompilerException;
use DataAccessKit\Repository\Fixture\AbsoluteSQLFileRepositoryInterface;
use DataAccessKit\Repository\Fixture\CountBadParameterNameRepositoryInterface;
use DataAccessKit\Repository\Fixture\CountBadReturnTypeRepositoryInterface;
use DataAccessKit\Repository\Fixture\DelegateClassDoesNotExistRepositoryInterface;
use DataAccessKit\Repository\Fixture\DelegateMethodDoesNotExistRepositoryInterface;
use DataAccessKit\Repository\Fixture\EmptyFileNameSQLFileRepositoryInterface;
use DataAccessKit\Repository\Fixture\FileDoesNotExistSQLFileRepositoryInterface;
use DataAccessKit\Repository\Fixture\FindBadParameterNameRepositoryInterface;
use DataAccessKit\Repository\Fixture\FindBadReturnTypeRepositoryInterface;
use DataAccessKit\Repository\Fixture\MacroColumnsExceptAllColumnRepositoryInterface;
use DataAccessKit\Repository\Fixture\MacroColumnsExceptFromRepositoryInterface;
use DataAccessKit\Repository\Fixture\MacroColumnsExceptMultipleFromRepositoryInterface;
use DataAccessKit\Repository\Fixture\MacroColumnsExceptMultipleRepositoryInterface;
use DataAccessKit\Repository\Fixture\MacroColumnsExceptRepositoryInterface;
use DataAccessKit\Repository\Fixture\MacroUnknownRepositoryInterface;
use DataAccessKit\Repository\Fixture\MacroColumnsExceptUnknownColumnRepositoryInterface;
use DataAccessKit\Repository\Fixture\MacroColumnsFromRepositoryInterface;
use DataAccessKit\Repository\Fixture\MacroColumnsRepositoryInterface;
use DataAccessKit\Repository\Fixture\CountRepositoryInterface;
Expand All @@ -31,6 +42,12 @@
use DataAccessKit\Repository\Fixture\SimpleSQLNullableObjectRepositoryInterface;
use DataAccessKit\Repository\Fixture\SimpleSQLObjectRepositoryInterface;
use DataAccessKit\Repository\Fixture\MacroTableSQLRepositoryInterface;
use DataAccessKit\Repository\Fixture\UnhandledMethodRepositoryInterface;
use DataAccessKit\Repository\Fixture\UnknownVariableSQLRepositoryInterface;
use DataAccessKit\Repository\Fixture\UnsupportedReturnTypeIntersectRepositoryInterface;
use DataAccessKit\Repository\Fixture\UnsupportedReturnTypeMixedRepositoryInterface;
use DataAccessKit\Repository\Fixture\UnsupportedReturnTypeObjectRepositoryInterface;
use DataAccessKit\Repository\Fixture\UnsupportedReturnTypeUnionRepositoryInterface;
use DataAccessKit\Repository\Fixture\UnusedVariableSQLRepositoryInterface;
use DataAccessKit\Repository\Fixture\VariableSQLRepositoryInterface;
use DataAccessKit\Repository\Fixture\VoidSQLRepositoryInterface;
Expand All @@ -56,20 +73,6 @@ protected function setUp(): void
$this->compiler = new Compiler(new Registry(new DefaultNameConverter()));
}

public function testCompileAcceptsOnlyInterface()
{
$this->expectException(CompilerException::class);
$this->expectExceptionMessage("must be an interface");
$this->compiler->compile($this->compiler->prepare(CompilerTest::class));
}

public function testCompileAcceptsOnlyInterfaceWithAttribute()
{
$this->expectException(CompilerException::class);
$this->expectExceptionMessage("must have a #[\\DataAccessKit\\Repository\\Attribute\\Repository] attribute");
$this->compiler->compile($this->compiler->prepare(NoAttributeInterface::class));
}

#[DataProvider("provideCompile")]
public function testCompile(string $interfaceName)
{
Expand Down Expand Up @@ -113,7 +116,7 @@ public static function provideCompile()
public function testCompileError(string $interfaceName): void
{
try {
$this->compiler->compile($this->compiler->prepare(UnusedVariableSQLRepositoryInterface::class));
$this->compiler->compile($this->compiler->prepare($interfaceName));
} catch (CompilerException $e) {
$this->assertMatchesSnapshot($e->getMessage());
}
Expand All @@ -122,7 +125,26 @@ public function testCompileError(string $interfaceName): void
public static function provideCompileError(): iterable
{
return static::provideRepositoryClasses([
CompilerTest::class,
NoAttributeInterface::class,
UnusedVariableSQLRepositoryInterface::class,
FindBadReturnTypeRepositoryInterface::class,
CountBadReturnTypeRepositoryInterface::class,
UnhandledMethodRepositoryInterface::class,
FindBadParameterNameRepositoryInterface::class,
CountBadParameterNameRepositoryInterface::class,
DelegateClassDoesNotExistRepositoryInterface::class,
DelegateMethodDoesNotExistRepositoryInterface::class,
FileDoesNotExistSQLFileRepositoryInterface::class,
EmptyFileNameSQLFileRepositoryInterface::class,
UnsupportedReturnTypeUnionRepositoryInterface::class,
UnsupportedReturnTypeIntersectRepositoryInterface::class,
UnsupportedReturnTypeMixedRepositoryInterface::class,
UnsupportedReturnTypeObjectRepositoryInterface::class,
UnknownVariableSQLRepositoryInterface::class,
MacroColumnsExceptUnknownColumnRepositoryInterface::class,
MacroColumnsExceptAllColumnRepositoryInterface::class,
MacroUnknownRepositoryInterface::class,
]);
}

Expand Down
16 changes: 16 additions & 0 deletions data-access-kit/test/Repository/Fixture/Bar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Attribute\Column;
use DataAccessKit\Attribute\Table;

#[Table]
class Bar
{
#[Column(primary: true, generated: true)]
public int $id;

#[Column]
public string $title;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Repository;

#[Repository(Foo::class)]
interface CountBadParameterNameRepositoryInterface
{
public function countByTitle(string $tytle): int;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Repository;

#[Repository(Foo::class)]
interface CountBadReturnTypeRepositoryInterface
{
public function countByTitle(string $title): Foo;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Delegate;
use DataAccessKit\Repository\Attribute\Repository;

#[Repository(Foo::class)]
interface DelegateClassDoesNotExistRepositoryInterface
{
#[Delegate('This\Class\Does\Not\Exist')]
public function foo();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Delegate;
use DataAccessKit\Repository\Attribute\Repository;

#[Repository(Foo::class)]
interface DelegateMethodDoesNotExistRepositoryInterface
{
#[Delegate(DeepThought::class, method: "thisMethodDoesNotExist")]
public function computeTheAnswer(): int;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Repository;
use DataAccessKit\Repository\Attribute\SQLFile;

#[Repository(Foo::class)]
interface EmptyFileNameSQLFileRepositoryInterface
{
#[SQLFile("")]
public function findByTitle(string $title): iterable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Repository;
use DataAccessKit\Repository\Attribute\SQLFile;

#[Repository(Foo::class)]
interface FileDoesNotExistSQLFileRepositoryInterface
{
#[SQLFile(file: __DIR__ . "/file-does-not-exist.sql")]
public function findByTitle(string $title): iterable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Repository;

#[Repository(Foo::class)]
interface FindBadParameterNameRepositoryInterface
{
public function findByTitle(string $tytle): iterable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Repository;

#[Repository(Foo::class)]
interface FindBadReturnTypeRepositoryInterface
{
public function findByTitle(string $title): int;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Repository;
use DataAccessKit\Repository\Attribute\SQL;

#[Repository(Foo::class)]
interface MacroColumnsExceptAllColumnRepositoryInterface
{
#[SQL("SELECT %columns(except id, title, description) FROM foos")]
public function allColumnsExcept(): iterable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Repository;
use DataAccessKit\Repository\Attribute\SQL;

#[Repository(Foo::class)]
interface MacroColumnsExceptUnknownColumnRepositoryInterface
{
#[SQL("SELECT %columns(except non_existent_column) FROM foos")]
public function allColumnsExcept(): iterable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Repository;
use DataAccessKit\Repository\Attribute\SQL;

#[Repository(Foo::class)]
interface MacroUnknownRepositoryInterface
{
#[SQL("SELECT %clonums FROM foos")]
public function allColumns(): iterable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Find;
use DataAccessKit\Repository\Attribute\Repository;
use DataAccessKit\Repository\Attribute\SQL;

#[Repository(Foo::class)]
interface MultipleMethodAttributesRepositoryInterface
{
#[SQL("SELECT * FROM foos WHERE title = @title")]
#[Find(where: "title = @title")]
public function findByTitle(string $title): iterable;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Repository;

#[Repository(Foo::class)]
interface UnhandledMethodRepositoryInterface
{
public function unhandled(): void;
}
Loading

0 comments on commit 91d761b

Please sign in to comment.