diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Builder/CallStatementTest.php | 19 | ||||
-rw-r--r-- | tests/Builder/SelectStatementTest.php | 136 | ||||
-rw-r--r-- | tests/Builder/TruncateStatementTest.php | 39 | ||||
-rw-r--r-- | tests/Lexer/IsMethodsTest.php | 7 | ||||
-rw-r--r-- | tests/Utils/CLITest.php | 211 | ||||
-rw-r--r-- | tests/Utils/ErrorTest.php | 7 |
6 files changed, 417 insertions, 2 deletions
diff --git a/tests/Builder/CallStatementTest.php b/tests/Builder/CallStatementTest.php new file mode 100644 index 0000000..f11686e --- /dev/null +++ b/tests/Builder/CallStatementTest.php @@ -0,0 +1,19 @@ +<?php + +namespace PhpMyAdmin\SqlParser\Tests\Builder; + +use PhpMyAdmin\SqlParser\Parser; +use PhpMyAdmin\SqlParser\Tests\TestCase; + +class CallStatementTest extends TestCase +{ + public function testBuilder() + { + $query = 'CALL foo()'; + + $parser = new Parser($query); + $stmt = $parser->statements[0]; + + $this->assertEquals($query, $stmt->build()); + } +} diff --git a/tests/Builder/SelectStatementTest.php b/tests/Builder/SelectStatementTest.php index 2c7350a..a22cf08 100644 --- a/tests/Builder/SelectStatementTest.php +++ b/tests/Builder/SelectStatementTest.php @@ -53,6 +53,142 @@ class SelectStatementTest extends TestCase ); } + public function testBuilderAliasOrder() + { + $parser = new Parser( + 'SELECT sgu.id, sgu.email_address FROM `sf_guard_user` sgu ' + . 'RIGHT JOIN `student_course_booking` scb ON sgu.id = scb.user_id ' + . 'WHERE `has_found_course` = \'1\' GROUP BY sgu.id ' + . 'ORDER BY scb.id LIMIT 0,300' + ); + $stmt = $parser->statements[0]; + + $this->assertEquals( + 'SELECT sgu.id, sgu.email_address FROM `sf_guard_user` AS `sgu` ' + . 'RIGHT JOIN `student_course_booking` AS `scb` ON sgu.id = scb.user_id ' + . 'WHERE `has_found_course` = \'1\' GROUP BY sgu.id ' + . 'ORDER BY scb.id ASC LIMIT 0, 300', + $stmt->build() + ); + } + + public function testBuilderAliasOrderMultiple() + { + $parser = new Parser( + 'SELECT sgu.id, sgu.email_address FROM `sf_guard_user` sgu ' + . 'RIGHT JOIN `student_course_booking` scb ON sgu.id = scb.user_id ' + . 'WHERE `has_found_course` = \'1\' GROUP BY sgu.id ' + . 'ORDER BY scb.id DESC, scb.order LIMIT 0,300' + ); + $stmt = $parser->statements[0]; + + $this->assertEquals( + 'SELECT sgu.id, sgu.email_address FROM `sf_guard_user` AS `sgu` ' + . 'RIGHT JOIN `student_course_booking` AS `scb` ON sgu.id = scb.user_id ' + . 'WHERE `has_found_course` = \'1\' GROUP BY sgu.id ' + . 'ORDER BY scb.id DESC, scb.order ASC LIMIT 0, 300', + $stmt->build() + ); + } + + public function testBuilderAliasOrderMultipleFunctions() + { + $parser = new Parser( + 'SELECT sgu.id, sgu.email_address FROM `sf_guard_user` sgu ' + . 'RIGHT JOIN `student_course_booking` scb ON sgu.id = scb.user_id ' + . 'WHERE `has_found_course` = \'1\' GROUP BY sgu.id ' + . 'ORDER BY scb.id DESC, YEAR(scb.dob) LIMIT 0,300' + ); + $stmt = $parser->statements[0]; + + $this->assertEquals( + 'SELECT sgu.id, sgu.email_address FROM `sf_guard_user` AS `sgu` ' + . 'RIGHT JOIN `student_course_booking` AS `scb` ON sgu.id = scb.user_id ' + . 'WHERE `has_found_course` = \'1\' GROUP BY sgu.id ' + . 'ORDER BY scb.id DESC, YEAR(scb.dob) ASC LIMIT 0, 300', + $stmt->build() + ); + } + + public function testBuilderAliasGroupByMultipleFunctions() + { + $parser = new Parser( + 'SELECT sgu.id, sgu.email_address FROM `sf_guard_user` sgu ' + . 'RIGHT JOIN `student_course_booking` scb ON sgu.id = scb.user_id ' + . 'WHERE `has_found_course` = \'1\' ' + . 'GROUP BY scb.id, YEAR(scb.dob) LIMIT 0,300' + ); + $stmt = $parser->statements[0]; + + $this->assertEquals( + 'SELECT sgu.id, sgu.email_address FROM `sf_guard_user` AS `sgu` ' + . 'RIGHT JOIN `student_course_booking` AS `scb` ON sgu.id = scb.user_id ' + . 'WHERE `has_found_course` = \'1\' ' + . 'GROUP BY scb.id, YEAR(scb.dob) LIMIT 0, 300', + $stmt->build() + ); + } + + public function testBuilderAliasGroupByMultipleFunctionsOrderRemoved() + { + $parser = new Parser( + 'SELECT sgu.id, sgu.email_address FROM `sf_guard_user` sgu ' + . 'RIGHT JOIN `student_course_booking` scb ON sgu.id = scb.user_id ' + . 'WHERE `has_found_course` = \'1\' ' + . 'GROUP BY scb.id ASC, YEAR(scb.dob) DESC LIMIT 0,300' + ); + $stmt = $parser->statements[0]; + + // The order is not kept, is this an expected behavior ? + // Ref: 4af06d24b041e499fb0e75ab3a98caf9a91700ef + // Issue: #154 + $this->assertEquals( + 'SELECT sgu.id, sgu.email_address FROM `sf_guard_user` AS `sgu` ' + . 'RIGHT JOIN `student_course_booking` AS `scb` ON sgu.id = scb.user_id ' + . 'WHERE `has_found_course` = \'1\' ' + . 'GROUP BY scb.id, YEAR(scb.dob) LIMIT 0, 300', + $stmt->build() + ); + } + + public function testBuilderAliasOrderCase() + { + $parser = new Parser( + 'SELECT * FROM `world_borders` ORDER BY CASE ' + . 'WHEN REGION = 2 THEN 99 ' + . 'WHEN REGION > 3 THEN REGION+1 ' + . 'ELSE 100 END LIMIT 0,300' + ); + $stmt = $parser->statements[0]; + + $this->assertEquals( + 'SELECT * FROM `world_borders` ORDER BY CASE ' + . 'WHEN REGION = 2 THEN 99 ' + . 'WHEN REGION > 3 THEN REGION+1 ' + . 'ELSE 100 END ASC LIMIT 0, 300', + $stmt->build() + ); + } + + public function testBuilderAliasGroupByCase() + { + $parser = new Parser( + 'SELECT * FROM `world_borders` GROUP BY CASE ' + . 'WHEN REGION = 2 THEN 99 ' + . 'WHEN REGION > 3 THEN REGION+1 ' + . 'ELSE 100 END LIMIT 0,300' + ); + $stmt = $parser->statements[0]; + + $this->assertEquals( + 'SELECT * FROM `world_borders` GROUP BY CASE ' + . 'WHEN REGION = 2 THEN 99 ' + . 'WHEN REGION > 3 THEN REGION+1 ' + . 'ELSE 100 END LIMIT 0, 300', + $stmt->build() + ); + } + public function testBuilderEndOptions() { /* Assertion 1 */ diff --git a/tests/Builder/TruncateStatementTest.php b/tests/Builder/TruncateStatementTest.php new file mode 100644 index 0000000..1abee17 --- /dev/null +++ b/tests/Builder/TruncateStatementTest.php @@ -0,0 +1,39 @@ +<?php + +namespace PhpMyAdmin\SqlParser\Tests\Builder; + +use PhpMyAdmin\SqlParser\Parser; +use PhpMyAdmin\SqlParser\Tests\TestCase; + +class TruncateStatementTest extends TestCase +{ + public function testBuilder() + { + $query = 'TRUNCATE TABLE mytable;'; + + $parser = new Parser($query); + $stmt = $parser->statements[0]; + + $this->assertEquals($query, $stmt->build()); + } + + public function testBuilderDbtable() + { + $query = 'TRUNCATE TABLE mydb.mytable;'; + + $parser = new Parser($query); + $stmt = $parser->statements[0]; + + $this->assertEquals($query, $stmt->build()); + } + + public function testBuilderDbtableBackQuotes() + { + $query = 'TRUNCATE TABLE `mydb`.`mytable`;'; + + $parser = new Parser($query); + $stmt = $parser->statements[0]; + + $this->assertEquals($query, $stmt->build()); + } +} diff --git a/tests/Lexer/IsMethodsTest.php b/tests/Lexer/IsMethodsTest.php index 9095907..e967514 100644 --- a/tests/Lexer/IsMethodsTest.php +++ b/tests/Lexer/IsMethodsTest.php @@ -69,6 +69,7 @@ class IsMethodsTest extends TestCase $this->assertEquals(Token::FLAG_COMMENT_C, Context::isComment('/*comment */')); $this->assertEquals(Token::FLAG_COMMENT_SQL, Context::isComment('-- my comment')); + $this->assertNull(Context::isComment('')); $this->assertNull(Context::isComment('--not a comment')); } @@ -108,7 +109,8 @@ class IsMethodsTest extends TestCase $this->assertEquals(Token::FLAG_STRING_SINGLE_QUOTES, Context::isString("'foo bar'")); $this->assertEquals(Token::FLAG_STRING_DOUBLE_QUOTES, Context::isString('"foo bar"')); - $this->assertEquals(Context::isString('foo bar'), null); + $this->assertNull(Context::isString('')); + $this->assertNull(Context::isString('foo bar')); } public function testIsSymbol() @@ -119,7 +121,8 @@ class IsMethodsTest extends TestCase $this->assertEquals(Token::FLAG_SYMBOL_VARIABLE, Context::isSymbol('@id')); $this->assertEquals(Token::FLAG_SYMBOL_BACKTICK, Context::isSymbol('`id`')); - $this->assertEquals(Context::isSymbol('id'), null); + $this->assertNull(Context::isSymbol('')); + $this->assertNull(Context::isSymbol('id')); } public function testisSeparator() diff --git a/tests/Utils/CLITest.php b/tests/Utils/CLITest.php index 7e53aca..2f7102f 100644 --- a/tests/Utils/CLITest.php +++ b/tests/Utils/CLITest.php @@ -16,6 +16,14 @@ class CLITest extends TestCase return $cli; } + private function getCLIStdIn($input, $getopt) + { + $cli = $this->getMockBuilder('PhpMyAdmin\SqlParser\Utils\CLI')->setMethods(['getopt', 'readStdin'])->getMock(); + $cli->method('getopt')->willReturn($getopt); + $cli->method('readStdin')->willReturn($input); + return $cli; + } + /** * Test that getopt call works. * @@ -103,6 +111,144 @@ class CLITest extends TestCase ]; } + + /** + * @dataProvider highlightParamsStdIn + * + * @param mixed $input + * @param mixed $getopt + * @param mixed $output + * @param mixed $result + */ + public function testRunHighlightStdIn($input, $getopt, $output, $result) + { + $cli = $this->getCLIStdIn($input, $getopt); + $this->expectOutputString($output); + $this->assertEquals($result, $cli->runHighlight()); + } + + public function highlightParamsStdIn() + { + return [ + [ + 'SELECT 1', + [], + "\x1b[35mSELECT\n \x1b[92m1\x1b[0m\n", + 0, + ], + [ + 'SELECT /* comment */ 1 /* other */', + [ + 'f' => 'text', + ], + "SELECT\n /* comment */ 1 /* other */\n", + 0, + ], + [ + 'SELECT 1', + [ + 'f' => 'foo', + ], + "ERROR: Invalid value for format!\n", + 1, + ], + [ + 'SELECT 1', + [ + 'f' => 'html', + ], + '<span class="sql-reserved">SELECT</span>' . '<br/>' . + ' <span class="sql-number">1</span>' . "\n", + 0, + ], + [ + '', + ['h' => true], + 'Usage: highlight-query --query SQL [--format html|cli|text]' . "\n" . + ' cat file.sql | highlight-query' . "\n", + 0, + ], + [ + '', + [], + 'ERROR: Missing parameters!' . "\n" . + 'Usage: highlight-query --query SQL [--format html|cli|text]' . "\n" . + ' cat file.sql | highlight-query' . "\n", + 1, + ], + [ + '', + false, + '', + 1, + ], + ]; + } + + /** + * @param mixed $input + * @param mixed $getopt + * @param mixed $output + * @param mixed $result + * + * @dataProvider lintParamsStdIn + */ + public function testRunLintFromStdIn($input, $getopt, $output, $result) + { + $cli = $this->getCLIStdIn($input, $getopt); + $this->expectOutputString($output); + $this->assertEquals($result, $cli->runLint()); + } + + public function lintParamsStdIn() + { + return [ + [ + 'SELECT 1', + [], + '', + 0, + ], + [ + 'SELECT SELECT', + [], + '#1: An expression was expected. (near "SELECT" at position 7)' . "\n" . + '#2: This type of clause was previously parsed. (near "SELECT" at position 7)' . "\n" . + '#3: An expression was expected. (near "" at position 0)' . "\n", + 10, + ], + [ + 'SELECT SELECT', + ['c' => 'MySql80000'], + '#1: An expression was expected. (near "SELECT" at position 7)' . "\n" . + '#2: This type of clause was previously parsed. (near "SELECT" at position 7)' . "\n" . + '#3: An expression was expected. (near "" at position 0)' . "\n", + 10, + ], + [ + '', + [], + 'ERROR: Missing parameters!' . "\n" . + 'Usage: lint-query --query SQL' . "\n" . + ' cat file.sql | lint-query' . "\n", + 1, + ], + [ + '', + ['h' => true], + 'Usage: lint-query --query SQL' . "\n" . + ' cat file.sql | lint-query' . "\n", + 0, + ], + [ + '', + false, + '', + 1, + ], + ]; + } + /** * @param mixed $getopt * @param mixed $output @@ -138,6 +284,16 @@ class CLITest extends TestCase 10, ], [ + [ + 'q' => 'SELECT SELECT', + 'c' => 'MySql80000', + ], + '#1: An expression was expected. (near "SELECT" at position 7)' . "\n" . + '#2: This type of clause was previously parsed. (near "SELECT" at position 7)' . "\n" . + '#3: An expression was expected. (near "" at position 0)' . "\n", + 10, + ], + [ ['h' => true], 'Usage: lint-query --query SQL' . "\n" . ' cat file.sql | lint-query' . "\n", @@ -212,6 +368,61 @@ class CLITest extends TestCase } /** + * @param mixed $input + * @param mixed $getopt + * @param mixed $output + * @param mixed $result + * + * @dataProvider tokenizeParamsStdIn + */ + public function testRunTokenizeStdIn($input, $getopt, $output, $result) + { + $cli = $this->getCLIStdIn($input, $getopt); + $this->expectOutputString($output); + $this->assertEquals($result, $cli->runTokenize()); + } + + public function tokenizeParamsStdIn() + { + $result = ( + "[TOKEN 0]\nType = 1\nFlags = 3\nValue = 'SELECT'\nToken = 'SELECT'\n\n" + . "[TOKEN 1]\nType = 3\nFlags = 0\nValue = ' '\nToken = ' '\n\n" + . "[TOKEN 2]\nType = 6\nFlags = 0\nValue = 1\nToken = '1'\n\n" + . "[TOKEN 3]\nType = 9\nFlags = 0\nValue = NULL\nToken = NULL\n\n" + ); + + return [ + [ + 'SELECT 1', + [], + $result, + 0, + ], + [ + '', + ['h' => true], + 'Usage: tokenize-query --query SQL' . "\n" . + ' cat file.sql | tokenize-query' . "\n", + 0, + ], + [ + '', + [], + 'ERROR: Missing parameters!' . "\n" . + 'Usage: tokenize-query --query SQL' . "\n" . + ' cat file.sql | tokenize-query' . "\n", + 1, + ], + [ + '', + false, + '', + 1, + ], + ]; + } + + /** * @param string $cmd * @param int $result * diff --git a/tests/Utils/ErrorTest.php b/tests/Utils/ErrorTest.php index 7e1326f..eec1130 100644 --- a/tests/Utils/ErrorTest.php +++ b/tests/Utils/ErrorTest.php @@ -39,5 +39,12 @@ class ErrorTest extends TestCase ['#1: error msg (near "token" at position 100)'], Error::format([['error msg', 42, 'token', 100]]) ); + $this->assertEquals( + [ + '#1: error msg (near "token" at position 100)', + '#2: error msg (near "token" at position 200)', + ], + Error::format([['error msg', 42, 'token', 100], ['error msg', 42, 'token', 200]]) + ); } } |