summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/unittests/clangd/JSONExprTests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/unittests/clangd/JSONExprTests.cpp')
-rw-r--r--clang-tools-extra/unittests/clangd/JSONExprTests.cpp74
1 files changed, 74 insertions, 0 deletions
diff --git a/clang-tools-extra/unittests/clangd/JSONExprTests.cpp b/clang-tools-extra/unittests/clangd/JSONExprTests.cpp
index efa9eb34ea8..25f43842f5f 100644
--- a/clang-tools-extra/unittests/clangd/JSONExprTests.cpp
+++ b/clang-tools-extra/unittests/clangd/JSONExprTests.cpp
@@ -15,6 +15,9 @@
namespace clang {
namespace clangd {
namespace json {
+void PrintTo(const Expr &E, std::ostream *OS) {
+ llvm::raw_os_ostream(*OS) << llvm::formatv("{0:2}", E);
+}
namespace {
std::string s(const Expr &E) { return llvm::formatv("{0}", E).str(); }
@@ -108,6 +111,77 @@ TEST(JSONExprTests, PrettyPrinting) {
}));
}
+TEST(JSONTest, Parse) {
+ auto Compare = [](llvm::StringRef S, Expr Expected) {
+ if (auto E = parse(S)) {
+ // Compare both string forms and with operator==, in case we have bugs.
+ EXPECT_EQ(*E, Expected);
+ EXPECT_EQ(sp(*E), sp(Expected));
+ } else {
+ handleAllErrors(E.takeError(), [S](const llvm::ErrorInfoBase &E) {
+ FAIL() << "Failed to parse JSON >>> " << S << " <<<: " << E.message();
+ });
+ }
+ };
+
+ Compare(R"(true)", true);
+ Compare(R"(false)", false);
+ Compare(R"(null)", nullptr);
+
+ Compare(R"(42)", 42);
+ Compare(R"(2.5)", 2.5);
+ Compare(R"(2e50)", 2e50);
+ Compare(R"(1.2e3456789)", 1.0 / 0.0);
+
+ Compare(R"("foo")", "foo");
+ Compare(R"("\"\\\b\f\n\r\t")", "\"\\\b\f\n\r\t");
+ Compare(R"("\u0000")", llvm::StringRef("\0", 1));
+ Compare("\"\x7f\"", "\x7f");
+ Compare(R"("\ud801\udc37")", "\U00010437"); // UTF16 surrogate pair escape.
+ Compare("\"\xE2\x82\xAC\xF0\x9D\x84\x9E\"", "\u20ac\U0001d11e"); // UTF8
+ Compare(R"("\ud801")", "\ufffd"); // Invalid codepoint.
+
+ Compare(R"({"":0,"":0})", obj{{"", 0}});
+ Compare(R"({"obj":{},"arr":[]})", obj{{"obj", obj{}}, {"arr", {}}});
+ Compare(R"({"\n":{"\u0000":[[[[]]]]}})",
+ obj{{"\n", obj{
+ {llvm::StringRef("\0", 1), {{{{}}}}},
+ }}});
+ Compare("\r[\n\t] ", {});
+}
+
+TEST(JSONTest, ParseErrors) {
+ auto ExpectErr = [](llvm::StringRef Msg, llvm::StringRef S) {
+ if (auto E = parse(S)) {
+ // Compare both string forms and with operator==, in case we have bugs.
+ FAIL() << "Parsed JSON >>> " << S << " <<< but wanted error: " << Msg;
+ } else {
+ handleAllErrors(E.takeError(), [S, Msg](const llvm::ErrorInfoBase &E) {
+ EXPECT_THAT(E.message(), testing::HasSubstr(Msg)) << S;
+ });
+ }
+ };
+ ExpectErr("Unexpected EOF", "");
+ ExpectErr("Unexpected EOF", "[");
+ ExpectErr("Text after end of document", "[][]");
+ ExpectErr("Text after end of document", "[][]");
+ ExpectErr("Invalid bareword", "fuzzy");
+ ExpectErr("Expected , or ]", "[2?]");
+ ExpectErr("Expected object key", "{a:2}");
+ ExpectErr("Expected : after object key", R"({"a",2})");
+ ExpectErr("Expected , or } after object property", R"({"a":2 "b":3})");
+ ExpectErr("Expected JSON value", R"([&%!])");
+ ExpectErr("Invalid number", "1e1.0");
+ ExpectErr("Unterminated string", R"("abc\"def)");
+ ExpectErr("Control character in string", "\"abc\ndef\"");
+ ExpectErr("Invalid escape sequence", R"("\030")");
+ ExpectErr("Invalid \\u escape sequence", R"("\usuck")");
+ ExpectErr("[3:3, byte=19]", R"({
+ "valid": 1,
+ invalid: 2
+})");
+}
+
} // namespace
} // namespace json
} // namespace clangd
OpenPOWER on IntegriCloud