Skip to content

Commit

Permalink
Refactor db hook tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kwizer15 committed Oct 4, 2024
1 parent 77dfdd5 commit c2e709d
Show file tree
Hide file tree
Showing 13 changed files with 201 additions and 67 deletions.
105 changes: 74 additions & 31 deletions tests/Unit/DBTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

use PHPUnit\Framework\TestCase;
use Tests\Unit\Mock\DBTestable;
use Tests\Unit\Mock\ObjectMock\DecryptableAndChangableMock;
use Tests\Unit\Mock\ObjectMock\DecryptableMock;
use Tests\Unit\Mock\ObjectMock\ObjectWithDecryptAndChange;
use Tests\Unit\Mock\ObjectMock\ObjectWithDecrypt;
use Tests\Unit\Mock\ObjectMock\DecryptableWithChangedMock;
use Tests\Unit\Mock\ObjectMock\ChangableMock;
use Tests\Unit\Mock\ObjectMock\ObjectMock;
use Tests\Unit\Mock\ObjectMock\ObjectWithEncrypt;
use Tests\Unit\Mock\ObjectMock\ObjectWithIdField;
use Tests\Unit\Mock\ObjectMock\ObjectWithPreInsert;
use Tests\Unit\Mock\ObjectMock\ObjectWithPreSave;
Expand Down Expand Up @@ -124,49 +125,51 @@ public function test_query_with_bad_parameter(): void

public function test_fetch_all_class_decrypt(): void
{
$results = \DB::Prepare('SELECT 1 AS var', [], \DB::FETCH_TYPE_ALL, \PDO::FETCH_CLASS, DecryptableMock::class);
$results = \DB::Prepare('SELECT 1 AS var', [], \DB::FETCH_TYPE_ALL, \PDO::FETCH_CLASS, ObjectWithDecrypt::class);

$this->assertInstanceOf(DecryptableMock::class, $results[0]);
$this->assertInstanceOf(ObjectWithDecrypt::class, $results[0]);
$this->assertSame('1', $results[0]->var);
$this->assertTrue($results[0]->isDecrypted());
$this->assertTrue($results[0]->isMethodCalled('decrypt'));
}

public function test_fetch_all_class_decrypt_changed(): void
{
$results = \DB::Prepare('SELECT 1 AS var', [], \DB::FETCH_TYPE_ALL, \PDO::FETCH_CLASS, DecryptableAndChangableMock::class);
$results = \DB::Prepare('SELECT 1 AS publicVar', [], \DB::FETCH_TYPE_ALL, \PDO::FETCH_CLASS, ObjectWithDecryptAndChange::class);

$this->assertInstanceOf(DecryptableAndChangableMock::class, $results[0]);
$this->assertInstanceOf(ObjectWithDecryptAndChange::class, $results[0]);
$this->assertTrue($results[0]->isMethodCalled('setChanged'));
$this->assertFalse($results[0]->isChanged());
}

public function test_fetch_class_decrypt(): void
{
$results = \DB::Prepare('SELECT 1 AS publicVar', [], \DB::FETCH_TYPE_ROW, \PDO::FETCH_CLASS, DecryptableMock::class);
$results = \DB::Prepare('SELECT 1 AS publicVar', [], \DB::FETCH_TYPE_ROW, \PDO::FETCH_CLASS, ObjectWithDecrypt::class);

$this->assertInstanceOf(DecryptableMock::class, $results);
$this->assertInstanceOf(ObjectWithDecrypt::class, $results);
$this->assertSame('1', $results->publicVar);
$this->assertTrue($results->isDecrypted());
$this->assertTrue($results->isMethodCalled('decrypt'));
}

public function test_fetch_class_decrypt_changed(): void
{
$results = \DB::Prepare('SELECT 1 AS var', [], \DB::FETCH_TYPE_ROW, \PDO::FETCH_CLASS, DecryptableAndChangableMock::class);
$results = \DB::Prepare('SELECT 1 AS publicVar', [], \DB::FETCH_TYPE_ROW, \PDO::FETCH_CLASS, ObjectWithDecryptAndChange::class);

$this->assertInstanceOf(DecryptableAndChangableMock::class, $results);
$this->assertInstanceOf(ObjectWithDecryptAndChange::class, $results);
$this->assertTrue($results->isMethodCalled('setChanged'));
$this->assertFalse($results->isChanged());
}

public function test_fetch_class_no_decrypt_do_not_set_changed(): void
{
$results = \DB::Prepare('SELECT 1 AS var', [], \DB::FETCH_TYPE_ROW, \PDO::FETCH_CLASS, ChangableMock::class);
$results = \DB::Prepare('SELECT 1 AS publicVar', [], \DB::FETCH_TYPE_ROW, \PDO::FETCH_CLASS, ChangableMock::class);

$this->assertInstanceOf(ChangableMock::class, $results);
$this->assertNull($results->isChanged());
}

public function test_fetch_all_class_no_decrypt_do_not_set_changed(): void
{
$results = \DB::Prepare('SELECT 1 AS var', [], \DB::FETCH_TYPE_ALL, \PDO::FETCH_CLASS, ChangableMock::class);
$results = \DB::Prepare('SELECT 1 AS publicVar', [], \DB::FETCH_TYPE_ALL, \PDO::FETCH_CLASS, ChangableMock::class);

$this->assertInstanceOf(ChangableMock::class, $results[0]);
$this->assertNull($results[0]->isChanged());
Expand Down Expand Up @@ -210,7 +213,7 @@ public function test_optimize_database(): void

public function test_save_data(): void
{
$object = new ObjectMock();
$object = $this->thereIsAnObject();
$this->thereIsATableForObject($object);

\DB::save($object);
Expand All @@ -219,56 +222,96 @@ public function test_save_data(): void

}

public function test_call_presave_hook(): void
public static function hookProvider(): iterable
{
$object = new ObjectWithPreSave();
yield from self::hookCalledWithDirectFlagProvider();
yield from self::hookSkippedWithDirectFlagProvider();
}

/**
* @dataProvider hookProvider
*/
public function test_save_call_hooks(string $hook): void
{
$object = $this->thereIsAnObject()->withMethod($hook);
$this->thereIsATableForObject($object);

\DB::save($object);

$this->assertTrue($object->isPreSaveCalled());
$this->assertTrue($object->isMethodCalled($hook));

}

public function test_skip_presave_hook_with_direct_flag(): void
public static function hookSkippedWithDirectFlagProvider(): iterable
{
yield ['preSave'];
yield ['preInsert'];
yield ['postInsert'];
yield ['postSave'];
}

/**
* @dataProvider hookSkippedWithDirectFlagProvider
*/
public function test_save_skip_hook_with_direct_flag(string $hook): void
{
$object = new ObjectWithPreSave();
$object = $this->thereIsAnObject()->withMethod($hook);
$this->thereIsATableForObject($object);

\DB::save($object, true);

$this->assertFalse($object->isPreSaveCalled());
$this->assertFalse($object->isMethodCalled($hook));
}

public function test_save_set_private_id(): void
{
$object = new ObjectWithIdField();
$object = $this->thereIsAnObject()->withField('id');
$this->thereIsATableForObject($object);

\DB::save($object);

$this->assertTrue($object->isIdSet());
}

public function test_call_preinsert_hook(): void
/**
* @dataProvider hookProvider
*/
public function test_save_skip_call_hook_on_object_without_method(string $hook): void
{
$object = new ObjectWithPreInsert();
$object = $this->thereIsAnObject()->withoutMethod($hook);
$this->thereIsATableForObject($object);

\DB::save($object);

$this->assertTrue($object->isPreInsertCalled());
$this->assertFalse($object->isMethodCalled($hook));
}

public function test_skip_preinsert_hook_with_direct_flag(): void
public static function hookCalledWithDirectFlagProvider(): iterable
{
$object = new ObjectWithPreInsert();
yield ['encrypt'];
yield ['decrypt'];
}

/**
* @dataProvider hookCalledWithDirectFlagProvider
*/
public function test_save_call_encrypt_hook_with_direct_flag(string $hook): void
{
$object = $this->thereIsAnObject()->withMethod($hook);
$this->thereIsATableForObject($object);

\DB::save($object, true);

$this->assertFalse($object->isPreInsertCalled());
$this->assertTrue($object->isMethodCalled($hook));
}

/**
* @return ObjectMock
*/
private function thereIsAnObject(): ObjectMock
{
return new ObjectMock();
}

/**
* @before
Expand Down Expand Up @@ -348,11 +391,11 @@ private function thereIsABadDatabaseConfiguration(): void
$reflection->setStaticPropertyValue('connection', null);
}

private function expectPhpError(string $message): void
private function expectPhpError(string $message, int $errorType = E_USER_ERROR): void
{
$this->rollback();
$this->originalErrorHandler = set_error_handler(function (int $errno, string $errstr) use ($message): void {
$this->assertSame(E_USER_ERROR, $errno);
$this->originalErrorHandler = set_error_handler(function (int $errno, string $errstr) use ($message, $errorType): void {
$this->assertSame($errorType, $errno);
$this->assertEquals($message, $errstr);
});
}
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Mock/DBTestable.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static function &Prepare($_query, $_params, $_fetchType = self::FETCH_TYP
return $res;
}

public static function getOptimizationQueries()
public static function getOptimizationQueries(): array
{
$result = array_filter(self::$queries, static function ($query) {
return strpos($query[0], 'OPTIMIZE TABLE') === 0;
Expand Down
18 changes: 0 additions & 18 deletions tests/Unit/Mock/ObjectMock/DecryptableMock.php

This file was deleted.

52 changes: 52 additions & 0 deletions tests/Unit/Mock/ObjectMock/ObjectMock.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ class ObjectMock
{
public $publicVar = null;

public function __construct()
{
$this->methodsCalled = []; // do not declare as property
}

public function getTableName(): string
{
return 'object_mock';
Expand All @@ -15,4 +20,51 @@ public function getTableStructure(): string
{
return 'id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, publicVar VARCHAR(255)';
}

public function withMethod(string $method): self
{
switch ($method) {
case 'setId':
return new ObjectWithSetId();
case 'preSave':
return new ObjectWithPreSave();
case 'preInsert':
return new ObjectWithPreInsert();
case 'postInsert':
return new ObjectWithPostInsert();
case 'encrypt':
return new ObjectWithEncrypt();
case 'decrypt':
return new ObjectWithDecrypt();
case 'postSave':
return new ObjectWithPostSave();

}

throw new \Exception('Unknown method ' . $method);
}

public function __call(string $method, array $arguments)
{
$this->methodsCalled[] = $method;
}

public function isMethodCalled(string $method): bool
{
return in_array($method, $this->methodsCalled ?? [], true);
}

public function withField(string $field): self
{
if ($field === 'id') {
return new ObjectWithIdField();
}

throw new \Exception('Unknown field ' . $field);
}

public function withoutMethod(string $method): self
{
return $this;
}
}
10 changes: 10 additions & 0 deletions tests/Unit/Mock/ObjectMock/ObjectWithBadTypedId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Tests\Unit\Mock\ObjectMock;

class ObjectWithBadTypedId extends ObjectMock
{
public function setId(array $id)
{
}
}
11 changes: 11 additions & 0 deletions tests/Unit/Mock/ObjectMock/ObjectWithDecrypt.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Tests\Unit\Mock\ObjectMock;

class ObjectWithDecrypt extends ObjectMock
{
public function decrypt(): void
{
$this->methodsCalled[] = 'decrypt';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

namespace Tests\Unit\Mock\ObjectMock;

class DecryptableAndChangableMock extends DecryptableMock
class ObjectWithDecryptAndChange extends ObjectWithDecrypt
{
private $changed = null;

public function setChanged(bool $changed): void
{
$this->methodsCalled[] = 'setChanged';
$this->changed = $changed;
}

Expand Down
12 changes: 12 additions & 0 deletions tests/Unit/Mock/ObjectMock/ObjectWithEncrypt.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Tests\Unit\Mock\ObjectMock;

class ObjectWithEncrypt extends ObjectMock
{
public function encrypt(): void
{
$this->methodsCalled[] = 'encrypt';
}

}
11 changes: 11 additions & 0 deletions tests/Unit/Mock/ObjectMock/ObjectWithPostInsert.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Tests\Unit\Mock\ObjectMock;

class ObjectWithPostInsert extends ObjectMock
{
public function postInsert(): void
{
$this->methodsCalled[] = 'postInsert';
}
}
11 changes: 11 additions & 0 deletions tests/Unit/Mock/ObjectMock/ObjectWithPostSave.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Tests\Unit\Mock\ObjectMock;

class ObjectWithPostSave extends ObjectMock
{
public function postSave(): void
{
$this->methodsCalled[] = 'postSave';
}
}
Loading

0 comments on commit c2e709d

Please sign in to comment.