/Users/deen/code/yugabyte-db/src/yb/rocksdb/utilities/document/json_document_test.cc
Line | Count | Source |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under the BSD-style license found in the |
3 | | // LICENSE file in the root directory of this source tree. An additional grant |
4 | | // of patent rights can be found in the PATENTS file in the same directory. |
5 | | // |
6 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | |
21 | | #ifndef ROCKSDB_LITE |
22 | | |
23 | | #include <map> |
24 | | #include <set> |
25 | | #include <string> |
26 | | |
27 | | #include "yb/rocksdb/utilities/json_document.h" |
28 | | |
29 | | #include "yb/rocksdb/util/testutil.h" |
30 | | #include "yb/rocksdb/util/testharness.h" |
31 | | |
32 | | #include "yb/util/test_util.h" |
33 | | |
34 | | namespace rocksdb { |
35 | | namespace { |
36 | 3 | void AssertField(const JSONDocument& json, const std::string& field) { |
37 | 3 | ASSERT_TRUE(json.Contains(field)); |
38 | 3 | ASSERT_TRUE(json[field].IsNull()); |
39 | 3 | } |
40 | | |
41 | | void AssertField(const JSONDocument& json, const std::string& field, |
42 | 9 | const std::string& expected) { |
43 | 9 | ASSERT_TRUE(json.Contains(field)); |
44 | 9 | ASSERT_TRUE(json[field].IsString()); |
45 | 9 | ASSERT_EQ(expected, json[field].GetString()); |
46 | 9 | } |
47 | | |
48 | | void AssertField(const JSONDocument& json, const std::string& field, |
49 | 3 | int64_t expected) { |
50 | 3 | ASSERT_TRUE(json.Contains(field)); |
51 | 3 | ASSERT_TRUE(json[field].IsInt64()); |
52 | 3 | ASSERT_EQ(expected, json[field].GetInt64()); |
53 | 3 | } |
54 | | |
55 | | void AssertField(const JSONDocument& json, const std::string& field, |
56 | 3 | bool expected) { |
57 | 3 | ASSERT_TRUE(json.Contains(field)); |
58 | 3 | ASSERT_TRUE(json[field].IsBool()); |
59 | 3 | ASSERT_EQ(expected, json[field].GetBool()); |
60 | 3 | } |
61 | | |
62 | | void AssertField(const JSONDocument& json, const std::string& field, |
63 | 3 | double expected) { |
64 | 3 | ASSERT_TRUE(json.Contains(field)); |
65 | 3 | ASSERT_TRUE(json[field].IsDouble()); |
66 | 3 | ASSERT_EQ(expected, json[field].GetDouble()); |
67 | 3 | } |
68 | | } // namespace |
69 | | |
70 | | class JSONDocumentTest : public RocksDBTest { |
71 | | public: |
72 | | JSONDocumentTest() |
73 | | : rnd_(101) |
74 | 11 | {} |
75 | | |
76 | 3 | void AssertSampleJSON(const JSONDocument& json) { |
77 | 3 | AssertField(json, "title", std::string("json")); |
78 | 3 | AssertField(json, "type", std::string("object")); |
79 | | // properties |
80 | 3 | ASSERT_TRUE(json.Contains("properties")); |
81 | 3 | ASSERT_TRUE(json["properties"].Contains("flags")); |
82 | 3 | ASSERT_TRUE(json["properties"]["flags"].IsArray()); |
83 | 3 | ASSERT_EQ(3u, json["properties"]["flags"].Count()); |
84 | 3 | ASSERT_TRUE(json["properties"]["flags"][0].IsInt64()); |
85 | 3 | ASSERT_EQ(10, json["properties"]["flags"][0].GetInt64()); |
86 | 3 | ASSERT_TRUE(json["properties"]["flags"][1].IsString()); |
87 | 3 | ASSERT_EQ("parse", json["properties"]["flags"][1].GetString()); |
88 | 3 | ASSERT_TRUE(json["properties"]["flags"][2].IsObject()); |
89 | 3 | AssertField(json["properties"]["flags"][2], "tag", std::string("no")); |
90 | 3 | AssertField(json["properties"]["flags"][2], std::string("status")); |
91 | 3 | AssertField(json["properties"], "age", 110.5e-4); |
92 | 3 | AssertField(json["properties"], "depth", static_cast<int64_t>(-10)); |
93 | | // test iteration |
94 | 3 | std::set<std::string> expected({"flags", "age", "depth"}); |
95 | 9 | for (auto item : json["properties"].Items()) { |
96 | 9 | auto iter = expected.find(item.first); |
97 | 9 | ASSERT_TRUE(iter != expected.end()); |
98 | 9 | expected.erase(iter); |
99 | 9 | } |
100 | 3 | ASSERT_EQ(0U, expected.size()); |
101 | 3 | ASSERT_TRUE(json.Contains("latlong")); |
102 | 3 | ASSERT_TRUE(json["latlong"].IsArray()); |
103 | 3 | ASSERT_EQ(2u, json["latlong"].Count()); |
104 | 3 | ASSERT_TRUE(json["latlong"][0].IsDouble()); |
105 | 3 | ASSERT_EQ(53.25, json["latlong"][0].GetDouble()); |
106 | 3 | ASSERT_TRUE(json["latlong"][1].IsDouble()); |
107 | 3 | ASSERT_EQ(43.75, json["latlong"][1].GetDouble()); |
108 | 3 | AssertField(json, "enabled", true); |
109 | 3 | } |
110 | | |
111 | | const std::string kSampleJSON = |
112 | | "{ \"title\" : \"json\", \"type\" : \"object\", \"properties\" : { " |
113 | | "\"flags\": [10, \"parse\", {\"tag\": \"no\", \"status\": null}], " |
114 | | "\"age\": 110.5e-4, \"depth\": -10 }, \"latlong\": [53.25, 43.75], " |
115 | | "\"enabled\": true }"; |
116 | | |
117 | | const std::string kSampleJSONDifferent = |
118 | | "{ \"title\" : \"json\", \"type\" : \"object\", \"properties\" : { " |
119 | | "\"flags\": [10, \"parse\", {\"tag\": \"no\", \"status\": 2}], " |
120 | | "\"age\": 110.5e-4, \"depth\": -10 }, \"latlong\": [53.25, 43.75], " |
121 | | "\"enabled\": true }"; |
122 | | |
123 | | Random rnd_; |
124 | | }; |
125 | | |
126 | 1 | TEST_F(JSONDocumentTest, MakeNullTest) { |
127 | 1 | JSONDocument x; |
128 | 1 | ASSERT_TRUE(x.IsNull()); |
129 | 1 | ASSERT_TRUE(x.IsOwner()); |
130 | 1 | ASSERT_TRUE(!x.IsBool()); |
131 | 1 | } |
132 | | |
133 | 1 | TEST_F(JSONDocumentTest, MakeBoolTest) { |
134 | 1 | { |
135 | 1 | JSONDocument x(true); |
136 | 1 | ASSERT_TRUE(x.IsOwner()); |
137 | 1 | ASSERT_TRUE(x.IsBool()); |
138 | 1 | ASSERT_TRUE(!x.IsInt64()); |
139 | 1 | ASSERT_EQ(x.GetBool(), true); |
140 | 1 | } |
141 | | |
142 | 1 | { |
143 | 1 | JSONDocument x(false); |
144 | 1 | ASSERT_TRUE(x.IsOwner()); |
145 | 1 | ASSERT_TRUE(x.IsBool()); |
146 | 1 | ASSERT_TRUE(!x.IsInt64()); |
147 | 1 | ASSERT_EQ(x.GetBool(), false); |
148 | 1 | } |
149 | 1 | } |
150 | | |
151 | 1 | TEST_F(JSONDocumentTest, MakeInt64Test) { |
152 | 1 | JSONDocument x(static_cast<int64_t>(16)); |
153 | 1 | ASSERT_TRUE(x.IsInt64()); |
154 | 1 | ASSERT_TRUE(x.IsInt64()); |
155 | 1 | ASSERT_TRUE(!x.IsBool()); |
156 | 1 | ASSERT_TRUE(x.IsOwner()); |
157 | 1 | ASSERT_EQ(x.GetInt64(), 16); |
158 | 1 | } |
159 | | |
160 | 1 | TEST_F(JSONDocumentTest, MakeStringTest) { |
161 | 1 | JSONDocument x("string"); |
162 | 1 | ASSERT_TRUE(x.IsOwner()); |
163 | 1 | ASSERT_TRUE(x.IsString()); |
164 | 1 | ASSERT_TRUE(!x.IsBool()); |
165 | 1 | ASSERT_EQ(x.GetString(), "string"); |
166 | 1 | } |
167 | | |
168 | 1 | TEST_F(JSONDocumentTest, MakeDoubleTest) { |
169 | 1 | JSONDocument x(5.6); |
170 | 1 | ASSERT_TRUE(x.IsOwner()); |
171 | 1 | ASSERT_TRUE(x.IsDouble()); |
172 | 1 | ASSERT_TRUE(!x.IsBool()); |
173 | 1 | ASSERT_EQ(x.GetDouble(), 5.6); |
174 | 1 | } |
175 | | |
176 | 1 | TEST_F(JSONDocumentTest, MakeByTypeTest) { |
177 | 1 | { |
178 | 1 | JSONDocument x(JSONDocument::kNull); |
179 | 1 | ASSERT_TRUE(x.IsNull()); |
180 | 1 | } |
181 | 1 | { |
182 | 1 | JSONDocument x(JSONDocument::kBool); |
183 | 1 | ASSERT_TRUE(x.IsBool()); |
184 | 1 | } |
185 | 1 | { |
186 | 1 | JSONDocument x(JSONDocument::kString); |
187 | 1 | ASSERT_TRUE(x.IsString()); |
188 | 1 | } |
189 | 1 | { |
190 | 1 | JSONDocument x(JSONDocument::kInt64); |
191 | 1 | ASSERT_TRUE(x.IsInt64()); |
192 | 1 | } |
193 | 1 | { |
194 | 1 | JSONDocument x(JSONDocument::kDouble); |
195 | 1 | ASSERT_TRUE(x.IsDouble()); |
196 | 1 | } |
197 | 1 | { |
198 | 1 | JSONDocument x(JSONDocument::kObject); |
199 | 1 | ASSERT_TRUE(x.IsObject()); |
200 | 1 | } |
201 | 1 | { |
202 | 1 | JSONDocument x(JSONDocument::kArray); |
203 | 1 | ASSERT_TRUE(x.IsArray()); |
204 | 1 | } |
205 | 1 | } |
206 | | |
207 | 1 | TEST_F(JSONDocumentTest, Parsing) { |
208 | 1 | std::unique_ptr<JSONDocument> parsed_json( |
209 | 1 | JSONDocument::ParseJSON(kSampleJSON.c_str())); |
210 | 1 | ASSERT_TRUE(parsed_json->IsOwner()); |
211 | 1 | ASSERT_TRUE(parsed_json != nullptr); |
212 | 1 | AssertSampleJSON(*parsed_json); |
213 | | |
214 | | // test deep copying |
215 | 1 | JSONDocument copied_json_document(*parsed_json); |
216 | 1 | AssertSampleJSON(copied_json_document); |
217 | 1 | ASSERT_TRUE(copied_json_document == *parsed_json); |
218 | | |
219 | 1 | std::unique_ptr<JSONDocument> parsed_different_sample( |
220 | 1 | JSONDocument::ParseJSON(kSampleJSONDifferent.c_str())); |
221 | 1 | ASSERT_TRUE(parsed_different_sample != nullptr); |
222 | 1 | ASSERT_TRUE(!(*parsed_different_sample == copied_json_document)); |
223 | | |
224 | | // parse error |
225 | 1 | const std::string kFaultyJSON = |
226 | 1 | kSampleJSON.substr(0, kSampleJSON.size() - 10); |
227 | 1 | ASSERT_TRUE(JSONDocument::ParseJSON(kFaultyJSON.c_str()) == nullptr); |
228 | 1 | } |
229 | | |
230 | 1 | TEST_F(JSONDocumentTest, Serialization) { |
231 | 1 | std::unique_ptr<JSONDocument> parsed_json( |
232 | 1 | JSONDocument::ParseJSON(kSampleJSON.c_str())); |
233 | 1 | ASSERT_TRUE(parsed_json != nullptr); |
234 | 1 | ASSERT_TRUE(parsed_json->IsOwner()); |
235 | 1 | std::string serialized; |
236 | 1 | parsed_json->Serialize(&serialized); |
237 | | |
238 | 1 | std::unique_ptr<JSONDocument> deserialized_json( |
239 | 1 | JSONDocument::Deserialize(Slice(serialized))); |
240 | 1 | ASSERT_TRUE(deserialized_json != nullptr); |
241 | 1 | AssertSampleJSON(*deserialized_json); |
242 | | |
243 | | // deserialization failure |
244 | 1 | ASSERT_TRUE(JSONDocument::Deserialize( |
245 | 1 | Slice(serialized.data(), serialized.size() - 10)) == nullptr); |
246 | 1 | } |
247 | | |
248 | 1 | TEST_F(JSONDocumentTest, OperatorEqualsTest) { |
249 | | // kNull |
250 | 1 | ASSERT_TRUE(JSONDocument() == JSONDocument()); |
251 | | |
252 | | // kBool |
253 | 1 | ASSERT_TRUE(JSONDocument(false) != JSONDocument()); |
254 | 1 | ASSERT_TRUE(JSONDocument(false) == JSONDocument(false)); |
255 | 1 | ASSERT_TRUE(JSONDocument(true) == JSONDocument(true)); |
256 | 1 | ASSERT_TRUE(JSONDocument(false) != JSONDocument(true)); |
257 | | |
258 | | // kString |
259 | 1 | ASSERT_TRUE(JSONDocument("test") != JSONDocument()); |
260 | 1 | ASSERT_TRUE(JSONDocument("test") == JSONDocument("test")); |
261 | | |
262 | | // kInt64 |
263 | 1 | ASSERT_TRUE(JSONDocument(static_cast<int64_t>(15)) != JSONDocument()); |
264 | 1 | ASSERT_TRUE(JSONDocument(static_cast<int64_t>(15)) != |
265 | 1 | JSONDocument(static_cast<int64_t>(14))); |
266 | 1 | ASSERT_TRUE(JSONDocument(static_cast<int64_t>(15)) == |
267 | 1 | JSONDocument(static_cast<int64_t>(15))); |
268 | | |
269 | 1 | unique_ptr<JSONDocument> arrayWithInt8Doc(JSONDocument::ParseJSON("[8]")); |
270 | 1 | ASSERT_TRUE(arrayWithInt8Doc != nullptr); |
271 | 1 | ASSERT_TRUE(arrayWithInt8Doc->IsArray()); |
272 | 1 | ASSERT_TRUE((*arrayWithInt8Doc)[0].IsInt64()); |
273 | 1 | ASSERT_TRUE((*arrayWithInt8Doc)[0] == JSONDocument(static_cast<int64_t>(8))); |
274 | | |
275 | 1 | unique_ptr<JSONDocument> arrayWithInt16Doc(JSONDocument::ParseJSON("[512]")); |
276 | 1 | ASSERT_TRUE(arrayWithInt16Doc != nullptr); |
277 | 1 | ASSERT_TRUE(arrayWithInt16Doc->IsArray()); |
278 | 1 | ASSERT_TRUE((*arrayWithInt16Doc)[0].IsInt64()); |
279 | 1 | ASSERT_TRUE((*arrayWithInt16Doc)[0] == |
280 | 1 | JSONDocument(static_cast<int64_t>(512))); |
281 | | |
282 | 1 | unique_ptr<JSONDocument> arrayWithInt32Doc( |
283 | 1 | JSONDocument::ParseJSON("[1000000]")); |
284 | 1 | ASSERT_TRUE(arrayWithInt32Doc != nullptr); |
285 | 1 | ASSERT_TRUE(arrayWithInt32Doc->IsArray()); |
286 | 1 | ASSERT_TRUE((*arrayWithInt32Doc)[0].IsInt64()); |
287 | 1 | ASSERT_TRUE((*arrayWithInt32Doc)[0] == |
288 | 1 | JSONDocument(static_cast<int64_t>(1000000))); |
289 | | |
290 | | // kDouble |
291 | 1 | ASSERT_TRUE(JSONDocument(15.) != JSONDocument()); |
292 | 1 | ASSERT_TRUE(JSONDocument(15.) != JSONDocument(14.)); |
293 | 1 | ASSERT_TRUE(JSONDocument(15.) == JSONDocument(15.)); |
294 | 1 | } |
295 | | |
296 | 1 | TEST_F(JSONDocumentTest, JSONDocumentBuilderTest) { |
297 | 1 | unique_ptr<JSONDocument> parsedArray( |
298 | 1 | JSONDocument::ParseJSON("[1, [123, \"a\", \"b\"], {\"b\":\"c\"}]")); |
299 | 1 | ASSERT_TRUE(parsedArray != nullptr); |
300 | | |
301 | 1 | JSONDocumentBuilder builder; |
302 | 1 | ASSERT_TRUE(builder.WriteStartArray()); |
303 | 1 | ASSERT_TRUE(builder.WriteJSONDocument(1)); |
304 | | |
305 | 1 | ASSERT_TRUE(builder.WriteStartArray()); |
306 | 1 | ASSERT_TRUE(builder.WriteJSONDocument(123)); |
307 | 1 | ASSERT_TRUE(builder.WriteJSONDocument("a")); |
308 | 1 | ASSERT_TRUE(builder.WriteJSONDocument("b")); |
309 | 1 | ASSERT_TRUE(builder.WriteEndArray()); |
310 | | |
311 | 1 | ASSERT_TRUE(builder.WriteStartObject()); |
312 | 1 | ASSERT_TRUE(builder.WriteKeyValue("b", "c")); |
313 | 1 | ASSERT_TRUE(builder.WriteEndObject()); |
314 | | |
315 | 1 | ASSERT_TRUE(builder.WriteEndArray()); |
316 | | |
317 | 1 | ASSERT_TRUE(*parsedArray == builder.GetJSONDocument()); |
318 | 1 | } |
319 | | |
320 | 1 | TEST_F(JSONDocumentTest, OwnershipTest) { |
321 | 1 | std::unique_ptr<JSONDocument> parsed( |
322 | 1 | JSONDocument::ParseJSON(kSampleJSON.c_str())); |
323 | 1 | ASSERT_TRUE(parsed != nullptr); |
324 | 1 | ASSERT_TRUE(parsed->IsOwner()); |
325 | | |
326 | | // Copy constructor from owner -> owner |
327 | 1 | JSONDocument copy_constructor(*parsed); |
328 | 1 | ASSERT_TRUE(copy_constructor.IsOwner()); |
329 | | |
330 | | // Copy constructor from non-owner -> non-owner |
331 | 1 | JSONDocument non_owner((*parsed)["properties"]); |
332 | 1 | ASSERT_TRUE(!non_owner.IsOwner()); |
333 | | |
334 | | // Move constructor from owner -> owner |
335 | 1 | JSONDocument moved_from_owner(std::move(copy_constructor)); |
336 | 1 | ASSERT_TRUE(moved_from_owner.IsOwner()); |
337 | | |
338 | | // Move constructor from non-owner -> non-owner |
339 | 1 | JSONDocument moved_from_non_owner(std::move(non_owner)); |
340 | 1 | ASSERT_TRUE(!moved_from_non_owner.IsOwner()); |
341 | 1 | } |
342 | | |
343 | | } // namespace rocksdb |
344 | | |
345 | 13.2k | int main(int argc, char** argv) { |
346 | 13.2k | ::testing::InitGoogleTest(&argc, argv); |
347 | 13.2k | return RUN_ALL_TESTS(); |
348 | 13.2k | } |
349 | | |
350 | | #else |
351 | | #include <stdio.h> |
352 | | |
353 | | int main(int argc, char** argv) { |
354 | | fprintf(stderr, "SKIPPED as JSONDocument is not supported in ROCKSDB_LITE\n"); |
355 | | return 0; |
356 | | } |
357 | | |
358 | | #endif // !ROCKSDB_LITE |