Jeff Sharkey | 0e66ea6 | 2019-07-16 16:50:42 -0600 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package android.database.sqlite; |
| 18 | |
| 19 | import static org.junit.Assert.assertEquals; |
| 20 | import static org.junit.Assert.assertTrue; |
| 21 | import static org.junit.Assert.fail; |
| 22 | |
| 23 | import androidx.test.runner.AndroidJUnit4; |
| 24 | |
| 25 | import org.junit.Test; |
| 26 | import org.junit.runner.RunWith; |
| 27 | |
| 28 | import java.util.ArrayList; |
| 29 | import java.util.Arrays; |
| 30 | import java.util.List; |
| 31 | |
| 32 | @RunWith(AndroidJUnit4.class) |
| 33 | public class SQLiteTokenizerTest { |
| 34 | private List<String> getTokens(String sql) { |
| 35 | return SQLiteTokenizer.tokenize(sql, SQLiteTokenizer.OPTION_NONE); |
| 36 | } |
| 37 | |
| 38 | private void checkTokens(String sql, String spaceSeparatedExpectedTokens) { |
| 39 | final List<String> expected = spaceSeparatedExpectedTokens == null |
| 40 | ? new ArrayList<>() |
| 41 | : Arrays.asList(spaceSeparatedExpectedTokens.split(" +")); |
| 42 | |
| 43 | assertEquals(expected, getTokens(sql)); |
| 44 | } |
| 45 | |
| 46 | private void assertInvalidSql(String sql, String message) { |
| 47 | try { |
| 48 | getTokens(sql); |
| 49 | fail("Didn't throw InvalidSqlException"); |
| 50 | } catch (IllegalArgumentException e) { |
| 51 | assertTrue("Expected " + e.getMessage() + " to contain " + message, |
| 52 | e.getMessage().contains(message)); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | @Test |
| 57 | public void testWhitespaces() { |
| 58 | checkTokens(" select \t\r\n a\n\n ", "select a"); |
| 59 | checkTokens("a b", "a b"); |
| 60 | } |
| 61 | |
| 62 | @Test |
| 63 | public void testComment() { |
| 64 | checkTokens("--\n", null); |
| 65 | checkTokens("a--\n", "a"); |
| 66 | checkTokens("a--abcdef\n", "a"); |
| 67 | checkTokens("a--abcdef\nx", "a x"); |
| 68 | checkTokens("a--\nx", "a x"); |
| 69 | assertInvalidSql("a--abcdef", "Unterminated comment"); |
| 70 | assertInvalidSql("a--abcdef\ndef--", "Unterminated comment"); |
| 71 | |
| 72 | checkTokens("/**/", null); |
| 73 | assertInvalidSql("/*", "Unterminated comment"); |
| 74 | assertInvalidSql("/*/", "Unterminated comment"); |
| 75 | assertInvalidSql("/*\n* /*a", "Unterminated comment"); |
| 76 | checkTokens("a/**/", "a"); |
| 77 | checkTokens("/**/b", "b"); |
| 78 | checkTokens("a/**/b", "a b"); |
| 79 | checkTokens("a/* -- \n* /* **/b", "a b"); |
| 80 | } |
| 81 | |
| 82 | @Test |
| 83 | public void testStrings() { |
| 84 | assertInvalidSql("'", "Unterminated quote"); |
| 85 | assertInvalidSql("a'", "Unterminated quote"); |
| 86 | assertInvalidSql("a'''", "Unterminated quote"); |
| 87 | assertInvalidSql("a''' ", "Unterminated quote"); |
| 88 | checkTokens("''", null); |
| 89 | checkTokens("''''", null); |
| 90 | checkTokens("a''''b", "a b"); |
| 91 | checkTokens("a' '' 'b", "a b"); |
| 92 | checkTokens("'abc'", null); |
| 93 | checkTokens("'abc\ndef'", null); |
| 94 | checkTokens("a'abc\ndef'", "a"); |
| 95 | checkTokens("'abc\ndef'b", "b"); |
| 96 | checkTokens("a'abc\ndef'b", "a b"); |
| 97 | checkTokens("a'''abc\nd''ef'''b", "a b"); |
| 98 | } |
| 99 | |
| 100 | @Test |
| 101 | public void testDoubleQuotes() { |
| 102 | assertInvalidSql("\"", "Unterminated quote"); |
| 103 | assertInvalidSql("a\"", "Unterminated quote"); |
| 104 | assertInvalidSql("a\"\"\"", "Unterminated quote"); |
| 105 | assertInvalidSql("a\"\"\" ", "Unterminated quote"); |
| 106 | checkTokens("\"\"", ""); |
| 107 | checkTokens("\"\"\"\"", "\""); |
| 108 | checkTokens("a\"\"\"\"b", "a \" b"); |
| 109 | checkTokens("a\"\t\"\"\t\"b", "a \t\"\t b"); |
| 110 | checkTokens("\"abc\"", "abc"); |
| 111 | checkTokens("\"abc\ndef\"", "abc\ndef"); |
| 112 | checkTokens("a\"abc\ndef\"", "a abc\ndef"); |
| 113 | checkTokens("\"abc\ndef\"b", "abc\ndef b"); |
| 114 | checkTokens("a\"abc\ndef\"b", "a abc\ndef b"); |
| 115 | checkTokens("a\"\"\"abc\nd\"\"ef\"\"\"b", "a \"abc\nd\"ef\" b"); |
| 116 | } |
| 117 | |
| 118 | @Test |
| 119 | public void testBackQuotes() { |
| 120 | assertInvalidSql("`", "Unterminated quote"); |
| 121 | assertInvalidSql("a`", "Unterminated quote"); |
| 122 | assertInvalidSql("a```", "Unterminated quote"); |
| 123 | assertInvalidSql("a``` ", "Unterminated quote"); |
| 124 | checkTokens("``", ""); |
| 125 | checkTokens("````", "`"); |
| 126 | checkTokens("a````b", "a ` b"); |
| 127 | checkTokens("a`\t``\t`b", "a \t`\t b"); |
| 128 | checkTokens("`abc`", "abc"); |
| 129 | checkTokens("`abc\ndef`", "abc\ndef"); |
| 130 | checkTokens("a`abc\ndef`", "a abc\ndef"); |
| 131 | checkTokens("`abc\ndef`b", "abc\ndef b"); |
| 132 | checkTokens("a`abc\ndef`b", "a abc\ndef b"); |
| 133 | checkTokens("a```abc\nd``ef```b", "a `abc\nd`ef` b"); |
| 134 | } |
| 135 | |
| 136 | @Test |
| 137 | public void testBrackets() { |
| 138 | assertInvalidSql("[", "Unterminated quote"); |
| 139 | assertInvalidSql("a[", "Unterminated quote"); |
| 140 | assertInvalidSql("a[ ", "Unterminated quote"); |
| 141 | assertInvalidSql("a[[ ", "Unterminated quote"); |
| 142 | checkTokens("[]", ""); |
| 143 | checkTokens("[[]", "["); |
| 144 | checkTokens("a[[]b", "a [ b"); |
| 145 | checkTokens("a[\t[\t]b", "a \t[\t b"); |
| 146 | checkTokens("[abc]", "abc"); |
| 147 | checkTokens("[abc\ndef]", "abc\ndef"); |
| 148 | checkTokens("a[abc\ndef]", "a abc\ndef"); |
| 149 | checkTokens("[abc\ndef]b", "abc\ndef b"); |
| 150 | checkTokens("a[abc\ndef]b", "a abc\ndef b"); |
| 151 | checkTokens("a[[abc\nd[ef[]b", "a [abc\nd[ef[ b"); |
| 152 | } |
| 153 | |
| 154 | @Test |
| 155 | public void testSemicolons() { |
| 156 | assertInvalidSql(";", "Semicolon is not allowed"); |
| 157 | assertInvalidSql(" ;", "Semicolon is not allowed"); |
| 158 | assertInvalidSql("; ", "Semicolon is not allowed"); |
| 159 | assertInvalidSql("-;-", "Semicolon is not allowed"); |
| 160 | checkTokens("--;\n", null); |
| 161 | checkTokens("/*;*/", null); |
| 162 | checkTokens("';'", null); |
| 163 | checkTokens("[;]", ";"); |
| 164 | checkTokens("`;`", ";"); |
| 165 | } |
| 166 | |
| 167 | @Test |
| 168 | public void testTokens() { |
| 169 | checkTokens("a,abc,a00b,_1,_123,abcdef", "a abc a00b _1 _123 abcdef"); |
| 170 | checkTokens("a--\nabc/**/a00b''_1'''ABC'''`_123`abc[d]\"e\"f", |
| 171 | "a abc a00b _1 _123 abc d e f"); |
| 172 | } |
| 173 | } |