Parser.cpp (15780B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "gtest/gtest.h" 8 #include "Preferences.h" 9 10 using namespace mozilla; 11 12 // Keep this in sync with the declaration in Preferences.cpp. 13 // 14 // It's declared here to avoid polluting Preferences.h with test-only stuff. 15 void TestParseError(PrefValueKind aKind, const char* aText, 16 nsCString& aErrorMsg); 17 18 TEST(PrefsParser, Errors) 19 { 20 nsAutoCStringN<128> actualErrorMsg; 21 22 // Use a macro rather than a function so that the line number reported by 23 // gtest on failure is useful. 24 #define P(kind_, text_, expectedErrorMsg_) \ 25 do { \ 26 TestParseError(kind_, text_, actualErrorMsg); \ 27 ASSERT_STREQ(expectedErrorMsg_, actualErrorMsg.get()); \ 28 } while (0) 29 30 #define DEFAULT(text_, expectedErrorMsg_) \ 31 P(PrefValueKind::Default, text_, expectedErrorMsg_) 32 33 #define USER(text_, expectedErrorMsg_) \ 34 P(PrefValueKind::User, text_, expectedErrorMsg_) 35 36 // clang-format off 37 38 //------------------------------------------------------------------------- 39 // Valid syntax. (Other testing of more typical valid syntax and semantics is 40 // done in modules/libpref/test/unit/test_parser.js.) 41 //------------------------------------------------------------------------- 42 43 // Normal prefs. 44 DEFAULT(R"( 45 pref("bool", true); 46 sticky_pref("int", 123); 47 user_pref("string", "value"); 48 )", 49 "" 50 ); 51 52 // Totally empty input. 53 DEFAULT("", ""); 54 55 // Whitespace-only input. 56 DEFAULT(R"( 57 58 )" "\v \t \v \f", 59 "" 60 ); 61 62 // Comment-only inputs. 63 DEFAULT(R"(// blah)", ""); 64 DEFAULT(R"(# blah)", ""); 65 DEFAULT(R"(/* blah */)", ""); 66 67 //------------------------------------------------------------------------- 68 // All the lexing errors. (To be pedantic, some of the integer literal 69 // overflows are triggered in the parser, but put them all here so they're all 70 // in the one spot.) 71 //------------------------------------------------------------------------- 72 73 // Integer overflow errors. 74 DEFAULT(R"( 75 pref("int.ok", 2147483647); 76 pref("int.overflow", 2147483648); 77 pref("int.ok", +2147483647); 78 pref("int.overflow", +2147483648); 79 pref("int.ok", -2147483648); 80 pref("int.overflow", -2147483649); 81 pref("int.overflow", 4294967296); 82 pref("int.overflow", +4294967296); 83 pref("int.overflow", -4294967296); 84 pref("int.overflow", 4294967297); 85 pref("int.overflow", 1234567890987654321); 86 )", 87 "test:3: prefs parse error: integer literal overflowed\n" 88 "test:5: prefs parse error: integer literal overflowed\n" 89 "test:7: prefs parse error: integer literal overflowed\n" 90 "test:8: prefs parse error: integer literal overflowed\n" 91 "test:9: prefs parse error: integer literal overflowed\n" 92 "test:10: prefs parse error: integer literal overflowed\n" 93 "test:11: prefs parse error: integer literal overflowed\n" 94 "test:12: prefs parse error: integer literal overflowed\n" 95 ); 96 97 // Other integer errors. 98 DEFAULT(R"( 99 pref("int.unexpected", 100foo); 100 pref("int.ok", 0); 101 )", 102 "test:2: prefs parse error: unexpected character in integer literal\n" 103 ); 104 105 // \x00 is not allowed. 106 DEFAULT(R"( 107 pref("string.bad-x-escape", "foo\x00bar"); 108 pref("int.ok", 0); 109 )", 110 "test:2: prefs parse error: \\x00 is not allowed\n" 111 ); 112 113 // Various bad things after \x: end of string, punctuation, space, newline, 114 // EOF. 115 DEFAULT(R"( 116 pref("string.bad-x-escape", "foo\x"); 117 pref("string.bad-x-escape", "foo\x,bar"); 118 pref("string.bad-x-escape", "foo\x 12"); 119 pref("string.bad-x-escape", "foo\x 120 12"); 121 pref("string.bad-x-escape", "foo\x)", 122 "test:2: prefs parse error: malformed \\x escape sequence\n" 123 "test:3: prefs parse error: malformed \\x escape sequence\n" 124 "test:4: prefs parse error: malformed \\x escape sequence\n" 125 "test:5: prefs parse error: malformed \\x escape sequence\n" 126 "test:7: prefs parse error: malformed \\x escape sequence\n" 127 ); 128 129 // Not enough hex digits. 130 DEFAULT(R"( 131 pref("string.bad-x-escape", "foo\x1"); 132 pref("int.ok", 0); 133 )", 134 "test:2: prefs parse error: malformed \\x escape sequence\n" 135 ); 136 137 // Invalid hex digit. 138 DEFAULT(R"( 139 pref("string.bad-x-escape", "foo\x1G"); 140 pref("int.ok", 0); 141 )", 142 "test:2: prefs parse error: malformed \\x escape sequence\n" 143 ); 144 145 // \u0000 is not allowed. 146 // (The string literal is broken in two so that MSVC doesn't complain about 147 // an invalid universal-character-name.) 148 DEFAULT(R"( 149 pref("string.bad-u-escape", "foo\)" R"(u0000 bar"); 150 pref("int.ok", 0); 151 )", 152 "test:2: prefs parse error: \\u0000 is not allowed\n" 153 ); 154 155 // Various bad things after \u: end of string, punctuation, space, newline, 156 // EOF. 157 DEFAULT(R"( 158 pref("string.bad-u-escape", "foo\u"); 159 pref("string.bad-u-escape", "foo\u,bar"); 160 pref("string.bad-u-escape", "foo\u 1234"); 161 pref("string.bad-u-escape", "foo\u 162 1234"); 163 pref("string.bad-u-escape", "foo\u)", 164 "test:2: prefs parse error: malformed \\u escape sequence\n" 165 "test:3: prefs parse error: malformed \\u escape sequence\n" 166 "test:4: prefs parse error: malformed \\u escape sequence\n" 167 "test:5: prefs parse error: malformed \\u escape sequence\n" 168 "test:7: prefs parse error: malformed \\u escape sequence\n" 169 ); 170 171 // Not enough hex digits. 172 DEFAULT(R"( 173 pref("string.bad-u-escape", "foo\u1"); 174 pref("string.bad-u-escape", "foo\u12"); 175 pref("string.bad-u-escape", "foo\u123"); 176 pref("int.ok", 0); 177 )", 178 "test:2: prefs parse error: malformed \\u escape sequence\n" 179 "test:3: prefs parse error: malformed \\u escape sequence\n" 180 "test:4: prefs parse error: malformed \\u escape sequence\n" 181 ); 182 183 // Invalid hex digit. 184 DEFAULT(R"( 185 pref("string.bad-u-escape", "foo\u1G34"); 186 pref("int.ok", 0); 187 )", 188 "test:2: prefs parse error: malformed \\u escape sequence\n" 189 ); 190 191 // High surrogate not followed by low surrogate. 192 // (The string literal is broken in two so that MSVC doesn't complain about 193 // an invalid universal-character-name.) 194 DEFAULT(R"( 195 pref("string.bad-u-surrogate", "foo\)" R"(ud83c,blah"); 196 pref("int.ok", 0); 197 )", 198 "test:2: prefs parse error: expected low surrogate after high surrogate\n" 199 ); 200 201 // High surrogate followed by invalid low surrogate. 202 // (The string literal is broken in two so that MSVC doesn't complain about 203 // an invalid universal-character-name.) 204 DEFAULT(R"( 205 pref("string.bad-u-surrogate", "foo\)" R"(ud83c\u1234"); 206 pref("int.ok", 0); 207 )", 208 "test:2: prefs parse error: invalid low surrogate after high surrogate\n" 209 ); 210 211 // Low surrogate not preceded by high surrogate. 212 // (The string literal is broken in two so that MSVC doesn't complain about 213 // an invalid universal-character-name.) 214 DEFAULT(R"( 215 pref("string.bad-u-surrogate", "foo\)" R"(udc00"); 216 pref("int.ok", 0); 217 )", 218 "test:2: prefs parse error: expected high surrogate before low surrogate\n" 219 ); 220 221 // Unlike in JavaScript, \b, \f, \t, \v aren't allowed. 222 DEFAULT(R"( 223 pref("string.bad-escape", "foo\b"); 224 pref("string.bad-escape", "foo\f"); 225 pref("string.bad-escape", "foo\t"); 226 pref("string.bad-escape", "foo\v"); 227 pref("int.ok", 0); 228 )", 229 "test:2: prefs parse error: unexpected escape sequence character after '\\'\n" 230 "test:3: prefs parse error: unexpected escape sequence character after '\\'\n" 231 "test:4: prefs parse error: unexpected escape sequence character after '\\'\n" 232 "test:5: prefs parse error: unexpected escape sequence character after '\\'\n" 233 ); 234 235 // Various bad things after \: non-special letter, number, punctuation, 236 // space, newline, EOF. 237 DEFAULT(R"( 238 pref("string.bad-escape", "foo\Q"); 239 pref("string.bad-escape", "foo\1"); 240 pref("string.bad-escape", "foo\,"); 241 pref("string.bad-escape", "foo\ n"); 242 pref("string.bad-escape", "foo\ 243 n"); 244 pref("string.bad-escape", "foo\)", 245 "test:2: prefs parse error: unexpected escape sequence character after '\\'\n" 246 "test:3: prefs parse error: unexpected escape sequence character after '\\'\n" 247 "test:4: prefs parse error: unexpected escape sequence character after '\\'\n" 248 "test:5: prefs parse error: unexpected escape sequence character after '\\'\n" 249 "test:6: prefs parse error: unexpected escape sequence character after '\\'\n" 250 "test:8: prefs parse error: unexpected escape sequence character after '\\'\n" 251 ); 252 253 // Unterminated string literals. 254 255 // Simple case. 256 DEFAULT(R"( 257 pref("string.unterminated-string", "foo 258 )", 259 "test:3: prefs parse error: unterminated string literal\n" 260 ); 261 262 // Alternative case; `int` comes after the string and is seen as a keyword. 263 // The parser then skips to the ';', so no error about the unterminated 264 // string is issued. 265 DEFAULT(R"( 266 pref("string.unterminated-string", "foo); 267 pref("int.ok", 0); 268 )", 269 "test:3: prefs parse error: unknown keyword\n" 270 ); 271 272 // Mismatched quotes (1). 273 DEFAULT(R"( 274 pref("string.unterminated-string", "foo'); 275 )", 276 "test:3: prefs parse error: unterminated string literal\n" 277 ); 278 279 // Mismatched quotes (2). 280 DEFAULT(R"( 281 pref("string.unterminated-string", 'foo"); 282 )", 283 "test:3: prefs parse error: unterminated string literal\n" 284 ); 285 286 // Unknown keywords. 287 DEFAULT(R"( 288 foo; 289 preff("string.bad-keyword", true); 290 ticky_pref("string.bad-keyword", true); 291 User_pref("string.bad-keyword", true); 292 pref("string.bad-keyword", TRUE); 293 )", 294 "test:2: prefs parse error: unknown keyword\n" 295 "test:3: prefs parse error: unknown keyword\n" 296 "test:4: prefs parse error: unknown keyword\n" 297 "test:5: prefs parse error: unknown keyword\n" 298 "test:6: prefs parse error: unknown keyword\n" 299 ); 300 301 // Unterminated C-style comment. 302 DEFAULT(R"( 303 /* comment 304 )", 305 "test:3: prefs parse error: unterminated /* comment\n" 306 ); 307 308 // Malformed comments (single slashes), followed by whitespace, newline, EOF. 309 DEFAULT(R"( 310 / comment; 311 / 312 ; /)", 313 "test:2: prefs parse error: expected '/' or '*' after '/'\n" 314 "test:3: prefs parse error: expected '/' or '*' after '/'\n" 315 "test:4: prefs parse error: expected '/' or '*' after '/'\n" 316 ); 317 318 // C++-style comment ending in EOF (1). 319 DEFAULT(R"( 320 // comment)", 321 "" 322 ); 323 324 // C++-style comment ending in EOF (2). 325 DEFAULT(R"( 326 //)", 327 "" 328 ); 329 330 // Various unexpected characters. 331 DEFAULT(R"( 332 pref("unexpected.chars", &true); 333 pref("unexpected.chars" : true); 334 @pref("unexpected.chars", true); 335 pref["unexpected.chars": true]; 336 )", 337 "test:2: prefs parse error: unexpected character\n" 338 "test:3: prefs parse error: unexpected character\n" 339 "test:4: prefs parse error: unexpected character\n" 340 "test:5: prefs parse error: unexpected character\n" 341 ); 342 343 //------------------------------------------------------------------------- 344 // All the parsing errors. 345 //------------------------------------------------------------------------- 346 347 DEFAULT(R"( 348 "pref"("parse.error": true); 349 pref1("parse.error": true); 350 pref(123: true); 351 pref("parse.error" true); 352 pref("parse.error", pref); 353 pref("parse.error", -true); 354 pref("parse.error", +"value"); 355 pref("parse.error", true,); 356 pref("parse.error", true; 357 pref("parse.error", true, sticky, locked; 358 pref("parse.error", true) 359 pref("int.ok", 1); 360 pref("parse.error", true))", 361 "test:2: prefs parse error: expected pref specifier at start of pref definition\n" 362 "test:3: prefs parse error: expected '(' after pref specifier\n" 363 "test:4: prefs parse error: expected pref name after '('\n" 364 "test:5: prefs parse error: expected ',' after pref name\n" 365 "test:6: prefs parse error: expected pref value after ','\n" 366 "test:7: prefs parse error: expected integer literal after '-'\n" 367 "test:8: prefs parse error: expected integer literal after '+'\n" 368 "test:9: prefs parse error: expected pref attribute after ','\n" 369 "test:10: prefs parse error: expected ',' or ')' after pref value\n" 370 "test:11: prefs parse error: expected ',' or ')' after pref attribute\n" 371 "test:13: prefs parse error: expected ';' after ')'\n" 372 "test:14: prefs parse error: expected ';' after ')'\n" 373 ); 374 375 USER(R"( 376 pref("parse.error", true); 377 sticky_pref("parse.error", true); 378 user_pref("int.ok", 1); 379 )", 380 "test:2: prefs parse error: expected 'user_pref' at start of pref definition\n" 381 "test:3: prefs parse error: expected 'user_pref' at start of pref definition\n" 382 ); 383 384 USER(R"( 385 user_pref("parse.error", true; 386 user_pref("int.ok", 1); 387 )", 388 "test:2: prefs parse error: expected ')' after pref value\n" 389 ); 390 391 // Parse errors involving unexpected EOF. 392 393 DEFAULT(R"( 394 pref)", 395 "test:2: prefs parse error: expected '(' after pref specifier\n" 396 ); 397 398 DEFAULT(R"( 399 pref()", 400 "test:2: prefs parse error: expected pref name after '('\n" 401 ); 402 403 DEFAULT(R"( 404 pref("parse.error")", 405 "test:2: prefs parse error: expected ',' after pref name\n" 406 ); 407 408 DEFAULT(R"( 409 pref("parse.error",)", 410 "test:2: prefs parse error: expected pref value after ','\n" 411 ); 412 413 DEFAULT(R"( 414 pref("parse.error", -)", 415 "test:2: prefs parse error: expected integer literal after '-'\n" 416 ); 417 418 DEFAULT(R"( 419 pref("parse.error", +)", 420 "test:2: prefs parse error: expected integer literal after '+'\n" 421 ); 422 423 DEFAULT(R"( 424 pref("parse.error", true)", 425 "test:2: prefs parse error: expected ',' or ')' after pref value\n" 426 ); 427 428 USER(R"( 429 user_pref("parse.error", true)", 430 "test:2: prefs parse error: expected ')' after pref value\n" 431 ); 432 433 DEFAULT(R"( 434 pref("parse.error", true,)", 435 "test:2: prefs parse error: expected pref attribute after ','\n" 436 ); 437 438 DEFAULT(R"( 439 pref("parse.error", true, sticky)", 440 "test:2: prefs parse error: expected ',' or ')' after pref attribute\n" 441 ); 442 443 DEFAULT(R"( 444 pref("parse.error", true))", 445 "test:2: prefs parse error: expected ';' after ')'\n" 446 ); 447 448 // This is something we saw in practice with the old parser, which allowed 449 // repeated semicolons. 450 DEFAULT(R"( 451 pref("parse.error", true);; 452 pref("parse.error", true, locked);;; 453 pref("parse.error", true, sticky, locked);;;; 454 pref("int.ok", 0); 455 )", 456 "test:2: prefs parse error: expected pref specifier at start of pref definition\n" 457 "test:3: prefs parse error: expected pref specifier at start of pref definition\n" 458 "test:3: prefs parse error: expected pref specifier at start of pref definition\n" 459 "test:4: prefs parse error: expected pref specifier at start of pref definition\n" 460 "test:4: prefs parse error: expected pref specifier at start of pref definition\n" 461 "test:4: prefs parse error: expected pref specifier at start of pref definition\n" 462 ); 463 464 //------------------------------------------------------------------------- 465 // Invalid syntax after various newline combinations, for the purpose of 466 // testing that line numbers are correct. 467 //------------------------------------------------------------------------- 468 469 // In all of the following we have a \n, a \r, a \r\n, and then an error, so 470 // the error is on line 4. (Note: these ones don't use raw string literals 471 // because MSVC somehow swallows any \r that appears in them.) 472 473 DEFAULT("\n \r \r\n bad", 474 "test:4: prefs parse error: unknown keyword\n" 475 ); 476 477 DEFAULT("#\n#\r#\r\n bad", 478 "test:4: prefs parse error: unknown keyword\n" 479 ); 480 481 DEFAULT("//\n//\r//\r\n bad", 482 "test:4: prefs parse error: unknown keyword\n" 483 ); 484 485 DEFAULT("/*\n \r \r\n*/ bad", 486 "test:4: prefs parse error: unknown keyword\n" 487 ); 488 489 // Note: the escape sequences do *not* affect the line number. 490 DEFAULT("pref(\"foo\\n\n foo\\r\r foo\\r\\n\r\n foo\", bad);", 491 "test:4: prefs parse error: unknown keyword\n" 492 ); 493 494 // clang-format on 495 }