From 096ca5349483638a28accd746a882d3723564f95 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Fri, 15 Nov 2024 19:23:28 -0500 Subject: [PATCH] WIP on SQLite integration test migration --- tests/Integration/SQLite/CountTest.php | 39 +++ tests/Integration/SQLite/CustomTest.php | 94 ++++++ tests/Integration/SQLite/DefinitionTest.php | 36 ++ tests/Integration/SQLite/DeleteTest.php | 50 +++ tests/Integration/SQLite/DocumentListTest.php | 94 ++++++ tests/Integration/SQLite/DocumentTest.php | 244 ++++++++++++++ tests/Integration/SQLiteIntegrationTest.php | 60 ++++ tests/Pest.php | 1 + tests/integration/sqlite/CountTest.php | 70 ---- tests/integration/sqlite/CustomTest.php | 136 -------- tests/integration/sqlite/DefinitionTest.php | 75 ---- tests/integration/sqlite/DeleteTest.php | 81 ----- tests/integration/sqlite/DocumentListTest.php | 134 -------- tests/integration/sqlite/DocumentTest.php | 319 ------------------ tests/integration/sqlite/ThrowawayDb.php | 23 +- 15 files changed, 635 insertions(+), 821 deletions(-) create mode 100644 tests/Integration/SQLite/CountTest.php create mode 100644 tests/Integration/SQLite/CustomTest.php create mode 100644 tests/Integration/SQLite/DefinitionTest.php create mode 100644 tests/Integration/SQLite/DeleteTest.php create mode 100644 tests/Integration/SQLite/DocumentListTest.php create mode 100644 tests/Integration/SQLite/DocumentTest.php create mode 100644 tests/Integration/SQLiteIntegrationTest.php delete mode 100644 tests/integration/sqlite/CountTest.php delete mode 100644 tests/integration/sqlite/CustomTest.php delete mode 100644 tests/integration/sqlite/DefinitionTest.php delete mode 100644 tests/integration/sqlite/DeleteTest.php delete mode 100644 tests/integration/sqlite/DocumentListTest.php delete mode 100644 tests/integration/sqlite/DocumentTest.php diff --git a/tests/Integration/SQLite/CountTest.php b/tests/Integration/SQLite/CountTest.php new file mode 100644 index 0000000..4cb0646 --- /dev/null +++ b/tests/Integration/SQLite/CountTest.php @@ -0,0 +1,39 @@ + + * @license MIT + */ + +declare(strict_types=1); + +use BitBadger\PDODocument\{Count, DocumentException, Field}; +use Test\Integration\SQLite\ThrowawayDb; + +pest()->group('integration', 'sqlite'); + +describe('::all()', function () { + test('counts all documents', function () { + expect(Count::all(ThrowawayDb::TABLE))->toBe(5); + }); +}); + +describe('::byFields()', function () { + test('counts by numeric range', function () { + expect(Count::byFields(ThrowawayDb::TABLE, [Field::between('num_value', 10, 20)]))->toBe(3); + }); + test('counts by non-numeric range', function () { + expect(Count::byFields(ThrowawayDb::TABLE, [Field::between('value', 'aardvark', 'apple')]))->toBe(1); + }); +}); + +describe('::byContains()', function () { + test('throws an exception', function () { + expect(fn () => Count::byContains('', []))->toThrow(DocumentException::class); + }); +}); + +describe('::byJsonPath()', function () { + test('throws an exception', function () { + expect(fn () => Count::byJsonPath('', ''))->toThrow(DocumentException::class); + }); +}); diff --git a/tests/Integration/SQLite/CustomTest.php b/tests/Integration/SQLite/CustomTest.php new file mode 100644 index 0000000..accadc6 --- /dev/null +++ b/tests/Integration/SQLite/CustomTest.php @@ -0,0 +1,94 @@ + + * @license MIT + */ + +declare(strict_types=1); + +use BitBadger\PDODocument\{Count, Custom, DocumentException, Query}; +use BitBadger\PDODocument\Mapper\{CountMapper, DocumentMapper}; +use Test\Integration\SQLite\ThrowawayDb; +use Test\Integration\TestDocument; + +pest()->group('integration', 'sqlite'); + +describe('::runQuery()', function () { + test('runs a valid query successfully', function () { + $stmt = &Custom::runQuery('SELECT data FROM ' . ThrowawayDb::TABLE . ' LIMIT 1', []); + try { + expect($stmt)->not->toBeNull(); + } finally { + $stmt = null; + } + }); + test('fails with an invalid query', function () { + $stmt = null; + try { + expect(function () use (&$stmt) { $stmt = &Custom::runQuery('GRAB stuff FROM over_there UNTIL done', []); }) + ->toThrow(DocumentException::class); + } finally { + $stmt = null; + } + }); +}); + +describe('::list()', function () { + test('returns non-empty list when data is found', function () { + $list = Custom::list(Query::selectFromTable(ThrowawayDb::TABLE), [], new DocumentMapper(TestDocument::class)); + expect($list)->not->toBeNull(); + $count = 0; + foreach ($list->items() as $ignored) $count++; + expect($count)->toBe(5); + }); + test('returns empty list when not data is found', function () { + expect(Custom::list(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'num_value' > :value", + [':value' => 100], new DocumentMapper(TestDocument::class))) + ->not->toBeNull() + ->hasItems()->toBeFalse(); + + }); +}); + +describe('::array()', function () { + test('returns non-empty array when data is found', function () { + expect(Custom::array(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'sub' IS NOT NULL", [], + new DocumentMapper(TestDocument::class))) + ->not->toBeNull()->toHaveCount(2); + }); + test('returns empty array when data is not found', function () { + expect(Custom::array(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'value' = :value", + [':value' => 'not there'], new DocumentMapper(TestDocument::class))) + ->not->toBeNull()->toBeEmpty(); + }); +}); + +describe('::single()', function () { + test('returns a document when one is found', function () { + expect(Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = :id", [':id' => 'one'], + new DocumentMapper(TestDocument::class))) + ->isSome()->toBeTrue()->get()->id->toBe('one'); + }); + test('returns no document when none is found', function () { + expect(Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = :id", + [':id' => 'eighty'], new DocumentMapper(TestDocument::class))) + ->isNone()->toBeTrue(); + }); +}); + +describe('::nonQuery()', function () { + test('works when documents match the WHERE clause', function () { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + expect(Count::all(ThrowawayDb::TABLE))->toBe(0); + }); + test('works when no documents match the WHERE clause', function () { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE . " WHERE data->>'num_value' > :value", [':value' => 100]); + expect(Count::all(ThrowawayDb::TABLE))->toBe(5); + }); +}); + +describe('::scalar()', function () { + test('returns a scalar value', function () { + expect(Custom::scalar("SELECT 5 AS it", [], new CountMapper()))->toBe(5); + }); +}); diff --git a/tests/Integration/SQLite/DefinitionTest.php b/tests/Integration/SQLite/DefinitionTest.php new file mode 100644 index 0000000..d03da73 --- /dev/null +++ b/tests/Integration/SQLite/DefinitionTest.php @@ -0,0 +1,36 @@ + + * @license MIT + */ + +declare(strict_types=1); + +use BitBadger\PDODocument\{Definition, DocumentException, DocumentIndex}; + +pest()->group('integration', 'sqlite'); + +describe('::ensureTable()', function () { + test('creates table and PK index', function () { + expect($this->dbObjectExists('ensured'))->toBeFalse() + ->and($this->dbObjectExists('idx_ensured_key'))->toBeFalse(); + Definition::ensureTable('ensured'); + expect($this->dbObjectExists('ensured'))->toBeTrue() + ->and($this->dbObjectExists('idx_ensured_key'))->toBeTrue(); + }); +}); + +describe('::ensureFieldIndex()', function () { + test('creates an index', function () { + expect($this->dbObjectExists('idx_ensured_test'))->toBeFalse(); + Definition::ensureTable('ensured'); + Definition::ensureFieldIndex('ensured', 'test', ['name', 'age']); + expect($this->dbObjectExists('idx_ensured_test'))->toBeTrue(); + }); +}); + +describe('::ensureDocumentIndex()', function () { + test('throws an exception', function () { + expect(fn () => Definition::ensureDocumentIndex('', DocumentIndex::Full))->toThrow(DocumentException::class); + }); +}); diff --git a/tests/Integration/SQLite/DeleteTest.php b/tests/Integration/SQLite/DeleteTest.php new file mode 100644 index 0000000..de10d81 --- /dev/null +++ b/tests/Integration/SQLite/DeleteTest.php @@ -0,0 +1,50 @@ + + * @license MIT + */ + +declare(strict_types=1); + +use BitBadger\PDODocument\{Count, Delete, DocumentException, Field}; +use Test\Integration\SQLite\ThrowawayDb; + +pest()->group('integration', 'sqlite'); + +describe('::byId()', function () { + test('deletes a document when one exists', function () { + expect(Count::all(ThrowawayDb::TABLE))->toBe(5); + Delete::byId(ThrowawayDb::TABLE, 'four'); + expect(Count::all(ThrowawayDb::TABLE))->toBe(4); + }); + test('does nothing when the document does not exist', function () { + expect(Count::all(ThrowawayDb::TABLE))->toBe(5); + Delete::byId(ThrowawayDb::TABLE, 'negative four'); + expect(Count::all(ThrowawayDb::TABLE))->toBe(5); + }); +}); + +describe('::byFields()', function () { + test('deletes matching documents', function () { + expect(Count::all(ThrowawayDb::TABLE))->toBe(5); + Delete::byFields(ThrowawayDb::TABLE, [Field::notEqual('value', 'purple')]); + expect(Count::all(ThrowawayDb::TABLE))->toBe(2); + }); + test('does nothing when no documents match', function () { + expect(Count::all(ThrowawayDb::TABLE))->toBe(5); + Delete::byFields(ThrowawayDb::TABLE, [Field::equal('value', 'crimson')]); + expect(Count::all(ThrowawayDb::TABLE))->toBe(5); + }); +}); + +describe('::byContains()', function () { + test('throws an exception', function () { + expect(fn () => Delete::byContains('', []))->toThrow(DocumentException::class); + }); +}); + +describe('::byJsonPath()', function () { + test('throws an exception', function () { + expect(fn () => Delete::byJsonPath('', ''))->toThrow(DocumentException::class); + }); +}); diff --git a/tests/Integration/SQLite/DocumentListTest.php b/tests/Integration/SQLite/DocumentListTest.php new file mode 100644 index 0000000..52f97be --- /dev/null +++ b/tests/Integration/SQLite/DocumentListTest.php @@ -0,0 +1,94 @@ + + * @license MIT + */ + +declare(strict_types=1); + +use BitBadger\PDODocument\{DocumentException, DocumentList, Query}; +use BitBadger\PDODocument\Mapper\DocumentMapper; +use Test\Integration\SQLite\ThrowawayDb; +use Test\Integration\TestDocument; + +pest()->group('integration', 'sqlite'); + +describe('::create()', function () { + test('creates a document list', function () { + $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], + new DocumentMapper(TestDocument::class)); + expect($list)->not->toBeNull(); + $list = null; // free database result + }); +}); + +describe('->items()', function () { + test('enumerates items in the list', function () { + $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], + new DocumentMapper(TestDocument::class)); + expect($list)->not->toBeNull(); + $count = 0; + foreach ($list->items() as $item) { + expect(['one', 'two', 'three', 'four', 'five'])->toContain($item->id); + $count++; + } + expect($count)->toBe(5); + }); + test('fails when the list is exhausted', function () { + $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], + new DocumentMapper(TestDocument::class)); + expect($list)->not->toBeNull()->hasItems()->toBeTrue(); + $ignored = iterator_to_array($list->items()); + expect($list)->hasItems()->toBeFalse() + ->and(fn () => iterator_to_array($list->items()))->toThrow(DocumentException::class); + }); +}); + +describe('->hasItems()', function () { + test('returns true when items exist', function () { + $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], + new DocumentMapper(TestDocument::class)); + expect($list)->not->toBeNull()->hasItems()->toBeTrue(); + foreach ($list->items() as $ignored) { + expect($list)->hasItems()->toBeTrue(); + } + expect($list)->hasItems()->toBeFalse(); + }); + test('returns false when no items exist', function () { + expect(DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'num_value' < 0", [], + new DocumentMapper(TestDocument::class))) + ->not->toBeNull()->hasItems()->toBeFalse(); + }); +}); + +describe('->map()', function () { + test('transforms the list', function () { + $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], + new DocumentMapper(TestDocument::class)); + expect($list)->not->toBeNull()->hasItems()->toBeTrue(); + foreach ($list->map(fn($doc) => strrev($doc->id)) as $mapped) { + expect(['eno', 'owt', 'eerht', 'ruof', 'evif'])->toContain($mapped); + } + }); +}); + +describe('->iter()', function () { + test('walks the list', function () { + $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], + new DocumentMapper(TestDocument::class)); + expect($list)->not->toBeNull()->hasItems()->toBeTrue(); + $splats = []; + $list->iter(function ($doc) use (&$splats) { $splats[] = str_repeat('*', strlen($doc->id)); }); + expect(implode(' ', $splats))->toBe('*** *** ***** **** ****'); + }); +}); + +describe('->mapToArray()', function () { + test('creates an associative array', function () { + $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], + new DocumentMapper(TestDocument::class)); + expect($list)->not->toBeNull()->hasItems()->toBeTrue() + ->and($list->mapToArray(fn($it) => $it->id, fn($it) => $it->value)) + ->toBe(['one' => 'FIRST!', 'two' => 'another', 'three' => '', 'four' => 'purple', 'five' => 'purple']); + }); +}); diff --git a/tests/Integration/SQLite/DocumentTest.php b/tests/Integration/SQLite/DocumentTest.php new file mode 100644 index 0000000..ac66802 --- /dev/null +++ b/tests/Integration/SQLite/DocumentTest.php @@ -0,0 +1,244 @@ + + * @license MIT + */ + +declare(strict_types=1); + +use BitBadger\PDODocument\{AutoId, + Configuration, + Count, + Custom, + Delete, + Document, + DocumentException, + DocumentList, + Exists, + Field, + Find, + Query}; +use BitBadger\PDODocument\Mapper\{ArrayMapper}; +use Test\Integration\NumDocument; +use Test\Integration\SQLite\ThrowawayDb; +use Test\Integration\SubDocument; +use Test\Integration\TestDocument; + +pest()->group('integration', 'sqlite'); + +describe('::insert()', function () { + test('inserts an array with no automatic ID', function () { + Document::insert(ThrowawayDb::TABLE, ['id' => 'turkey', 'sub' => ['foo' => 'gobble', 'bar' => 'gobble']]); + $tryDoc = Find::byId(ThrowawayDb::TABLE, 'turkey', TestDocument::class); + expect($tryDoc)->isSome()->toBeTrue() + ->and($tryDoc->get()) + ->id->toBe('turkey') + ->num_value->toBe(0) + ->sub->not->toBeNull() + ->sub->foo->toBe('gobble') + ->sub->bar->toBe('gobble') + ->and($tryDoc->get()->value)->toBeEmpty(); + }); + test('inserts an array with auto-number ID, not provided', function () { + Configuration::$autoId = AutoId::Number; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + + Document::insert(ThrowawayDb::TABLE, ['id' => 0, 'value' => 'new', 'num_value' => 8]); + $doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE, [], new ArrayMapper()); + expect($doc)->isSome()->toBeTrue() + ->and(json_decode($doc->get()['data']))->id->toBe(1); + + Document::insert(ThrowawayDb::TABLE, ['id' => 0, 'value' => 'again', 'num_value' => 7]); + $doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = 2", [], + new ArrayMapper()); + expect($doc)->isSome()->toBeTrue() + ->and(json_decode($doc->get()['data']))->id->toBe(2); + } finally { + Configuration::$autoId = AutoId::None; + } + }); + test('inserts an array with auto-number ID, provided', function () { + Configuration::$autoId = AutoId::Number; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + Document::insert(ThrowawayDb::TABLE, ['id' => 7, 'value' => 'new', 'num_value' => 8]); + $doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE, [], new ArrayMapper()); + expect($doc)->isSome()->toBeTrue() + ->and(json_decode($doc->get()['data']))->id->toBe(7); + } finally { + Configuration::$autoId = AutoId::None; + } + }); + test('inserts an array with auto-UUID ID, not provided', function () { + Configuration::$autoId = AutoId::UUID; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + Document::insert(ThrowawayDb::TABLE, ['id' => '', 'num_value' => 5]); + expect(Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 5)], TestDocument::class)) + ->isSome()->toBeTrue()->get()->id->not->toBeEmpty(); + } finally { + Configuration::$autoId = AutoId::None; + } + }); + test('inserts an array with auto-UUID ID, provided', function () { + Configuration::$autoId = AutoId::UUID; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + $uuid = AutoId::generateUUID(); + Document::insert(ThrowawayDb::TABLE, ['id' => $uuid, 'value' => 'uuid', 'num_value' => 12]); + expect(Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 12)], TestDocument::class)) + ->isSome()->toBeTrue()->get()->id->toBe($uuid); + } finally { + Configuration::$autoId = AutoId::None; + } + }); + test('inserts an array with auto-string ID, not provided', function () { + Configuration::$autoId = AutoId::RandomString; + Configuration::$idStringLength = 6; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + Document::insert(ThrowawayDb::TABLE, ['id' => '', 'value' => 'new', 'num_value' => 8]); + expect(Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 8)], TestDocument::class)) + ->isSome()->toBeTrue()->get()->id->toHaveLength(6); + } finally { + Configuration::$autoId = AutoId::None; + Configuration::$idStringLength = 16; + } + }); + test('inserts an array with auto-string ID, provided', function () { + Configuration::$autoId = AutoId::RandomString; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + Document::insert(ThrowawayDb::TABLE, ['id' => 'my-key', 'value' => 'old', 'num_value' => 3]); + expect(Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 3)], TestDocument::class)) + ->isSome()->toBeTrue()->get()->id->toBe('my-key'); + } finally { + Configuration::$autoId = AutoId::None; + } + }); + test('inserts an object with no automatic ID', function () { + Document::insert(ThrowawayDb::TABLE, new TestDocument('turkey', sub: new SubDocument('gobble', 'gobble'))); + $tryDoc = Find::byId(ThrowawayDb::TABLE, 'turkey', TestDocument::class); + expect($tryDoc)->isSome()->toBeTrue() + ->and($tryDoc->get()) + ->id->toBe('turkey') + ->num_value->toBe(0) + ->sub->not->toBeNull() + ->sub->foo->toBe('gobble') + ->sub->bar->toBe('gobble') + ->and($tryDoc->get()->value)->toBeEmpty(); + }); + test('inserts an object with auto-number ID, not provided', function () { + Configuration::$autoId = AutoId::Number; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + + Document::insert(ThrowawayDb::TABLE, new NumDocument(value: 'taco')); + expect(Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('value', 'taco')], NumDocument::class)) + ->isSome()->toBeTrue()->get()->id->toBe(1); + + Document::insert(ThrowawayDb::TABLE, new NumDocument(value: 'burrito')); + expect(Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('value', 'burrito')], NumDocument::class)) + ->isSome()->toBeTrue()->get()->id->toBe(2); + } finally { + Configuration::$autoId = AutoId::None; + } + }); + test('inserts an object with auto-number ID, provided', function () { + Configuration::$autoId = AutoId::Number; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + Document::insert(ThrowawayDb::TABLE, new NumDocument(64, 'large')); + expect(Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('value', 'large')], NumDocument::class)) + ->isSome()->toBeTrue()->get()->id->toBe(64); + } finally { + Configuration::$autoId = AutoId::None; + } + }); + test('inserts an object with auto-UUID ID, not provided', function () { + Configuration::$autoId = AutoId::UUID; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + Document::insert(ThrowawayDb::TABLE, new TestDocument(value: 'something', num_value: 9)); + expect(Find::firstByFields(ThrowawayDb::TABLE, [Field::exists('value')], TestDocument::class)) + ->isSome()->toBeTrue()->get()->id->not->toBeEmpty(); + } finally { + Configuration::$autoId = AutoId::None; + } + }); + test('inserts an object with auto-UUID ID, provided', function () { + Configuration::$autoId = AutoId::UUID; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + $uuid = AutoId::generateUUID(); + Document::insert(ThrowawayDb::TABLE, new TestDocument($uuid, num_value: 14)); + expect(Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 14)], TestDocument::class)) + ->isSome()->toBeTrue()->get()->id->toBe($uuid); + } finally { + Configuration::$autoId = AutoId::None; + } + }); + test('inserts an object with auto-string ID, not provided', function () { + Configuration::$autoId = AutoId::RandomString; + Configuration::$idStringLength = 40; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + Document::insert(ThrowawayDb::TABLE, new TestDocument(num_value: 55)); + expect(Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 55)], TestDocument::class)) + ->isSome()->toBeTrue()->get()->id->toHaveLength(40); + } finally { + Configuration::$autoId = AutoId::None; + Configuration::$idStringLength = 16; + } + }); + test('inserts an object with auto-string ID, provided', function () { + Configuration::$autoId = AutoId::RandomString; + try { + Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); + Document::insert(ThrowawayDb::TABLE, new TestDocument('my-key', num_value: 3)); + expect(Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 3)], TestDocument::class)) + ->isSome()->toBeTrue()->get()->id->toBe('my-key'); + } finally { + Configuration::$autoId = AutoId::None; + } + }); + test('throws an exception for duplicate key', function () { + expect(fn () => Document::insert(ThrowawayDb::TABLE, new TestDocument('one'))) + ->toThrow(DocumentException::class); + }); +}); + +describe('::save()', function () { + test('inserts a new document', function () { + Document::save(ThrowawayDb::TABLE, new TestDocument('test', sub: new SubDocument('a', 'b'))); + expect(Find::byId(ThrowawayDb::TABLE, 'one', TestDocument::class))->isSome()->toBeTrue(); + }); + test('updates an existing document', function () { + Document::save(ThrowawayDb::TABLE, new TestDocument('two', num_value: 44)); + $tryDoc = Find::byId(ThrowawayDb::TABLE, 'two', TestDocument::class); + expect($tryDoc)->isSome()->toBeTrue() + ->and($tryDoc->get()) + ->num_value->toBe(44) + ->sub->toBeNull(); + }); +}); + +describe('::update()', function () { + test('replaces an existing document', function () { + Document::update(ThrowawayDb::TABLE, 'one', new TestDocument('one', 'howdy', 8, new SubDocument('y', 'z'))); + $tryDoc = Find::byId(ThrowawayDb::TABLE, 'one', TestDocument::class); + expect($tryDoc)->isSome()->toBeTrue() + ->and($tryDoc->get()) + ->num_value->toBe(8) + ->sub->not->toBeNull() + ->sub->foo->toBe('y') + ->sub->bar->toBe('z') + ->and($tryDoc->get()->value)->toBe('howdy'); + }); + test('does nothing for a non-existent document', function () { + expect(Exists::byId(ThrowawayDb::TABLE, 'two-hundred'))->toBeFalse(); + Document::update(ThrowawayDb::TABLE, 'two-hundred', new TestDocument('200')); + expect(Find::byId(ThrowawayDb::TABLE, 'two-hundred', TestDocument::class))->isNone()->toBeTrue(); + }); +}); diff --git a/tests/Integration/SQLiteIntegrationTest.php b/tests/Integration/SQLiteIntegrationTest.php new file mode 100644 index 0000000..7330f32 --- /dev/null +++ b/tests/Integration/SQLiteIntegrationTest.php @@ -0,0 +1,60 @@ + + * @license MIT + * @see https://github.com/Zaid-Ajaj/ThrowawayDb The origin concept + */ + +declare(strict_types=1); + +namespace Test\Integration; + +use BitBadger\PDODocument\{Configuration, Custom, Delete, DocumentException, Field}; +use BitBadger\PDODocument\Mapper\ExistsMapper; +use PHPUnit\Framework\TestCase; +use Test\Integration\SQLite\ThrowawayDb; + +/** + * Integration Test Class wrapper for SQLite integration tests + */ +class SQLiteIntegrationTest extends TestCase +{ + /** @var string Database name for throwaway database */ + static private string $dbName = ''; + + public static function setUpBeforeClass(): void + { + self::$dbName = ThrowawayDb::create(false); + } + + protected function setUp(): void + { + parent::setUp(); + ThrowawayDb::loadData(); + } + + protected function tearDown(): void + { + Delete::byFields(ThrowawayDb::TABLE, [ Field::exists(Configuration::$idField)]); + parent::tearDown(); + } + + public static function tearDownAfterClass(): void + { + ThrowawayDb::destroy(self::$dbName); + self::$dbName = ''; + } + + /** + * Does the given named object exist in the database? + * + * @param string $name The name of the object whose existence should be verified + * @return bool True if the object exists, false if not + * @throws DocumentException If any is encountered + */ + protected function dbObjectExists(string $name): bool + { + return Custom::scalar('SELECT EXISTS (SELECT 1 FROM sqlite_master WHERE name = :name)', + [':name' => $name], new ExistsMapper()); + } +} diff --git a/tests/Pest.php b/tests/Pest.php index 26bbdc0..55d027f 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -13,6 +13,7 @@ // pest()->extend(Tests\TestCase::class)->in('Feature'); pest()->extend(Test\Integration\PgIntegrationTest::class)->in('Integration/PostgreSQL'); +pest()->extend(Test\Integration\SQLiteIntegrationTest::class)->in('Integration/SQLite'); /* |-------------------------------------------------------------------------- diff --git a/tests/integration/sqlite/CountTest.php b/tests/integration/sqlite/CountTest.php deleted file mode 100644 index b94e3d1..0000000 --- a/tests/integration/sqlite/CountTest.php +++ /dev/null @@ -1,70 +0,0 @@ - - * @license MIT - */ - -declare(strict_types=1); - -namespace Test\Integration\SQLite; - -use BitBadger\PDODocument\{Count, DocumentException, Field}; -use PHPUnit\Framework\Attributes\TestDox; -use PHPUnit\Framework\TestCase; - -/** - * SQLite integration tests for the Count class - */ -#[TestDox('Count (SQLite integration)')] -class CountTest extends TestCase -{ - /** @var string Database name for throwaway database */ - private string $dbName; - - protected function setUp(): void - { - parent::setUp(); - $this->dbName = ThrowawayDb::create(); - } - - protected function tearDown(): void - { - ThrowawayDb::destroy($this->dbName); - parent::tearDown(); - } - - #[TestDox('all() succeeds')] - public function testAllSucceeds(): void - { - $count = Count::all(ThrowawayDb::TABLE); - $this->assertEquals(5, $count, 'There should have been 5 matching documents'); - } - - #[TestDox('byFields() succeeds for a numeric range')] - public function testByFieldsSucceedsForANumericRange(): void - { - $count = Count::byFields(ThrowawayDb::TABLE, [Field::between('num_value', 10, 20)]); - $this->assertEquals(3, $count, 'There should have been 3 matching documents'); - } - - #[TestDox('byFields() succeeds for a non-numeric range')] - public function testByFieldsSucceedsForANonNumericRange(): void - { - $count = Count::byFields(ThrowawayDb::TABLE, [Field::between('value', 'aardvark', 'apple')]); - $this->assertEquals(1, $count, 'There should have been 1 matching document'); - } - - #[TestDox('byContains() fails')] - public function testByContainsFails(): void - { - $this->expectException(DocumentException::class); - Count::byContains('', []); - } - - #[TestDox('byJsonPath() fails')] - public function testByJsonPathFails(): void - { - $this->expectException(DocumentException::class); - Count::byJsonPath('', ''); - } -} diff --git a/tests/integration/sqlite/CustomTest.php b/tests/integration/sqlite/CustomTest.php deleted file mode 100644 index a167975..0000000 --- a/tests/integration/sqlite/CustomTest.php +++ /dev/null @@ -1,136 +0,0 @@ - - * @license MIT - */ - -declare(strict_types=1); - -namespace Test\Integration\SQLite; - -use BitBadger\PDODocument\{Count, Custom, DocumentException, Query}; -use BitBadger\PDODocument\Mapper\{CountMapper, DocumentMapper}; -use PHPUnit\Framework\Attributes\TestDox; -use PHPUnit\Framework\TestCase; -use Test\Integration\TestDocument; - -/** - * SQLite Integration tests for the Custom class - */ -#[TestDox('Custom (SQLite integration)')] -class CustomTest extends TestCase -{ - /** @var string Database name for throwaway database */ - private string $dbName; - - public function setUp(): void - { - parent::setUp(); - $this->dbName = ThrowawayDb::create(); - } - - public function tearDown(): void - { - ThrowawayDb::destroy($this->dbName); - } - - #[TestDox('runQuery() succeeds with a valid query')] - public function testRunQuerySucceedsWithAValidQuery(): void - { - $stmt = &Custom::runQuery('SELECT data FROM ' . ThrowawayDb::TABLE . ' LIMIT 1', []); - try { - $this->assertNotNull($stmt, 'The statement should not have been null'); - } finally { - $stmt = null; - } - } - - #[TestDox('runQuery() fails with an invalid query')] - public function testRunQueryFailsWithAnInvalidQuery(): void - { - $this->expectException(DocumentException::class); - $stmt = &Custom::runQuery('GRAB stuff FROM over_there UNTIL done', []); - try { - $this->assertTrue(false, 'This code should not be reached'); - } finally { - $stmt = null; - } - } - - #[TestDox('list() succeeds when data is found')] - public function testListSucceedsWhenDataIsFound(): void - { - $list = Custom::list(Query::selectFromTable(ThrowawayDb::TABLE), [], new DocumentMapper(TestDocument::class)); - $this->assertNotNull($list, 'The document list should not be null'); - $count = 0; - foreach ($list->items() as $ignored) $count++; - $this->assertEquals(5, $count, 'There should have been 5 documents in the list'); - } - - #[TestDox('list() succeeds when no data is found')] - public function testListSucceedsWhenNoDataIsFound(): void - { - $list = Custom::list(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'num_value' > :value", - [':value' => 100], new DocumentMapper(TestDocument::class)); - $this->assertNotNull($list, 'The document list should not be null'); - $this->assertFalse($list->hasItems(), 'There should have been no documents in the list'); - } - - #[TestDox('array() succeeds when data is found')] - public function testArraySucceedsWhenDataIsFound(): void - { - $array = Custom::array(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'sub' IS NOT NULL", [], - new DocumentMapper(TestDocument::class)); - $this->assertNotNull($array, 'The document array should not be null'); - $this->assertCount(2, $array, 'There should have been 2 documents in the array'); - } - - #[TestDox('array() succeeds when no data is found')] - public function testArraySucceedsWhenNoDataIsFound(): void - { - $array = Custom::array(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'value' = :value", - [':value' => 'not there'], new DocumentMapper(TestDocument::class)); - $this->assertNotNull($array, 'The document array should not be null'); - $this->assertCount(0, $array, 'There should have been no documents in the array'); - } - - #[TestDox('single() succeeds when a row is found')] - public function testSingleSucceedsWhenARowIsFound(): void - { - $doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = :id", [':id' => 'one'], - new DocumentMapper(TestDocument::class)); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertEquals('one', $doc->get()->id, 'The incorrect document was returned'); - } - - #[TestDox('single() succeeds when a row is not found')] - public function testSingleSucceedsWhenARowIsNotFound(): void - { - $doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = :id", - [':id' => 'eighty'], new DocumentMapper(TestDocument::class)); - $this->assertTrue($doc->isNone(), 'There should not have been a document returned'); - } - - #[TestDox('nonQuery() succeeds when operating on data')] - public function testNonQuerySucceedsWhenOperatingOnData(): void - { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - $remaining = Count::all(ThrowawayDb::TABLE); - $this->assertEquals(0, $remaining, 'There should be no documents remaining in the table'); - } - - #[TestDox('nonQuery() succeeds when no data matches WHERE clause')] - public function testNonQuerySucceedsWhenNoDataMatchesWhereClause(): void - { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE . " WHERE data->>'num_value' > :value", [':value' => 100]); - $remaining = Count::all(ThrowawayDb::TABLE); - $this->assertEquals(5, $remaining, 'There should be 5 documents remaining in the table'); - } - - #[TestDox('scalar() succeeds')] - public function testScalarSucceeds(): void - { - $value = Custom::scalar("SELECT 5 AS it", [], new CountMapper()); - $this->assertEquals(5, $value, 'The scalar value was not returned correctly'); - } -} diff --git a/tests/integration/sqlite/DefinitionTest.php b/tests/integration/sqlite/DefinitionTest.php deleted file mode 100644 index d861126..0000000 --- a/tests/integration/sqlite/DefinitionTest.php +++ /dev/null @@ -1,75 +0,0 @@ - - * @license MIT - */ - -declare(strict_types=1); - -namespace Test\Integration\SQLite; - -use BitBadger\PDODocument\{Custom, Definition, DocumentException, DocumentIndex}; -use BitBadger\PDODocument\Mapper\ExistsMapper; -use PHPUnit\Framework\Attributes\TestDox; -use PHPUnit\Framework\TestCase; - -/** - * SQLite integration tests for the Definition class - */ -#[TestDox('Definition (SQLite integration)')] -class DefinitionTest extends TestCase -{ - /** @var string Database name for throwaway database */ - private string $dbName; - - protected function setUp(): void - { - parent::setUp(); - $this->dbName = ThrowawayDb::create(withData: false); - } - - protected function tearDown(): void - { - ThrowawayDb::destroy($this->dbName); - parent::tearDown(); - } - - /** - * Does the given named object exist in the database? - * - * @param string $name The name of the object whose existence should be verified - * @return bool True if the object exists, false if not - * @throws DocumentException If any is encountered - */ - private function itExists(string $name): bool - { - return Custom::scalar('SELECT EXISTS (SELECT 1 FROM sqlite_master WHERE name = :name)', - [':name' => $name], new ExistsMapper()); - } - - #[TestDox('ensureTable() succeeds')] - public function testEnsureTableSucceeds(): void - { - $this->assertFalse($this->itExists('ensured'), 'The table should not exist already'); - $this->assertFalse($this->itExists('idx_ensured_key'), 'The key index should not exist already'); - Definition::ensureTable('ensured'); - $this->assertTrue($this->itExists('ensured'), 'The table should now exist'); - $this->assertTrue($this->itExists('idx_ensured_key'), 'The key index should now exist'); - } - - #[TestDox('ensureFieldIndex() succeeds')] - public function testEnsureFieldIndexSucceeds(): void - { - $this->assertFalse($this->itExists('idx_ensured_test'), 'The index should not exist already'); - Definition::ensureTable('ensured'); - Definition::ensureFieldIndex('ensured', 'test', ['name', 'age']); - $this->assertTrue($this->itExists('idx_ensured_test'), 'The index should now exist'); - } - - #[TestDox('ensureDocumentIndex() fails')] - public function testEnsureDocumentIndexFails(): void - { - $this->expectException(DocumentException::class); - Definition::ensureDocumentIndex('nope', DocumentIndex::Full); - } -} diff --git a/tests/integration/sqlite/DeleteTest.php b/tests/integration/sqlite/DeleteTest.php deleted file mode 100644 index 11d5dd9..0000000 --- a/tests/integration/sqlite/DeleteTest.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @license MIT - */ - -declare(strict_types=1); - -namespace Test\Integration\SQLite; - -use BitBadger\PDODocument\{Count, Delete, DocumentException, Field}; -use PHPUnit\Framework\Attributes\TestDox; -use PHPUnit\Framework\TestCase; - -/** - * SQLite integration tests for the Delete class - */ -#[TestDox('Delete (SQLite integration)')] -class DeleteTest extends TestCase -{ - /** @var string Database name for throwaway database */ - private string $dbName; - - protected function setUp(): void - { - parent::setUp(); - $this->dbName = ThrowawayDb::create(); - } - - protected function tearDown(): void - { - ThrowawayDb::destroy($this->dbName); - parent::tearDown(); - } - - #[TestDox('byId() succeeds when a document is deleted')] - public function testByIdSucceedsWhenADocumentIsDeleted(): void - { - $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start'); - Delete::byId(ThrowawayDb::TABLE, 'four'); - $this->assertEquals(4, Count::all(ThrowawayDb::TABLE), 'There should have been 4 documents remaining'); - } - - #[TestDox('byId() succeeds when a document is not deleted')] - public function testByIdSucceedsWhenADocumentIsNotDeleted(): void - { - $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start'); - Delete::byId(ThrowawayDb::TABLE, 'negative four'); - $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents remaining'); - } - - #[TestDox('byFields() succeeds when documents are deleted')] - public function testByFieldsSucceedsWhenDocumentsAreDeleted(): void - { - $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start'); - Delete::byFields(ThrowawayDb::TABLE, [Field::notEqual('value', 'purple')]); - $this->assertEquals(2, Count::all(ThrowawayDb::TABLE), 'There should have been 2 documents remaining'); - } - - #[TestDox('byFields() succeeds when documents are not deleted')] - public function testByFieldsSucceedsWhenDocumentsAreNotDeleted(): void - { - $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start'); - Delete::byFields(ThrowawayDb::TABLE, [Field::equal('value', 'crimson')]); - $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents remaining'); - } - - #[TestDox('byContains() fails')] - public function testByContainsFails(): void - { - $this->expectException(DocumentException::class); - Delete::byContains('', []); - } - - #[TestDox('byJsonPath() fails')] - public function testByJsonPathFails(): void - { - $this->expectException(DocumentException::class); - Delete::byJsonPath('', ''); - } -} diff --git a/tests/integration/sqlite/DocumentListTest.php b/tests/integration/sqlite/DocumentListTest.php deleted file mode 100644 index 8ea2647..0000000 --- a/tests/integration/sqlite/DocumentListTest.php +++ /dev/null @@ -1,134 +0,0 @@ - - * @license MIT - */ - -declare(strict_types=1); - -namespace Test\Integration\SQLite; - -use BitBadger\PDODocument\{DocumentException, DocumentList, Query}; -use BitBadger\PDODocument\Mapper\DocumentMapper; -use PHPUnit\Framework\Attributes\TestDox; -use PHPUnit\Framework\TestCase; -use Test\Integration\TestDocument; - -/** - * SQLite integration tests for the DocumentList class - */ -#[TestDox('DocumentList (SQLite integration)')] -class DocumentListTest extends TestCase -{ - /** @var string Database name for throwaway database */ - private string $dbName; - - protected function setUp(): void - { - parent::setUp(); - $this->dbName = ThrowawayDb::create(); - } - - protected function tearDown(): void - { - ThrowawayDb::destroy($this->dbName); - parent::tearDown(); - } - - #[TestDox('create() succeeds')] - public function testCreateSucceeds(): void - { - $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], - new DocumentMapper(TestDocument::class)); - $this->assertNotNull($list, 'There should have been a document list created'); - $list = null; - } - - #[TestDox('items() succeeds')] - public function testItemsSucceeds(): void - { - $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], - new DocumentMapper(TestDocument::class)); - $this->assertNotNull($list, 'There should have been a document list created'); - $count = 0; - foreach ($list->items() as $item) { - $this->assertContains($item->id, ['one', 'two', 'three', 'four', 'five'], - 'An unexpected document ID was returned'); - $count++; - } - $this->assertEquals(5, $count, 'There should have been 5 documents returned'); - } - - #[TestDox('items() fails when already consumed')] - public function testItemsFailsWhenAlreadyConsumed(): void - { - $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], - new DocumentMapper(TestDocument::class)); - $this->assertNotNull($list, 'There should have been a document list created'); - $this->assertTrue($list->hasItems(), 'There should be items in the list'); - $ignored = iterator_to_array($list->items()); - $this->assertFalse($list->hasItems(), 'The list should no longer have items'); - $this->expectException(DocumentException::class); - iterator_to_array($list->items()); - } - - #[TestDox('hasItems() succeeds with empty results')] - public function testHasItemsSucceedsWithEmptyResults(): void - { - $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'num_value' < 0", [], - new DocumentMapper(TestDocument::class)); - $this->assertNotNull($list, 'There should have been a document list created'); - $this->assertFalse($list->hasItems(), 'There should be no items in the list'); - } - - #[TestDox('hasItems() succeeds with non-empty results')] - public function testHasItemsSucceedsWithNonEmptyResults(): void - { - $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], - new DocumentMapper(TestDocument::class)); - $this->assertNotNull($list, 'There should have been a document list created'); - $this->assertTrue($list->hasItems(), 'There should be items in the list'); - foreach ($list->items() as $ignored) { - $this->assertTrue($list->hasItems(), 'There should be items remaining in the list'); - } - $this->assertFalse($list->hasItems(), 'There should be no remaining items in the list'); - } - - #[TestDox('map() succeeds')] - public function testMapSucceeds(): void - { - $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], - new DocumentMapper(TestDocument::class)); - $this->assertNotNull($list, 'There should have been a document list created'); - $this->assertTrue($list->hasItems(), 'There should be items in the list'); - foreach ($list->map(fn($doc) => strrev($doc->id)) as $mapped) { - $this->assertContains($mapped, ['eno', 'owt', 'eerht', 'ruof', 'evif'], - 'An unexpected mapped value was returned'); - } - } - - #[TestDox('iter() succeeds')] - public function testIterSucceeds(): void - { - $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], - new DocumentMapper(TestDocument::class)); - $this->assertNotNull($list, 'There should have been a document list created'); - $this->assertTrue($list->hasItems(), 'There should be items in the list'); - $splats = []; - $list->iter(function ($doc) use (&$splats) { $splats[] = str_repeat('*', strlen($doc->id)); }); - $this->assertEquals('*** *** ***** **** ****', implode(' ', $splats), - 'Iteration did not have the expected result'); - } - - #[TestDox('mapToArray() succeeds')] - public function testMapToArraySucceeds(): void - { - $list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [], - new DocumentMapper(TestDocument::class)); - $this->assertNotNull($list, 'There should have been a document list created'); - $this->assertTrue($list->hasItems(), 'There should be items in the list'); - $lookup = $list->mapToArray(fn($it) => $it->id, fn($it) => $it->value); - $expected = ['one' => 'FIRST!', 'two' => 'another', 'three' => '', 'four' => 'purple', 'five' => 'purple']; - $this->assertEquals($expected, $lookup, 'The array was not mapped correctly'); - } -} diff --git a/tests/integration/sqlite/DocumentTest.php b/tests/integration/sqlite/DocumentTest.php deleted file mode 100644 index 6abbbde..0000000 --- a/tests/integration/sqlite/DocumentTest.php +++ /dev/null @@ -1,319 +0,0 @@ - - * @license MIT - */ - -declare(strict_types=1); - -namespace Test\Integration\SQLite; - -use BitBadger\PDODocument\{AutoId, Configuration, Custom, Document, DocumentException, Field, Find}; -use BitBadger\PDODocument\Mapper\ArrayMapper; -use PHPUnit\Framework\Attributes\TestDox; -use PHPUnit\Framework\TestCase; -use Test\Integration\{NumDocument, SubDocument, TestDocument}; - -/** - * SQLite integration tests for the Document class - */ -#[TestDox('Document (SQLite integration)')] -class DocumentTest extends TestCase -{ - /** @var string Database name for throwaway database */ - private string $dbName; - - protected function setUp(): void - { - parent::setUp(); - $this->dbName = ThrowawayDb::create(); - } - - protected function tearDown(): void - { - ThrowawayDb::destroy($this->dbName); - parent::tearDown(); - } - - #[TestDox('insert() succeeds for array no auto ID')] - public function testInsertSucceedsForArrayNoAutoId(): void - { - Document::insert(ThrowawayDb::TABLE, ['id' => 'turkey', 'sub' => ['foo' => 'gobble', 'bar' => 'gobble']]); - $tryDoc = Find::byId(ThrowawayDb::TABLE, 'turkey', TestDocument::class); - $this->assertTrue($tryDoc->isSome(), 'There should have been a document inserted'); - $doc = $tryDoc->get(); - $this->assertEquals('turkey', $doc->id, 'The ID was incorrect'); - $this->assertEquals('', $doc->value, 'The value was incorrect'); - $this->assertEquals(0, $doc->num_value, 'The numeric value was incorrect'); - $this->assertNotNull($doc->sub, 'The sub-document should not have been null'); - $this->assertEquals('gobble', $doc->sub->foo, 'The sub-document foo property was incorrect'); - $this->assertEquals('gobble', $doc->sub->bar, 'The sub-document bar property was incorrect'); - } - - #[TestDox('insert() succeeds for array with auto number ID not provided')] - public function testInsertSucceedsForArrayWithAutoNumberIdNotProvided(): void - { - Configuration::$autoId = AutoId::Number; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - - Document::insert(ThrowawayDb::TABLE, ['id' => 0, 'value' => 'new', 'num_value' => 8]); - $doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE, [], new ArrayMapper()); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $obj = json_decode($doc->get()['data']); - $this->assertEquals(1, $obj->id, 'The ID 1 should have been auto-generated'); - - Document::insert(ThrowawayDb::TABLE, ['id' => 0, 'value' => 'again', 'num_value' => 7]); - $doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = 2", [], - new ArrayMapper()); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $obj = json_decode($doc->get()['data']); - $this->assertEquals(2, $obj->id, 'The ID 2 should have been auto-generated'); - } finally { - Configuration::$autoId = AutoId::None; - } - } - - #[TestDox('insert() succeeds for array with auto number ID with ID provided')] - public function testInsertSucceedsForArrayWithAutoNumberIdWithIdProvided(): void - { - Configuration::$autoId = AutoId::Number; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - Document::insert(ThrowawayDb::TABLE, ['id' => 7, 'value' => 'new', 'num_value' => 8]); - $doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE, [], new ArrayMapper()); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $obj = json_decode($doc->get()['data']); - $this->assertEquals(7, $obj->id, 'The ID 7 should have been stored'); - } finally { - Configuration::$autoId = AutoId::None; - } - } - - #[TestDox('insert() succeeds for array with auto UUID ID not provided')] - public function testInsertSucceedsForArrayWithAutoUuidIdNotProvided(): void - { - Configuration::$autoId = AutoId::UUID; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - Document::insert(ThrowawayDb::TABLE, ['id' => '', 'num_value' => 5]); - $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 5)], TestDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertNotEmpty($doc->get()->id, 'The ID should have been auto-generated'); - } finally { - Configuration::$autoId = AutoId::None; - } - } - - #[TestDox('insert() succeeds for array with auto UUID ID with ID provided')] - public function testInsertSucceedsForArrayWithAutoUuidIdWithIdProvided(): void - { - Configuration::$autoId = AutoId::UUID; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - $uuid = AutoId::generateUUID(); - Document::insert(ThrowawayDb::TABLE, ['id' => $uuid, 'value' => 'uuid', 'num_value' => 12]); - $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 12)], TestDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertEquals($uuid, $doc->get()->id, 'The ID should not have been changed'); - } finally { - Configuration::$autoId = AutoId::None; - } - } - - #[TestDox('insert() succeeds for array with auto string ID not provided')] - public function testInsertSucceedsForArrayWithAutoStringIdNotProvided(): void - { - Configuration::$autoId = AutoId::RandomString; - Configuration::$idStringLength = 6; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - Document::insert(ThrowawayDb::TABLE, ['id' => '', 'value' => 'new', 'num_value' => 8]); - $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 8)], TestDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertEquals(6, strlen($doc->get()->id), - 'The ID should have been auto-generated and had 6 characters'); - } finally { - Configuration::$autoId = AutoId::None; - Configuration::$idStringLength = 16; - } - } - - #[TestDox('insert() succeeds for array with auto string ID with ID provided')] - public function testInsertSucceedsForArrayWithAutoStringIdWithIdProvided(): void - { - Configuration::$autoId = AutoId::RandomString; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - Document::insert(ThrowawayDb::TABLE, ['id' => 'my-key', 'value' => 'old', 'num_value' => 3]); - $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 3)], TestDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertEquals('my-key', $doc->get()->id, 'The ID should not have been changed'); - } finally { - Configuration::$autoId = AutoId::None; - } - } - - #[TestDox('insert() succeeds for object no auto ID')] - public function testInsertSucceedsForObjectNoAutoId(): void - { - Document::insert(ThrowawayDb::TABLE, new TestDocument('turkey', sub: new SubDocument('gobble', 'gobble'))); - $tryDoc = Find::byId(ThrowawayDb::TABLE, 'turkey', TestDocument::class); - $this->assertNotFalse($tryDoc->isSome(), 'There should have been a document inserted'); - $doc = $tryDoc->get(); - $this->assertEquals('turkey', $doc->id, 'The ID was incorrect'); - $this->assertEquals('', $doc->value, 'The value was incorrect'); - $this->assertEquals(0, $doc->num_value, 'The numeric value was incorrect'); - $this->assertNotNull($doc->sub, 'The sub-document should not have been null'); - $this->assertEquals('gobble', $doc->sub->foo, 'The sub-document foo property was incorrect'); - $this->assertEquals('gobble', $doc->sub->bar, 'The sub-document bar property was incorrect'); - } - - #[TestDox('insert() succeeds for object with auto number ID not provided')] - public function testInsertSucceedsForObjectWithAutoNumberIdNotProvided(): void - { - Configuration::$autoId = AutoId::Number; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - - Document::insert(ThrowawayDb::TABLE, new NumDocument(value: 'taco')); - $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('value', 'taco')], NumDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertEquals(1, $doc->get()->id, 'The ID 1 should have been auto-generated'); - - Document::insert(ThrowawayDb::TABLE, new NumDocument(value: 'burrito')); - $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('value', 'burrito')], NumDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertEquals(2, $doc->get()->id, 'The ID 2 should have been auto-generated'); - } finally { - Configuration::$autoId = AutoId::None; - } - } - - #[TestDox('insert() succeeds for object with auto number ID with ID provided')] - public function testInsertSucceedsForObjectWithAutoNumberIdWithIdProvided(): void - { - Configuration::$autoId = AutoId::Number; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - Document::insert(ThrowawayDb::TABLE, new NumDocument(64, 'large')); - $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('value', 'large')], NumDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertEquals(64, $doc->get()->id, 'The ID 64 should have been stored'); - } finally { - Configuration::$autoId = AutoId::None; - } - } - - #[TestDox('insert() succeeds for object with auto UUID ID not provided')] - public function testInsertSucceedsForObjectWithAutoUuidIdNotProvided(): void - { - Configuration::$autoId = AutoId::UUID; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - Document::insert(ThrowawayDb::TABLE, new TestDocument(value: 'something', num_value: 9)); - $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::exists('value')], TestDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertNotEmpty($doc->get()->id, 'The ID should have been auto-generated'); - } finally { - Configuration::$autoId = AutoId::None; - } - } - - #[TestDox('insert() succeeds for object with auto UUID ID with ID provided')] - public function testInsertSucceedsForObjectWithAutoUuidIdWithIdProvided(): void - { - Configuration::$autoId = AutoId::UUID; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - $uuid = AutoId::generateUUID(); - Document::insert(ThrowawayDb::TABLE, new TestDocument($uuid, num_value: 14)); - $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 14)], TestDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertEquals($uuid, $doc->get()->id, 'The ID should not have been changed'); - } finally { - Configuration::$autoId = AutoId::None; - } - } - - #[TestDox('insert() succeeds for object with auto string ID not provided')] - public function testInsertSucceedsForObjectWithAutoStringIdNotProvided(): void - { - Configuration::$autoId = AutoId::RandomString; - Configuration::$idStringLength = 40; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - Document::insert(ThrowawayDb::TABLE, new TestDocument(num_value: 55)); - $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 55)], TestDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertEquals(40, strlen($doc->get()->id), - 'The ID should have been auto-generated and had 40 characters'); - } finally { - Configuration::$autoId = AutoId::None; - Configuration::$idStringLength = 16; - } - } - - #[TestDox('insert() succeeds for object with auto string ID with ID provided')] - public function testInsertSucceedsForObjectWithAutoStringIdWithIdProvided(): void - { - Configuration::$autoId = AutoId::RandomString; - try { - Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); - Document::insert(ThrowawayDb::TABLE, new TestDocument('my-key', num_value: 3)); - $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::equal('num_value', 3)], TestDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - $this->assertEquals('my-key', $doc->get()->id, 'The ID should not have been changed'); - } finally { - Configuration::$autoId = AutoId::None; - } - } - - #[TestDox('insert() fails for duplicate key')] - public function testInsertFailsForDuplicateKey(): void - { - $this->expectException(DocumentException::class); - Document::insert(ThrowawayDb::TABLE, new TestDocument('one')); - } - - #[TestDox('save() succeeds when a document is inserted')] - public function testSaveSucceedsWhenADocumentIsInserted(): void - { - Document::save(ThrowawayDb::TABLE, new TestDocument('test', sub: new SubDocument('a', 'b'))); - $doc = Find::byId(ThrowawayDb::TABLE, 'one', TestDocument::class); - $this->assertTrue($doc->isSome(), 'There should have been a document returned'); - } - - #[TestDox('save() succeeds when a document is updated')] - public function testSaveSucceedsWhenADocumentIsUpdated(): void - { - Document::save(ThrowawayDb::TABLE, new TestDocument('two', num_value: 44)); - $tryDoc = Find::byId(ThrowawayDb::TABLE, 'two', TestDocument::class); - $this->assertTrue($tryDoc->isSome(), 'There should have been a document returned'); - $doc = $tryDoc->get(); - $this->assertEquals(44, $doc->num_value, 'The numeric value was not updated'); - $this->assertNull($doc->sub, 'The sub-document should have been null'); - } - - #[TestDox('update() succeeds when replacing a document')] - public function testUpdateSucceedsWhenReplacingADocument(): void - { - Document::update(ThrowawayDb::TABLE, 'one', new TestDocument('one', 'howdy', 8, new SubDocument('y', 'z'))); - $tryDoc = Find::byId(ThrowawayDb::TABLE, 'one', TestDocument::class); - $this->assertTrue($tryDoc->isSome(), 'There should have been a document returned'); - $doc = $tryDoc->get(); - $this->assertEquals('howdy', $doc->value, 'The value was incorrect'); - $this->assertEquals(8, $doc->num_value, 'The numeric value was incorrect'); - $this->assertNotNull($doc->sub, 'The sub-document should not have been null'); - $this->assertEquals('y', $doc->sub->foo, 'The sub-document foo property was incorrect'); - $this->assertEquals('z', $doc->sub->bar, 'The sub-document bar property was incorrect'); - } - - #[TestDox('update() succeeds when no document is replaced')] - public function testUpdateSucceedsWhenNoDocumentIsReplaced(): void - { - Document::update(ThrowawayDb::TABLE, 'two-hundred', new TestDocument('200')); - $doc = Find::byId(ThrowawayDb::TABLE, 'two-hundred', TestDocument::class); - $this->assertTrue($doc->isNone(), 'There should not have been a document returned'); - } -} diff --git a/tests/integration/sqlite/ThrowawayDb.php b/tests/integration/sqlite/ThrowawayDb.php index b199f31..1cb9a3d 100644 --- a/tests/integration/sqlite/ThrowawayDb.php +++ b/tests/integration/sqlite/ThrowawayDb.php @@ -21,6 +21,20 @@ class ThrowawayDb /** @var string The table used for document manipulation */ public const TABLE = 'test_table'; + /** + * Load data into the test table + * + * @throws DocumentException If any is encountered + */ + public static function loadData(): void + { + Document::insert(self::TABLE, new TestDocument('one', 'FIRST!', 0)); + Document::insert(self::TABLE, new TestDocument('two', 'another', 10, new SubDocument('green', 'blue'))); + Document::insert(self::TABLE, new TestDocument('three', '', 4)); + Document::insert(self::TABLE, new TestDocument('four', 'purple', 17, new SubDocument('green', 'red'))); + Document::insert(self::TABLE, new TestDocument('five', 'purple', 18)); + } + /** * Create a throwaway SQLite database * @@ -34,13 +48,10 @@ class ThrowawayDb Configuration::useDSN("sqlite:./$fileName"); Configuration::resetPDO(); + Definition::ensureTable(self::TABLE); + if ($withData) { - Definition::ensureTable(self::TABLE); - Document::insert(self::TABLE, new TestDocument('one', 'FIRST!', 0)); - Document::insert(self::TABLE, new TestDocument('two', 'another', 10, new SubDocument('green', 'blue'))); - Document::insert(self::TABLE, new TestDocument('three', '', 4)); - Document::insert(self::TABLE, new TestDocument('four', 'purple', 17, new SubDocument('green', 'red'))); - Document::insert(self::TABLE, new TestDocument('five', 'purple', 18)); + self::loadData(); } return $fileName;