2305 lines
77 KiB
C++
2305 lines
77 KiB
C++
#include <cstdlib>
|
|
#include <cstddef>
|
|
#include <cstring>
|
|
#include <cstdio>
|
|
#include <cstdint>
|
|
#include <cmath>
|
|
#include <memory>
|
|
#include <deque>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <utility>
|
|
#include <iostream>
|
|
#include <unordered_map>
|
|
#include <map>
|
|
#include <gtest/gtest.h>
|
|
#include "json/dom.h"
|
|
#include "json/alloc.h"
|
|
#include "json/stats.h"
|
|
#include "json/selector.h"
|
|
#include "module_sim.h"
|
|
|
|
jsn::string& getReplyString() {
|
|
static jsn::string replyString;
|
|
return replyString;
|
|
}
|
|
|
|
static void appendReplyString(const jsn::string& s) {
|
|
jsn::string& rs = getReplyString();
|
|
rs = rs + s;
|
|
}
|
|
|
|
int cs_replyWithBuffer(ValkeyModuleCtx *, const char *buffer, size_t length) {
|
|
appendReplyString(jsn::string(buffer, length));
|
|
return 0;
|
|
}
|
|
|
|
const char *GetString(ReplyBuffer *b) {
|
|
b->Reply(); // Send the string :)
|
|
return getReplyString().c_str();
|
|
}
|
|
|
|
void Clear(rapidjson::StringBuffer *b) {
|
|
b->Clear();
|
|
}
|
|
|
|
void Clear(ReplyBuffer *b) {
|
|
getReplyString().clear();
|
|
b->Clear();
|
|
}
|
|
|
|
size_t cobsize(ValkeyModuleCtx *) {
|
|
return 0;
|
|
}
|
|
|
|
extern size_t hash_function(const char *, size_t);
|
|
|
|
/* Since unit tests run outside of Valkey server, we need to map Valkey'
|
|
* memory management functions to cstdlib functions. */
|
|
void SetupAllocFuncs(size_t numShards) {
|
|
setupValkeyModulePointers();
|
|
//
|
|
// Now setup the KeyTable, the RapidJson library now depends on it
|
|
//
|
|
KeyTable::Config c;
|
|
c.malloc = dom_alloc;
|
|
c.free = dom_free;
|
|
c.hash = hash_function;
|
|
c.numShards = numShards;
|
|
keyTable = new KeyTable(c);
|
|
ValkeyModule_ReplyWithStringBuffer = cs_replyWithBuffer;
|
|
getReplyString().clear();
|
|
}
|
|
|
|
class DomTest : public ::testing::Test {
|
|
protected:
|
|
const char *json1 = "{"
|
|
"\"firstName\":\"John\","
|
|
"\"lastName\":\"Smith\","
|
|
"\"age\":27,"
|
|
"\"weight\":135.17,"
|
|
"\"isAlive\":true,"
|
|
"\"address\":{"
|
|
"\"street\":\"21 2nd Street\","
|
|
"\"city\":\"New York\","
|
|
"\"state\":\"NY\","
|
|
"\"zipcode\":\"10021-3100\""
|
|
"},"
|
|
"\"phoneNumbers\":["
|
|
"{"
|
|
"\"type\":\"home\","
|
|
"\"number\":\"212 555-1234\""
|
|
"},"
|
|
"{"
|
|
"\"type\":\"office\","
|
|
"\"number\":\"646 555-4567\""
|
|
"}"
|
|
"],"
|
|
"\"children\":[],"
|
|
"\"spouse\":null,"
|
|
"\"groups\":{}"
|
|
"}";
|
|
JDocument *doc1;
|
|
const char* json2 = "{"
|
|
"\"firstName\":\"John\","
|
|
"\"lastName\":\"Smith\","
|
|
"\"age\":27,"
|
|
"\"weight\":135.17,"
|
|
"\"isAlive\":true,"
|
|
"\"spouse\":null,"
|
|
"\"children\":[],"
|
|
"\"groups\":{}"
|
|
"}";
|
|
JDocument *doc2;
|
|
const char *json3 = "{"
|
|
"\"a\":{},"
|
|
"\"b\":{\"a\":\"a\"},"
|
|
"\"c\":{\"a\":\"a\", \"b\":1},"
|
|
"\"d\":{\"a\":\"a\", \"b\":\"b\"},"
|
|
"\"e\":{\"a\":1, \"b\":\"b\", \"c\":3}"
|
|
"}";
|
|
JDocument *doc3;
|
|
const char *json4 = "{\"a\":[], \"b\":[1], \"c\":[1,2], \"d\":[1,2,3], \"e\":[1,2,3,4,5]}";
|
|
JDocument *doc4;
|
|
const char *json5 = "{\"a\":{\"b\":{\"c\":{\"d\":{\"e\":{\"f\":{\"g\":{\"h:\":1}}}}}}}}";
|
|
JDocument *doc5;
|
|
const char *json6 = "{"
|
|
"\"a\":["
|
|
"[[1,2],[3,4],[5,6]],"
|
|
"[[7,8],[9,10],[11,12]]"
|
|
"]"
|
|
"}";
|
|
JDocument *doc6;
|
|
|
|
void SetUp() override {
|
|
JsonUtilCode rc = jsonstats_init();
|
|
ASSERT_EQ(rc, JSONUTIL_SUCCESS);
|
|
SetupAllocFuncs(16);
|
|
|
|
rc = dom_parse(nullptr, json1, strlen(json1), &doc1);
|
|
ASSERT_EQ(rc, JSONUTIL_SUCCESS);
|
|
rc = dom_parse(nullptr, json2, strlen(json2), &doc2);
|
|
ASSERT_EQ(rc, JSONUTIL_SUCCESS);
|
|
rc = dom_parse(nullptr, json3, strlen(json3), &doc3);
|
|
ASSERT_EQ(rc, JSONUTIL_SUCCESS);
|
|
rc = dom_parse(nullptr, json4, strlen(json4), &doc4);
|
|
ASSERT_EQ(rc, JSONUTIL_SUCCESS);
|
|
rc = dom_parse(nullptr, json5, strlen(json5), &doc5);
|
|
ASSERT_EQ(rc, JSONUTIL_SUCCESS);
|
|
rc = dom_parse(nullptr, json6, strlen(json6), &doc6);
|
|
ASSERT_EQ(rc, JSONUTIL_SUCCESS);
|
|
}
|
|
|
|
void TearDown() override {
|
|
dom_free_doc(doc1);
|
|
dom_free_doc(doc2);
|
|
dom_free_doc(doc3);
|
|
dom_free_doc(doc4);
|
|
dom_free_doc(doc5);
|
|
dom_free_doc(doc6);
|
|
delete keyTable;
|
|
keyTable = nullptr;
|
|
}
|
|
};
|
|
|
|
TEST_F(DomTest, testParseObject) {
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, json1, strlen(json1), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testParseArray) {
|
|
const char *input = "[1,2,3]";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize(doc, nullptr, oss);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(oss.GetString(), input);
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testParseString) {
|
|
const char *input = "\"abc\"";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize(doc, nullptr, oss);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(oss.GetString(), input);
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testParseNumber) {
|
|
const char *input = "123";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize(doc, nullptr, oss);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(oss.GetString(), input);
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testParseBool) {
|
|
const char *input = "false";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize(doc, nullptr, oss);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(oss.GetString(), input);
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testParseNull) {
|
|
const char *input = "null";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize(doc, nullptr, oss);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(oss.GetString(), input);
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testParseInvalidJSON) {
|
|
const char *input = "{\"a\"}";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_JSON_PARSE_ERROR);
|
|
EXPECT_TRUE(doc == nullptr);
|
|
}
|
|
|
|
TEST_F(DomTest, testParseDuplicates) {
|
|
const char *input = "{\"a\":1, \"b\":2, \"a\":3}";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize(doc, nullptr, oss);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
const char *result = "{\"a\":3,\"b\":2}";
|
|
EXPECT_STREQ(oss.GetString(), result);
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testSerialize_DefaultFormat) {
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize(doc1, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), json1);
|
|
}
|
|
|
|
TEST_F(DomTest, testSerialize_CustomFormatArray) {
|
|
PrintFormat format;
|
|
format.newline = "\n";
|
|
format.indent = "\t";
|
|
format.space = ".";
|
|
jsn::vector<std::pair<jsn::string, jsn::string>> tests{
|
|
{"[]", "[]"},
|
|
{"[0]", "[\n\t0\n]"},
|
|
{"[0,1]", "[\n\t0,\n\t1\n]"},
|
|
{"[[]]", "[\n\t[]\n]"},
|
|
{"[[0]]", "[\n\t[\n\t\t0\n\t]\n]"},
|
|
{"[[0,1]]", "[\n\t[\n\t\t0,\n\t\t1\n\t]\n]"},
|
|
{"{}", "{}"},
|
|
{"{\"a\":0}", "{\n\t\"a\":.0\n}"},
|
|
{"{\"a\":0,\"b\":1}", "{\n\t\"a\":.0,\n\t\"b\":.1\n}"},
|
|
{"{\"a\":{\"b\":1}}", "{\n\t\"a\":.{\n\t\t\"b\":.1\n\t}\n}"}
|
|
};
|
|
for (auto p : tests) {
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, p.first.c_str(), p.first.length(), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize(doc, &format, oss);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(oss.GetString(), p.second);
|
|
dom_free_doc(doc);
|
|
}
|
|
}
|
|
|
|
TEST_F(DomTest, testSerialize_CustomFormat) {
|
|
PrintFormat format;
|
|
format.indent = "\t";
|
|
format.newline = "\n";
|
|
format.space = " ";
|
|
const char* exp_json = "{\n\t\"firstName\": \"John\",\n\t\"lastName\": \"Smith\",\n\t\"age\": 27,"
|
|
"\n\t\"weight\": 135.17,\n\t\"isAlive\": true,\n\t\"spouse\": null,"
|
|
"\n\t\"children\": [],\n\t\"groups\": {}\n}";
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize(doc2, &format, oss);
|
|
EXPECT_STREQ(oss.GetString(), exp_json);
|
|
|
|
format.indent = "**";
|
|
format.newline = "\n";
|
|
format.space = "--";
|
|
exp_json = "{\n**\"firstName\":--\"John\",\n**\"lastName\":--\"Smith\",\n**\"age\":--27,"
|
|
"\n**\"weight\":--135.17,\n**\"isAlive\":--true,\n**\"spouse\":--null,"
|
|
"\n**\"children\":--[],\n**\"groups\":--{}\n}";
|
|
Clear(&oss);
|
|
dom_serialize(doc2, &format, oss);
|
|
EXPECT_STREQ(oss.GetString(), exp_json);
|
|
}
|
|
|
|
TEST_F(DomTest, testSetString) {
|
|
const char *new_val = "\"Boston\"";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".address.city", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc1, ".address.city", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), new_val);
|
|
}
|
|
|
|
TEST_F(DomTest, testSetNumber) {
|
|
const char *new_val = "37";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".age", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc1, ".age", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), new_val);
|
|
}
|
|
|
|
TEST_F(DomTest, testSetNull) {
|
|
const char *new_val = "null";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".address.street", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc1, ".address.street", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), new_val);
|
|
}
|
|
|
|
TEST_F(DomTest, testSet_NX_XX_ErrorConditions) {
|
|
// Test NX error condition
|
|
const char *new_val = "123";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".firstName", new_val, true, false);
|
|
EXPECT_EQ(rc, JSONUTIL_NX_XX_CONDITION_NOT_SATISFIED);
|
|
|
|
// Test XX error condition
|
|
rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, true);
|
|
EXPECT_EQ(rc, JSONUTIL_NX_XX_CONDITION_NOT_SATISFIED);
|
|
|
|
// NX and XX must be mutually exclusive
|
|
rc = dom_set_value(nullptr, doc1, ".firstName", new_val, true, true);
|
|
EXPECT_EQ(rc, JSONUTIL_NX_XX_SHOULD_BE_MUTUALLY_EXCLUSIVE);
|
|
}
|
|
|
|
TEST_F(DomTest, testGet_ErrorConditions) {
|
|
ReplyBuffer oss;
|
|
JsonUtilCode rc = dom_get_value_as_str(doc1, ".bar", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_JSON_PATH_NOT_EXIST);
|
|
EXPECT_EQ(strlen(GetString(&oss)), 0);
|
|
}
|
|
|
|
TEST_F(DomTest, testUnicode) {
|
|
const char *new_val = "\"hyvää-élève\"";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".firstName", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc1, ".firstName", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), new_val);
|
|
}
|
|
|
|
TEST_F(DomTest, testGetString) {
|
|
ReplyBuffer oss;
|
|
JsonUtilCode rc = dom_get_value_as_str(doc1, ".address.city", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "\"New York\"");
|
|
|
|
Clear(&oss);
|
|
rc = dom_get_value_as_str(doc1, ".phoneNumbers[1].number", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "\"646 555-4567\"");
|
|
}
|
|
|
|
TEST_F(DomTest, testGetNumber) {
|
|
ReplyBuffer oss;
|
|
JsonUtilCode rc = dom_get_value_as_str(doc1, ".age", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "27");
|
|
}
|
|
|
|
TEST_F(DomTest, testGetBool) {
|
|
ReplyBuffer oss;
|
|
JsonUtilCode rc = dom_get_value_as_str(doc1, ".isAlive", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "true");
|
|
}
|
|
|
|
TEST_F(DomTest, testGetNull) {
|
|
ReplyBuffer oss;
|
|
JsonUtilCode rc = dom_get_value_as_str(doc1, ".spouse", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "null");
|
|
}
|
|
|
|
TEST_F(DomTest, testGetObject) {
|
|
ReplyBuffer oss;
|
|
JsonUtilCode rc = dom_get_value_as_str(doc1, ".address", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "{\"street\":\"21 2nd Street\",\"city\":\"New York\",\"state\":\"NY\","
|
|
"\"zipcode\":\"10021-3100\"}");
|
|
}
|
|
|
|
TEST_F(DomTest, testGetArray) {
|
|
ReplyBuffer oss;
|
|
JsonUtilCode rc = dom_get_value_as_str(doc1, ".phoneNumbers", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[{\"type\":\"home\",\"number\":\"212 555-1234\"},{\"type\":\"office\","
|
|
"\"number\":\"646 555-4567\"}]");
|
|
|
|
Clear(&oss);
|
|
rc = dom_get_value_as_str(doc1, ".children", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[]");
|
|
}
|
|
|
|
TEST_F(DomTest, testGet_multiPaths) {
|
|
const char *paths[] = { ".firstName", ".lastName" };
|
|
ReplyBuffer oss;
|
|
JsonUtilCode rc = dom_get_values_as_str(doc1, paths, 2, nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "{\".firstName\":\"John\",\".lastName\":\"Smith\"}");
|
|
|
|
// Test pretty print
|
|
PrintFormat format;
|
|
format.indent = "\t";
|
|
format.newline = "\n";
|
|
format.space = " ";
|
|
const char* exp_json = "{\n\t\".firstName\": \"John\",\n\t\".lastName\": \"Smith\"\n}";
|
|
Clear(&oss);
|
|
rc = dom_get_values_as_str(doc1, paths, 2, &format, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), exp_json);
|
|
}
|
|
|
|
TEST_F(DomTest, testDelete) {
|
|
size_t num_vals_deleted;
|
|
JsonUtilCode rc = dom_delete_value(doc1, ".spouse", num_vals_deleted);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(num_vals_deleted, 1);
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc1, ".spouse", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_JSON_PATH_NOT_EXIST);
|
|
EXPECT_EQ(oss.GetLength(), 0);
|
|
|
|
rc = dom_delete_value(doc1, ".phoneNumbers", num_vals_deleted);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(num_vals_deleted, 1);
|
|
Clear(&oss);
|
|
rc = dom_get_value_as_str(doc1, ".phoneNumbers", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_JSON_PATH_NOT_EXIST);
|
|
EXPECT_EQ(oss.GetLength(), 0);
|
|
}
|
|
|
|
TEST_F(DomTest, testDelete_v2path) {
|
|
const char *input = "{\"x\": {}, \"y\": {\"a\":\"a\"}, \"z\": {\"a\":\"\", \"b\":\"b\"}}";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
size_t num_vals_deleted;
|
|
rc = dom_delete_value(doc, "$.z.*", num_vals_deleted);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(num_vals_deleted, 2);
|
|
const char *exp = "{\"x\":{},\"y\":{\"a\":\"a\"},\"z\":{}}";
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc, ".", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), exp);
|
|
|
|
rc = dom_delete_value(doc, "$.*", num_vals_deleted);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(num_vals_deleted, 3);
|
|
exp = "{}";
|
|
Clear(&oss);
|
|
rc = dom_get_value_as_str(doc, ".", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), exp);
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testDelete_v2path_array) {
|
|
const char *input = "[0,1,2,3,4,5,6,7,8,9]";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
size_t num_vals_deleted;
|
|
rc = dom_delete_value(doc, "$[6:10]", num_vals_deleted);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(num_vals_deleted, 4);
|
|
const char *exp = "[0,1,2,3,4,5]";
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc, ".", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), exp);
|
|
|
|
rc = dom_delete_value(doc, "$[*]", num_vals_deleted);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(num_vals_deleted, 6);
|
|
exp = "[]";
|
|
Clear(&oss);
|
|
rc = dom_get_value_as_str(doc, ".", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), exp);
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumIncrBy_int) {
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
JsonUtilCode rc = dom_increment_by(doc1, ".age", &parser.Parse("1", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 28);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
rc = dom_increment_by(doc1, ".age", &parser.Parse("-5", 2).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 23);
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumIncrBy_float1) {
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
JsonUtilCode rc = dom_increment_by(doc1, ".age", &parser.Parse("0.5", 3).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 27.5);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
rc = dom_increment_by(doc1, ".age", &parser.Parse("0.5", 3).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 28);
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumIncrBy_float2) {
|
|
const char *new_val = "1";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("0.5", 3).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 1.5);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("0.5", 3).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 2);
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumIncrBy_int64_overflow) {
|
|
const char *new_val = "9223372036854775807";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
// should not overflow
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("0", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
// The result exceeds max_int64, and is converted to a double number.
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("1", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 9223372036854775808.0);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("12", 2).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 9223372036854775820.0);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("12", 2).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 9223372036854775832.0);
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumIncrBy_int64_overflow_negative) {
|
|
const char *new_val = "-9223372036854775808";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
// should not overflow
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("0", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], INT64_MIN);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
// The result exceeds min_int64, but is converted to a double number.
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("-1", 2).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], -9223372036854775809.0);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("-11", 3).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], -9223372036854775820.0);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("-11", 3).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], -9223372036854775831.0);
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumIncrBy_double_overflow) {
|
|
const char *new_val = "1.7e308";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
// should not overflow
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("0", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 1);
|
|
EXPECT_EQ(res[0], 1.7e308);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("1.0", 3).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 1);
|
|
EXPECT_EQ(res[0], 1.7e308);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
// should overflow
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("1.7e308", 7).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_ADDITION_OVERFLOW);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("0.85e308", 8).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_ADDITION_OVERFLOW);
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumIncrBy_double_overflow_negative) {
|
|
const char *new_val = "-1.7e308";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
// should not overflow
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("0", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], -1.7e308);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("-1.0", 4).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], -1.7e308);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
// should overflow
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("-1.7e308", 8).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_ADDITION_OVERFLOW);
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumIncrBy_string_value) {
|
|
Selector selector;
|
|
const char *new_val = "-1.5e308";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
rc = selector.getValues(*doc1, ".foo");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getResultSet().size(), 1);
|
|
EXPECT_STREQ(selector.getResultSet()[0].first->GetDoubleString(), "-1.5e308");
|
|
|
|
// should not overflow
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("0", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], -1.5e308);
|
|
|
|
rc = selector.getValues(*doc1, ".foo");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getResultSet().size(), 1);
|
|
// +0 is not a true no-op, because it will re-calculate and reformat a double
|
|
EXPECT_STREQ(selector.getResultSet()[0].first->GetDoubleString(), "-1.5e+308");
|
|
}
|
|
|
|
TEST_F(DomTest, testNumIncrMultBy_string_value_overflow) {
|
|
Selector selector;
|
|
const char *new_val = "-1.7e308";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
rc = selector.getValues(*doc1, ".foo");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getResultSet().size(), 1);
|
|
EXPECT_STREQ(selector.getResultSet()[0].first->GetDoubleString(), "-1.7e308");
|
|
|
|
// should not overflow
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_increment_by(doc1, ".foo", &parser.Parse("-1", 2).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], -1.7e308);
|
|
|
|
rc = selector.getValues(*doc1, ".foo");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getResultSet().size(), 1);
|
|
EXPECT_STREQ(selector.getResultSet()[0].first->GetDoubleString(), "-1.6999999999999999e+308");
|
|
//
|
|
// should not overflow
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("0.5", 3).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], -8.5e307);
|
|
|
|
rc = selector.getValues(*doc1, ".foo");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getResultSet().size(), 1);
|
|
EXPECT_STREQ(selector.getResultSet()[0].first->GetDoubleString(), "-8.4999999999999997e+307");
|
|
|
|
// should overflow
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("1.0e300", 7).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_MULTIPLICATION_OVERFLOW);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("1.7e308", 7).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_MULTIPLICATION_OVERFLOW);
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testToggle) {
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foobool", "true", false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<int> vec;
|
|
bool is_v2_path;
|
|
rc = dom_toggle(doc1, ".foobool", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 0);
|
|
|
|
rc = dom_toggle(doc1, ".foobool", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 1);
|
|
|
|
// test a non-array
|
|
rc = dom_set_value(nullptr, doc1, ".foostr", "\"ok\"", false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
rc = dom_toggle(doc1, ".foostr", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_JSON_ELEMENT_NOT_BOOL);
|
|
}
|
|
|
|
TEST_F(DomTest, testToggle_v2path) {
|
|
const char *input1 = "[true, false, 1, null, \"foo\", [], {}]";
|
|
JDocument *d1;
|
|
JsonUtilCode rc = dom_parse(nullptr, input1, strlen(input1), &d1);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<int> vec;
|
|
bool is_v2_path;
|
|
rc = dom_toggle(d1, "$[*]", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 7);
|
|
EXPECT_EQ(vec[0], 0);
|
|
EXPECT_EQ(vec[1], 1);
|
|
EXPECT_EQ(vec[2], -1);
|
|
EXPECT_EQ(vec[3], -1);
|
|
EXPECT_EQ(vec[4], -1);
|
|
EXPECT_EQ(vec[5], -1);
|
|
EXPECT_EQ(vec[6], -1);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(d1, ".", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[false,true,1,null,\"foo\",[],{}]");
|
|
|
|
dom_free_doc(d1);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumMutiBy_int64) {
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
JsonUtilCode rc = dom_multiply_by(doc1, ".age", &parser.Parse("10", 2).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 1);
|
|
EXPECT_EQ(res[0], 270);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
rc = dom_multiply_by(doc1, ".age", &parser.Parse("10", 2).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 1);
|
|
EXPECT_EQ(res[0], 2700);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
rc = dom_multiply_by(doc1, ".age", &parser.Parse("0.01", 4).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 1);
|
|
EXPECT_EQ(res[0], 27);
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumMutiBy_double) {
|
|
const char *new_val = "1";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("0.5", 3).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 0.5);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("0.5", 3).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 0.25);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("4", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], 1);
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumMutiBy_int64_overflow) {
|
|
const char *new_val = "9223372036854775800";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
// should not overflow
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("1", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res[0], INT64_MAX);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("2", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("INT64_MAX", 9).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
// should overflow
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("1.0e300", 7).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_MULTIPLICATION_OVERFLOW);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("1.7e308", 7).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_MULTIPLICATION_OVERFLOW);
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumMutiBy_int64_overflow_negative) {
|
|
const char *new_val = "-9223372036854775808";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
// should not overflow
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("1", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 1);
|
|
EXPECT_EQ(res[0], INT64_MIN);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("2", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 1);
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("INT64_MAX", 9).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 1);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
// should overflow
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("-0.85e308", 9).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_MULTIPLICATION_OVERFLOW);
|
|
EXPECT_TRUE(res.empty());
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("-1.7e308", 8).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_MULTIPLICATION_OVERFLOW);
|
|
EXPECT_TRUE(res.empty());
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumMutiBy_double_overflow) {
|
|
const char *new_val = "1.7e308";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
// should not overflow
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("1.0", 3).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 1);
|
|
EXPECT_EQ(res[0], 1.7e308);
|
|
EXPECT_FALSE(isV2Path);
|
|
|
|
// should overflow
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("0.85e308", 8).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_MULTIPLICATION_OVERFLOW);
|
|
EXPECT_TRUE(res.empty());
|
|
EXPECT_FALSE(isV2Path);
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("1.7e308", 7).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_MULTIPLICATION_OVERFLOW);
|
|
EXPECT_TRUE(res.empty());
|
|
EXPECT_FALSE(isV2Path);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumMutiBy_double_overflow_negative) {
|
|
const char *new_val = "1.7e308";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".foo", new_val, false, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
// should not overflow
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("-1.0", 4).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 1);
|
|
EXPECT_EQ(res[0], -1.7e308);
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("-1.01", 5).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
// should overflow
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("-0.85e308", 9).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_MULTIPLICATION_OVERFLOW);
|
|
EXPECT_TRUE(res.empty());
|
|
rc = dom_multiply_by(doc1, ".foo", &parser.Parse("-1.7e308", 8).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_MULTIPLICATION_OVERFLOW);
|
|
EXPECT_TRUE(res.empty());
|
|
}
|
|
|
|
TEST_F(DomTest, testStrLen) {
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_string_length(doc1, ".address.state", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 2);
|
|
|
|
rc = dom_string_length(doc1, ".firstName", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 4);
|
|
}
|
|
|
|
TEST_F(DomTest, testStrLen_v2path) {
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_string_length(doc1, "$.address.state", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 2);
|
|
|
|
rc = dom_string_length(doc1, "$.firstName", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 4);
|
|
}
|
|
|
|
TEST_F(DomTest, testStrLen_v2path_wildcard) {
|
|
const char *input = "{\"x\": {\"a\":\"\", \"b\":\"b\", \"c\":\"cc\", \"d\":\"ddd\"}}";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
rc = dom_string_length(doc, "$.x.*", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 4);
|
|
for (size_t i=0; i < vec.size(); i++) {
|
|
EXPECT_EQ(vec[i], i);
|
|
}
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testStrAppend) {
|
|
const char *s = "\"son\"";
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_string_append(doc1, ".firstName", s, strlen(s), vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 7);
|
|
|
|
s = "\" Senior\"";
|
|
rc = dom_string_append(doc1, ".firstName", s, strlen(s), vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 14);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc1, ".firstName", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "\"Johnson Senior\"");
|
|
}
|
|
|
|
TEST_F(DomTest, testStrAppend_v2path) {
|
|
const char *s = "\"son\"";
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_string_append(doc1, "$.firstName", s, strlen(s), vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 7);
|
|
|
|
s = "\" Senior\"";
|
|
rc = dom_string_append(doc1, "$.firstName", s, strlen(s), vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 14);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc1, ".firstName", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "\"Johnson Senior\"");
|
|
}
|
|
|
|
TEST_F(DomTest, testStrAppend_v2path_wildcard) {
|
|
const char *input = "{\"x\": {\"a\":\"\", \"b\":\"b\", \"c\":\"cc\", \"d\":\"ddd\"}}";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
const char *s = "\"z\"";
|
|
rc = dom_string_append(doc, "$.x.*", s, strlen(s), vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 4);
|
|
for (size_t i=0; i < vec.size(); i++) {
|
|
EXPECT_EQ(vec[i], i+1);
|
|
}
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testObjLen) {
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_object_length(doc1, ".address", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 4);
|
|
}
|
|
|
|
TEST_F(DomTest, testObjLen_v2path_wildcard) {
|
|
const char *input = "{\"x\": {}, \"y\": {\"a\":\"a\"}, \"z\": {\"a\":\"\", \"b\":\"b\"}}";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
rc = dom_object_length(doc, "$.*", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 3);
|
|
for (size_t i=0; i < vec.size(); i++) {
|
|
EXPECT_EQ(vec[i], i);
|
|
}
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testObjKeys) {
|
|
jsn::vector<jsn::vector<jsn::string>> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_object_keys(doc1, ".address", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0].size(), 4);
|
|
EXPECT_STREQ(vec[0][0].c_str(), "street");
|
|
EXPECT_STREQ(vec[0][1].c_str(), "city");
|
|
EXPECT_STREQ(vec[0][2].c_str(), "state");
|
|
EXPECT_STREQ(vec[0][3].c_str(), "zipcode");
|
|
}
|
|
|
|
TEST_F(DomTest, testObjKeys_v2path_wildcard) {
|
|
const char *input = "{\"x\": {}, \"y\": {\"a\":\"a\"}, \"z\": {\"a\":\"\", \"b\":\"b\"}}";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<jsn::vector<jsn::string>> vec;
|
|
bool is_v2_path;
|
|
rc = dom_object_keys(doc, "$.*", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 3);
|
|
EXPECT_TRUE(vec[0].empty());
|
|
EXPECT_EQ(vec[1].size(), 1);
|
|
EXPECT_EQ(vec[2].size(), 2);
|
|
EXPECT_STREQ(vec[1][0].c_str(), "a");
|
|
EXPECT_STREQ(vec[2][0].c_str(), "a");
|
|
EXPECT_STREQ(vec[2][1].c_str(), "b");
|
|
|
|
rc = dom_object_keys(doc, ".x", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_TRUE(vec[0].empty());
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testArrLen) {
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_array_length(doc1, ".children", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 0);
|
|
|
|
rc = dom_array_length(doc1, ".phoneNumbers", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 2);
|
|
}
|
|
|
|
TEST_F(DomTest, testArrLen_v2path) {
|
|
const char *input = "[ [\"Marry\", \"Bob\", \"Tom\"], [\"Peter\", \"Marry\", \"Carol\"],"
|
|
"[\"Peter\", \"Jane\"], [] ]";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
rc = dom_array_length(doc, "$[*]", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 4);
|
|
EXPECT_EQ(vec[0], 3);
|
|
EXPECT_EQ(vec[1], 3);
|
|
EXPECT_EQ(vec[2], 2);
|
|
EXPECT_EQ(vec[3], 0);
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testArrAppend) {
|
|
const char *jsons[] = { "\"John\"" };
|
|
size_t json_lens[] = { 6 };
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
|
|
JsonUtilCode rc = dom_array_append(nullptr, doc1, ".children", jsons, json_lens, 1, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 1);
|
|
|
|
jsons[0] = "\"Mary\"";
|
|
json_lens[0] = 6;
|
|
rc = dom_array_append(nullptr, doc1, ".children", jsons, json_lens, 1, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 2);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc1, ".children", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[\"John\",\"Mary\"]");
|
|
}
|
|
|
|
TEST_F(DomTest, testArrAppend_multiValues) {
|
|
const char *jsons[] = { "\"John\"", "\"Mary\"", "\"Tom\"" };
|
|
size_t json_lens[] = { 6, 6, 5 };
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_array_append(nullptr, doc1, ".children", jsons, json_lens, 3, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 3);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc1, ".children", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[\"John\",\"Mary\",\"Tom\"]");
|
|
}
|
|
|
|
TEST_F(DomTest, testArrAppend_v2path) {
|
|
const char *input = "[ [\"Marry\", \"Bob\"], [\"Peter\"], [] ]";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
const char *jsons[] = { "\"John\"", "\"Tom\"" };
|
|
size_t json_lens[] = { 6, 5 };
|
|
rc = dom_array_append(nullptr, doc, "$[*]", jsons, json_lens, 2, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 3);
|
|
EXPECT_EQ(vec[0], 4);
|
|
EXPECT_EQ(vec[1], 3);
|
|
EXPECT_EQ(vec[2], 2);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc, "$[*]", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[[\"Marry\",\"Bob\",\"John\",\"Tom\"],[\"Peter\",\"John\",\"Tom\"],"
|
|
"[\"John\",\"Tom\"]]");
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testArrPop) {
|
|
const char *jsons[] = { "\"John\"", "\"Mary\"", "\"Tom\"" };
|
|
size_t json_lens[] = { 6, 6, 5 };
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_array_append(nullptr, doc1, ".children", jsons, json_lens, 3, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 3);
|
|
|
|
jsn::vector<rapidjson::StringBuffer> vec_oss;
|
|
rc = dom_array_pop(doc1, ".children", 1, vec_oss, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec_oss.size(), 1);
|
|
EXPECT_STREQ(vec_oss[0].GetString(), "\"Mary\"");
|
|
EXPECT_EQ(vec_oss[0].GetLength(), 6);
|
|
|
|
rc = dom_array_pop(doc1, ".children", -1, vec_oss, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec_oss.size(), 1);
|
|
EXPECT_STREQ(vec_oss[0].GetString(), "\"Tom\"");
|
|
EXPECT_EQ(vec_oss[0].GetLength(), 5);
|
|
|
|
rc = dom_array_pop(doc1, ".children", 0, vec_oss, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec_oss.size(), 1);
|
|
EXPECT_STREQ(vec_oss[0].GetString(), "\"John\"");
|
|
EXPECT_EQ(vec_oss[0].GetLength(), 6);
|
|
}
|
|
|
|
TEST_F(DomTest, testArrPop_v2path) {
|
|
const char *input = "[ [\"Marry\", \"Bob\", \"Tom\"], [\"Peter\", \"Carol\"], [\"Jane\"], [] ]";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<rapidjson::StringBuffer> vec;
|
|
bool is_v2_path;
|
|
rc = dom_array_pop(doc, "$[*]", 0, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 4);
|
|
EXPECT_STREQ(vec[0].GetString(), "\"Marry\"");
|
|
EXPECT_STREQ(vec[1].GetString(), "\"Peter\"");
|
|
EXPECT_STREQ(vec[2].GetString(), "\"Jane\"");
|
|
EXPECT_EQ(vec[3].GetLength(), 0);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc, "$[*]", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[[\"Bob\",\"Tom\"],[\"Carol\"],[],[]]");
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testArrInsert) {
|
|
const char *vals[1] = {"\"john\""};
|
|
size_t val_lens[1] = { 6 };
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_array_insert(nullptr, doc1, ".children", 0, vals, val_lens, 1, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 1u);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc1, ".children", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[\"john\"]");
|
|
}
|
|
|
|
TEST_F(DomTest, testArrInsert_v2path) {
|
|
const char *input = "[ [\"Marry\", \"Bob\"], [\"Peter\"], [] ]";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
const char *jsons[] = { "\"John\"", "\"Tom\"" };
|
|
size_t json_lens[] = { 6, 5 };
|
|
rc = dom_array_insert(nullptr, doc, "$[*]", 0, jsons, json_lens, 2, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 3);
|
|
EXPECT_EQ(vec[0], 4);
|
|
EXPECT_EQ(vec[1], 3);
|
|
EXPECT_EQ(vec[2], 2);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc, "$[*]", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[[\"John\",\"Tom\",\"Marry\",\"Bob\"],"
|
|
"[\"John\",\"Tom\",\"Peter\"],[\"John\",\"Tom\"]]");
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testClear) {
|
|
const char *jsons[] = { "\"John\"", "\"Mary\"", "\"Tom\"" };
|
|
size_t json_lens[] = { 6, 6, 5 };
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_array_append(nullptr, doc1, ".children", jsons, json_lens, 3, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 3);
|
|
|
|
// return value should be the number of elements deleted, same as above
|
|
size_t containers_cleared;
|
|
rc = dom_clear(doc1, ".children", containers_cleared);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(containers_cleared, 1);
|
|
|
|
// zero elements should remain
|
|
rc = dom_array_length(doc1, ".children", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 0);
|
|
|
|
// clear empty array
|
|
rc = dom_clear(doc1, ".children", containers_cleared);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(containers_cleared, 0);
|
|
|
|
rc = dom_array_length(doc1, ".children", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 0);
|
|
|
|
// clear an object
|
|
rc = dom_object_length(doc1, ".address", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 4);
|
|
|
|
rc = dom_clear(doc1, ".address", containers_cleared);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(containers_cleared, 1);
|
|
|
|
vec.clear();
|
|
rc = dom_object_length(doc1, ".address", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 0);
|
|
}
|
|
|
|
TEST_F(DomTest, testClear_v2path) {
|
|
const char *input1 = "{\"a\":{}, \"b\":{\"a\": 1, \"b\": null, \"c\": true}, "
|
|
"\"c\":1, \"d\":true, \"e\":null, \"f\":\"d\", \"g\": 4, \"h\": 4.5}";
|
|
JDocument *d1;
|
|
JsonUtilCode rc = dom_parse(nullptr, input1, strlen(input1), &d1);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
size_t elements_cleared;
|
|
rc = dom_clear(d1, "$.*", elements_cleared);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(elements_cleared, 6); // everything except the null gets cleared
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(d1, ".", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "{\"a\":{},\"b\":{},\"c\":0,\"d\":false,\"e\":null,\"f\":\"\",\"g\":0,\"h\":0.0}");
|
|
|
|
const char *input2 = "[[], [0], [0,1], [0,1,2], 1, true, null, \"d\"]";
|
|
JDocument *d2;
|
|
rc = dom_parse(nullptr, input2, strlen(input2), &d2);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
rc = dom_clear(d2, "$[*]", elements_cleared);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(elements_cleared, 6);
|
|
|
|
Clear(&oss);
|
|
rc = dom_get_value_as_str(d2, ".", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[[],[],[],[],0,false,null,\"\"]");
|
|
|
|
dom_free_doc(d1);
|
|
dom_free_doc(d2);
|
|
}
|
|
|
|
TEST_F(DomTest, testArrTrim) {
|
|
const char *jsons[] = { "\"John\"", "\"Mary\"", "\"Tom\"" };
|
|
size_t json_lens[] = { 6, 6, 5 };
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_array_append(nullptr, doc1, ".children", jsons, json_lens, 3, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 3);
|
|
|
|
rc = dom_array_trim(doc1, ".children", 1, 2, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 2);
|
|
|
|
rc = dom_array_trim(doc1, ".children", 0, 0, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 1);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc1, ".children", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[\"Mary\"]");
|
|
|
|
rc = dom_array_trim(doc1, ".children", -1, 5, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 1);
|
|
|
|
Clear(&oss);
|
|
rc = dom_get_value_as_str(doc1, ".children", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[\"Mary\"]");
|
|
|
|
rc = dom_array_trim(doc1, ".phoneNumbers", 2, 0, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 0);
|
|
|
|
rc = dom_array_length(doc1, ".phoneNumbers", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 0);
|
|
}
|
|
|
|
TEST_F(DomTest, testArrTrim_v2path) {
|
|
const char *input = "[ [\"Marry\", \"Bob\", \"Tom\"], [\"Peter\", \"Carol\"], [\"Jane\"], [] ]";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
rc = dom_array_trim(doc, "$[*]", 0, 1, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 4);
|
|
EXPECT_EQ(vec[0], 2);
|
|
EXPECT_EQ(vec[1], 2);
|
|
EXPECT_EQ(vec[2], 1);
|
|
EXPECT_EQ(vec[3], 0);
|
|
|
|
ReplyBuffer oss;
|
|
rc = dom_get_value_as_str(doc, "$[*]", nullptr, oss, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss), "[[\"Marry\",\"Bob\"],[\"Peter\",\"Carol\"],[\"Jane\"],[]]");
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testArrIndex) {
|
|
const char *jsons[] = { "\"John\"", "\"Marry\"", "\"Tom\"" };
|
|
size_t json_lens[] = { 6, 7, 5 };
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_array_append(nullptr, doc1, ".children", jsons, json_lens, 3, vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec[0], 3);
|
|
|
|
jsn::vector<int64_t> indexes;
|
|
rc = dom_array_index_of(doc1, ".children", "\"Marry\"", 7, 0, 2, indexes, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(indexes.size(), 1);
|
|
EXPECT_EQ(indexes[0], 1);
|
|
|
|
rc = dom_array_index_of(doc1, ".children", "\"Tom\"", 5, 0, -1, indexes, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(indexes.size(), 1);
|
|
EXPECT_EQ(indexes[0], 2);
|
|
}
|
|
|
|
TEST_F(DomTest, testArrIndex_v2path) {
|
|
const char *input = "[ [\"Marry\", \"Bob\", \"Tom\"], [\"Peter\", \"Marry\", \"Carol\"], "
|
|
"[\"Peter\", \"Jane\"], [] ]";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<int64_t> indexes;
|
|
bool is_v2_path;
|
|
rc = dom_array_index_of(doc, "$[*]", "\"Marry\"", 7, 0, 2, indexes, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(indexes.size(), 4);
|
|
EXPECT_EQ(indexes[0], 0);
|
|
EXPECT_EQ(indexes[1], 1);
|
|
EXPECT_EQ(indexes[2], -1);
|
|
EXPECT_EQ(indexes[3], -1);
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testValueType) {
|
|
jsn::vector<jsn::string> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_value_type(doc1, ".firstName", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_STREQ(vec[0].c_str(), "string");
|
|
|
|
rc = dom_value_type(doc1, ".age", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_STREQ(vec[0].c_str(), "integer");
|
|
|
|
rc = dom_value_type(doc1, ".weight", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_STREQ(vec[0].c_str(), "number");
|
|
|
|
rc = dom_value_type(doc1, ".isAlive", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_STREQ(vec[0].c_str(), "boolean");
|
|
|
|
rc = dom_value_type(doc1, ".spouse", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_STREQ(vec[0].c_str(), "null");
|
|
|
|
rc = dom_value_type(doc1, ".children", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_STREQ(vec[0].c_str(), "array");
|
|
|
|
rc = dom_value_type(doc1, ".phoneNumbers", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_STREQ(vec[0].c_str(), "array");
|
|
|
|
rc = dom_value_type(doc1, ".", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_STREQ(vec[0].c_str(), "object");
|
|
|
|
rc = dom_value_type(doc1, ".groups", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_STREQ(vec[0].c_str(), "object");
|
|
}
|
|
|
|
TEST_F(DomTest, testType_v2path) {
|
|
const char *input = "[1, 2.3, \"foo\", true, null, {}, []]";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<jsn::string> vec;
|
|
bool is_v2_path;
|
|
rc = dom_value_type(doc, "$[*]", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 7);
|
|
EXPECT_STREQ(vec[0].c_str(), "integer");
|
|
EXPECT_STREQ(vec[1].c_str(), "number");
|
|
EXPECT_STREQ(vec[2].c_str(), "string");
|
|
EXPECT_STREQ(vec[3].c_str(), "boolean");
|
|
EXPECT_STREQ(vec[4].c_str(), "null");
|
|
EXPECT_STREQ(vec[5].c_str(), "object");
|
|
EXPECT_STREQ(vec[6].c_str(), "array");
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumFields) {
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
JsonUtilCode rc = dom_num_fields(doc1, ".", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 20);
|
|
|
|
rc = dom_num_fields(doc1, ".firstName", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 1);
|
|
|
|
rc = dom_num_fields(doc1, ".age", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 1);
|
|
|
|
rc = dom_num_fields(doc1, ".isAlive", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 1);
|
|
|
|
rc = dom_num_fields(doc1, ".spouse", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 1);
|
|
|
|
rc = dom_num_fields(doc1, ".groups", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 0);
|
|
|
|
rc = dom_num_fields(doc1, ".children", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 0);
|
|
|
|
rc = dom_num_fields(doc1, ".address", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 4);
|
|
|
|
rc = dom_num_fields(doc1, ".phoneNumbers", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_FALSE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 1);
|
|
EXPECT_EQ(vec[0], 6);
|
|
}
|
|
|
|
TEST_F(DomTest, testNumFields_v2path) {
|
|
const char *input = "[1, 2.3, \"foo\", true, null, {}, [], {\"a\":1, \"b\":2}, [1,2,3]]";
|
|
JDocument *doc;
|
|
JsonUtilCode rc = dom_parse(nullptr, input, strlen(input), &doc);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<size_t> vec;
|
|
bool is_v2_path;
|
|
rc = dom_num_fields(doc, "$[*]", vec, is_v2_path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_TRUE(is_v2_path);
|
|
EXPECT_EQ(vec.size(), 9);
|
|
EXPECT_EQ(vec[0], 1);
|
|
EXPECT_EQ(vec[1], 1);
|
|
EXPECT_EQ(vec[2], 1);
|
|
EXPECT_EQ(vec[3], 1);
|
|
EXPECT_EQ(vec[4], 1);
|
|
EXPECT_EQ(vec[5], 0);
|
|
EXPECT_EQ(vec[6], 0);
|
|
EXPECT_EQ(vec[7], 2);
|
|
EXPECT_EQ(vec[8], 3);
|
|
|
|
dom_free_doc(doc);
|
|
}
|
|
|
|
TEST_F(DomTest, testSelector_get_legacyPath_wildcard) {
|
|
const char *path = ".address.*";
|
|
Selector selector;
|
|
JsonUtilCode rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 4);
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize_value(*rs[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"21 2nd Street\"");
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs[1].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"New York\"");
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs[2].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"NY\"");
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs[3].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"10021-3100\"");
|
|
|
|
path = ".address.city.*";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_INVALID_JSON_PATH);
|
|
EXPECT_TRUE(selector.getResultSet().empty());
|
|
}
|
|
|
|
TEST_F(DomTest, testSelector_get_v2path_wildcard) {
|
|
const char *path = "$.address.*";
|
|
Selector selector;
|
|
JsonUtilCode rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
rapidjson::StringBuffer oss;
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 4);
|
|
dom_serialize_value(*rs[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"21 2nd Street\"");
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs[1].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"New York\"");
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs[2].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"NY\"");
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs[3].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"10021-3100\"");
|
|
|
|
path = "$.address.city.*";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_INVALID_USE_OF_WILDCARD);
|
|
EXPECT_TRUE(selector.getResultSet().empty());
|
|
|
|
path = "$.address.city";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs2 = selector.getResultSet();
|
|
EXPECT_EQ(rs2.size(), 1);
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs2[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"New York\"");
|
|
}
|
|
|
|
TEST_F(DomTest, testSelector_get_array_legacyPath) {
|
|
const char *path = ".phoneNumbers[0]";
|
|
Selector selector;
|
|
JsonUtilCode rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 1);
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize_value(*rs[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "{\"type\":\"home\",\"number\":\"212 555-1234\"}");
|
|
|
|
path = ".phoneNumbers[0].type";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs2 = selector.getResultSet();
|
|
EXPECT_EQ(rs2.size(), 1);
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs2[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"home\"");
|
|
|
|
path = ".phoneNumbers[2]";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_INDEX_OUT_OF_ARRAY_BOUNDARIES);
|
|
EXPECT_TRUE(selector.getResultSet().empty());
|
|
|
|
path = ".phoneNumbers[2].number";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_INDEX_OUT_OF_ARRAY_BOUNDARIES);
|
|
EXPECT_TRUE(selector.getResultSet().empty());
|
|
|
|
path = ".phoneNumbers[x]";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_ARRAY_INDEX_NOT_NUMBER);
|
|
EXPECT_TRUE(selector.getResultSet().empty());
|
|
|
|
path = ".phoneNumbers[x].number";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_ARRAY_INDEX_NOT_NUMBER);
|
|
EXPECT_TRUE(selector.getResultSet().empty());
|
|
}
|
|
|
|
TEST_F(DomTest, testSelector_get_array_negativeIndex_legacy_and_v2ath) {
|
|
const char *path = ".phoneNumbers[-1]";
|
|
Selector selector;
|
|
JsonUtilCode rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 1);
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize_value(*rs[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "{\"type\":\"office\",\"number\":\"646 555-4567\"}");
|
|
|
|
path = "$['phoneNumbers'][-2]['number']";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs2 = selector.getResultSet();
|
|
EXPECT_EQ(rs2.size(), 1);
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs2[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"212 555-1234\"");
|
|
|
|
path = "$['phoneNumbers'][-3]['number']";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_INDEX_OUT_OF_ARRAY_BOUNDARIES);
|
|
EXPECT_TRUE(selector.getResultSet().empty());
|
|
}
|
|
|
|
TEST_F(DomTest, testSelector_get_array_legacyPath_wildcard) {
|
|
const char *path = ".phoneNumbers[*]";
|
|
Selector selector;
|
|
JsonUtilCode rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 2);
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize_value(*rs[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "{\"type\":\"home\",\"number\":\"212 555-1234\"}");
|
|
|
|
path = ".phoneNumbers[*].number";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs2 = selector.getResultSet();
|
|
EXPECT_EQ(rs2.size(), 2);
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs2[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"212 555-1234\"");
|
|
}
|
|
|
|
TEST_F(DomTest, testSelector_get_array_v2path_wildcard) {
|
|
const char *path = "$.phoneNumbers[*]";
|
|
Selector selector;
|
|
JsonUtilCode rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 2);
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize_value(*rs[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "{\"type\":\"home\",\"number\":\"212 555-1234\"}");
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs[1].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "{\"type\":\"office\",\"number\":\"646 555-4567\"}");
|
|
|
|
path = "$.phoneNumbers[*].number";
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs2 = selector.getResultSet();
|
|
EXPECT_EQ(rs2.size(), 2);
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs2[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"212 555-1234\"");
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs2[1].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), "\"646 555-4567\"");
|
|
}
|
|
|
|
// Test array slice
|
|
TEST_F(DomTest, testSelector_get_array_slice_v2path_wildcard) {
|
|
const char *path = "$.e[1:4]";
|
|
Selector selector;
|
|
JsonUtilCode rc = selector.getValues(*doc4, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 3);
|
|
EXPECT_EQ(rs[0].first->GetInt(), 2);
|
|
|
|
path = "$.e[2:]";
|
|
rc = selector.getValues(*doc4, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs2 = selector.getResultSet();
|
|
EXPECT_EQ(rs2.size(), 3);
|
|
EXPECT_EQ(rs2[2].first->GetInt(), 5);
|
|
|
|
path = "$.e[:4]";
|
|
rc = selector.getValues(*doc4, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs3 = selector.getResultSet();
|
|
EXPECT_EQ(rs3.size(), 4);
|
|
EXPECT_EQ(rs3[3].first->GetInt(), 4);
|
|
|
|
path = "$.e[0:5:2]";
|
|
rc = selector.getValues(*doc4, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs4 = selector.getResultSet();
|
|
EXPECT_EQ(rs4.size(), 3);
|
|
EXPECT_EQ(rs4[1].first->GetInt(), 3);
|
|
|
|
path = "$.e[:5:2]";
|
|
rc = selector.getValues(*doc4, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs5 = selector.getResultSet();
|
|
EXPECT_EQ(rs5.size(), 3);
|
|
EXPECT_EQ(rs5[1].first->GetInt(), 3);
|
|
|
|
path = "$.e[4:0:-2]";
|
|
rc = selector.getValues(*doc4, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs6 = selector.getResultSet();
|
|
EXPECT_EQ(rs6.size(), 2);
|
|
EXPECT_EQ(rs6[0].first->GetInt(), 5);
|
|
}
|
|
|
|
// Test array union
|
|
TEST_F(DomTest, testSelector_get_array_union_v2path) {
|
|
const char *path = "$.e[0,2]";
|
|
Selector selector;
|
|
JsonUtilCode rc = selector.getValues(*doc4, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 2);
|
|
EXPECT_EQ(rs[0].first->GetInt(), 1);
|
|
EXPECT_EQ(rs[1].first->GetInt(), 3);
|
|
}
|
|
|
|
TEST_F(DomTest, testSelector_set_v2path_part1) {
|
|
const char *path = ".address.*";
|
|
const char *new_val = "\"foo\"";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, path, new_val);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
Selector selector;
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 4);
|
|
for (auto &vInfo : rs) {
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize_value(*vInfo.first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), new_val);
|
|
}
|
|
|
|
path = ".address.city.foo";
|
|
rc = dom_set_value(nullptr, doc1, path, new_val);
|
|
EXPECT_EQ(rc, JSONUTIL_CANNOT_INSERT_MEMBER_INTO_NON_OBJECT_VALUE);
|
|
|
|
path = ".address.foo.city";
|
|
rc = dom_set_value(nullptr, doc1, path, new_val);
|
|
EXPECT_EQ(rc, JSONUTIL_JSON_PATH_NOT_EXIST);
|
|
}
|
|
|
|
TEST_F(DomTest, testSelector_set_v2path_part2) {
|
|
const char *path = "$.phoneNumbers[*].number";
|
|
const char *new_val = "\"123\"";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, path, new_val);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
Selector selector;
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 2);
|
|
for (auto &vInfo : rs) {
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize_value(*vInfo.first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), new_val);
|
|
}
|
|
|
|
path = "$.phoneNumbers[x].number";
|
|
rc = dom_set_value(nullptr, doc1, path, new_val);
|
|
EXPECT_EQ(rc, JSONUTIL_ARRAY_INDEX_NOT_NUMBER);
|
|
|
|
path = "$.phoneNumbers[2].number";
|
|
rc = dom_set_value(nullptr, doc1, path, new_val);
|
|
EXPECT_EQ(rc, JSONUTIL_INDEX_OUT_OF_ARRAY_BOUNDARIES);
|
|
}
|
|
|
|
TEST_F(DomTest, testSelector_set_v2path_part3) {
|
|
const char *path = "$.phoneNumbers[-1].number";
|
|
const char *new_val = "\"123\"";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, path, new_val);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
Selector selector;
|
|
rc = selector.getValues(*doc1, path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 1);
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize_value(*rs[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), new_val);
|
|
|
|
path = "$.phoneNumbers[-3].number";
|
|
rc = dom_set_value(nullptr, doc1, path, new_val);
|
|
EXPECT_EQ(rc, JSONUTIL_INDEX_OUT_OF_ARRAY_BOUNDARIES);
|
|
}
|
|
|
|
TEST_F(DomTest, testSelector_set_v2path_part4) {
|
|
const char *new_val = "\"z\"";
|
|
const char *path1 = "['address']['z']";
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, path1, new_val);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
Selector selector;
|
|
rc = selector.getValues(*doc1, path1);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 1);
|
|
rapidjson::StringBuffer oss;
|
|
dom_serialize_value(*rs[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), new_val);
|
|
|
|
Clear(&oss);
|
|
ReplyBuffer oss2;
|
|
rc = dom_get_value_as_str(doc1, path1, nullptr, oss2, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss2), new_val);
|
|
|
|
const char *path2 = ".address.z";
|
|
rc = selector.getValues(*doc1, path2);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs2 = selector.getResultSet();
|
|
EXPECT_EQ(rs2.size(), 1);
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs2[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), new_val);
|
|
|
|
Clear(&oss);
|
|
Clear(&oss2);
|
|
rc = dom_get_value_as_str(doc1, path2, nullptr, oss2, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss2), new_val);
|
|
|
|
const char *path3 = "$.address.z";
|
|
rc = selector.getValues(*doc1, path3);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs3 = selector.getResultSet();
|
|
EXPECT_EQ(rs3.size(), 1);
|
|
Clear(&oss);
|
|
dom_serialize_value(*rs3[0].first, nullptr, oss);
|
|
EXPECT_STREQ(oss.GetString(), new_val);
|
|
|
|
const char *exp = "[\"z\"]";
|
|
Clear(&oss2);
|
|
rc = dom_get_value_as_str(doc1, path3, nullptr, oss2, false);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_STREQ(GetString(&oss2), exp);
|
|
}
|
|
|
|
TEST_F(DomTest, testSelector_v2path_pathDepth) {
|
|
Selector selector;
|
|
JsonUtilCode rc = selector.getValues(*doc1, ".address");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getMaxPathDepth(), 1);
|
|
|
|
rc = selector.getValues(*doc1, ".address.city");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getMaxPathDepth(), 2);
|
|
|
|
rc = selector.getValues(*doc1, ".address.*");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getMaxPathDepth(), 2);
|
|
|
|
rc = selector.getValues(*doc1, "$.address.*");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getMaxPathDepth(), 2);
|
|
|
|
rc = selector.getValues(*doc1, "$.*.*");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getMaxPathDepth(), 2);
|
|
|
|
rc = selector.getValues(*doc1, "$.phoneNumbers[*].type");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getMaxPathDepth(), 3);
|
|
|
|
rc = selector.getValues(*doc1, "$.phoneNumbers[*].*");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(selector.getMaxPathDepth(), 3);
|
|
}
|
|
|
|
TEST_F(DomTest, test_v2path_NumIncrBy1) {
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".k1", "[1, 2, 3]");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_increment_by(doc1, "$.k1[*]", &parser.Parse("1", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 3);
|
|
EXPECT_EQ(res[0], 2);
|
|
EXPECT_EQ(res[1], 3);
|
|
EXPECT_EQ(res[2], 4);
|
|
|
|
Selector selector;
|
|
rc = selector.getValues(*doc1, "$.k1[*]");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 3);
|
|
EXPECT_EQ(rs[0].first->GetInt(), 2);
|
|
EXPECT_EQ(rs[1].first->GetInt(), 3);
|
|
EXPECT_EQ(rs[2].first->GetInt(), 4);
|
|
}
|
|
|
|
TEST_F(DomTest, test_v2path_NumIncrBy2) {
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".k1", "{\"a\":1, \"b\":2, \"c\":3}");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_increment_by(doc1, "$.k1.*", &parser.Parse("1", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 3);
|
|
EXPECT_EQ(res[0], 2);
|
|
EXPECT_EQ(res[1], 3);
|
|
EXPECT_EQ(res[2], 4);
|
|
|
|
Selector selector;
|
|
rc = selector.getValues(*doc1, "$.k1.*");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 3);
|
|
EXPECT_EQ(rs[0].first->GetInt(), 2);
|
|
EXPECT_EQ(rs[1].first->GetInt(), 3);
|
|
EXPECT_EQ(rs[2].first->GetInt(), 4);
|
|
}
|
|
|
|
TEST_F(DomTest, test_v2path_NumMultBy1) {
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".k1", "[1, 2, 3]");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_multiply_by(doc1, "$.k1[*]", &parser.Parse("2", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 3);
|
|
EXPECT_EQ(res[0], 2);
|
|
EXPECT_EQ(res[1], 4);
|
|
EXPECT_EQ(res[2], 6);
|
|
|
|
Selector selector;
|
|
rc = selector.getValues(*doc1, "$.k1[*]");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 3);
|
|
EXPECT_EQ(rs[0].first->GetInt(), 2);
|
|
EXPECT_EQ(rs[1].first->GetInt(), 4);
|
|
EXPECT_EQ(rs[2].first->GetInt(), 6);
|
|
}
|
|
|
|
TEST_F(DomTest, test_v2path_NumMultBy2) {
|
|
JsonUtilCode rc = dom_set_value(nullptr, doc1, ".k1", "{\"a\":1, \"b\":2, \"c\":3}");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
|
|
jsn::vector<double> res;
|
|
bool isV2Path;
|
|
JParser parser;
|
|
rc = dom_multiply_by(doc1, "$.k1.*", &parser.Parse("2", 1).GetJValue(), res, isV2Path);
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
EXPECT_EQ(res.size(), 3);
|
|
EXPECT_EQ(res[0], 2);
|
|
EXPECT_EQ(res[1], 4);
|
|
EXPECT_EQ(res[2], 6);
|
|
|
|
Selector selector;
|
|
rc = selector.getValues(*doc1, "$.k1.*");
|
|
EXPECT_EQ(rc, JSONUTIL_SUCCESS);
|
|
auto &rs = selector.getResultSet();
|
|
EXPECT_EQ(rs.size(), 3);
|
|
EXPECT_EQ(rs[0].first->GetInt(), 2);
|
|
EXPECT_EQ(rs[1].first->GetInt(), 4);
|
|
EXPECT_EQ(rs[2].first->GetInt(), 6);
|
|
}
|
|
|
|
class HTTest : public ::testing::Test {
|
|
void SetUp() override {
|
|
JsonUtilCode rc = jsonstats_init();
|
|
ASSERT_EQ(rc, JSONUTIL_SUCCESS);
|
|
setShards(0x10);
|
|
}
|
|
void TearDown() override {
|
|
delete keyTable;
|
|
keyTable = nullptr;
|
|
}
|
|
void setShards(size_t numShards) {
|
|
if (keyTable) delete keyTable;
|
|
SetupAllocFuncs(numShards);
|
|
}
|
|
};
|
|
|
|
TEST_F(HTTest, hashfunc) {
|
|
enum {key_count = 1 << 18, max_dups = 7};
|
|
std::unordered_map<size_t, size_t> hashes;
|
|
for (size_t i = 0; i < key_count; ++i) {
|
|
std::string s = std::to_string(i);
|
|
size_t h = hash_function(s.c_str(), s.size()) & 0x7FFFF;
|
|
hashes[h]++;
|
|
}
|
|
// Now sort by frequency
|
|
std::map<size_t, jsn::set<size_t>> by_frequency;
|
|
for (auto [h, f] : hashes) {
|
|
by_frequency[f].insert(h);
|
|
}
|
|
ASSERT_LE(by_frequency.begin()->first, max_dups);
|
|
}
|
|
|
|
TEST_F(HTTest, HTIngestTest) {
|
|
for (auto num_keys : { 1<<18 }) {
|
|
rapidjson::hashTableStats.reset();
|
|
std::ostringstream os;
|
|
os << '{';
|
|
for (int i = 0; i < num_keys; ++i) {
|
|
if (i != 0) os << ',';
|
|
os << '"' << i << '"' << ':' << i;
|
|
}
|
|
os << '}';
|
|
|
|
JDocument *doc;
|
|
EXPECT_EQ(JSONUTIL_SUCCESS, dom_parse(nullptr, os.str().c_str(), os.str().size(), &doc));
|
|
KeyTable::Stats s = keyTable->getStats();
|
|
EXPECT_EQ(s.handles, num_keys);
|
|
EXPECT_EQ(rapidjson::hashTableStats.rehashUp, 0);
|
|
EXPECT_EQ(rapidjson::hashTableStats.rehashDown, 0);
|
|
EXPECT_EQ(rapidjson::hashTableStats.convertToHT, 0);
|
|
EXPECT_EQ(rapidjson::hashTableStats.reserveHT, 1);
|
|
EXPECT_EQ("", keyTable->validate());
|
|
EXPECT_EQ("", validate(doc));
|
|
// Now make a second identical document
|
|
JDocument *doc2;
|
|
std::cerr << "***** Start second parse ****\n";
|
|
EXPECT_EQ(JSONUTIL_SUCCESS, dom_parse(nullptr, os.str().c_str(), os.str().size(), &doc2));
|
|
s = keyTable->getStats();
|
|
EXPECT_EQ(s.rehashes, 0);
|
|
EXPECT_EQ(s.handles, 2*num_keys);
|
|
EXPECT_EQ(rapidjson::hashTableStats.rehashUp, 0);
|
|
EXPECT_EQ(rapidjson::hashTableStats.rehashDown, 0);
|
|
EXPECT_EQ(rapidjson::hashTableStats.convertToHT, 0);
|
|
EXPECT_EQ(rapidjson::hashTableStats.reserveHT, 2);
|
|
EXPECT_EQ("", keyTable->validate());
|
|
EXPECT_EQ("", validate(doc));
|
|
EXPECT_EQ("", validate(doc2));
|
|
EXPECT_EQ(s.size, num_keys);
|
|
dom_free_doc(doc2);
|
|
EXPECT_EQ(keyTable->getStats().handles, num_keys);
|
|
EXPECT_EQ(keyTable->getStats().size, num_keys);
|
|
dom_free_doc(doc);
|
|
EXPECT_EQ(keyTable->getStats().handles, 0);
|
|
EXPECT_EQ(keyTable->getStats().size, 0);
|
|
}
|
|
}
|