| // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
| // This source code is licensed under both the GPLv2 (found in the |
| // COPYING file in the root directory) and Apache 2.0 License |
| // (found in the LICENSE.Apache file in the root directory). |
| |
| #ifndef ROCKSDB_LITE |
| |
| #include <map> |
| #include <set> |
| #include <string> |
| |
| #include "rocksdb/utilities/json_document.h" |
| |
| #include "util/testutil.h" |
| #include "util/testharness.h" |
| |
| namespace rocksdb { |
| namespace { |
| void AssertField(const JSONDocument& json, const std::string& field) { |
| ASSERT_TRUE(json.Contains(field)); |
| ASSERT_TRUE(json[field].IsNull()); |
| } |
| |
| void AssertField(const JSONDocument& json, const std::string& field, |
| const std::string& expected) { |
| ASSERT_TRUE(json.Contains(field)); |
| ASSERT_TRUE(json[field].IsString()); |
| ASSERT_EQ(expected, json[field].GetString()); |
| } |
| |
| void AssertField(const JSONDocument& json, const std::string& field, |
| int64_t expected) { |
| ASSERT_TRUE(json.Contains(field)); |
| ASSERT_TRUE(json[field].IsInt64()); |
| ASSERT_EQ(expected, json[field].GetInt64()); |
| } |
| |
| void AssertField(const JSONDocument& json, const std::string& field, |
| bool expected) { |
| ASSERT_TRUE(json.Contains(field)); |
| ASSERT_TRUE(json[field].IsBool()); |
| ASSERT_EQ(expected, json[field].GetBool()); |
| } |
| |
| void AssertField(const JSONDocument& json, const std::string& field, |
| double expected) { |
| ASSERT_TRUE(json.Contains(field)); |
| ASSERT_TRUE(json[field].IsDouble()); |
| ASSERT_DOUBLE_EQ(expected, json[field].GetDouble()); |
| } |
| } // namespace |
| |
| class JSONDocumentTest : public testing::Test { |
| public: |
| JSONDocumentTest() |
| : rnd_(101) |
| {} |
| |
| void AssertSampleJSON(const JSONDocument& json) { |
| AssertField(json, "title", std::string("json")); |
| AssertField(json, "type", std::string("object")); |
| // properties |
| ASSERT_TRUE(json.Contains("properties")); |
| ASSERT_TRUE(json["properties"].Contains("flags")); |
| ASSERT_TRUE(json["properties"]["flags"].IsArray()); |
| ASSERT_EQ(3u, json["properties"]["flags"].Count()); |
| ASSERT_TRUE(json["properties"]["flags"][0].IsInt64()); |
| ASSERT_EQ(10, json["properties"]["flags"][0].GetInt64()); |
| ASSERT_TRUE(json["properties"]["flags"][1].IsString()); |
| ASSERT_EQ("parse", json["properties"]["flags"][1].GetString()); |
| ASSERT_TRUE(json["properties"]["flags"][2].IsObject()); |
| AssertField(json["properties"]["flags"][2], "tag", std::string("no")); |
| AssertField(json["properties"]["flags"][2], std::string("status")); |
| AssertField(json["properties"], "age", 110.5e-4); |
| AssertField(json["properties"], "depth", static_cast<int64_t>(-10)); |
| // test iteration |
| std::set<std::string> expected({"flags", "age", "depth"}); |
| for (auto item : json["properties"].Items()) { |
| auto iter = expected.find(item.first); |
| ASSERT_TRUE(iter != expected.end()); |
| expected.erase(iter); |
| } |
| ASSERT_EQ(0U, expected.size()); |
| ASSERT_TRUE(json.Contains("latlong")); |
| ASSERT_TRUE(json["latlong"].IsArray()); |
| ASSERT_EQ(2u, json["latlong"].Count()); |
| ASSERT_TRUE(json["latlong"][0].IsDouble()); |
| ASSERT_EQ(53.25, json["latlong"][0].GetDouble()); |
| ASSERT_TRUE(json["latlong"][1].IsDouble()); |
| ASSERT_EQ(43.75, json["latlong"][1].GetDouble()); |
| AssertField(json, "enabled", true); |
| } |
| |
| const std::string kSampleJSON = |
| "{ \"title\" : \"json\", \"type\" : \"object\", \"properties\" : { " |
| "\"flags\": [10, \"parse\", {\"tag\": \"no\", \"status\": null}], " |
| "\"age\": 110.5e-4, \"depth\": -10 }, \"latlong\": [53.25, 43.75], " |
| "\"enabled\": true }"; |
| |
| const std::string kSampleJSONDifferent = |
| "{ \"title\" : \"json\", \"type\" : \"object\", \"properties\" : { " |
| "\"flags\": [10, \"parse\", {\"tag\": \"no\", \"status\": 2}], " |
| "\"age\": 110.5e-4, \"depth\": -10 }, \"latlong\": [53.25, 43.75], " |
| "\"enabled\": true }"; |
| |
| Random rnd_; |
| }; |
| |
| TEST_F(JSONDocumentTest, MakeNullTest) { |
| JSONDocument x; |
| ASSERT_TRUE(x.IsNull()); |
| ASSERT_TRUE(x.IsOwner()); |
| ASSERT_TRUE(!x.IsBool()); |
| } |
| |
| TEST_F(JSONDocumentTest, MakeBoolTest) { |
| { |
| JSONDocument x(true); |
| ASSERT_TRUE(x.IsOwner()); |
| ASSERT_TRUE(x.IsBool()); |
| ASSERT_TRUE(!x.IsInt64()); |
| ASSERT_EQ(x.GetBool(), true); |
| } |
| |
| { |
| JSONDocument x(false); |
| ASSERT_TRUE(x.IsOwner()); |
| ASSERT_TRUE(x.IsBool()); |
| ASSERT_TRUE(!x.IsInt64()); |
| ASSERT_EQ(x.GetBool(), false); |
| } |
| } |
| |
| TEST_F(JSONDocumentTest, MakeInt64Test) { |
| JSONDocument x(static_cast<int64_t>(16)); |
| ASSERT_TRUE(x.IsInt64()); |
| ASSERT_TRUE(x.IsInt64()); |
| ASSERT_TRUE(!x.IsBool()); |
| ASSERT_TRUE(x.IsOwner()); |
| ASSERT_EQ(x.GetInt64(), 16); |
| } |
| |
| TEST_F(JSONDocumentTest, MakeStringTest) { |
| JSONDocument x("string"); |
| ASSERT_TRUE(x.IsOwner()); |
| ASSERT_TRUE(x.IsString()); |
| ASSERT_TRUE(!x.IsBool()); |
| ASSERT_EQ(x.GetString(), "string"); |
| } |
| |
| TEST_F(JSONDocumentTest, MakeDoubleTest) { |
| JSONDocument x(5.6); |
| ASSERT_TRUE(x.IsOwner()); |
| ASSERT_TRUE(x.IsDouble()); |
| ASSERT_TRUE(!x.IsBool()); |
| ASSERT_EQ(x.GetDouble(), 5.6); |
| } |
| |
| TEST_F(JSONDocumentTest, MakeByTypeTest) { |
| { |
| JSONDocument x(JSONDocument::kNull); |
| ASSERT_TRUE(x.IsNull()); |
| } |
| { |
| JSONDocument x(JSONDocument::kBool); |
| ASSERT_TRUE(x.IsBool()); |
| } |
| { |
| JSONDocument x(JSONDocument::kString); |
| ASSERT_TRUE(x.IsString()); |
| } |
| { |
| JSONDocument x(JSONDocument::kInt64); |
| ASSERT_TRUE(x.IsInt64()); |
| } |
| { |
| JSONDocument x(JSONDocument::kDouble); |
| ASSERT_TRUE(x.IsDouble()); |
| } |
| { |
| JSONDocument x(JSONDocument::kObject); |
| ASSERT_TRUE(x.IsObject()); |
| } |
| { |
| JSONDocument x(JSONDocument::kArray); |
| ASSERT_TRUE(x.IsArray()); |
| } |
| } |
| |
| TEST_F(JSONDocumentTest, Parsing) { |
| std::unique_ptr<JSONDocument> parsed_json( |
| JSONDocument::ParseJSON(kSampleJSON.c_str())); |
| ASSERT_TRUE(parsed_json->IsOwner()); |
| ASSERT_TRUE(parsed_json != nullptr); |
| AssertSampleJSON(*parsed_json); |
| |
| // test deep copying |
| JSONDocument copied_json_document(*parsed_json); |
| AssertSampleJSON(copied_json_document); |
| ASSERT_TRUE(copied_json_document == *parsed_json); |
| |
| std::unique_ptr<JSONDocument> parsed_different_sample( |
| JSONDocument::ParseJSON(kSampleJSONDifferent.c_str())); |
| ASSERT_TRUE(parsed_different_sample != nullptr); |
| ASSERT_TRUE(!(*parsed_different_sample == copied_json_document)); |
| |
| // parse error |
| const std::string kFaultyJSON = |
| kSampleJSON.substr(0, kSampleJSON.size() - 10); |
| ASSERT_TRUE(JSONDocument::ParseJSON(kFaultyJSON.c_str()) == nullptr); |
| } |
| |
| TEST_F(JSONDocumentTest, Serialization) { |
| std::unique_ptr<JSONDocument> parsed_json( |
| JSONDocument::ParseJSON(kSampleJSON.c_str())); |
| ASSERT_TRUE(parsed_json != nullptr); |
| ASSERT_TRUE(parsed_json->IsOwner()); |
| std::string serialized; |
| parsed_json->Serialize(&serialized); |
| |
| std::unique_ptr<JSONDocument> deserialized_json( |
| JSONDocument::Deserialize(Slice(serialized))); |
| ASSERT_TRUE(deserialized_json != nullptr); |
| AssertSampleJSON(*deserialized_json); |
| |
| // deserialization failure |
| ASSERT_TRUE(JSONDocument::Deserialize( |
| Slice(serialized.data(), serialized.size() - 10)) == nullptr); |
| } |
| |
| TEST_F(JSONDocumentTest, OperatorEqualsTest) { |
| // kNull |
| ASSERT_TRUE(JSONDocument() == JSONDocument()); |
| |
| // kBool |
| ASSERT_TRUE(JSONDocument(false) != JSONDocument()); |
| ASSERT_TRUE(JSONDocument(false) == JSONDocument(false)); |
| ASSERT_TRUE(JSONDocument(true) == JSONDocument(true)); |
| ASSERT_TRUE(JSONDocument(false) != JSONDocument(true)); |
| |
| // kString |
| ASSERT_TRUE(JSONDocument("test") != JSONDocument()); |
| ASSERT_TRUE(JSONDocument("test") == JSONDocument("test")); |
| |
| // kInt64 |
| ASSERT_TRUE(JSONDocument(static_cast<int64_t>(15)) != JSONDocument()); |
| ASSERT_TRUE(JSONDocument(static_cast<int64_t>(15)) != |
| JSONDocument(static_cast<int64_t>(14))); |
| ASSERT_TRUE(JSONDocument(static_cast<int64_t>(15)) == |
| JSONDocument(static_cast<int64_t>(15))); |
| |
| unique_ptr<JSONDocument> arrayWithInt8Doc(JSONDocument::ParseJSON("[8]")); |
| ASSERT_TRUE(arrayWithInt8Doc != nullptr); |
| ASSERT_TRUE(arrayWithInt8Doc->IsArray()); |
| ASSERT_TRUE((*arrayWithInt8Doc)[0].IsInt64()); |
| ASSERT_TRUE((*arrayWithInt8Doc)[0] == JSONDocument(static_cast<int64_t>(8))); |
| |
| unique_ptr<JSONDocument> arrayWithInt16Doc(JSONDocument::ParseJSON("[512]")); |
| ASSERT_TRUE(arrayWithInt16Doc != nullptr); |
| ASSERT_TRUE(arrayWithInt16Doc->IsArray()); |
| ASSERT_TRUE((*arrayWithInt16Doc)[0].IsInt64()); |
| ASSERT_TRUE((*arrayWithInt16Doc)[0] == |
| JSONDocument(static_cast<int64_t>(512))); |
| |
| unique_ptr<JSONDocument> arrayWithInt32Doc( |
| JSONDocument::ParseJSON("[1000000]")); |
| ASSERT_TRUE(arrayWithInt32Doc != nullptr); |
| ASSERT_TRUE(arrayWithInt32Doc->IsArray()); |
| ASSERT_TRUE((*arrayWithInt32Doc)[0].IsInt64()); |
| ASSERT_TRUE((*arrayWithInt32Doc)[0] == |
| JSONDocument(static_cast<int64_t>(1000000))); |
| |
| // kDouble |
| ASSERT_TRUE(JSONDocument(15.) != JSONDocument()); |
| ASSERT_TRUE(JSONDocument(15.) != JSONDocument(14.)); |
| ASSERT_TRUE(JSONDocument(15.) == JSONDocument(15.)); |
| } |
| |
| TEST_F(JSONDocumentTest, JSONDocumentBuilderTest) { |
| unique_ptr<JSONDocument> parsedArray( |
| JSONDocument::ParseJSON("[1, [123, \"a\", \"b\"], {\"b\":\"c\"}]")); |
| ASSERT_TRUE(parsedArray != nullptr); |
| |
| JSONDocumentBuilder builder; |
| ASSERT_TRUE(builder.WriteStartArray()); |
| ASSERT_TRUE(builder.WriteJSONDocument(1)); |
| |
| ASSERT_TRUE(builder.WriteStartArray()); |
| ASSERT_TRUE(builder.WriteJSONDocument(123)); |
| ASSERT_TRUE(builder.WriteJSONDocument("a")); |
| ASSERT_TRUE(builder.WriteJSONDocument("b")); |
| ASSERT_TRUE(builder.WriteEndArray()); |
| |
| ASSERT_TRUE(builder.WriteStartObject()); |
| ASSERT_TRUE(builder.WriteKeyValue("b", "c")); |
| ASSERT_TRUE(builder.WriteEndObject()); |
| |
| ASSERT_TRUE(builder.WriteEndArray()); |
| |
| ASSERT_TRUE(*parsedArray == builder.GetJSONDocument()); |
| } |
| |
| TEST_F(JSONDocumentTest, OwnershipTest) { |
| std::unique_ptr<JSONDocument> parsed( |
| JSONDocument::ParseJSON(kSampleJSON.c_str())); |
| ASSERT_TRUE(parsed != nullptr); |
| ASSERT_TRUE(parsed->IsOwner()); |
| |
| // Copy constructor from owner -> owner |
| JSONDocument copy_constructor(*parsed); |
| ASSERT_TRUE(copy_constructor.IsOwner()); |
| |
| // Copy constructor from non-owner -> non-owner |
| JSONDocument non_owner((*parsed)["properties"]); |
| ASSERT_TRUE(!non_owner.IsOwner()); |
| |
| // Move constructor from owner -> owner |
| JSONDocument moved_from_owner(std::move(copy_constructor)); |
| ASSERT_TRUE(moved_from_owner.IsOwner()); |
| |
| // Move constructor from non-owner -> non-owner |
| JSONDocument moved_from_non_owner(std::move(non_owner)); |
| ASSERT_TRUE(!moved_from_non_owner.IsOwner()); |
| } |
| |
| } // namespace rocksdb |
| |
| int main(int argc, char** argv) { |
| ::testing::InitGoogleTest(&argc, argv); |
| return RUN_ALL_TESTS(); |
| } |
| |
| #else |
| #include <stdio.h> |
| |
| int main(int argc, char** argv) { |
| fprintf(stderr, "SKIPPED as JSONDocument is not supported in ROCKSDB_LITE\n"); |
| return 0; |
| } |
| |
| #endif // !ROCKSDB_LITE |