/* * Copyright (C) 2021 Duowan Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Linux only, need gtest #include #ifdef XGTEST #include #else #include "gtest_stub.h" #endif #include "xpack/json.h" #include "xpack/bson.h" #include "string.h" using namespace std; struct Base { int a; string b; Base(const int _a=0, const string&_b=""):a(_a), b(_b){} XPACK(O(a, b)); }; struct POD { int a; char b[10]; XPACK(O(a, b)); }; // ++++++++++++++++++++++BuiltInTypes++++++++++++++++++++++++++++ struct BuiltInTypes { signed char sch; char ch; unsigned char uch; short sh; unsigned short ush; int i; unsigned int ui; long l; unsigned long ul; long long ll; unsigned long long ull; float f; double d; long double ld; bool b; XPACK(AF(F(ATTR), sch, "xml:s:ch"), X(F(ATTR), ch, uch, sh, ush), O(i, ui, l, ul, ll, ull, f, d, ld, b)); }; void checkBuiltInTypes(const BuiltInTypes&a, const BuiltInTypes&b) { EXPECT_EQ(a.sch, b.sch); EXPECT_EQ(a.ch, b.ch); EXPECT_EQ(a.uch, b.uch); EXPECT_EQ(a.sh, b.sh); EXPECT_EQ(a.ush, b.ush); EXPECT_EQ(a.i, b.i); EXPECT_EQ(a.ui, b.ui); EXPECT_EQ(a.l, b.l); EXPECT_EQ(a.ul, b.ul); EXPECT_EQ(a.ll, b.ll); EXPECT_EQ(a.ull, b.ull); EXPECT_FLOAT_EQ(a.f, b.f); EXPECT_DOUBLE_EQ(a.d, b.d); EXPECT_DOUBLE_EQ(a.ld, b.ld); EXPECT_TRUE(a.b); } TEST(builtin, types) { BuiltInTypes bt; bt.sch = 0x7f; bt.ch = 0x7f; bt.uch = 0x80; bt.sh = 0x7fff; bt.ush = 0x8000; bt.i = 0x7fffffff; bt.ui = 0x80000000; bt.l = 0x7fffffffffffffff; bt.ul = 0x8000000000000000; bt.ll = bt.l; bt.ull = bt.ul; bt.f = 1.234; bt.d = 9.678; bt.ld = 30.678; bt.b = true; xpack::BsonEncoder en; string js = en.encode_as_json(bt); cout<<"bson:"< m; set s; vector v; list l; vector > vv; XPACK(O(m, s, v, l, vv)); }; void checkContainerBase(ContainerBase&cb) { EXPECT_EQ(cb.m.size(), 2U); EXPECT_EQ(cb.m["a"], 1); EXPECT_EQ(cb.m["b"], 2); EXPECT_EQ(cb.s.size(), 2U); EXPECT_TRUE(cb.s.find(3)!=cb.s.end()); EXPECT_TRUE(cb.s.find(4)!=cb.s.end()); EXPECT_TRUE(cb.s.find(5)==cb.s.end()); EXPECT_EQ(cb.v.size(), 2U); EXPECT_EQ(cb.v[0], 5); EXPECT_EQ(cb.v[1], 6); EXPECT_EQ(cb.l.size(), 2U); EXPECT_EQ(*(cb.l.begin()), 7); EXPECT_EQ(*(++cb.l.begin()), 8); EXPECT_EQ(cb.vv.size(), 2U); EXPECT_EQ(cb.vv[0].size(), 2U); EXPECT_EQ(cb.vv[1].size(), 2U); EXPECT_EQ(cb.vv[0][0], 11); EXPECT_EQ(cb.vv[0][1], 12); EXPECT_EQ(cb.vv[1][0], 22); EXPECT_EQ(cb.vv[1][1], 23); } TEST(container, base) { string s = "{\"m\":{\"a\":1, \"b\":2}, \"s\":[3, 4], \"v\":[5,6], \"l\":[7, 8], \"vv\":[[11,12],[22,23]]}"; ContainerBase cb; xpack::json::decode(s, cb); checkContainerBase(cb); xpack::BsonEncoder en; string js = en.encode_as_json(cb); ContainerBase j1; xpack::bson::decode(en.encode(cb), j1); checkContainerBase(j1); } struct ContainerStruct { map m; vector v; list l; vector > vv; XPACK(O(m, v, l, vv)); }; void checkContainerStruct(ContainerStruct&a) { EXPECT_EQ(a.m.size(), 2U); EXPECT_EQ(a.m["a"].a, 1); EXPECT_EQ(a.m["a"].b, "good"); EXPECT_EQ(a.m["b"].a, 2); EXPECT_EQ(a.m["b"].b, "nice"); EXPECT_EQ(a.v.size(), 2U); EXPECT_EQ(a.v[0].a, 3); EXPECT_EQ(a.v[0].b, "hello"); EXPECT_EQ(a.v[1].a, 4); EXPECT_EQ(a.v[1].b, "wow"); list::const_iterator lit = a.l.begin(); EXPECT_EQ(a.l.size(), 2U); EXPECT_EQ(lit->a, 5); EXPECT_EQ(lit->b, "dida"); ++lit; EXPECT_EQ(lit->a, 6); EXPECT_EQ(lit->b, "haha"); EXPECT_EQ(a.vv.size(), 2U); EXPECT_EQ(a.vv[0].size(), 1U); EXPECT_EQ(a.vv[1].size(), 2U); EXPECT_EQ(a.vv[0][0].a, 7); EXPECT_EQ(a.vv[0][0].b, "lala"); EXPECT_EQ(a.vv[1][0].a, 8); EXPECT_EQ(a.vv[1][0].b, "wawa"); EXPECT_EQ(a.vv[1][1].a, 9); EXPECT_EQ(a.vv[1][1].b, "kaka"); } TEST(container, struct) { ContainerStruct cb; cb.m["a"] = Base(1, "good"); cb.m["b"] = Base(2, "nice"); cb.v.push_back(Base(3, "hello")); cb.v.push_back(Base(4, "wow")); cb.l.push_back(Base(5, "dida")); cb.l.push_back(Base(6, "haha")); cb.vv.resize(2); cb.vv[0].resize(1); cb.vv[1].resize(2); cb.vv[0][0].a = 7; cb.vv[0][0].b = "lala"; cb.vv[1][0].a = 8; cb.vv[1][0].b = "wawa"; cb.vv[1][1].a = 9; cb.vv[1][1].b = "kaka"; xpack::BsonEncoder en; string js = en.encode_as_json(cb); ContainerStruct j1; xpack::bson::decode(en.encode(cb), j1); checkContainerStruct(j1); } // ++++++++++++++++++ BSON TYPES ++++++++++++++++++++++++++++ struct BsonTypes { bson_date_time_t dt; bson_timestamp_t ts; bson_binary_t binary; bson_regex_t regex; bson_oid_t oid; bson_decimal128_t decimal; XPACK(A(oid, "_id"), O(dt, ts, binary, regex, decimal)); }; void checkBsonTypes(const BsonTypes&a, const BsonTypes&b, bool checkDecimal) { EXPECT_EQ(a.dt.ts, b.dt.ts); EXPECT_EQ(a.ts.timestamp, b.ts.timestamp); EXPECT_EQ(a.ts.increment, b.ts.increment); EXPECT_EQ(a.binary.data, b.binary.data); EXPECT_EQ(a.binary.subType, b.binary.subType); EXPECT_EQ(a.regex.pattern, b.regex.pattern); EXPECT_EQ(a.regex.options, b.regex.options); EXPECT_EQ(0, memcmp(a.oid.bytes, b.oid.bytes, sizeof(a.oid.bytes))); if (checkDecimal) { EXPECT_EQ(a.decimal.high, b.decimal.high); EXPECT_EQ(a.decimal.low, b.decimal.low); } } TEST(base, bson_types) { BsonTypes bt; bt.dt.ts = 1638374400018; bt.ts.timestamp = 1638374400; bt.ts.increment = 1; bt.binary.data = "hello"; bt.binary.subType = BSON_SUBTYPE_USER; bt.regex.pattern = "^([0-9a-zA-Z]+)"; bt.regex.options = "i"; bt.regex.ver = 2; uint8_t bytes[] = {0x57, 0xe1, 0x93, 0xd7, 0xa9, 0xcc, 0x81, 0xb4, 0x02, 0x74, 0x98, 0xb5}; memcpy((void*)bt.oid.bytes, bytes, sizeof(bt.oid.bytes)); bt.decimal.high = 1; bt.decimal.low = 2; string js = xpack::json::encode(bt); cout<<"json:"< v(3); v[0] = 1; v[1] = 2; v[2] = 3; cout<<"json1:"< m; QVector v; QList l; QVector > vv; XPACK(O(m, v, l, vv)); }; void checkContainerQT(ContainerQT&a) { EXPECT_EQ(a.m.size(), 2); EXPECT_EQ(a.m["a"].a, 1); EXPECT_EQ(a.m["a"].b, "good"); EXPECT_EQ(a.m["b"].a, 2); EXPECT_EQ(a.m["b"].b, "nice"); EXPECT_EQ(a.v.size(), 2); EXPECT_EQ(a.v[0].a, 3); EXPECT_EQ(a.v[0].b, "hello"); EXPECT_EQ(a.v[1].a, 4); EXPECT_EQ(a.v[1].b, "wow"); QList::const_iterator lit = a.l.begin(); EXPECT_EQ(a.l.size(), 2); EXPECT_EQ(lit->a, 5); EXPECT_EQ(lit->b, "dida"); ++lit; EXPECT_EQ(lit->a, 6); EXPECT_EQ(lit->b, "haha"); EXPECT_EQ(a.vv.size(), 2); EXPECT_EQ(a.vv[0].size(), 1); EXPECT_EQ(a.vv[1].size(), 2); EXPECT_EQ(a.vv[0][0].a, 7); EXPECT_EQ(a.vv[0][0].b, "lala"); EXPECT_EQ(a.vv[1][0].a, 8); EXPECT_EQ(a.vv[1][0].b, "wawa"); EXPECT_EQ(a.vv[1][1].a, 9); EXPECT_EQ(a.vv[1][1].b, "kaka"); } TEST(container, QT) { ContainerQT cb; cb.m["a"] = Base(1, "good"); cb.m["b"] = Base(2, "nice"); cb.v.push_back(Base(3, "hello")); cb.v.push_back(Base(4, "wow")); cb.l.push_back(Base(5, "dida")); cb.l.push_back(Base(6, "haha")); cb.vv.resize(2); cb.vv[0].resize(1); cb.vv[1].resize(2); cb.vv[0][0].a = 7; cb.vv[0][0].b = "lala"; cb.vv[1][0].a = 8; cb.vv[1][0].b = "wawa"; cb.vv[1][1].a = 9; cb.vv[1][1].b = "kaka"; xpack::BsonEncoder en; en.encode(NULL, cb, NULL); string js = en.Json(); ContainerQT j1; xpack::bson::decode(en.String(), j1); checkContainerQT(j1); } #endif // +++++++++++++++++ flags ++++++++++++++++++ struct FlagM { int a; string b; XPACK(O(a), M(b)); }; TEST(flags, M) { static xpack::BsonBuilder bd("{'a':1}"); bool except = false; try { FlagM j1; xpack::bson::decode(bd.Encode(), j1); } catch(...) { except = true; } EXPECT_TRUE(except); } // ++++++++++++++++++bug history+++++++++++++++++++++++ TEST(bughis, notexists) { Base b(9, ""); static xpack::BsonBuilder bd("{'a':1}"); xpack::bson::decode(bd.Encode(), b); EXPECT_EQ(b.a, 1); } int main(int argc, char *argv[]) { #ifdef XGTEST testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); #else (void)argc; (void)argv; TC_CONTAINER::RUN(); return 0; #endif }