summaryrefslogtreecommitdiffstats
path: root/modules/libpref/test/gtest/Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/libpref/test/gtest/Parser.cpp')
-rw-r--r--modules/libpref/test/gtest/Parser.cpp496
1 files changed, 496 insertions, 0 deletions
diff --git a/modules/libpref/test/gtest/Parser.cpp b/modules/libpref/test/gtest/Parser.cpp
new file mode 100644
index 0000000000..972d32cfca
--- /dev/null
+++ b/modules/libpref/test/gtest/Parser.cpp
@@ -0,0 +1,496 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/ArrayUtils.h"
+#include "Preferences.h"
+
+using namespace mozilla;
+
+// Keep this in sync with the declaration in Preferences.cpp.
+//
+// It's declared here to avoid polluting Preferences.h with test-only stuff.
+void TestParseError(PrefValueKind aKind, const char* aText,
+ nsCString& aErrorMsg);
+
+TEST(PrefsParser, Errors)
+{
+ nsAutoCStringN<128> actualErrorMsg;
+
+// Use a macro rather than a function so that the line number reported by
+// gtest on failure is useful.
+#define P(kind_, text_, expectedErrorMsg_) \
+ do { \
+ TestParseError(kind_, text_, actualErrorMsg); \
+ ASSERT_STREQ(expectedErrorMsg_, actualErrorMsg.get()); \
+ } while (0)
+
+#define DEFAULT(text_, expectedErrorMsg_) \
+ P(PrefValueKind::Default, text_, expectedErrorMsg_)
+
+#define USER(text_, expectedErrorMsg_) \
+ P(PrefValueKind::User, text_, expectedErrorMsg_)
+
+ // clang-format off
+
+ //-------------------------------------------------------------------------
+ // Valid syntax. (Other testing of more typical valid syntax and semantics is
+ // done in modules/libpref/test/unit/test_parser.js.)
+ //-------------------------------------------------------------------------
+
+ // Normal prefs.
+ DEFAULT(R"(
+pref("bool", true);
+sticky_pref("int", 123);
+user_pref("string", "value");
+ )",
+ ""
+ );
+
+ // Totally empty input.
+ DEFAULT("", "");
+
+ // Whitespace-only input.
+ DEFAULT(R"(
+
+ )" "\v \t \v \f",
+ ""
+ );
+
+ // Comment-only inputs.
+ DEFAULT(R"(// blah)", "");
+ DEFAULT(R"(# blah)", "");
+ DEFAULT(R"(/* blah */)", "");
+
+ //-------------------------------------------------------------------------
+ // All the lexing errors. (To be pedantic, some of the integer literal
+ // overflows are triggered in the parser, but put them all here so they're all
+ // in the one spot.)
+ //-------------------------------------------------------------------------
+
+ // Integer overflow errors.
+ DEFAULT(R"(
+pref("int.ok", 2147483647);
+pref("int.overflow", 2147483648);
+pref("int.ok", +2147483647);
+pref("int.overflow", +2147483648);
+pref("int.ok", -2147483648);
+pref("int.overflow", -2147483649);
+pref("int.overflow", 4294967296);
+pref("int.overflow", +4294967296);
+pref("int.overflow", -4294967296);
+pref("int.overflow", 4294967297);
+pref("int.overflow", 1234567890987654321);
+ )",
+ "test:3: prefs parse error: integer literal overflowed\n"
+ "test:5: prefs parse error: integer literal overflowed\n"
+ "test:7: prefs parse error: integer literal overflowed\n"
+ "test:8: prefs parse error: integer literal overflowed\n"
+ "test:9: prefs parse error: integer literal overflowed\n"
+ "test:10: prefs parse error: integer literal overflowed\n"
+ "test:11: prefs parse error: integer literal overflowed\n"
+ "test:12: prefs parse error: integer literal overflowed\n"
+ );
+
+ // Other integer errors.
+ DEFAULT(R"(
+pref("int.unexpected", 100foo);
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: unexpected character in integer literal\n"
+ );
+
+ // \x00 is not allowed.
+ DEFAULT(R"(
+pref("string.bad-x-escape", "foo\x00bar");
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: \\x00 is not allowed\n"
+ );
+
+ // Various bad things after \x: end of string, punctuation, space, newline,
+ // EOF.
+ DEFAULT(R"(
+pref("string.bad-x-escape", "foo\x");
+pref("string.bad-x-escape", "foo\x,bar");
+pref("string.bad-x-escape", "foo\x 12");
+pref("string.bad-x-escape", "foo\x
+12");
+pref("string.bad-x-escape", "foo\x)",
+ "test:2: prefs parse error: malformed \\x escape sequence\n"
+ "test:3: prefs parse error: malformed \\x escape sequence\n"
+ "test:4: prefs parse error: malformed \\x escape sequence\n"
+ "test:5: prefs parse error: malformed \\x escape sequence\n"
+ "test:7: prefs parse error: malformed \\x escape sequence\n"
+ );
+
+ // Not enough hex digits.
+ DEFAULT(R"(
+pref("string.bad-x-escape", "foo\x1");
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: malformed \\x escape sequence\n"
+ );
+
+ // Invalid hex digit.
+ DEFAULT(R"(
+pref("string.bad-x-escape", "foo\x1G");
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: malformed \\x escape sequence\n"
+ );
+
+ // \u0000 is not allowed.
+ // (The string literal is broken in two so that MSVC doesn't complain about
+ // an invalid universal-character-name.)
+ DEFAULT(R"(
+pref("string.bad-u-escape", "foo\)" R"(u0000 bar");
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: \\u0000 is not allowed\n"
+ );
+
+ // Various bad things after \u: end of string, punctuation, space, newline,
+ // EOF.
+ DEFAULT(R"(
+pref("string.bad-u-escape", "foo\u");
+pref("string.bad-u-escape", "foo\u,bar");
+pref("string.bad-u-escape", "foo\u 1234");
+pref("string.bad-u-escape", "foo\u
+1234");
+pref("string.bad-u-escape", "foo\u)",
+ "test:2: prefs parse error: malformed \\u escape sequence\n"
+ "test:3: prefs parse error: malformed \\u escape sequence\n"
+ "test:4: prefs parse error: malformed \\u escape sequence\n"
+ "test:5: prefs parse error: malformed \\u escape sequence\n"
+ "test:7: prefs parse error: malformed \\u escape sequence\n"
+ );
+
+ // Not enough hex digits.
+ DEFAULT(R"(
+pref("string.bad-u-escape", "foo\u1");
+pref("string.bad-u-escape", "foo\u12");
+pref("string.bad-u-escape", "foo\u123");
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: malformed \\u escape sequence\n"
+ "test:3: prefs parse error: malformed \\u escape sequence\n"
+ "test:4: prefs parse error: malformed \\u escape sequence\n"
+ );
+
+ // Invalid hex digit.
+ DEFAULT(R"(
+pref("string.bad-u-escape", "foo\u1G34");
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: malformed \\u escape sequence\n"
+ );
+
+ // High surrogate not followed by low surrogate.
+ // (The string literal is broken in two so that MSVC doesn't complain about
+ // an invalid universal-character-name.)
+ DEFAULT(R"(
+pref("string.bad-u-surrogate", "foo\)" R"(ud83c,blah");
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: expected low surrogate after high surrogate\n"
+ );
+
+ // High surrogate followed by invalid low surrogate.
+ // (The string literal is broken in two so that MSVC doesn't complain about
+ // an invalid universal-character-name.)
+ DEFAULT(R"(
+pref("string.bad-u-surrogate", "foo\)" R"(ud83c\u1234");
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: invalid low surrogate after high surrogate\n"
+ );
+
+ // Low surrogate not preceded by high surrogate.
+ // (The string literal is broken in two so that MSVC doesn't complain about
+ // an invalid universal-character-name.)
+ DEFAULT(R"(
+pref("string.bad-u-surrogate", "foo\)" R"(udc00");
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: expected high surrogate before low surrogate\n"
+ );
+
+ // Unlike in JavaScript, \b, \f, \t, \v aren't allowed.
+ DEFAULT(R"(
+pref("string.bad-escape", "foo\b");
+pref("string.bad-escape", "foo\f");
+pref("string.bad-escape", "foo\t");
+pref("string.bad-escape", "foo\v");
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: unexpected escape sequence character after '\\'\n"
+ "test:3: prefs parse error: unexpected escape sequence character after '\\'\n"
+ "test:4: prefs parse error: unexpected escape sequence character after '\\'\n"
+ "test:5: prefs parse error: unexpected escape sequence character after '\\'\n"
+ );
+
+ // Various bad things after \: non-special letter, number, punctuation,
+ // space, newline, EOF.
+ DEFAULT(R"(
+pref("string.bad-escape", "foo\Q");
+pref("string.bad-escape", "foo\1");
+pref("string.bad-escape", "foo\,");
+pref("string.bad-escape", "foo\ n");
+pref("string.bad-escape", "foo\
+n");
+pref("string.bad-escape", "foo\)",
+ "test:2: prefs parse error: unexpected escape sequence character after '\\'\n"
+ "test:3: prefs parse error: unexpected escape sequence character after '\\'\n"
+ "test:4: prefs parse error: unexpected escape sequence character after '\\'\n"
+ "test:5: prefs parse error: unexpected escape sequence character after '\\'\n"
+ "test:6: prefs parse error: unexpected escape sequence character after '\\'\n"
+ "test:8: prefs parse error: unexpected escape sequence character after '\\'\n"
+ );
+
+ // Unterminated string literals.
+
+ // Simple case.
+ DEFAULT(R"(
+pref("string.unterminated-string", "foo
+ )",
+ "test:3: prefs parse error: unterminated string literal\n"
+ );
+
+ // Alternative case; `int` comes after the string and is seen as a keyword.
+ // The parser then skips to the ';', so no error about the unterminated
+ // string is issued.
+ DEFAULT(R"(
+pref("string.unterminated-string", "foo);
+pref("int.ok", 0);
+ )",
+ "test:3: prefs parse error: unknown keyword\n"
+ );
+
+ // Mismatched quotes (1).
+ DEFAULT(R"(
+pref("string.unterminated-string", "foo');
+ )",
+ "test:3: prefs parse error: unterminated string literal\n"
+ );
+
+ // Mismatched quotes (2).
+ DEFAULT(R"(
+pref("string.unterminated-string", 'foo");
+ )",
+ "test:3: prefs parse error: unterminated string literal\n"
+ );
+
+ // Unknown keywords.
+ DEFAULT(R"(
+foo;
+preff("string.bad-keyword", true);
+ticky_pref("string.bad-keyword", true);
+User_pref("string.bad-keyword", true);
+pref("string.bad-keyword", TRUE);
+ )",
+ "test:2: prefs parse error: unknown keyword\n"
+ "test:3: prefs parse error: unknown keyword\n"
+ "test:4: prefs parse error: unknown keyword\n"
+ "test:5: prefs parse error: unknown keyword\n"
+ "test:6: prefs parse error: unknown keyword\n"
+ );
+
+ // Unterminated C-style comment.
+ DEFAULT(R"(
+/* comment
+ )",
+ "test:3: prefs parse error: unterminated /* comment\n"
+ );
+
+ // Malformed comments (single slashes), followed by whitespace, newline, EOF.
+ DEFAULT(R"(
+/ comment;
+/
+; /)",
+ "test:2: prefs parse error: expected '/' or '*' after '/'\n"
+ "test:3: prefs parse error: expected '/' or '*' after '/'\n"
+ "test:4: prefs parse error: expected '/' or '*' after '/'\n"
+ );
+
+ // C++-style comment ending in EOF (1).
+ DEFAULT(R"(
+// comment)",
+ ""
+ );
+
+ // C++-style comment ending in EOF (2).
+ DEFAULT(R"(
+//)",
+ ""
+ );
+
+ // Various unexpected characters.
+ DEFAULT(R"(
+pref("unexpected.chars", &true);
+pref("unexpected.chars" : true);
+@pref("unexpected.chars", true);
+pref["unexpected.chars": true];
+ )",
+ "test:2: prefs parse error: unexpected character\n"
+ "test:3: prefs parse error: unexpected character\n"
+ "test:4: prefs parse error: unexpected character\n"
+ "test:5: prefs parse error: unexpected character\n"
+ );
+
+ //-------------------------------------------------------------------------
+ // All the parsing errors.
+ //-------------------------------------------------------------------------
+
+ DEFAULT(R"(
+"pref"("parse.error": true);
+pref1("parse.error": true);
+pref(123: true);
+pref("parse.error" true);
+pref("parse.error", pref);
+pref("parse.error", -true);
+pref("parse.error", +"value");
+pref("parse.error", true,);
+pref("parse.error", true;
+pref("parse.error", true, sticky, locked;
+pref("parse.error", true)
+pref("int.ok", 1);
+pref("parse.error", true))",
+ "test:2: prefs parse error: expected pref specifier at start of pref definition\n"
+ "test:3: prefs parse error: expected '(' after pref specifier\n"
+ "test:4: prefs parse error: expected pref name after '('\n"
+ "test:5: prefs parse error: expected ',' after pref name\n"
+ "test:6: prefs parse error: expected pref value after ','\n"
+ "test:7: prefs parse error: expected integer literal after '-'\n"
+ "test:8: prefs parse error: expected integer literal after '+'\n"
+ "test:9: prefs parse error: expected pref attribute after ','\n"
+ "test:10: prefs parse error: expected ',' or ')' after pref value\n"
+ "test:11: prefs parse error: expected ',' or ')' after pref attribute\n"
+ "test:13: prefs parse error: expected ';' after ')'\n"
+ "test:14: prefs parse error: expected ';' after ')'\n"
+ );
+
+ USER(R"(
+pref("parse.error", true);
+sticky_pref("parse.error", true);
+user_pref("int.ok", 1);
+ )",
+ "test:2: prefs parse error: expected 'user_pref' at start of pref definition\n"
+ "test:3: prefs parse error: expected 'user_pref' at start of pref definition\n"
+ );
+
+ USER(R"(
+user_pref("parse.error", true;
+user_pref("int.ok", 1);
+ )",
+ "test:2: prefs parse error: expected ')' after pref value\n"
+ );
+
+ // Parse errors involving unexpected EOF.
+
+ DEFAULT(R"(
+pref)",
+ "test:2: prefs parse error: expected '(' after pref specifier\n"
+ );
+
+ DEFAULT(R"(
+pref()",
+ "test:2: prefs parse error: expected pref name after '('\n"
+ );
+
+ DEFAULT(R"(
+pref("parse.error")",
+ "test:2: prefs parse error: expected ',' after pref name\n"
+ );
+
+ DEFAULT(R"(
+pref("parse.error",)",
+ "test:2: prefs parse error: expected pref value after ','\n"
+ );
+
+ DEFAULT(R"(
+pref("parse.error", -)",
+ "test:2: prefs parse error: expected integer literal after '-'\n"
+ );
+
+ DEFAULT(R"(
+pref("parse.error", +)",
+ "test:2: prefs parse error: expected integer literal after '+'\n"
+ );
+
+ DEFAULT(R"(
+pref("parse.error", true)",
+ "test:2: prefs parse error: expected ',' or ')' after pref value\n"
+ );
+
+ USER(R"(
+user_pref("parse.error", true)",
+ "test:2: prefs parse error: expected ')' after pref value\n"
+ );
+
+ DEFAULT(R"(
+pref("parse.error", true,)",
+ "test:2: prefs parse error: expected pref attribute after ','\n"
+ );
+
+ DEFAULT(R"(
+pref("parse.error", true, sticky)",
+ "test:2: prefs parse error: expected ',' or ')' after pref attribute\n"
+ );
+
+ DEFAULT(R"(
+pref("parse.error", true))",
+ "test:2: prefs parse error: expected ';' after ')'\n"
+ );
+
+ // This is something we saw in practice with the old parser, which allowed
+ // repeated semicolons.
+ DEFAULT(R"(
+pref("parse.error", true);;
+pref("parse.error", true, locked);;;
+pref("parse.error", true, sticky, locked);;;;
+pref("int.ok", 0);
+ )",
+ "test:2: prefs parse error: expected pref specifier at start of pref definition\n"
+ "test:3: prefs parse error: expected pref specifier at start of pref definition\n"
+ "test:3: prefs parse error: expected pref specifier at start of pref definition\n"
+ "test:4: prefs parse error: expected pref specifier at start of pref definition\n"
+ "test:4: prefs parse error: expected pref specifier at start of pref definition\n"
+ "test:4: prefs parse error: expected pref specifier at start of pref definition\n"
+ );
+
+ //-------------------------------------------------------------------------
+ // Invalid syntax after various newline combinations, for the purpose of
+ // testing that line numbers are correct.
+ //-------------------------------------------------------------------------
+
+ // In all of the following we have a \n, a \r, a \r\n, and then an error, so
+ // the error is on line 4. (Note: these ones don't use raw string literals
+ // because MSVC somehow swallows any \r that appears in them.)
+
+ DEFAULT("\n \r \r\n bad",
+ "test:4: prefs parse error: unknown keyword\n"
+ );
+
+ DEFAULT("#\n#\r#\r\n bad",
+ "test:4: prefs parse error: unknown keyword\n"
+ );
+
+ DEFAULT("//\n//\r//\r\n bad",
+ "test:4: prefs parse error: unknown keyword\n"
+ );
+
+ DEFAULT("/*\n \r \r\n*/ bad",
+ "test:4: prefs parse error: unknown keyword\n"
+ );
+
+ // Note: the escape sequences do *not* affect the line number.
+ DEFAULT("pref(\"foo\\n\n foo\\r\r foo\\r\\n\r\n foo\", bad);",
+ "test:4: prefs parse error: unknown keyword\n"
+ );
+
+ // clang-format on
+}