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 com.android.providers.tv.util; 18 19 import android.annotation.Nullable; 20 import android.test.AndroidTestCase; 21 import android.util.Pair; 22 import java.util.ArrayList; 23 import java.util.Arrays; 24 import java.util.List; 25 import java.util.function.Consumer; 26 27 /** 28 * Tests for {@link SqliteTokenFinder}. 29 * 30 * Modified from 31 * packages/providers/ContactsProvider/tests/src/com/android/providers/contacts/sqlite/SqlCheckerTest.java 32 */ 33 public class SqliteTokenFinderTest extends AndroidTestCase { getTokens(String sql)34 private List<Pair<Integer, String>> getTokens(String sql) { 35 List<Pair<Integer, String>> tokens = new ArrayList<>(); 36 SqliteTokenFinder.findTokens(sql, new Consumer<Pair<Integer, String>>() { 37 @Override 38 public void accept(Pair<Integer, String> pair) { 39 tokens.add(pair); 40 } 41 }); 42 return tokens; 43 } 44 checkTokens(String sql, Pair<Integer, String>... tokens)45 private void checkTokens(String sql, Pair<Integer, String>... tokens) { 46 final List<Pair<Integer, String>> expected = Arrays.asList(tokens); 47 48 assertEquals(expected, getTokens(sql)); 49 } 50 checkTokensRegular(String sql, @Nullable String tokens)51 private void checkTokensRegular(String sql, @Nullable String tokens) { 52 List<Pair<Integer, String>> expected = new ArrayList<>(); 53 54 if (tokens != null) { 55 for (String token : tokens.split(" ")) { 56 expected.add(Pair.create(SqliteTokenFinder.TYPE_REGULAR, token)); 57 } 58 } 59 60 assertEquals(expected, getTokens(sql)); 61 } 62 assertInvalidSql(String sql, String message)63 private void assertInvalidSql(String sql, String message) { 64 try { 65 getTokens(sql); 66 fail("Didn't throw Exception"); 67 } catch (Exception e) { 68 assertTrue("Expected " + e.getMessage() + " to contain " + message, 69 e.getMessage().contains(message)); 70 } 71 } 72 testWhitespaces()73 public void testWhitespaces() { 74 checkTokensRegular(" select \t\r\n a\n\n ", "select a"); 75 checkTokensRegular("a b", "a b"); 76 } 77 testComment()78 public void testComment() { 79 checkTokensRegular("--\n", null); 80 checkTokensRegular("a--\n", "a"); 81 checkTokensRegular("a--abcdef\n", "a"); 82 checkTokensRegular("a--abcdef\nx", "a x"); 83 checkTokensRegular("a--\nx", "a x"); 84 checkTokensRegular("a--abcdef", "a"); 85 checkTokensRegular("a--abcdef\ndef--", "a def"); 86 87 checkTokensRegular("/**/", null); 88 assertInvalidSql("/*", "Unterminated comment"); 89 assertInvalidSql("/*/", "Unterminated comment"); 90 assertInvalidSql("/*\n* /*a", "Unterminated comment"); 91 checkTokensRegular("a/**/", "a"); 92 checkTokensRegular("/**/b", "b"); 93 checkTokensRegular("a/**/b", "a b"); 94 checkTokensRegular("a/* -- \n* /* **/b", "a b"); 95 } 96 testSingleQuotes()97 public void testSingleQuotes() { 98 assertInvalidSql("'", "Unterminated quote"); 99 assertInvalidSql("a'", "Unterminated quote"); 100 assertInvalidSql("a'''", "Unterminated quote"); 101 assertInvalidSql("a''' ", "Unterminated quote"); 102 checkTokens("''", Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, "")); 103 104 // 2 consecutive quotes inside quotes stands for a quote. e.g.'let''s go' -> let's go 105 checkTokens( 106 "''''", 107 Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, "\'")); 108 checkTokens( 109 "a''''b", 110 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 111 Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, "\'"), 112 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 113 checkTokens( 114 "a' '' 'b", 115 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 116 Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, " \' "), 117 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 118 checkTokens("'abc'", Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, "abc")); 119 checkTokens("'abc\ndef'", Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, "abc\ndef")); 120 checkTokens( 121 "a'abc\ndef'", 122 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 123 Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, "abc\ndef")); 124 checkTokens( 125 "'abc\ndef'b", 126 Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, "abc\ndef"), 127 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 128 checkTokens("a'abc\ndef'b", 129 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 130 Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, "abc\ndef"), 131 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 132 checkTokens( 133 "a'''abc\nd''ef'''b", 134 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 135 Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, "\'abc\nd\'ef\'"), 136 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 137 } 138 testDoubleQuotes()139 public void testDoubleQuotes() { 140 assertInvalidSql("\"", "Unterminated quote"); 141 assertInvalidSql("a\"", "Unterminated quote"); 142 assertInvalidSql("a\"\"\"", "Unterminated quote"); 143 assertInvalidSql("a\"\"\" ", "Unterminated quote"); 144 checkTokens("\"\"", Pair.create(SqliteTokenFinder.TYPE_IN_DOUBLE_QUOTES, "")); 145 checkTokens("\"\"\"\"", Pair.create(SqliteTokenFinder.TYPE_IN_DOUBLE_QUOTES, "\"")); 146 checkTokens( 147 "a\"\"\"\"b", 148 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 149 Pair.create(SqliteTokenFinder.TYPE_IN_DOUBLE_QUOTES, "\""), 150 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 151 checkTokens("a\"\t\"\"\t\"b", 152 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 153 Pair.create(SqliteTokenFinder.TYPE_IN_DOUBLE_QUOTES, "\t\"\t"), 154 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 155 checkTokens("\"abc\"", Pair.create(SqliteTokenFinder.TYPE_IN_DOUBLE_QUOTES, "abc")); 156 checkTokens( 157 "\"abc\ndef\"", 158 Pair.create(SqliteTokenFinder.TYPE_IN_DOUBLE_QUOTES, "abc\ndef")); 159 checkTokens( 160 "a\"abc\ndef\"", 161 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 162 Pair.create(SqliteTokenFinder.TYPE_IN_DOUBLE_QUOTES, "abc\ndef")); 163 checkTokens( 164 "\"abc\ndef\"b", 165 Pair.create(SqliteTokenFinder.TYPE_IN_DOUBLE_QUOTES, "abc\ndef"), 166 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 167 checkTokens("a\"abc\ndef\"b", 168 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 169 Pair.create(SqliteTokenFinder.TYPE_IN_DOUBLE_QUOTES, "abc\ndef"), 170 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 171 checkTokens("a\"\"\"abc\nd\"\"ef\"\"\"b", 172 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 173 Pair.create(SqliteTokenFinder.TYPE_IN_DOUBLE_QUOTES, "\"abc\nd\"ef\""), 174 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 175 } 176 testBackquotes()177 public void testBackquotes() { 178 assertInvalidSql("`", "Unterminated quote"); 179 assertInvalidSql("a`", "Unterminated quote"); 180 assertInvalidSql("a```", "Unterminated quote"); 181 assertInvalidSql("a``` ", "Unterminated quote"); 182 checkTokens("``", Pair.create(SqliteTokenFinder.TYPE_IN_BACKQUOTES, "")); 183 checkTokens("````", Pair.create(SqliteTokenFinder.TYPE_IN_BACKQUOTES, "`")); 184 checkTokens( 185 "a````b", 186 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 187 Pair.create(SqliteTokenFinder.TYPE_IN_BACKQUOTES, "`"), 188 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 189 checkTokens( 190 "a`\t``\t`b", 191 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 192 Pair.create(SqliteTokenFinder.TYPE_IN_BACKQUOTES, "\t`\t"), 193 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 194 checkTokens("`abc`", Pair.create(SqliteTokenFinder.TYPE_IN_BACKQUOTES, "abc")); 195 checkTokens( 196 "`abc\ndef`", 197 Pair.create(SqliteTokenFinder.TYPE_IN_BACKQUOTES, "abc\ndef")); 198 checkTokens( 199 "a`abc\ndef`", 200 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 201 Pair.create(SqliteTokenFinder.TYPE_IN_BACKQUOTES, "abc\ndef")); 202 checkTokens( 203 "`abc\ndef`b", 204 Pair.create(SqliteTokenFinder.TYPE_IN_BACKQUOTES, "abc\ndef"), 205 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 206 checkTokens( 207 "a`abc\ndef`b", 208 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 209 Pair.create(SqliteTokenFinder.TYPE_IN_BACKQUOTES, "abc\ndef"), 210 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 211 checkTokens( 212 "a```abc\nd``ef```b", 213 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 214 Pair.create(SqliteTokenFinder.TYPE_IN_BACKQUOTES, "`abc\nd`ef`"), 215 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 216 } 217 testBrackets()218 public void testBrackets() { 219 assertInvalidSql("[", "Unterminated quote"); 220 assertInvalidSql("a[", "Unterminated quote"); 221 assertInvalidSql("a[ ", "Unterminated quote"); 222 assertInvalidSql("a[[ ", "Unterminated quote"); 223 checkTokens("[]", Pair.create(SqliteTokenFinder.TYPE_IN_BRACKETS, "")); 224 checkTokens("[[]", Pair.create(SqliteTokenFinder.TYPE_IN_BRACKETS, "[")); 225 checkTokens( 226 "a[[]b", 227 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 228 Pair.create(SqliteTokenFinder.TYPE_IN_BRACKETS, "["), 229 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 230 checkTokens( 231 "a[\t[\t]b", 232 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 233 Pair.create(SqliteTokenFinder.TYPE_IN_BRACKETS, "\t[\t"), 234 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 235 checkTokens("[abc]", Pair.create(SqliteTokenFinder.TYPE_IN_BRACKETS, "abc")); 236 checkTokens( 237 "[abc\ndef]", 238 Pair.create(SqliteTokenFinder.TYPE_IN_BRACKETS, "abc\ndef")); 239 checkTokens( 240 "a[abc\ndef]", 241 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 242 Pair.create(SqliteTokenFinder.TYPE_IN_BRACKETS, "abc\ndef")); 243 checkTokens( 244 "[abc\ndef]b", 245 Pair.create(SqliteTokenFinder.TYPE_IN_BRACKETS, "abc\ndef"), 246 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 247 checkTokens( 248 "a[abc\ndef]b", 249 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 250 Pair.create(SqliteTokenFinder.TYPE_IN_BRACKETS, "abc\ndef"), 251 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 252 checkTokens( 253 "a[[abc\nd[ef[]b", 254 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 255 Pair.create(SqliteTokenFinder.TYPE_IN_BRACKETS, "[abc\nd[ef["), 256 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "b")); 257 } 258 testTokens()259 public void testTokens() { 260 checkTokensRegular("a,abc,a00b,_1,_123,abcdef", "a abc a00b _1 _123 abcdef"); 261 checkTokens( 262 "a--\nabc/**/a00b''_1'''ABC'''`_123`abc[d]\"e\"f", 263 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a"), 264 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "abc"), 265 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "a00b"), 266 Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, ""), 267 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "_1"), 268 Pair.create(SqliteTokenFinder.TYPE_IN_SINGLE_QUOTES, "'ABC'"), 269 Pair.create(SqliteTokenFinder.TYPE_IN_BACKQUOTES, "_123"), 270 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "abc"), 271 Pair.create(SqliteTokenFinder.TYPE_IN_BRACKETS, "d"), 272 Pair.create(SqliteTokenFinder.TYPE_IN_DOUBLE_QUOTES, "e"), 273 Pair.create(SqliteTokenFinder.TYPE_REGULAR, "f")); 274 } 275 } 276