packages/sql-catalog/tests/Unit/Extension/Mysqli/MysqliExtensionTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Extension\Mysqli;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use SqlCatalog\Core\Extension\SinkCallKind;
11use SqlCatalog\Core\Extension\SinkSpec;
12use SqlCatalog\Extension\Mysqli\MysqliExtension;
13
14#[CoversClass(MysqliExtension::class)]
15#[UsesClass(SinkSpec::class)]
16final class MysqliExtensionTest extends TestCase
17{
18 public function testNameIsHowTheCommandLineSelectsIt(): void
19 {
20 self::assertSame('mysqli', (new MysqliExtension())->name());
21 }
22
23 public function testDescriptionMentionsWhatItCovers(): void
24 {
25 self::assertStringContainsString('mysqli', (new MysqliExtension())->description());
26 }
27
28 public function testSinksCoverBothTheObjectAndTheProceduralApi(): void
29 {
30 $kinds = array_map(static fn (SinkSpec $sink): SinkCallKind => $sink->callKind, (new MysqliExtension())->sinks());
31 self::assertContains(SinkCallKind::Method, $kinds);
32 self::assertContains(SinkCallKind::FunctionCall, $kinds);
33 }
34
35 public function testMethodSinksBindVariadicValues(): void
36 {
37 $bind = array_values(array_filter(
38 (new MysqliExtension())->methodSinks(),
39 static fn (SinkSpec $sink): bool => $sink->id === 'mysqli.stmt.bind_param',
40 ));
41 self::assertSame(1, $bind[0]->valuesFrom);
42 }
43
44 public function testFunctionSinksTakeTheStatementAsTheSecondArgument(): void
45 {
46 $positions = array_map(
47 static fn (SinkSpec $sink): ?int => $sink->sqlParameter,
48 (new MysqliExtension())->functionSinks(),
49 );
50 self::assertSame([1], array_values(array_unique($positions)));
51 }
52 public function testEverySinkIsDescribedExactly(): void
53 {
54 $described = array_map(
55 static fn (SinkSpec $sink): string => implode('|', [
56 $sink->id,
57 $sink->callKind->value,
58 $sink->receiverType ?? '-',
59 $sink->name,
60 $sink->role->value,
61 $sink->sqlParameter ?? '-',
62 $sink->valuesParameter ?? '-',
63 $sink->valuesFrom ?? '-',
64 $sink->nameParameter ?? '-',
65 $sink->valueParameter ?? '-',
66 ($sink->kind === null ? '-' : $sink->kind->value) . '/' . ($sink->handleType ?? '-'),
67 ]),
68 (new MysqliExtension())->sinks(),
69 );
70
71 self::assertSame(
72 [
73 'mysqli.query|method|mysqli|query|query|0|-|-|-|-|-/-',
74 'mysqli.real_query|method|mysqli|real_query|query|0|-|-|-|-|-/-',
75 'mysqli.multi_query|method|mysqli|multi_query|query|0|-|-|-|-|-/-',
76 'mysqli.execute_query|method|mysqli|execute_query|query|0|1|-|-|-|-/-',
77 'mysqli.prepare|method|mysqli|prepare|prepare|0|-|-|-|-|-/mysqli_stmt',
78 'mysqli.stmt.bind_param|method|mysqli_stmt|bind_param|bind|-|-|1|-|-|-/-',
79 'mysqli.stmt.execute|method|mysqli_stmt|execute|execute|-|0|-|-|-|-/-',
80 'mysqli.fn.query|function|-|mysqli_query|query|1|-|-|-|-|-/-',
81 'mysqli.fn.real_query|function|-|mysqli_real_query|query|1|-|-|-|-|-/-',
82 'mysqli.fn.multi_query|function|-|mysqli_multi_query|query|1|-|-|-|-|-/-',
83 'mysqli.fn.execute_query|function|-|mysqli_execute_query|query|1|2|-|-|-|-/-',
84 'mysqli.fn.prepare|function|-|mysqli_prepare|prepare|1|-|-|-|-|-/mysqli_stmt',
85 ],
86 $described,
87 );
88 }
89
90 public function testGlobalsAreEmptyBecauseTheHandleIsNotReachedThroughOne(): void
91 {
92 self::assertSame([], (new MysqliExtension())->globals());
93 }
94}
95