packages/ztd-query-sqlite/tests/Unit/Sql/Transaction/SqliteTransactionStatementParserTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Sql\Transaction;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use ZtdQuery\Platform\Sqlite\Sql\SqliteLexerProfile;
12use ZtdQuery\Platform\Sqlite\Sql\Transaction\SqliteTransactionStatementParser;
13use ZtdQuery\Shadow\ShadowStore;
14use ZtdQuery\Shadow\ShadowTransactions;
15
16#[CoversClass(SqliteTransactionStatementParser::class)]
17#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Transaction\TransactionTokens::class)]
18#[UsesClass(SqliteLexerProfile::class)]
19final class SqliteTransactionStatementParserTest extends TestCase
20{
21 #[DataProvider('providerSqliteTransactionForms')]
22 public function testParsesSqliteTransactionForms(string $sql): void
23 {
24 self::assertNotNull((new SqliteTransactionStatementParser())->parse($sql));
25 }
26
27 /**
28 * @return array<string, array{string}>
29 */
30 public static function providerSqliteTransactionForms(): array
31 {
32 return [
33 'begin' => ['BEGIN;'],
34 'begin transaction' => ['BEGIN TRANSACTION'],
35 'begin deferred' => ['BEGIN DEFERRED'],
36 'begin deferred transaction' => ['BEGIN DEFERRED TRANSACTION'],
37 'begin immediate' => ['BEGIN IMMEDIATE'],
38 'begin immediate transaction' => ['BEGIN IMMEDIATE TRANSACTION'],
39 'begin exclusive' => ['BEGIN EXCLUSIVE'],
40 'begin exclusive transaction' => ['BEGIN EXCLUSIVE TRANSACTION'],
41 'commit' => ['COMMIT'],
42 'commit transaction' => ['COMMIT TRANSACTION'],
43 'end' => ['END'],
44 'end transaction' => ['END TRANSACTION'],
45 'rollback' => ['ROLLBACK'],
46 'rollback transaction' => ['ROLLBACK TRANSACTION'],
47 'savepoint' => ['SAVEPOINT `a``b`'],
48 'rollback to' => ['ROLLBACK TO point'],
49 'rollback to savepoint' => ['ROLLBACK TO SAVEPOINT point'],
50 'release' => ['RELEASE point'],
51 'release savepoint' => ['RELEASE SAVEPOINT point'],
52 ];
53 }
54
55 public function testRejectsNonSqliteAndMalformedForms(): void
56 {
57 $parser = new SqliteTransactionStatementParser();
58
59 self::assertNull($parser->parse(''));
60 self::assertNull($parser->parse('START TRANSACTION'));
61 self::assertNull($parser->parse('COMMIT WORK'));
62 self::assertNull($parser->parse('SAVEPOINT point extra'));
63 self::assertNull($parser->parse('SAVEPOINT `broken'));
64 }
65
66 public function testAppliesUnescapedSqliteSavepointName(): void
67 {
68 $store = new ShadowStore();
69 $store->set('items', [['id' => 1]]);
70 $transactions = new ShadowTransactions($store);
71 $transactions->begin();
72 $statement = (new SqliteTransactionStatementParser())->parse('SAVEPOINT `a``b`');
73 self::assertNotNull($statement);
74 $statement->apply($transactions);
75 $store->insert('items', [['id' => 2]]);
76
77 $transactions->rollBackTo('a`b');
78
79 self::assertSame([['id' => 1]], $store->get('items'));
80 }
81}
82