Skip to content

Commit 911192a

Browse files
committed
Prepare test case template
1 parent 7499560 commit 911192a

12 files changed

Lines changed: 449 additions & 41 deletions

File tree

.scrutinizer.yml

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +0,0 @@
1-
checks:
2-
php: true
3-
4-
filter:
5-
paths:
6-
- "src/*"
7-
8-
tools:
9-
external_code_coverage:
10-
timeout: 600 # Timeout in seconds.
11-
runs: 2 # How many code coverage submissions Scrutinizer will wait
12-
13-
build:
14-
nodes:
15-
analysis:
16-
environment:
17-
php: 8.0
18-
19-
tests:
20-
override:
21-
- php-scrutinizer-run

CHANGELOG.md

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/OptimisticLock.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function __construct(
5959
private string $field = 'version',
6060
?string $column = null,
6161
/** @Enum({"microtime", "random-string", "increment", "datetime"}) */
62-
#[ExpectedValues(valuesFromClass: Listener::class)]
62+
#[ExpectedValues(valuesFromClass: self::class)]
6363
private ?string $rule = null,
6464
) {
6565
$this->column = $column;

tests/Behavior/Functional/Driver/Common/BaseTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function getDriver(): DriverInterface
3737
return static::$driverCache[static::DRIVER] = $this->driver;
3838
}
3939

40-
public function setUp(): void
40+
protected function setUp(): void
4141
{
4242
$this->setUpLogger($this->getDriver());
4343
if (self::$config['debug'] ?? false) {
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cycle\ORM\Entity\Behavior\Tests\Functional\Driver\Common\Integration;
6+
7+
use Cycle\Annotated\Embeddings;
8+
use Cycle\Annotated\Entities;
9+
use Cycle\Annotated\MergeColumns;
10+
use Cycle\Annotated\MergeIndexes;
11+
use Cycle\Annotated\TableInheritance;
12+
use Cycle\ORM\Collection\ArrayCollectionFactory;
13+
use Cycle\ORM\Config\RelationConfig;
14+
use Cycle\ORM\Entity\Behavior\EventDrivenCommandGenerator;
15+
use Cycle\ORM\Entity\Behavior\Tests\Utils\SimpleContainer;
16+
use Cycle\ORM\Factory;
17+
use Cycle\ORM\ORM;
18+
use Cycle\ORM\ORMInterface;
19+
use Cycle\ORM\Schema;
20+
use Cycle\ORM\SchemaInterface;
21+
use Cycle\ORM\Transaction;
22+
use Cycle\ORM\Transaction\UnitOfWork;
23+
use Cycle\Schema\Compiler;
24+
use Cycle\Schema\Generator\ForeignKeys;
25+
use Cycle\Schema\Generator\GenerateModifiers;
26+
use Cycle\Schema\Generator\GenerateRelations;
27+
use Cycle\Schema\Generator\GenerateTypecast;
28+
use Cycle\Schema\Generator\RenderModifiers;
29+
use Cycle\Schema\Generator\RenderRelations;
30+
use Cycle\Schema\Generator\RenderTables;
31+
use Cycle\Schema\Generator\ResetTables;
32+
use Cycle\Schema\Generator\SyncTables;
33+
use Cycle\Schema\Generator\ValidateEntities;
34+
use Cycle\Schema\Registry;
35+
use Spiral\Attributes\AttributeReader;
36+
use Spiral\Tokenizer\Config\TokenizerConfig;
37+
use Spiral\Tokenizer\Tokenizer;
38+
39+
class BaseTest extends \Cycle\ORM\Entity\Behavior\Tests\Functional\Driver\Common\BaseTest
40+
{
41+
protected SchemaInterface $schema;
42+
protected ORMInterface $orm;
43+
44+
public function tearDown(): void
45+
{
46+
$this->disableProfiling();
47+
unset($this->orm, $this->schema);
48+
parent::tearDown();
49+
}
50+
51+
/**
52+
* @param non-empty-array<non-empty-string>|non-empty-string $entitiesPath
53+
*/
54+
protected function prepareOrm(string|array $entitiesPath): void
55+
{
56+
$tokenizer = new Tokenizer(new TokenizerConfig([
57+
'directories' => (array) $entitiesPath,
58+
'exclude' => [],
59+
]));
60+
61+
$reader = new AttributeReader();
62+
63+
$classLocator = $tokenizer->classLocator();
64+
65+
$this->schema = new Schema((new Compiler())->compile($this->registry = new Registry($this->dbal), [
66+
new ResetTables(),
67+
new Embeddings($classLocator, $reader),
68+
new Entities($classLocator, $reader),
69+
new TableInheritance($reader),
70+
new MergeColumns($reader),
71+
new GenerateRelations(),
72+
new GenerateModifiers(),
73+
new ValidateEntities(),
74+
new RenderTables(),
75+
new RenderRelations(),
76+
new RenderModifiers(),
77+
new ForeignKeys(),
78+
new MergeIndexes($reader),
79+
new SyncTables(),
80+
new GenerateTypecast(),
81+
]));
82+
83+
$this->orm = new ORM(
84+
new Factory(
85+
$this->dbal,
86+
RelationConfig::getDefault(),
87+
null,
88+
new ArrayCollectionFactory(),
89+
),
90+
$this->schema,
91+
new EventDrivenCommandGenerator($this->schema, new SimpleContainer()),
92+
);
93+
}
94+
95+
protected function save(object ...$entities): void
96+
{
97+
$uow = new UnitOfWork($this->orm);
98+
99+
foreach ($entities as $entity) {
100+
$uow->persistDeferred($entity);
101+
}
102+
$result = $uow->run();
103+
$result->isSuccess() or throw $uow->getLastError();
104+
}
105+
106+
protected function cleanHeap(): void
107+
{
108+
$this->orm->getHeap()->clean();
109+
}
110+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cycle\ORM\Entity\Behavior\Tests\Functional\Driver\Common\Integration\CaseTemplate;
6+
7+
use Cycle\ORM\Entity\Behavior\Tests\Traits\TableTrait;
8+
use Cycle\ORM\Select;
9+
use Cycle\ORM\Entity\Behavior\Tests\Functional\Driver\Common\Integration\BaseTest;
10+
11+
abstract class CaseTest extends BaseTest
12+
{
13+
use TableTrait;
14+
15+
public function testPreparedData(): void
16+
{
17+
// Get entity
18+
$user = (new Select($this->orm, Entity\User::class))
19+
->load('posts')
20+
->wherePK(2)
21+
->fetchOne();
22+
\assert($user instanceof Entity\User);
23+
24+
// Check results
25+
self::assertNotNull($user->createdAt);
26+
self::assertNotNull($user->updatedAt);
27+
self::assertSame(0, $user->createdAt <=> $user->updatedAt);
28+
}
29+
30+
public function testCreatedAt(): void
31+
{
32+
// Get entity
33+
$user = $this->orm->make(Entity\User::class, ['login' => 'new-user', 'passwordHash' => '123456789']);
34+
35+
self::assertFalse(isset($user->createdAt));
36+
$this->save($user);
37+
38+
self::assertNotNull($user->createdAt);
39+
40+
// Reload entity
41+
$id = $user->id;
42+
$this->cleanHeap();
43+
$user = (new Select($this->orm, Entity\User::class))
44+
->wherePK($id)
45+
->fetchOne();
46+
self::assertNotNull($user->createdAt);
47+
}
48+
49+
public function testUpdatedAt(): void
50+
{
51+
// Get entity
52+
$user = (new Select($this->orm, Entity\User::class))
53+
->wherePK(2)
54+
->fetchOne();
55+
\assert($user instanceof Entity\User);
56+
$updatedAt = $user->updatedAt;
57+
58+
// Change data
59+
$user->passwordHash = 'new-password-hash';
60+
$this->save($user);
61+
62+
// Check results
63+
self::assertSame(1, $user->updatedAt <=> $updatedAt);
64+
}
65+
66+
protected function setUp(): void
67+
{
68+
// Init DB
69+
parent::setUp();
70+
$this->prepareOrm(__DIR__ . '/Entity');
71+
$this->save(...$this->fillData());
72+
$this->orm->getHeap()->clean();
73+
}
74+
75+
private function fillData(): iterable
76+
{
77+
/**
78+
* @var callable(class-string, array): object $c
79+
*/
80+
$c = \Closure::fromCallable([$this->orm, 'make']);
81+
82+
// Users
83+
$u1 = $c(Entity\User::class, ['login' => 'user-1', 'passwordHash' => '123456789']);
84+
$u2 = $c(Entity\User::class, ['login' => 'user-2', 'passwordHash' => '852741963']);
85+
$u3 = $c(Entity\User::class, ['login' => 'user-3', 'passwordHash' => '321654987']);
86+
$u4 = $c(Entity\User::class, ['login' => 'user-4', 'passwordHash' => '321456987']);
87+
88+
// Posts
89+
$p1 = $c(Entity\Post::class, ['slug' => 'slug-string-1', 'title' => 'Title 1', 'public' => true, 'content' => 'Foo-bar-baz content 1']);
90+
$p2 = $c(Entity\Post::class, ['slug' => 'slug-string-2', 'title' => 'Title 2', 'public' => true, 'content' => 'Foo-bar-baz content 2']);
91+
$p3 = $c(Entity\Post::class, ['slug' => 'slug-string-3', 'title' => 'Title 3', 'public' => false, 'content' => 'Foo-bar-baz content 3']);
92+
$p4 = $c(Entity\Post::class, ['slug' => 'slug-string-4', 'title' => 'Title 4', 'public' => true, 'content' => 'Foo-bar-baz content 4']);
93+
$p5 = $c(Entity\Post::class, ['slug' => 'slug-string-5', 'title' => 'Title 5', 'public' => true, 'content' => 'Foo-bar-baz content 5']);
94+
$p6 = $c(Entity\Post::class, ['slug' => 'slug-string-6', 'title' => 'Title 6', 'public' => true, 'content' => 'Foo-bar-baz content 6']);
95+
96+
// Link posts with users
97+
$u1->posts = [$p1];
98+
$u2->posts = [$p2, $p3];
99+
$u3->posts = [$p4, $p5, $p6];
100+
101+
// Comments
102+
$c1 = $c(Entity\Comment::class, ['post' => $p1, 'user' => $u2, 'content' => 'Foo-bar-baz comment 1', 'public' => true]);
103+
$c2 = $c(Entity\Comment::class, ['post' => $p1, 'user' => $u1, 'content' => 'Reply to comment 1', 'public' => true]);
104+
$c3 = $c(Entity\Comment::class, ['post' => $p2, 'user' => $u1, 'content' => 'Foo-bar-baz comment 2', 'public' => true]);
105+
$c4 = $c(Entity\Comment::class, ['post' => $p2, 'user' => $u2, 'content' => 'Reply to comment 2', 'public' => true]);
106+
$c5 = $c(Entity\Comment::class, ['post' => $p2, 'user' => $u3, 'content' => 'Foo-bar-baz comment 3', 'public' => true]);
107+
$c6 = $c(Entity\Comment::class, ['post' => $p2, 'user' => $u4, 'content' => 'Hidden comment', 'public' => false]);
108+
$c7 = $c(Entity\Comment::class, ['post' => $p2, 'user' => $u4, 'content' => 'Yet another comment', 'public' => true]);
109+
110+
// Tags
111+
$t1 = $c(Entity\Tag::class, ['label' => 'tag-1']);
112+
$t2 = $c(Entity\Tag::class, ['label' => 'tag-2']);
113+
$t3 = $c(Entity\Tag::class, ['label' => 'tag-3']);
114+
$t4 = $c(Entity\Tag::class, ['label' => 'tag-4']);
115+
$t5 = $c(Entity\Tag::class, ['label' => 'tag-5']);
116+
117+
// Link tags with posts
118+
$t1->posts = [$p1, $p2];
119+
$t2->posts = [$p2, $p3];
120+
$t3->posts = [$p3, $p4, $p5];
121+
$t4->posts = [$p4, $p5];
122+
$t5->posts = [$p5, $p6, $p1];
123+
124+
// yield all the entities
125+
yield from [$u1, $u2, $u3, $u4];
126+
yield from [$p1, $p2, $p3, $p4, $p5, $p6];
127+
yield from [$c1, $c2, $c3, $c4, $c5, $c6, $c7];
128+
yield from [$t1, $t2, $t3, $t4, $t5];
129+
}
130+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cycle\ORM\Entity\Behavior\Tests\Functional\Driver\Common\Integration\CaseTemplate\Entity;
6+
7+
use Cycle\Annotated\Annotation\Column;
8+
use Cycle\Annotated\Annotation\Entity;
9+
use Cycle\Annotated\Annotation\Relation\BelongsTo;
10+
use Cycle\ORM\Entity\Behavior\CreatedAt;
11+
use Cycle\ORM\Entity\Behavior\SoftDelete;
12+
use Cycle\ORM\Entity\Behavior\UpdatedAt;
13+
14+
#[Entity(role: Comment::ROLE, table: 'comment')]
15+
#[CreatedAt(field: 'createdAt', column: 'created_at')]
16+
#[UpdatedAt(field: 'updatedAt', column: 'updated_at')]
17+
#[SoftDelete(field: 'deletedAt', column: 'deleted_at')]
18+
class Comment
19+
{
20+
public const ROLE = 'comment';
21+
22+
#[Column(type: 'bigPrimary')]
23+
public ?int $id = null;
24+
25+
#[Column(type: 'boolean')]
26+
public bool $public = false;
27+
28+
#[Column(type: 'text')]
29+
public string $content;
30+
31+
#[Column(type: 'datetime', nullable: true)]
32+
public ?\DateTimeImmutable $published_at = null;
33+
34+
public \DateTimeImmutable $createdAt;
35+
public \DateTimeImmutable $updatedAt;
36+
public ?\DateTimeImmutable $deletedAt = null;
37+
38+
#[BelongsTo(target: User::class, innerKey: 'userId', fkCreate: false)]
39+
public User $user;
40+
41+
#[BelongsTo(target: Post::class, innerKey: 'postId', fkCreate: false)]
42+
public ?Post $post = null;
43+
44+
#[Column(type: 'bigInteger', name: 'user_id')]
45+
public ?int $userId = null;
46+
47+
#[Column(type: 'bigInteger', name: 'post_id')]
48+
public ?int $postId = null;
49+
50+
private function __construct() {}
51+
}

0 commit comments

Comments
 (0)