-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathQueryStringifierTest.php
More file actions
130 lines (123 loc) · 5.15 KB
/
QueryStringifierTest.php
File metadata and controls
130 lines (123 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<?hh // strict
namespace Slack\SQLFake;
use type Facebook\HackTest\{DataProvider, HackTest};
use function Facebook\FBExpect\expect;
use namespace HH\Lib\SQL;
final class QueryStringifierTest extends HackTest {
public static function provideValidQueries(): vec<(SQL\Query, string)> {
return vec[
tuple(new SQL\Query('Hello, World!'), 'Hello, World!'),
tuple(new SQL\Query('5 %% 3'), '5 % 3'),
tuple(new SQL\Query('SELECT %d', 5), 'SELECT 5'),
tuple(new SQL\Query('SELECT %f', 3.1415926), 'SELECT 3.1415926'),
tuple(new SQL\Query('SELECT %f', (float)(3 * 10 ** 20)), 'SELECT 300000000000000000000.'),
tuple(new SQL\Query('SELECT %s', '"'), 'SELECT "\\""'),
tuple(new SQL\Query('SELECT %s', '\\'), 'SELECT "\\\\"'),
tuple(new SQL\Query('SELECT %C FROM %T', 'col', 'table'), 'SELECT `col` FROM `table`'),
tuple(
new SQL\Query('SELECT %C FROM %T', 'evil`; SLEEP(1); --', 'table'),
'SELECT `evil``; SLEEP(1); --` FROM `table`',
),
tuple(new SQL\Query('%K SELECT 1', 'pool(high_perf)'), '/*pool(high_perf)*/ SELECT 1'),
tuple(new SQL\Query('SELECT %Ld', vec[]), 'SELECT '),
tuple(new SQL\Query('SELECT %Ld', vec[1, 2, 42]), 'SELECT 1, 2, 42'),
tuple(new SQL\Query('SELECT %Lf', vec[]), 'SELECT '),
tuple(new SQL\Query('SELECT %Lf', vec[1.2, 2.1, 42.42]), 'SELECT 1.2, 2.1, 42.42'),
tuple(new SQL\Query('SELECT %Ls', vec[]), 'SELECT '),
tuple(new SQL\Query('SELECT %Ls', vec['a', '"', '\\']), 'SELECT "a", "\\"", "\\\\"'),
tuple(new SQL\Query('SELECT %LC FROM %T', vec['col', 'ev`il'], 't'), 'SELECT `col`, `ev``il` FROM `t`'),
tuple(new SQL\Query('SELECT %C %=d', 'c', null), 'SELECT `c` IS NULL'),
tuple(new SQL\Query('SELECT %C %=d', 'c', 5), 'SELECT `c` = 5'),
tuple(new SQL\Query('SELECT %C %=f', 'c', null), 'SELECT `c` IS NULL'),
tuple(new SQL\Query('SELECT %C %=f', 'c', 53.35), 'SELECT `c` = 53.35'),
tuple(new SQL\Query('SELECT %C %=s', 'c', null), 'SELECT `c` IS NULL'),
tuple(new SQL\Query('SELECT %C %=s', 'c', '"; --'), 'SELECT `c` = "\\"; --"'),
tuple(
new SQL\Query('SELECT * FROM %Q', new SQL\Query('%T', 'your_imagination')),
'SELECT * FROM `your_imagination`',
),
tuple(
new SQL\Query(
'%K SELECT %LC FROM %T WHERE %C %=d %% 8 AND %C %=s AND %C IN(%Ld) ORDER BY %Q',
'advanced',
vec['a', 'b', 'c'],
't',
'd',
5,
'e',
null,
'f',
vec[1, 2, 3],
new SQL\Query('%C, %C DESC', 'a', 'b'),
),
'/*advanced*/ SELECT `a`, `b`, `c` FROM `t` WHERE `d` = 5 % 8 AND `e` IS NULL AND `f` IN(1, 2, 3) ORDER BY `a`, `b` DESC',
),
];
}
<<DataProvider('provideValidQueries')>>
public function testCorrectStringification(SQL\Query $query, string $expected): void {
expect(QueryStringifier::createForTypesafeHack()->formatQuery($query))->toEqual($expected);
}
public function provideInvalidQueries(): vec<(SQL\Query, string)> {
return vec[
tuple(new SQL\Query('SELECT "dangerous character"'), 'Saw dangerous character " in SQL query'),
tuple(new SQL\Query("SELECT 'dangerous character'"), 'Saw dangerous character \' in SQL query'),
tuple(new SQL\Query('SELECT `dangerous character`'), 'Saw dangerous character ` in SQL query'),
tuple(new SQL\Query('SELECT ;'), 'Saw dangerous character ; in SQL query'),
tuple(
/* HH_FIXME[4038] no format_eof() method */
new SQL\Query('SELECT %'),
"Invalid format specifier, got ''",
),
tuple(
/* HH_FIXME[4038] format_upcase_b() method */
new SQL\Query('SELECT %B FROM'),
"Invalid format specifier, got 'B '",
),
tuple(
new SQL\Query('SELECT %s', static::tellALie<string>(3)),
'Expected ?string for specifier %s at index 0, got integer. Query: SELECT %s',
),
tuple(
new SQL\Query('SELECT %Ls', static::tellALie<vec<string>>('not a vec')),
'Expected vec<string> for specifier %Ls at index 0, got string. Query: SELECT %Ls',
),
tuple(
new SQL\Query('SELECT %Ls', static::tellALie<vec<string>>(vec[null])),
'Expected all elements of vec to be string for specifier %Ls at index 0, got NULL. Query: SELECT %Ls',
),
tuple(
/* HH_FIXME[4105] Too many arguments */
new SQL\Query('no modifiers', 'an argument'),
'Too many arguments provided, got 1, expected 0. Format: no modifiers',
),
tuple(
/* HH_FIXME[4105] Too many arguments */
new SQL\Query('one %s modifier', 'ok', 'bad'),
'Too many arguments provided, got 2, expected 1. Format: one %s modifier',
),
tuple(
/* HH_FIXME[4104] Too few arguments */
new SQL\Query('one %s modifier'),
'Too few arguments provided, got 0. Format: one %s modifier',
),
];
}
<<DataProvider('provideInvalidQueries')>>
public function testRuntimeGuarding(SQL\Query $query, string $exception_message): void {
try {
QueryStringifier::createForTypesafeHack()->formatQuery($query);
expect(false)->toBeTrue('Expected an exception, got none');
} catch (SQLFakeParseException $e) {
do {
$message = $e->getMessage();
$e = $e->getPrevious();
} while ($e is nonnull);
expect($message)->toContainSubstring($exception_message);
}
}
private static function tellALie<T>(mixed $mixed): T {
/* HH_FIXME[4110] We are telling lies intentionally. */
return $mixed;
}
}