diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/scheme/tests/ut | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/scheme/tests/ut')
-rw-r--r-- | library/cpp/scheme/tests/ut/fuzz_ops_found_bugs_ut.cpp | 12 | ||||
-rw-r--r-- | library/cpp/scheme/tests/ut/scheme_cast_ut.cpp | 162 | ||||
-rw-r--r-- | library/cpp/scheme/tests/ut/scheme_json_ut.cpp | 161 | ||||
-rw-r--r-- | library/cpp/scheme/tests/ut/scheme_merge_ut.cpp | 172 | ||||
-rw-r--r-- | library/cpp/scheme/tests/ut/scheme_path_ut.cpp | 159 | ||||
-rw-r--r-- | library/cpp/scheme/tests/ut/scheme_proto_ut.cpp | 220 | ||||
-rw-r--r-- | library/cpp/scheme/tests/ut/scheme_ut.cpp | 879 | ||||
-rw-r--r-- | library/cpp/scheme/tests/ut/scheme_ut.proto | 84 | ||||
-rw-r--r-- | library/cpp/scheme/tests/ut/ya.make | 24 |
9 files changed, 1873 insertions, 0 deletions
diff --git a/library/cpp/scheme/tests/ut/fuzz_ops_found_bugs_ut.cpp b/library/cpp/scheme/tests/ut/fuzz_ops_found_bugs_ut.cpp new file mode 100644 index 0000000000..a445b0f87c --- /dev/null +++ b/library/cpp/scheme/tests/ut/fuzz_ops_found_bugs_ut.cpp @@ -0,0 +1,12 @@ +#include <library/cpp/scheme/scheme.h> +#include <library/cpp/scheme/tests/fuzz_ops/lib/fuzz_ops.h> +#include <library/cpp/testing/unittest/registar.h> +#include <util/string/hex.h> + +Y_UNIT_TEST_SUITE(TTestSchemeFuzzOpsFoundBugs) { + using namespace NSc::NUt; + + Y_UNIT_TEST(TestBug1) { + FuzzOps(HexDecode("98040129000525"), true); + } +}; diff --git a/library/cpp/scheme/tests/ut/scheme_cast_ut.cpp b/library/cpp/scheme/tests/ut/scheme_cast_ut.cpp new file mode 100644 index 0000000000..4f907157e9 --- /dev/null +++ b/library/cpp/scheme/tests/ut/scheme_cast_ut.cpp @@ -0,0 +1,162 @@ +#include <library/cpp/scheme/scheme.h> +#include <library/cpp/scheme/scheme_cast.h> + +#include <library/cpp/testing/unittest/registar.h> + +#include <util/stream/null.h> +#include <util/string/subst.h> +#include <util/string/util.h> + +using namespace NJsonConverters; + +using TVI = TVector<int>; +using THI = THashMap<int, int>; +using TMI = TMap<int, int>; +using THSI = THashSet<int>; +using TSI = TSet<int>; +using TPI = std::pair<int, int>; + +Y_UNIT_TEST_SUITE(TSchemeCastTest) { + Y_UNIT_TEST(TestYVector) { + TVI v; + for (int i = 0; i < 3; ++i) + v.push_back(i); + + UNIT_ASSERT_VALUES_EQUAL("[0,1,2]", ToJson(v)); + + TVI y(FromJson<TVI>(ToJson(v))); + UNIT_ASSERT_VALUES_EQUAL(v.size(), y.size()); + UNIT_ASSERT(std::equal(v.begin(), v.end(), y.begin())); + } + + Y_UNIT_TEST(TestYHash) { + THI h; + for (int i = 0; i < 3; ++i) + h[i] = i * i; + + const TString etalon = "{\"0\":0,\"1\":1,\"2\":4}"; + UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(h, true)); + + THI h2(FromJson<THI>(ToJson(h))); + UNIT_ASSERT_VALUES_EQUAL(ToJson(h2, true), ToJson(h, true)); + } + + Y_UNIT_TEST(TestYMap) { + TMI h; + for (int i = 0; i < 3; ++i) + h[i] = i * i; + + const TString etalon = "{\"0\":0,\"1\":1,\"2\":4}"; + UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(h, true)); + + TMI h2(FromJson<TMI>(ToJson(h))); + UNIT_ASSERT_VALUES_EQUAL(ToJson(h2, true), ToJson(h, true)); + } + + Y_UNIT_TEST(TestYHashSet) { + THSI h; + for (int i = 0; i < 3; ++i) + h.insert(i * i); + + const TString etalon = "{\"0\":null,\"1\":null,\"4\":null}"; + UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(h, true)); + + THSI h2(FromJson<THSI>(ToJson(h))); + UNIT_ASSERT_VALUES_EQUAL(ToJson(h2, true), ToJson(h, true)); + } + + Y_UNIT_TEST(TestYSet) { + TSI h; + for (int i = 0; i < 3; ++i) + h.insert(i * i); + + const TString etalon = "{\"0\":null,\"1\":null,\"4\":null}"; + UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(h, true)); + + TSI h2(FromJson<TSI>(ToJson(h))); + UNIT_ASSERT_VALUES_EQUAL(ToJson(h2, true), ToJson(h, true)); + } + + Y_UNIT_TEST(TestTPair) { + TPI p(1, 1); + + const TString etalon = "[1,1]"; + UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(p, true)); + + TPI p2(FromJson<TPI>(ToJson(p))); + UNIT_ASSERT_VALUES_EQUAL(ToJson(p2, true), ToJson(p, true)); + } + + struct TCustom: public IJsonSerializable { + int A, B; + TCustom() + : A(0) + , B(0){}; + TCustom(int a, int b) + : A(a) + , B(b) + { + } + NSc::TValue ToTValue() const override { + NSc::TValue res; + res["a"] = A; + res["b"] = B; + return res; + } + void FromTValue(const NSc::TValue& v, const bool) override { + A = v["a"].GetNumber(); + B = v["b"].GetNumber(); + } + + bool operator<(const TCustom& rhs) const { + return A < rhs.A; + } + }; + + Y_UNIT_TEST(TestTCustom) { + TCustom x(2, 3); + + const TString etalon = "{\"a\":2,\"b\":3}"; + UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(x, true)); + + TCustom x2(FromJson<TCustom>(ToJson(x))); + UNIT_ASSERT_VALUES_EQUAL(ToJson(x2, true), ToJson(x, true)); + } + + Y_UNIT_TEST(TestVectorOfPairs) { + typedef TVector<TPI> TVPI; + TVPI v; + + for (int i = 0; i < 3; ++i) + v.push_back(TPI(i, i * i)); + + const TString etalon = "[[0,0],[1,1],[2,4]]"; + UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(v, true)); + + TVPI v2(FromJson<TVPI>(ToJson(v))); + UNIT_ASSERT_VALUES_EQUAL(ToJson(v2, true), ToJson(v, true)); + } + + Y_UNIT_TEST(TestSetOfCustom) { + typedef TSet<TCustom> TSC; + TSC s; + s.insert(TCustom(2, 3)); + + const TString etalon = "{\"{\\\"a\\\":2,\\\"b\\\":3}\":null}"; + UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(s, true)); + + TSC s2(FromJson<TSC>(ToJson(s))); + UNIT_ASSERT_VALUES_EQUAL(ToJson(s2, true), ToJson(s, true)); + } + + Y_UNIT_TEST(TestExceptions) { + NSc::TValue v = 1; + const TString json = v.ToJson(); + UNIT_ASSERT_EXCEPTION(FromJson<TVI>(json, true), yexception); + UNIT_ASSERT_EXCEPTION(FromJson<THI>(json, true), yexception); + UNIT_ASSERT_EXCEPTION(FromJson<TMI>(json, true), yexception); + UNIT_ASSERT_EXCEPTION(FromJson<THSI>(json, true), yexception); + UNIT_ASSERT_EXCEPTION(FromJson<TSI>(json, true), yexception); + UNIT_ASSERT_EXCEPTION(FromJson<TPI>(json, true), yexception); + } +}; diff --git a/library/cpp/scheme/tests/ut/scheme_json_ut.cpp b/library/cpp/scheme/tests/ut/scheme_json_ut.cpp new file mode 100644 index 0000000000..daeb2654f9 --- /dev/null +++ b/library/cpp/scheme/tests/ut/scheme_json_ut.cpp @@ -0,0 +1,161 @@ +#include <library/cpp/scheme/scimpl_private.h> +#include <library/cpp/scheme/ut_utils/scheme_ut_utils.h> +#include <library/cpp/testing/unittest/registar.h> + +#include <util/stream/null.h> +#include <util/string/subst.h> +#include <util/string/util.h> + +#include <type_traits> +#include <library/cpp/string_utils/quote/quote.h> + +using namespace std::string_view_literals; + +Y_UNIT_TEST_SUITE(TSchemeJsonTest) { + Y_UNIT_TEST(TestJson) { + const char* json = "[\n" + " {\n" + " \"url\":\"foo\",\n" + " \"title\":\"bar\",\n" + " \"passages\":[\"foo\", \"bar\"],\n" + " }\n" + "]"; + + { + const NSc::TValue& v = NSc::TValue::FromJson(json); + UNIT_ASSERT_VALUES_EQUAL("bar", (TStringBuf)v.TrySelect("0/passages/1")); + UNIT_ASSERT(v.PathExists("0/passages/0")); + UNIT_ASSERT(v.PathExists("[0]/[passages]/[0]")); + UNIT_ASSERT(v.PathExists("[0][passages][0]")); + UNIT_ASSERT(v.PathExists("")); + UNIT_ASSERT(!v.PathExists("`")); + UNIT_ASSERT(v.TrySelect("").Has(0)); + UNIT_ASSERT(!v.PathExists("1")); + UNIT_ASSERT(!v.PathExists("0/passages1")); + UNIT_ASSERT(!v.PathExists("0/passages/2")); + UNIT_ASSERT(!v.PathExists("0/passages/2")); + UNIT_ASSERT_VALUES_EQUAL(0, (double)v.TrySelect("0/passages/2")); + UNIT_ASSERT(!v.PathExists("0/passages/2")); + } + { + const NSc::TValue& vv = NSc::TValue::FromJson("[ test ]]"); + UNIT_ASSERT(vv.IsNull()); + } + { + const char* json = "[a,b],[a,b]"; + const NSc::TValue& v = NSc::TValue::FromJson(json); + UNIT_ASSERT(v.IsNull()); + } + { + const char* json = "[null,null]"; + const NSc::TValue& v = NSc::TValue::FromJson(json); + UNIT_ASSERT(v.PathExists("1")); + UNIT_ASSERT(!v.PathExists("2")); + } + { + const char* json = "{ a : b : c }"; + NSc::TValue v; + UNIT_ASSERT(!NSc::TValue::FromJson(v, json)); + UNIT_ASSERT(v.IsNull()); + } + { + const char* json = "[a:b]"; + UNIT_ASSERT(NSc::TValue::FromJson(json).IsNull()); + } + { + UNIT_ASSERT_VALUES_EQUAL("{\n \"a\" : \"b\",\n \"c\" : \"d\"\n}", + NSc::TValue::FromJson("{a:b,c:d}").ToJson(NSc::TValue::JO_PRETTY)); + } + } + + Y_UNIT_TEST(TestSafeJson) { + TString ss; + ss.reserve(256); + + for (int i = 0; i < 256; ++i) { + ss.append((char)i); + } + + NSc::TValue v; + v[ss] = "xxx"; + v["xxx"] = ss; + + UNIT_ASSERT_VALUES_EQUAL("{\"xxx\":null}", v.ToJson(NSc::TValue::JO_SKIP_UNSAFE)); + UNIT_ASSERT_VALUES_EQUAL("{\"xxx\":null}", v.ToJson(NSc::TValue::JO_SAFE)); + + UNIT_ASSERT_VALUES_EQUAL("{" + "\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r" + "\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018" + "\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F !\\\"#$%&'()*+,-./0123456789" + ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\u007F" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93" + "\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7" + "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB" + "\xBC\xBD\xBE\xBF\\xC0\\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE" + "\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1" + "\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4" + "\\xF5\\xF6\\xF7\\xF8\\xF9\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\":" + "\"xxx\"," + "\"xxx\":" + "\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r" + "\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018" + "\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F !\\\"#$%&'()*+,-./0123456789" + ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\u007F" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93" + "\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7" + "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB" + "\xBC\xBD\xBE\xBF\\xC0\\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE" + "\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1" + "\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4" + "\\xF5\\xF6\\xF7\\xF8\\xF9\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\"" + "}", + v.ToJson(NSc::TValue::JO_SORT_KEYS)); + UNIT_ASSERT(NSc::TValue::Equal(v, NSc::TValue::FromJson(v.ToJson()))); + + { + NSc::TValue value; + TString articleName{"\xC2\xC2\xCF"}; + value["text"] = articleName; + UNIT_ASSERT_VALUES_EQUAL(value.ToJson(), "{\"text\":\"\xC2\xC2\xCF\"}"); + UNIT_ASSERT_VALUES_EQUAL(value.ToJsonSafe(), "{\"text\":null}"); + } + } + + Y_UNIT_TEST(TestJsonEscape) { + NSc::TValue v("\10\7\6\5\4\3\2\1\0"sv); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "\"\\b\\u0007\\u0006\\u0005\\u0004\\u0003\\u0002\\u0001\\u0000\""); + } + + Y_UNIT_TEST(TestStrictJson) { + UNIT_ASSERT_NO_EXCEPTION(NSc::TValue::FromJsonThrow("{a:b}")); + UNIT_ASSERT_EXCEPTION(NSc::TValue::FromJsonThrow("{a:b}", NSc::TValue::JO_PARSER_STRICT), yexception); + UNIT_ASSERT_NO_EXCEPTION(NSc::TValue::FromJsonThrow("{\"a\":\"b\"}", NSc::TValue::JO_PARSER_STRICT)); + } + + Y_UNIT_TEST(TestJsonValue) { + NSc::TValue a = NSc::NUt::AssertFromJson("{a:[null,-1,2,3.4,str,{b:{c:d}}],e:f}"); + NSc::TValue b = NSc::TValue::FromJsonValue(a.ToJsonValue()); + UNIT_ASSERT_JSON_EQ_JSON(a, b); + } + + Y_UNIT_TEST(TestJsonEmptyContainers) { + { + NSc::TValue a = NSc::NUt::AssertFromJson("{a:[]}"); + NSc::TValue b = NSc::TValue::FromJsonValue(a.ToJsonValue()); + UNIT_ASSERT_JSON_EQ_JSON(a, b); + } + { + NSc::TValue a = NSc::NUt::AssertFromJson("{a:{}}"); + NSc::TValue b = NSc::TValue::FromJsonValue(a.ToJsonValue()); + UNIT_ASSERT_JSON_EQ_JSON(a, b); + } + } + + Y_UNIT_TEST(TestDuplicateKeys) { + const TStringBuf duplicatedKeys = "{\"a\":[{\"b\":1, \"b\":42}]}"; + UNIT_ASSERT_NO_EXCEPTION(NSc::TValue::FromJsonThrow(duplicatedKeys)); + UNIT_ASSERT_EXCEPTION(NSc::TValue::FromJsonThrow(duplicatedKeys, NSc::TValue::JO_PARSER_DISALLOW_DUPLICATE_KEYS), yexception); + UNIT_ASSERT(NSc::TValue::FromJson(duplicatedKeys).IsDict()); + UNIT_ASSERT(NSc::TValue::FromJson(duplicatedKeys, NSc::TValue::JO_PARSER_DISALLOW_DUPLICATE_KEYS).IsNull()); + } +}; diff --git a/library/cpp/scheme/tests/ut/scheme_merge_ut.cpp b/library/cpp/scheme/tests/ut/scheme_merge_ut.cpp new file mode 100644 index 0000000000..2a06cf110d --- /dev/null +++ b/library/cpp/scheme/tests/ut/scheme_merge_ut.cpp @@ -0,0 +1,172 @@ +#include <library/cpp/scheme/scimpl_private.h> +#include <library/cpp/scheme/ut_utils/scheme_ut_utils.h> +#include <library/cpp/testing/unittest/registar.h> + +#include <util/stream/null.h> +#include <library/cpp/string_utils/quote/quote.h> +#include <util/string/subst.h> +#include <util/string/util.h> + +#include <type_traits> + + +Y_UNIT_TEST_SUITE(TSchemeMergeTest) { + + void DoTestReverseMerge(TStringBuf lhs, TStringBuf rhs, TStringBuf res) { + NSc::TValue v = NSc::TValue::FromJson(lhs); + v.ReverseMerge(NSc::TValue::FromJson(rhs)); + UNIT_ASSERT(NSc::TValue::Equal(v, NSc::TValue::FromJson(res))); + } + + Y_UNIT_TEST(TestReverseMerge) { + DoTestReverseMerge("{a:{x:y, b:c}}", "{a:{u:w, b:d}}", "{a:{u:w, x:y, b:c}}"); + DoTestReverseMerge("null", "{x:y}", "{x:y}"); + DoTestReverseMerge("null", "[b]", "[b]"); + DoTestReverseMerge("[a]", "[b]", "[a]"); + DoTestReverseMerge("{x:null}", "{x:b}", "{x:b}"); + } + + Y_UNIT_TEST(TestMerge) { + TStringBuf data = "{ a : [ { b : 1, d : { e : -1.e5 } }, { f : 0, g : [ h, i ] } ] }"; + NSc::TValue v = NSc::TValue::FromJson(data); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(true), v.Clone().ToJson(true)); + UNIT_ASSERT(v.Has("a")); + UNIT_ASSERT(v["a"].Has(1)); + UNIT_ASSERT(v["a"][0].Has("b")); + UNIT_ASSERT(v["a"][0].Has("d")); + UNIT_ASSERT(1 == v["a"][0]["b"]); + UNIT_ASSERT(v["a"][0]["d"].Has("e")); + UNIT_ASSERT(-1.e5 == v["a"][0]["d"]["e"]); + UNIT_ASSERT(v["a"][1].Has("f")); + UNIT_ASSERT(v["a"][1].Has("g")); + UNIT_ASSERT(0. == v["a"][1]["f"]); + UNIT_ASSERT(v["a"][1]["g"].IsArray()); + UNIT_ASSERT(v["a"][1]["g"].Has(1)); + UNIT_ASSERT(TStringBuf("h") == v["a"][1]["g"][0]); + UNIT_ASSERT(TStringBuf("i") == v["a"][1]["g"][1]); + + { + TStringBuf data = "{ a : [ { d : 42 }, { g : [ 3 ] } ], q : r }"; + + NSc::TValue v1 = NSc::TValue::FromJson(data); + UNIT_ASSERT_VALUES_EQUAL(v1.ToJson(true), v1.Clone().ToJson(true)); + UNIT_ASSERT(NSc::TValue::Equal(v1, v1.FromJson(v1.ToJson()))); + + NSc::TValue v2; + v2.MergeUpdate(v["a"]); + UNIT_ASSERT_C(NSc::TValue::Equal(v["a"], v2), Sprintf("\n%s\n!=\n%s\n", v["a"].ToJson().data(), v2.ToJson().data())); + + v.MergeUpdate(v1); + UNIT_ASSERT_C(!NSc::TValue::Equal(v["a"], v2), Sprintf("\n%s\n!=\n%s\n", v["a"].ToJson().data(), v2.ToJson().data())); + v2.MergeUpdate(v1["a"]); + UNIT_ASSERT_C(NSc::TValue::Equal(v["a"], v2), Sprintf("\n%s\n!=\n%s\n", v["a"].ToJson().data(), v2.ToJson().data())); + } + + UNIT_ASSERT(v.Has("a")); + UNIT_ASSERT(v.Has("q")); + UNIT_ASSERT(TStringBuf("r") == v["q"]); + UNIT_ASSERT(v["a"].Has(1)); + UNIT_ASSERT(!v["a"][0].Has("b")); + UNIT_ASSERT(v["a"][0].Has("d")); + UNIT_ASSERT(!v["a"][0]["d"].IsArray()); + UNIT_ASSERT(!v["a"][0]["d"].IsDict()); + UNIT_ASSERT(42 == v["a"][0]["d"]); + UNIT_ASSERT(!v["a"][1].Has("f")); + UNIT_ASSERT(v["a"][1].Has("g")); + UNIT_ASSERT(v["a"][1]["g"].IsArray()); + UNIT_ASSERT(!v["a"][1]["g"].Has(1)); + UNIT_ASSERT(3 == v["a"][1]["g"][0]); + } + + Y_UNIT_TEST(TestMerge1) { + TStringBuf data = "[ { a : { b : d } } ]"; + + NSc::TValue wcopy = NSc::TValue::FromJson(data); + + TStringBuf data1 = "[ { a : { b : c } } ]"; + + wcopy.MergeUpdateJson(data1); + + { + TString json = wcopy.ToJson(true); + SubstGlobal(json, "\"", ""); + UNIT_ASSERT_VALUES_EQUAL(json, "[{a:{b:c}}]"); + } + } + + Y_UNIT_TEST(TestMerge2) { + TStringBuf data = "{ a : { b : c }, q : { x : y } }"; + + NSc::TValue wcopy = NSc::TValue::FromJson(data); + + TStringBuf data1 = "{ a : { e : f } }"; + + wcopy.MergeUpdateJson(data1); + + { + TString json = wcopy.ToJson(true); + SubstGlobal(json, "\"", ""); + UNIT_ASSERT_VALUES_EQUAL(json, "{a:{b:c,e:f},q:{x:y}}"); + } + } + + Y_UNIT_TEST(TestMerge3) { + TStringBuf data = "{ g : { x : { a : { b : c }, q : { x : y } }, y : fff } }"; + + NSc::TValue wcopy = NSc::TValue::FromJson(data); + + TStringBuf data1 = "{ g : { x : { a : { e : f } } } }"; + + wcopy.MergeUpdateJson(data1); + + { + TString json = wcopy.ToJson(true); + SubstGlobal(json, "\"", ""); + UNIT_ASSERT_VALUES_EQUAL(json, "{g:{x:{a:{b:c,e:f},q:{x:y}},y:fff}}"); + } + } + + Y_UNIT_TEST(TestMerge4) { + TStringBuf data = "{ a : 1, b : { c : 2, d : { q : f } } }"; + NSc::TValue val = NSc::TValue::FromJson(data); + + TStringBuf data1 = "{ a : 2, b : { c : 3, d : { q : e }, g : h } }"; + + val.MergeUpdateJson(data1); + + { + TString json = val.ToJson(true); + SubstGlobal(json, "\"", ""); + + UNIT_ASSERT_VALUES_EQUAL(json, "{a:2,b:{c:3,d:{q:e},g:h}}"); + } + } + + Y_UNIT_TEST(TestMerge5) { + NSc::TValue v0; + v0.GetOrAdd("x").MergeUpdate(NSc::TValue(1)); + UNIT_ASSERT_VALUES_EQUAL(v0.ToJson(), "{\"x\":1}"); + } + + Y_UNIT_TEST(TestMerge6) { + NSc::TValue va = NSc::TValue::FromJson("{\"x\":\"abc\",\"y\":\"def\"}"); + NSc::TValue vb = va.Get("y"); + NSc::TValue diff; + diff["y"] = vb; + va.MergeUpdate(diff); + UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), "{\"x\":\"abc\",\"y\":\"def\"}"); + UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), "\"def\""); + UNIT_ASSERT_VALUES_EQUAL(diff.ToJson(), "{\"y\":\"def\"}"); + } + + Y_UNIT_TEST(TestMerge7) { + NSc::TValue v; + v["a"] = NSc::TValue::FromJson("[0.125,0.12,0.1,0.08,0.06]"); + UNIT_ASSERT_JSON_EQ_JSON(v, "{a:[0.125,0.12,0.1,0.08,0.06]}"); + + NSc::TValue a = v.TrySelectOrAdd("a")->MergeUpdateJson("[1,2,3]"); + + UNIT_ASSERT_JSON_EQ_JSON(a, "[1,2,3]"); + UNIT_ASSERT_JSON_EQ_JSON(v, "{a:[1,2,3]}"); + } +}; diff --git a/library/cpp/scheme/tests/ut/scheme_path_ut.cpp b/library/cpp/scheme/tests/ut/scheme_path_ut.cpp new file mode 100644 index 0000000000..0d4d79d483 --- /dev/null +++ b/library/cpp/scheme/tests/ut/scheme_path_ut.cpp @@ -0,0 +1,159 @@ +#include <library/cpp/scheme/scimpl_private.h> +#include <library/cpp/scheme/ut_utils/scheme_ut_utils.h> +#include <library/cpp/testing/unittest/registar.h> + +#include <util/stream/null.h> +#include <util/string/subst.h> +#include <util/string/util.h> + +#include <type_traits> +#include <library/cpp/string_utils/quote/quote.h> + +Y_UNIT_TEST_SUITE(TSchemePathTest) { + void DoTestSelect(TStringBuf path, TStringBuf expected, TStringBuf delexpected) { + NSc::TValue v; + UNIT_ASSERT(!v.PathExists(path)); + UNIT_ASSERT(NSc::TValue::PathValid(path)); + UNIT_ASSERT(NSc::TValue::Same(v.TrySelect(path), NSc::Null())); + *v.TrySelectOrAdd(path) = 1; + NSc::NUt::AssertSchemeJson(expected, v); + UNIT_ASSERT(v.PathExists(path)); + UNIT_ASSERT(1 == v.TrySelectOrAdd(path)->GetNumber()); + UNIT_ASSERT(1 == v.TrySelect(path).GetNumber()); + UNIT_ASSERT(1 == v.TrySelectAndDelete(path).GetNumber()); + UNIT_ASSERT(NSc::TValue::Same(v.TrySelectAndDelete(path), NSc::Null())); + NSc::NUt::AssertSchemeJson(delexpected, v); + UNIT_ASSERT(!v.PathExists(path)); + UNIT_ASSERT(NSc::TValue::Same(v.TrySelect(path), NSc::Null())); + } + + Y_UNIT_TEST(TestSelect) { + NSc::TValue v; + UNIT_ASSERT(!v.PathValid(" ")); + UNIT_ASSERT(v.PathExists("")); + UNIT_ASSERT(v.PathExists("//")); + + UNIT_ASSERT(NSc::TValue::Same(v, *v.TrySelectOrAdd("//"))); + NSc::NUt::AssertSchemeJson("null", v); + UNIT_ASSERT(NSc::TValue::Same(v.TrySelectAndDelete("//"), NSc::Null())); + NSc::NUt::AssertSchemeJson("null", v); + + v.SetDict(); + UNIT_ASSERT(NSc::TValue::Same(v, *v.TrySelectOrAdd("//"))); + NSc::NUt::AssertSchemeJson("{}", v); + UNIT_ASSERT(NSc::TValue::Same(v.TrySelectAndDelete("//"), NSc::Null())); + NSc::NUt::AssertSchemeJson("{}", v); + + v.SetArray(); + UNIT_ASSERT(NSc::TValue::Same(v, *v.TrySelectOrAdd("//"))); + NSc::NUt::AssertSchemeJson("[]", v); + UNIT_ASSERT(NSc::TValue::Same(v.TrySelectAndDelete("//"), NSc::Null())); + NSc::NUt::AssertSchemeJson("[]", v); + + DoTestSelect("[]", "{'':1}", "{}"); + DoTestSelect("[ ]", "{' ':1}", "{}"); + DoTestSelect("[0]", "[1]", "[]"); + DoTestSelect("[1]", "[null,1]", "[null]"); + DoTestSelect("foo/[0]/bar", "{foo:[{bar:1}]}", "{foo:[{}]}"); + DoTestSelect("foo/1/bar", "{foo:[null,{bar:1}]}", "{foo:[null,{}]}"); + DoTestSelect("foo[-1]bar", "{foo:{'-1':{bar:1}}}", "{foo:{'-1':{}}}"); + DoTestSelect("'foo'/\"0\"/'bar'", "{foo:{'0':{bar:1}}}", "{foo:{'0':{}}}"); + DoTestSelect("'\\''", "{'\\'':1}", "{}"); + } + + Y_UNIT_TEST(TestSelectAndMerge) { + NSc::TValue v; + v.TrySelectOrAdd("blender/enabled")->MergeUpdateJson("1"); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::FromJson("1").ToJson(), "1"); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "{\"blender\":{\"enabled\":1}}"); + } + + Y_UNIT_TEST(TestPathEscapes) { + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a"), "a"); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath(""), R"=("")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("[]"), R"=("[]")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("[]ab"), R"=("[]ab")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a[]b"), R"=("a[]b")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("ab[]"), R"=("ab[]")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("[ab]"), R"=("[ab]")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("[ab"), R"=("[ab")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a[b"), R"=("a[b")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("ab["), R"=("ab[")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("]ab"), R"=("]ab")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a]b"), R"=("a]b")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("ab]"), R"=("ab]")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath(R"=(\)="), R"=("\\")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath(R"=(\\)="), R"=("\\\\")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("/"), R"=("/")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("//"), R"=("//")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("///"), R"=("///")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("/ab"), R"=("/ab")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a/b"), R"=("a/b")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("ab/"), R"=("ab/")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("//ab"), R"=("//ab")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a//b"), R"=("a//b")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("ab//"), R"=("ab//")="); + UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("6400"), R"=("6400")="); + + { + NSc::TValue val; + *val.TrySelectOrAdd("") = 100; + const TString res = R"=(100)="; + UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res); + } + { + NSc::TValue val; + *val.TrySelectOrAdd("a") = 100; + const TString res = R"=({"a":100})="; + UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res); + } + { + NSc::TValue val; + *val.TrySelectOrAdd(R"=(////)=") = 100; + const TString res = R"=(100)="; + UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res); + } + { + NSc::TValue val; + *val.TrySelectOrAdd(R"=()=") = 100; + const TString res = R"=(100)="; + UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res); + } + { + NSc::TValue val; + *val.TrySelectOrAdd(R"=("")=") = 100; + const TString res = R"=({"":100})="; + UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res); + } + { + NSc::TValue val; + *val.TrySelectOrAdd(R"=("[1]")=") = 100; + const TString res = R"=({"[1]":100})="; + UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res); + } + { + NSc::TValue val; + *val.TrySelectOrAdd(R"=("\"\"")=") = 100; + const TString res = R"=({"\"\"":100})="; + UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res); + } + { + NSc::TValue val; + *val.TrySelectOrAdd(R"=("/10/")=") = 100; + const TString res = R"=({"/10/":100})="; + UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res); + } + { + NSc::TValue val; + *val.TrySelectOrAdd(R"=(/"[10]"//""/"\"/10/\""///)=") = 100; + const TString res = R"=({"[10]":{"":{"\"/10/\"":100}}})="; + UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res); + } + { + NSc::TValue val; + *val.TrySelectOrAdd(R"=(/"[10]"//""/"\"/10/\""///)=") = 100; + const TString res = R"=({"[10]":{"":{"\"/10/\"":100}}})="; + UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res); + } + } +}; diff --git a/library/cpp/scheme/tests/ut/scheme_proto_ut.cpp b/library/cpp/scheme/tests/ut/scheme_proto_ut.cpp new file mode 100644 index 0000000000..e711a0d092 --- /dev/null +++ b/library/cpp/scheme/tests/ut/scheme_proto_ut.cpp @@ -0,0 +1,220 @@ +#include <library/cpp/protobuf/util/is_equal.h> +#include <library/cpp/scheme/scheme.h> +#include <library/cpp/scheme/tests/ut/scheme_ut.pb.h> +#include <library/cpp/testing/unittest/registar.h> + +Y_UNIT_TEST_SUITE(TSchemeProtoTest) { + void DoTestProtobuf(bool fromProto, bool mapAsDict); + + Y_UNIT_TEST(TestFromProtobuf) { + DoTestProtobuf(true, false); + } + + Y_UNIT_TEST(TestToProtobuf) { + DoTestProtobuf(false, false); + } + + Y_UNIT_TEST(TestFromProtobufWithDict) { + DoTestProtobuf(true, true); + } + + Y_UNIT_TEST(TestToProtobufWithDict) { + DoTestProtobuf(false, true); + } + + template <class T> + void AddMapPair(NSc::TValue& v, TStringBuf key, T value, bool mapAsDict) { + if (mapAsDict) { + v[key] = value; + } else { + auto& newElement = v.Push(); + newElement["key"] = key; + newElement["value"] = value; + } + } + + void DoTestProtobuf(bool fromProto, bool mapAsDict) { + NSc::TMessage m; + NSc::TValue v; + m.SetDouble((double)1 / 3), v["Double"] = (double)1 / 3; + m.SetFloat((float)1 / 3), v["Float"] = (float)1 / 3; + m.SetInt32(1000000), v["Int32"] = 1000000; + m.SetInt64(1000000000000LL), v["Int64"] = 1000000000000LL; + m.SetUInt32(555555), v["UInt32"] = 555555; + m.SetUInt64(555555555555LL), v["UInt64"] = 555555555555LL; + m.SetSInt32(-555555), v["SInt32"] = -555555; + m.SetSInt64(-555555555555LL), v["SInt64"] = -555555555555LL; + m.SetFixed32(123456), v["Fixed32"] = 123456; + m.SetFixed64(123456123456LL), v["Fixed64"] = 123456123456LL; + m.SetSFixed32(-123456), v["SFixed32"] = -123456; + m.SetSFixed64(-123456123456LL), v["SFixed64"] = -123456123456LL; + m.SetBool(true), v["Bool"] = true; + m.SetString("String"), v["String"] = "String"; + m.SetBytes("Bytes"), v["Bytes"] = "Bytes"; + m.SetEnum(NSc::VALUE1), v["Enum"] = "VALUE1"; + + auto& mapDoublesP = *m.mutable_mapdoubles(); + auto& mapDoublesV = v["MapDoubles"]; + mapDoublesP["pi"] = 3.14; + AddMapPair(mapDoublesV, "pi", 3.14, mapAsDict); + if (fromProto && mapAsDict) { + // can not add two entries in dict, as it represent over array with unstable order + mapDoublesP["back_e"] = 1 / 2.7; + AddMapPair(mapDoublesV, "back_e", 1 / 2.7, mapAsDict); + } + + auto& mapInt32sP = *m.mutable_mapint32s(); + auto& mapInt32sV = v["MapInt32s"]; + mapInt32sP["pi"] = -7; + AddMapPair(mapInt32sV, "pi", -7, mapAsDict); + if (fromProto && mapAsDict) { + // can not add two entries in dict, as it represent over array with unstable order + mapInt32sP["back_e"] = 42; + AddMapPair(mapInt32sV, "back_e", 42, mapAsDict); + } + + auto& mapStringP = *m.mutable_mapstring(); + auto& mapStringV = v["MapString"]; + mapStringP["intro"] = "body"; + AddMapPair(mapStringV, "intro", "body", mapAsDict); + if (fromProto && mapAsDict) { + // can not add two entries in dict, as it represent over array with unstable order + mapStringP["deep"] = "blue"; + AddMapPair(mapStringV, "deep", "blue", mapAsDict); + } + + m.AddDoubles((double)1 / 3), v["Doubles"][0] = (double)1 / 3; + m.AddDoubles((double)1 / 4), v["Doubles"][1] = (double)1 / 4; + + m.AddFloats((float)1 / 3), v["Floats"][0] = (float)1 / 3; + m.AddFloats((float)1 / 4), v["Floats"][1] = (float)1 / 4; + + m.AddInt32s(1000000), v["Int32s"][0] = 1000000; + m.AddInt32s(2000000), v["Int32s"][1] = 2000000; + + m.AddInt64s(1000000000000LL), v["Int64s"][0] = 1000000000000LL; + m.AddInt64s(2000000000000LL), v["Int64s"][1] = 2000000000000LL; + + m.AddUInt32s(555555), v["UInt32s"][0] = 555555; + m.AddUInt32s(655555), v["UInt32s"][1] = 655555; + + m.AddUInt64s(555555555555LL); + v["UInt64s"][0] = 555555555555LL; + m.AddUInt64s(655555555555LL); + v["UInt64s"][1] = 655555555555LL; + + m.AddSInt32s(-555555), v["SInt32s"][0] = -555555; + m.AddSInt32s(-655555), v["SInt32s"][1] = -655555; + + m.AddSInt64s(-555555555555LL), v["SInt64s"][0] = -555555555555LL; + m.AddSInt64s(-655555555555LL), v["SInt64s"][1] = -655555555555LL; + + m.AddFixed32s(123456), v["Fixed32s"][0] = 123456; + m.AddFixed32s(223456), v["Fixed32s"][1] = 223456; + + m.AddFixed64s(123456123456LL), v["Fixed64s"][0] = 123456123456LL; + m.AddFixed64s(223456123456LL), v["Fixed64s"][1] = 223456123456LL; + + m.AddSFixed32s(-123456), v["SFixed32s"][0] = -123456; + m.AddSFixed32s(-223456), v["SFixed32s"][1] = -223456; + + m.AddSFixed64s(-123456123456LL), v["SFixed64s"][0] = -123456123456LL; + m.AddSFixed64s(-223456123456LL), v["SFixed64s"][1] = -223456123456LL; + + m.AddBools(false), v["Bools"][0] = false; + m.AddBools(true), v["Bools"][1] = true; + + m.AddStrings("String1"), v["Strings"][0] = "String1"; + m.AddStrings("String2"), v["Strings"][1] = "String2"; + + m.AddBytess("Bytes1"), v["Bytess"][0] = "Bytes1"; + m.AddBytess("Bytes2"), v["Bytess"][1] = "Bytes2"; + + m.AddEnums(NSc::VALUE1), v["Enums"][0] = "VALUE1"; + m.AddEnums(NSc::VALUE2), v["Enums"][1] = "VALUE2"; + + NSc::TMessage2 m2; + NSc::TValue v2; + m2.SetDouble((double)1 / 3), v2["Double"] = (double)1 / 3; + m2.SetFloat((float)1 / 3), v2["Float"] = (float)1 / 3; + m2.SetInt32(1000000), v2["Int32"] = 1000000; + m2.SetInt64(1000000000000LL), v2["Int64"] = 1000000000000LL; + m2.SetUInt32(555555), v2["UInt32"] = 555555; + m2.SetUInt64(555555555555LL), v2["UInt64"] = 555555555555LL; + m2.SetSInt32(-555555), v2["SInt32"] = -555555; + m2.SetSInt64(-555555555555LL), v2["SInt64"] = -555555555555LL; + m2.SetFixed32(123456), v2["Fixed32"] = 123456; + m2.SetFixed64(123456123456LL), v2["Fixed64"] = 123456123456LL; + m2.SetSFixed32(-123456), v2["SFixed32"] = -123456; + m2.SetSFixed64(-123456123456LL), v2["SFixed64"] = -123456123456LL; + m2.SetBool(true), v2["Bool"] = true; + m2.SetString("String"), v2["String"] = "String"; + m2.SetBytes("Bytes"), v2["Bytes"] = "Bytes"; + m2.SetEnum(NSc::VALUE1), v2["Enum"] = "VALUE1"; + + m2.AddDoubles((double)1 / 3), v2["Doubles"][0] = (double)1 / 3; + m2.AddDoubles((double)1 / 4), v2["Doubles"][1] = (double)1 / 4; + + m2.AddFloats((float)1 / 3), v2["Floats"][0] = (float)1 / 3; + m2.AddFloats((float)1 / 4), v2["Floats"][1] = (float)1 / 4; + + m2.AddInt32s(1000000), v2["Int32s"][0] = 1000000; + m2.AddInt32s(2000000), v2["Int32s"][1] = 2000000; + + m2.AddInt64s(1000000000000LL), v2["Int64s"][0] = 1000000000000LL; + m2.AddInt64s(2000000000000LL), v2["Int64s"][1] = 2000000000000LL; + + m2.AddUInt32s(555555), v2["UInt32s"][0] = 555555; + m2.AddUInt32s(655555), v2["UInt32s"][1] = 655555; + + m2.AddUInt64s(555555555555LL); + v2["UInt64s"][0] = 555555555555LL; + m2.AddUInt64s(655555555555LL); + v2["UInt64s"][1] = 655555555555LL; + + m2.AddSInt32s(-555555), v2["SInt32s"][0] = -555555; + m2.AddSInt32s(-655555), v2["SInt32s"][1] = -655555; + + m2.AddSInt64s(-555555555555LL), v2["SInt64s"][0] = -555555555555LL; + m2.AddSInt64s(-655555555555LL), v2["SInt64s"][1] = -655555555555LL; + + m2.AddFixed32s(123456), v2["Fixed32s"][0] = 123456; + m2.AddFixed32s(223456), v2["Fixed32s"][1] = 223456; + + m2.AddFixed64s(123456123456LL), v2["Fixed64s"][0] = 123456123456LL; + m2.AddFixed64s(223456123456LL), v2["Fixed64s"][1] = 223456123456LL; + + m2.AddSFixed32s(-123456), v2["SFixed32s"][0] = -123456; + m2.AddSFixed32s(-223456), v2["SFixed32s"][1] = -223456; + + m2.AddSFixed64s(-123456123456LL), v2["SFixed64s"][0] = -123456123456LL; + m2.AddSFixed64s(-223456123456LL), v2["SFixed64s"][1] = -223456123456LL; + + m2.AddBools(false), v2["Bools"][0] = false; + m2.AddBools(true), v2["Bools"][1] = true; + + m2.AddStrings("String1"), v2["Strings"][0] = "String1"; + m2.AddStrings("String2"), v2["Strings"][1] = "String2"; + + m2.AddBytess("Bytes1"), v2["Bytess"][0] = "Bytes1"; + m2.AddBytess("Bytes2"), v2["Bytess"][1] = "Bytes2"; + + m2.AddEnums(NSc::VALUE1), v2["Enums"][0] = "VALUE1"; + m2.AddEnums(NSc::VALUE2), v2["Enums"][1] = "VALUE2"; + + *(m.MutableMessage()) = m2, v["Message"] = v2; + + *(m.AddMessages()) = m2, v["Messages"][0] = v2; + *(m.AddMessages()) = m2, v["Messages"][1] = v2; + + if (fromProto) { + UNIT_ASSERT(NSc::TValue::Equal(v, NSc::TValue::From(m, mapAsDict))); + } else { + NSc::TMessage proto; + v.To(proto); + + TString differentPath; + UNIT_ASSERT_C(NProtoBuf::IsEqual(m, proto, &differentPath), differentPath); + } + } +}; diff --git a/library/cpp/scheme/tests/ut/scheme_ut.cpp b/library/cpp/scheme/tests/ut/scheme_ut.cpp new file mode 100644 index 0000000000..1a5d07c31b --- /dev/null +++ b/library/cpp/scheme/tests/ut/scheme_ut.cpp @@ -0,0 +1,879 @@ +#include <library/cpp/scheme/scimpl_private.h> +#include <library/cpp/scheme/ut_utils/scheme_ut_utils.h> +#include <library/cpp/testing/unittest/registar.h> + +#include <util/stream/null.h> +#include <library/cpp/string_utils/quote/quote.h> +#include <util/string/subst.h> +#include <util/string/util.h> + +#include <type_traits> + +Y_UNIT_TEST_SUITE(TSchemeTest) { + + Y_UNIT_TEST(TestNaN) { + UNIT_ASSERT_VALUES_EQUAL("null", NSc::TValue(std::numeric_limits<double>::quiet_NaN()).ToJson()); + UNIT_ASSERT_VALUES_EQUAL("null", NSc::TValue(-std::numeric_limits<double>::infinity()).ToJson()); + UNIT_ASSERT_VALUES_EQUAL("null", NSc::TValue(std::numeric_limits<double>::infinity()).ToJson()); + UNIT_ASSERT_VALUES_EQUAL("1", NSc::TValue(1.0).ToJson()); + } + + Y_UNIT_TEST(TestNumbers) { + { + NSc::TValue vd; + UNIT_ASSERT_VALUES_EQUAL(2.5, vd.GetNumberMutable(2.5)); + UNIT_ASSERT_VALUES_EQUAL(2, vd.GetIntNumberMutable(-1)); + } + { + NSc::TValue vi; + UNIT_ASSERT_VALUES_EQUAL(2, vi.GetIntNumberMutable(2)); + UNIT_ASSERT_VALUES_EQUAL(2., vi.GetNumberMutable(-1)); + } + { + NSc::TValue vb = NSc::TValue::FromJson("true"); + + UNIT_ASSERT_VALUES_EQUAL("true", vb.ToJson()); + + UNIT_ASSERT(vb.IsBool()); + UNIT_ASSERT(vb.IsIntNumber()); + UNIT_ASSERT(vb.IsNumber()); + UNIT_ASSERT_VALUES_EQUAL(true, vb.GetBool()); + UNIT_ASSERT_VALUES_EQUAL(1, vb.GetIntNumber()); + UNIT_ASSERT_VALUES_EQUAL(1.0, vb.GetNumber()); + + NSc::TValue vb1 = vb.Clone(); + + UNIT_ASSERT(NSc::TValue::Equal(vb, vb1)); + + UNIT_ASSERT_VALUES_EQUAL(true, vb.GetBool()); + UNIT_ASSERT_VALUES_EQUAL(1, vb.GetIntNumber()); + UNIT_ASSERT_VALUES_EQUAL(1.0, vb.GetNumber()); + UNIT_ASSERT(vb.IsBool()); + UNIT_ASSERT_VALUES_EQUAL(1, vb.GetIntNumberMutable()); + UNIT_ASSERT(!vb.IsBool()); + + UNIT_ASSERT(NSc::TValue::Equal(vb, vb1)); + + UNIT_ASSERT(vb1.IsBool()); + UNIT_ASSERT_VALUES_EQUAL(1.0, vb1.GetNumberMutable()); + UNIT_ASSERT(!vb1.IsBool()); + + vb.SetBool(true); + + UNIT_ASSERT(vb.IsBool()); + UNIT_ASSERT(NSc::TValue::Equal(vb, vb1)); + + vb = NSc::TValue::FromJson("false"); + + UNIT_ASSERT_VALUES_EQUAL("false", vb.ToJson()); + UNIT_ASSERT(!NSc::TValue::Equal(vb, vb1)); + + UNIT_ASSERT(vb.IsBool()); + UNIT_ASSERT(vb.IsIntNumber()); + UNIT_ASSERT(vb.IsNumber()); + UNIT_ASSERT_VALUES_EQUAL(false, vb.GetBool()); + UNIT_ASSERT_VALUES_EQUAL(0.0, vb.GetNumber()); + UNIT_ASSERT_VALUES_EQUAL(0, vb.GetIntNumber()); + + NSc::TValue vd = NSc::TValue::FromJson("1.0"); + + UNIT_ASSERT(vd.IsNumber()); + UNIT_ASSERT(!vd.IsIntNumber()); + UNIT_ASSERT_VALUES_EQUAL(1.0, vd.GetNumber()); + UNIT_ASSERT_VALUES_EQUAL(1, vd.GetIntNumber()); + UNIT_ASSERT_VALUES_EQUAL(1.0, vd.GetNumberMutable()); + + NSc::TValue vi = NSc::TValue::FromJson("1"); + + UNIT_ASSERT(vi.IsNumber()); + UNIT_ASSERT(vi.IsIntNumber()); + UNIT_ASSERT_VALUES_EQUAL(1.0, vi.GetNumber()); + UNIT_ASSERT_VALUES_EQUAL(1, vi.GetIntNumber()); + UNIT_ASSERT_VALUES_EQUAL(1, vi.GetIntNumberMutable()); + + UNIT_ASSERT(NSc::TValue::Equal(vd, vi)); + + vd.SetNumber(1.5); + UNIT_ASSERT(vd.IsNumber()); + UNIT_ASSERT(!vd.IsIntNumber()); + UNIT_ASSERT_VALUES_EQUAL(1.5, vd.GetNumber()); + UNIT_ASSERT_VALUES_EQUAL(1, vd.GetIntNumber()); + UNIT_ASSERT_VALUES_EQUAL(1.5, vd.GetNumberMutable()); + + UNIT_ASSERT(!NSc::TValue::Equal(vd, vi)); + + UNIT_ASSERT_VALUES_EQUAL("1", vi.ToJson()); + UNIT_ASSERT_VALUES_EQUAL("1.5", vd.ToJson()); + + UNIT_ASSERT_VALUES_EQUAL(1, vd.GetIntNumberMutable()); + UNIT_ASSERT(NSc::TValue::Equal(vd, vi)); + vd.SetIntNumber(2); + UNIT_ASSERT(!NSc::TValue::Equal(vd, vi)); + vi.SetNumber(2.); + UNIT_ASSERT(NSc::TValue::Equal(vd, vi)); + vd.SetNumber(2.); + UNIT_ASSERT(NSc::TValue::Equal(vd, vi)); + vi.SetIntNumber(5); + vd.MergeUpdate(vi); + UNIT_ASSERT(vd.IsNumber()); + UNIT_ASSERT(vd.IsIntNumber()); + UNIT_ASSERT_VALUES_EQUAL(5, vd.GetIntNumber()); + vd.SetNumber(3.3); + vi.MergeUpdate(vd); + UNIT_ASSERT(vi.IsNumber()); + UNIT_ASSERT(!vi.IsIntNumber()); + UNIT_ASSERT_VALUES_EQUAL(3.3, vi.GetNumber()); + + vi.SetIntNumber(Max<i64>()); + UNIT_ASSERT_VALUES_EQUAL("9223372036854775807", vi.ToJson()); + } + } + + template <typename T> + void DoTestForce(T t) { + UNIT_ASSERT_VALUES_EQUAL_C(i64(t), NSc::TValue(i64(t)).ForceIntNumber(), ToString(t)); + UNIT_ASSERT_VALUES_EQUAL_C(double(t), NSc::TValue(double(t)).ForceNumber(), ToString(t)); + + UNIT_ASSERT_VALUES_EQUAL_C(i64(t), NSc::TValue(TStringBuf(ToString(i64(t)))).ForceIntNumber(), ToString(t)); + UNIT_ASSERT_VALUES_EQUAL_C(ToString(double(t)), ToString(NSc::TValue(TStringBuf(ToString(double(t)))).ForceNumber()), ToString(t)); + + UNIT_ASSERT_VALUES_EQUAL_C(ToString(i64(t)), NSc::TValue(TStringBuf(ToString(i64(t)))).ForceString(), ToString(t)); + UNIT_ASSERT_VALUES_EQUAL_C(ToString(double(t)), NSc::TValue(TStringBuf(ToString(double(t)))).ForceString(), ToString(t)); + } + + Y_UNIT_TEST(TestForce) { + DoTestForce(Max<i64>()); + DoTestForce(Min<i64>()); + DoTestForce(1.5); + DoTestForce(-1.5); + + UNIT_ASSERT_VALUES_EQUAL(1, NSc::TValue("32a").ForceIntNumber(1)); + UNIT_ASSERT_VALUES_EQUAL(1.5, NSc::TValue("32a").ForceNumber(1.5)); + } + + template <typename T> + void DoCheckRelations(T t, T tless, T tmore, const NSc::TValue& v, TStringBuf ss) { + UNIT_ASSERT_C((t == v), ss); + UNIT_ASSERT_C(!(t != v), ss); + UNIT_ASSERT_C((t <= v), ss); + UNIT_ASSERT_C((t >= v), ss); + UNIT_ASSERT_C(!(t < v), ss); + UNIT_ASSERT_C(!(t > v), ss); + + UNIT_ASSERT_C(!(tless == v), ss); + UNIT_ASSERT_C((tless != v), ss); + UNIT_ASSERT_C((tless <= v), ss); + UNIT_ASSERT_C(!(tless >= v), ss); + UNIT_ASSERT_C((tless < v), ss); + UNIT_ASSERT_C(!(tless > v), ss); + UNIT_ASSERT_C(!(tmore == v), ss); + UNIT_ASSERT_C((tmore != v), ss); + UNIT_ASSERT_C(!(tmore <= v), ss); + UNIT_ASSERT_C((tmore >= v), ss); + UNIT_ASSERT_C(!(tmore < v), ss); + UNIT_ASSERT_C((tmore > v), ss); + } + + void DoCheckRelations(const NSc::TValue& t, const NSc::TValue&, const NSc::TValue&, const NSc::TValue& v, TStringBuf ss) { + UNIT_ASSERT_C((t == v), ss); + UNIT_ASSERT_C(!(t != v), ss); + } + + // void DoCheckRelations(bool t, bool, bool, const NSc::TValue& v, TStringBuf ss) { + // UNIT_ASSERT_C((t == v), ss); + // UNIT_ASSERT_C(!(t != v), ss); + // } + + template <typename T> + void DoCheckAssignment(T t, T tless, T tmore, TStringBuf s, TStringBuf ss) { + bool expectint = std::is_integral<T>::value; + bool expectnum = std::is_arithmetic<T>::value; + bool expectbool = std::is_same<bool, T>::value; + + { + NSc::TValue v(t); + UNIT_ASSERT_VALUES_EQUAL_C(expectnum, v.IsNumber(), ss); + UNIT_ASSERT_VALUES_EQUAL_C(expectint, v.IsIntNumber(), ss); + UNIT_ASSERT_VALUES_EQUAL_C(expectbool, v.IsBool(), ss); + UNIT_ASSERT_VALUES_EQUAL_C(s, v.ToJson(), ss); + DoCheckRelations(t, tless, tmore, v, ss); + } + { + NSc::TValue v; + UNIT_ASSERT(v.IsNull()); + v = t; + UNIT_ASSERT(!v.IsNull()); + UNIT_ASSERT_VALUES_EQUAL_C(expectnum, v.IsNumber(), ss); + UNIT_ASSERT_VALUES_EQUAL_C(expectint, v.IsIntNumber(), ss); + UNIT_ASSERT_VALUES_EQUAL_C(expectbool, v.IsBool(), ss); + UNIT_ASSERT_VALUES_EQUAL_C(s, v.ToJson(), ss); + DoCheckRelations(t, tless, tmore, v, ss); + } + } + + template <size_t N> + void DoCheckAssignmentArr(const char (&t)[N], const char (&tless)[N], const char (&tmore)[N], TStringBuf s, TStringBuf ss) { + { + NSc::TValue v(t); + + UNIT_ASSERT_C(v.IsString(), ss); + UNIT_ASSERT_VALUES_EQUAL_C(s, v.ToJson(), ss); + DoCheckRelations(t, tless, tmore, v, ss); + } + { + NSc::TValue v; + v = t; + UNIT_ASSERT_C(v.IsString(), ss); + UNIT_ASSERT_VALUES_EQUAL_C(s, v.ToJson(), ss); + DoCheckRelations(t, tless, tmore, v, ss); + } + } + + template <typename T> + void DoCheckAssignmentNum(T t, T tless, T tmore, TStringBuf s, TStringBuf ss) { + DoCheckAssignment(t, tless, tmore, s, ss); + { + NSc::TValue v; + T tt = (v = t); + UNIT_ASSERT_VALUES_EQUAL_C(t, tt, ss); + } + } + + Y_UNIT_TEST(TestAssignments) { + for (int i = -2; i < 3; ++i) { + TString ii = ToString(i); + int iless = i - 1; + int imore = i + 1; + DoCheckAssignmentNum<signed char>(i, iless, imore, ii, "schar"); + DoCheckAssignmentNum<short>(i, iless, imore, ii, "short"); + DoCheckAssignmentNum<int>(i, iless, imore, ii, "int"); + DoCheckAssignmentNum<long>(i, iless, imore, ii, "long"); + DoCheckAssignmentNum<long long>(i, iless, imore, ii, "longlong"); + DoCheckAssignmentNum<i8>(i, iless, imore, ii, "i8"); + DoCheckAssignmentNum<i16>(i, iless, imore, ii, "i16"); + DoCheckAssignmentNum<i32>(i, iless, imore, ii, "i32"); + DoCheckAssignmentNum<i64>(i, iless, imore, ii, "i64"); + + DoCheckAssignmentNum<float>(i, iless, imore, ii, "float"); + DoCheckAssignmentNum<double>(i, iless, imore, ii, "double"); + } + + // DoCheckAssignment<bool>(true, true, true, "true", "bool"); + // DoCheckAssignment<bool>(false, false, false, "false", "bool"); + + for (int i = 1; i < 3; ++i) { + TString ii = ToString(i); + int iless = i - 1; + int imore = i + 1; + + DoCheckAssignmentNum<char>(i, iless, imore, ii, "char"); + + DoCheckAssignmentNum<signed char>(i, iless, imore, ii, "schar"); + DoCheckAssignmentNum<short>(i, iless, imore, ii, "short"); + DoCheckAssignmentNum<int>(i, iless, imore, ii, "int"); + DoCheckAssignmentNum<long>(i, iless, imore, ii, "long"); + DoCheckAssignmentNum<long long>(i, iless, imore, ii, "longlong"); + DoCheckAssignmentNum<i8>(i, iless, imore, ii, "i8"); + DoCheckAssignmentNum<i16>(i, iless, imore, ii, "i16"); + DoCheckAssignmentNum<i32>(i, iless, imore, ii, "i32"); + DoCheckAssignmentNum<i64>(i, iless, imore, ii, "i64"); + + DoCheckAssignmentNum<unsigned char>(i, iless, imore, ii, "uchar"); + DoCheckAssignmentNum<unsigned short>(i, iless, imore, ii, "ushort"); + DoCheckAssignmentNum<unsigned int>(i, iless, imore, ii, "uint"); + DoCheckAssignmentNum<unsigned long>(i, iless, imore, ii, "ulong"); + DoCheckAssignmentNum<unsigned long long>(i, iless, imore, ii, "ulonglong"); + DoCheckAssignmentNum<ui8>(i, iless, imore, ii, "ui8"); + DoCheckAssignmentNum<ui16>(i, iless, imore, ii, "ui16"); + DoCheckAssignmentNum<ui32>(i, iless, imore, ii, "ui32"); + DoCheckAssignmentNum<ui64>(i, iless, imore, ii, "ui64"); + + DoCheckAssignmentNum<float>(i, iless, imore, ii, "float"); + DoCheckAssignmentNum<double>(i, iless, imore, ii, "double"); + } + + TString uuu = "uuu"; + TString uua = "uua"; + TString uuz = "uuz"; + DoCheckAssignment<char*>(uuu.begin(), uua.begin(), uuz.begin(), "\"uuu\"", "char*"); + DoCheckAssignment<const char*>("www", "wwa", "wwz", "\"www\"", "const char*"); + DoCheckAssignmentArr("xxx", "xxa", "xxz", "\"xxx\"", "const char[]"); + DoCheckAssignment<TStringBuf>("yyy", "yya", "yyz", "\"yyy\"", "TStringBuf"); + +#if defined(_MSC_VER) + //TODO +#else + DoCheckAssignment<TString>("ttt", "tta", "ttz", "\"ttt\"", "TString"); +#endif + + NSc::TValue v; + v.SetDict(); + DoCheckAssignment<NSc::TValue>(v, v, v, "{}", "TValue"); + DoCheckAssignment<NSc::TValue&>(v, v, v, "{}", "TValue&"); + DoCheckAssignment<const NSc::TValue&>(v, v, v, "{}", "const TValue&"); + + NSc::TValue v1{1}; + UNIT_ASSERT_VALUES_EQUAL(v1.ToJson(), "1"); + } + + Y_UNIT_TEST(TestAssignmentDictChild) { + { + NSc::TValue v; + { + NSc::TValue b; + v["a"] = b; + } + v = v["a"]; + } + { + NSc::TValue v; + { + NSc::TValue b; + v["a"] = b; + } + v = v.Get("a"); + } + { + NSc::TValue v; + { + NSc::TValue b; + v["a"] = b; + } + v = std::move(v["a"]); + } + } + + Y_UNIT_TEST(TestInsert) { + NSc::TValue v; + v.Insert(0, "b"); + v.Insert(0, "a"); + v.Insert(2, "d"); + v.Insert(2, "c"); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), R"(["a","b","c","d"])"); + + v.AppendAll({1, 2, 3}); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), R"(["a","b","c","d",1,2,3])"); + + TVector<int> d{4, 5, 6}; + v.AppendAll(d); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), R"(["a","b","c","d",1,2,3,4,5,6])"); + UNIT_ASSERT_VALUES_EQUAL(d.size(), 3u); + TVector<TStringBuf> s{"x", "y", "z"}; + v.AppendAll(s.begin(), s.end()); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), R"(["a","b","c","d",1,2,3,4,5,6,"x","y","z"])"); + + UNIT_ASSERT_VALUES_EQUAL(v.Clone().Clear().AppendAll(s).ToJson(), R"(["x","y","z"])"); + UNIT_ASSERT_VALUES_EQUAL(v.Clone().Clear().AppendAll(TVector<TStringBuf>()).ToJson(), R"([])"); + + v.AddAll({{"a", "b"}, {"c", "d"}}); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), R"({"a":"b","c":"d"})"); + } + + Y_UNIT_TEST(TestFrontBack) { + NSc::TValue v; + const NSc::TValue& vv = v; + UNIT_ASSERT(NSc::TValue::Same(vv.Front(), NSc::Null())); + UNIT_ASSERT(NSc::TValue::Same(vv.Back(), NSc::Null())); + UNIT_ASSERT(!vv.IsArray()); + v.Back() = "a"; + UNIT_ASSERT_VALUES_EQUAL("a", vv.Front().GetString()); + UNIT_ASSERT_VALUES_EQUAL("a", vv.Back().GetString()); + UNIT_ASSERT(vv.IsArray()); + v.Push("b"); + UNIT_ASSERT_VALUES_EQUAL("a", vv.Front().GetString()); + UNIT_ASSERT_VALUES_EQUAL("b", vv.Back().GetString()); + + UNIT_ASSERT_VALUES_EQUAL("b", v.Pop().GetString()); + + UNIT_ASSERT_VALUES_EQUAL("a", vv.Front().GetString()); + UNIT_ASSERT_VALUES_EQUAL("a", vv.Back().GetString()); + + UNIT_ASSERT_VALUES_EQUAL("a", v.Pop().GetString()); + + UNIT_ASSERT(NSc::TValue::Same(vv.Front(), NSc::Null())); + UNIT_ASSERT(NSc::TValue::Same(vv.Back(), NSc::Null())); + + v.Front() = "a"; + UNIT_ASSERT_VALUES_EQUAL("a", vv.Front().GetString()); + UNIT_ASSERT_VALUES_EQUAL("a", vv.Back().GetString()); + } + + Y_UNIT_TEST(TestAssign) { + NSc::TValue v; + v.SetArray(); + v.Push() = "test"; + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "[\"test\"]"); + UNIT_ASSERT(NSc::TValue::SamePool(v[0], v)); + } + + NSc::TValue MutableRef(const NSc::TValue& v) { + return v; + } + + NSc::TValue Clone(const NSc::TValue& v) { + NSc::TValue v1 = v.Clone(); + UNIT_ASSERT_VALUES_EQUAL(v1.ToJson(true), v.ToJson(true)); + return v1; + } + + Y_UNIT_TEST(TestCOW) { + NSc::TValue vd = NSc::TValue::FromJson("{ a : 1, b : c}"); + NSc::TValue va = NSc::TValue::FromJson("[ x, y]"); + NSc::TValue vs = NSc::TValue::FromJson("foo"); + NSc::TValue vn = NSc::TValue::FromJson("1"); + TString sd = "{\"a\":1,\"b\":\"c\"}"; + TString sa = "[\"x\",\"y\"]"; + TString ss = "\"foo\""; + TString sn = "1"; + UNIT_ASSERT_VALUES_EQUAL(sd, vd.ToJson(true)); + UNIT_ASSERT_VALUES_EQUAL(sa, va.ToJson(true)); + UNIT_ASSERT_VALUES_EQUAL(ss, vs.ToJson(true)); + UNIT_ASSERT_VALUES_EQUAL(sn, vn.ToJson(true)); + + { + NSc::TValue v2 = MutableRef(vn); + v2 = -1; + + UNIT_ASSERT_VALUES_EQUAL(sn, vn.ToJson(true)); + + NSc::TValue v3 = Clone(vn); + v3 = -1; + + UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true)); + } + + { + NSc::TValue v2 = MutableRef(vs); + v2 = "xxx"; + + UNIT_ASSERT_VALUES_EQUAL(ss, vs.ToJson(true)); + + NSc::TValue v3 = Clone(vs); + v3 = "xxx"; + + UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true)); + } + + { + NSc::TValue v2 = MutableRef(vd); + v2["a"] = "zzz"; + + UNIT_ASSERT_VALUES_EQUAL(sd, vd.ToJson(true)); + + NSc::TValue v3 = Clone(vd); + v3["a"] = "zzz"; + + UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true)); + } + + { + NSc::TValue v2 = MutableRef(va); + v2[0] = "zzz"; + + UNIT_ASSERT_VALUES_EQUAL(sa, va.ToJson(true)); + + NSc::TValue v3 = Clone(va); + v3[0] = "zzz"; + + UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true)); + } + + { + NSc::TValue v2 = MutableRef(va); + + UNIT_ASSERT_VALUES_EQUAL(sa, va.ToJson(true)); + + NSc::TValue v3 = Clone(va); + + UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true)); + } + + { + NSc::TValue v2 = MutableRef(va); + v2.ClearArray(); + + UNIT_ASSERT_VALUES_EQUAL(sa, va.ToJson(true)); + + NSc::TValue v3 = Clone(va); + v3.ClearArray(); + + UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true)); + } + } + + Y_UNIT_TEST(TestOperators) { + UNIT_ASSERT("test" == NSc::TValue("test")); + UNIT_ASSERT(NSc::TValue("test") == "test"); + + UNIT_ASSERT("test1" != NSc::TValue("test")); + UNIT_ASSERT(NSc::TValue("test") != "test1"); + + UNIT_ASSERT("test1" > NSc::TValue("test")); + UNIT_ASSERT(NSc::TValue("test") < "test1"); + + UNIT_ASSERT("test" < NSc::TValue("test1")); + UNIT_ASSERT(NSc::TValue("test1") > "test"); + + UNIT_ASSERT(1 == NSc::TValue(1)); + UNIT_ASSERT(NSc::TValue(1) == 1); + + UNIT_ASSERT(2 != NSc::TValue(1)); + UNIT_ASSERT(NSc::TValue(1) != 2); + + UNIT_ASSERT(1 < NSc::TValue(2)); + UNIT_ASSERT(NSc::TValue(2) > 1); + + UNIT_ASSERT(2 > NSc::TValue(1)); + UNIT_ASSERT(NSc::TValue(1) < 2); + + UNIT_ASSERT(TString("test") == NSc::TValue("test")); + } + + Y_UNIT_TEST(TestDestructor) { + NSc::TValue v; + const NSc::TValue& v1 = v; + v1.GetString(); + v1.GetArray(); + v1.GetNumber(); + v1.GetDict(); + v.GetString(); + v.GetArray(); + v.GetNumber(); + v.GetDict(); + } + + void DoTestSamePool(TStringBuf json, TStringBuf jpath) { + NSc::TValue v = NSc::TValue::FromJson(json); + UNIT_ASSERT_C(NSc::TValue::SamePool(v, v.TrySelect(jpath)), json); + } + + Y_UNIT_TEST(TestSamePool) { + DoTestSamePool("", ""); + DoTestSamePool("a", ""); + DoTestSamePool("[a]", "0"); + DoTestSamePool("{a:b}", "a"); + DoTestSamePool("{a:{b:c}}", "a/b"); + DoTestSamePool("{a:{b:[c, {}]}}", "a/b/1"); + DoTestSamePool("{a:{b:[c, {d:{e:[]}}]}}", "a/b/1/d/e"); + UNIT_ASSERT(!NSc::TValue::SamePool(NSc::TValue(), NSc::TValue())); + UNIT_ASSERT(!NSc::TValue::SamePool(NSc::Null().Clone(), NSc::Null())); + UNIT_ASSERT(!NSc::TValue::SamePool(NSc::TValue() = 0, NSc::TValue())); + UNIT_ASSERT(!NSc::TValue::SamePool(NSc::TValue::FromJson("a"), NSc::TValue::FromJson("a"))); + NSc::TValue v, vv; + v["x"] = vv; + UNIT_ASSERT(!NSc::TValue::SamePool(v, vv)); + UNIT_ASSERT(!NSc::TValue::SamePool(v, v["x"])); + v = vv; + UNIT_ASSERT(NSc::TValue::SamePool(v, vv)); + } + + Y_UNIT_TEST(TestLoopDetection) { + NSc::NImpl::GetTlsInstance<NSc::NImpl::TSelfLoopContext>().ReportingMode + = NSc::NImpl::TSelfLoopContext::EMode::Stderr; + + NSc::TValue x; + + x["a"]["x"] = x; + x["b"][0] = x; + + UNIT_ASSERT(x.IsSameOrAncestorOf(x)); + UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a"))); + UNIT_ASSERT(x.Get("a").IsSameOrAncestorOf(x)); + + UNIT_ASSERT_VALUES_EQUAL(x.ToJson(), "{\"a\":{\"x\":null},\"b\":[null]}"); + + NSc::TValue y = x.Clone(); + + UNIT_ASSERT(y.Has("a")); + UNIT_ASSERT(y.Get("a").Has("x")); + UNIT_ASSERT(y.Get("a").Get("x").IsNull()); + UNIT_ASSERT(y.Get("a").Get("x").IsNull()); + + UNIT_ASSERT(y.Has("b")); + UNIT_ASSERT(y.Get("b").Has(0)); + UNIT_ASSERT(y.Get("b").Get(0).IsNull()); + + UNIT_ASSERT_VALUES_EQUAL(y.ToJson(), "{\"a\":{\"x\":null},\"b\":[null]}"); + + NSc::TValue z; + z.MergeUpdate(x); + + UNIT_ASSERT(z.Has("a")); + UNIT_ASSERT(z.Get("a").Has("x")); + UNIT_ASSERT(z.Get("a").Get("x").IsNull()); + + UNIT_ASSERT(z.Has("b")); + UNIT_ASSERT(z.Get("b").Has(0)); + UNIT_ASSERT(z.Get("b").Get(0).IsNull()); + + UNIT_ASSERT_VALUES_EQUAL(z.ToJson(), "{\"a\":{\"x\":null},\"b\":[null]}"); + + x["a"].Delete("x"); + x["b"].Delete(0); + + UNIT_ASSERT(x.IsSameOrAncestorOf(x)); + UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a"))); + UNIT_ASSERT(!x.Get("a").IsSameOrAncestorOf(x)); + } + + Y_UNIT_TEST(TestLoopDetectionThrow) { + NSc::NImpl::GetTlsInstance<NSc::NImpl::TSelfLoopContext>().ReportingMode + = NSc::NImpl::TSelfLoopContext::EMode::Throw; + + { + NSc::TValue x; + x["a"]["x"] = x; + + UNIT_ASSERT(x.IsSameOrAncestorOf(x)); + UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a"))); + UNIT_ASSERT(x.Get("a").IsSameOrAncestorOf(x)); + + UNIT_ASSERT_EXCEPTION(x.ToJson(), NSc::TSchemeException); + UNIT_ASSERT_EXCEPTION(x.Clone(), NSc::TSchemeException); + + NSc::TValue z; + UNIT_ASSERT_EXCEPTION(z.MergeUpdate(x), NSc::TSchemeException); + + UNIT_ASSERT_VALUES_EQUAL(z.ToJson(), "{\"a\":{\"x\":null}}"); + + x["a"].Delete("x"); + + UNIT_ASSERT(x.IsSameOrAncestorOf(x)); + UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a"))); + UNIT_ASSERT(!x.Get("a").IsSameOrAncestorOf(x)); + + UNIT_ASSERT_VALUES_EQUAL(x.ToJson(), "{\"a\":{}}"); + } + + { + NSc::TValue x; + x["a"][0] = x; + + UNIT_ASSERT(x.IsSameOrAncestorOf(x)); + UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a"))); + UNIT_ASSERT(x.Get("a").IsSameOrAncestorOf(x)); + + UNIT_ASSERT_EXCEPTION(x.ToJson(), NSc::TSchemeException); + UNIT_ASSERT_EXCEPTION(x.Clone(), NSc::TSchemeException); + + NSc::TValue z; + UNIT_ASSERT_EXCEPTION(z.MergeUpdate(x), NSc::TSchemeException); + + UNIT_ASSERT_VALUES_EQUAL(z.ToJson(), "{\"a\":[null]}"); + + x["a"].Delete(0); + + UNIT_ASSERT(x.IsSameOrAncestorOf(x)); + UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a"))); + UNIT_ASSERT(!x.Get("a").IsSameOrAncestorOf(x)); + + UNIT_ASSERT_VALUES_EQUAL(x.ToJson(), "{\"a\":[]}"); + } + } + + Y_UNIT_TEST(TestIsSameOrAncestorOf) { + NSc::TValue x; + UNIT_ASSERT(x.IsSameOrAncestorOf(x)); + + x["a"] = NSc::Null(); + UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a"))); + + NSc::TValue a = 1; + NSc::TValue b = 2; + NSc::TValue c = 3; + NSc::TValue d = 4; + + x["a"] = a; + x["b"] = b; + x["c"] = a; + UNIT_ASSERT(x.IsSameOrAncestorOf(a)); + UNIT_ASSERT(x.IsSameOrAncestorOf(b)); + UNIT_ASSERT(x.Get("a").IsSameOrAncestorOf(a)); + UNIT_ASSERT(x.Get("b").IsSameOrAncestorOf(b)); + UNIT_ASSERT(x.Get("c").IsSameOrAncestorOf(a)); + + UNIT_ASSERT(!x.Get("a").IsSameOrAncestorOf(b)); + UNIT_ASSERT(!x.Get("b").IsSameOrAncestorOf(a)); + + UNIT_ASSERT(!x.Get("a").Get(0).IsSameOrAncestorOf(a)); + + b.Push() = c; + b.Push() = d; + b.Push() = c; + + UNIT_ASSERT(x.Get("b").IsSameOrAncestorOf(b)); + UNIT_ASSERT(x.IsSameOrAncestorOf(c)); + UNIT_ASSERT(x.IsSameOrAncestorOf(d)); + UNIT_ASSERT(x.Get("b").Get(0).IsSameOrAncestorOf(c)); + UNIT_ASSERT(x.Get("b").Get(1).IsSameOrAncestorOf(d)); + UNIT_ASSERT(x.Get("b").Get(2).IsSameOrAncestorOf(c)); + + UNIT_ASSERT(b.Get(0).IsSameOrAncestorOf(b.Get(2))); + UNIT_ASSERT(b.Get(2).IsSameOrAncestorOf(b.Get(0))); + UNIT_ASSERT(b.Get(0).IsSameOrAncestorOf(c)); + UNIT_ASSERT(b.Get(1).IsSameOrAncestorOf(d)); + + UNIT_ASSERT(!b.Get(0).IsSameOrAncestorOf(d)); + UNIT_ASSERT(!b.Get(1).IsSameOrAncestorOf(c)); + } + + static void ByVal(NSc::TValue v) { + v["VAL"] = 1; + } + + static void ByRef(NSc::TValue& v) { + ByVal(v); + } + + static void ByRefAndModify(NSc::TValue& v) { + v["REF"] = 1; + ByVal(v); + } + + Y_UNIT_TEST(TestMove) { + using namespace NSc; + { + TValue v = TValue::FromJson("{}"); + ByRef(v); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "{\"VAL\":1}"); + } + { + TValue v = TValue::FromJson("{}"); + ByVal(v); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "{\"VAL\":1}"); + } + { + TValue v; + ByVal(v); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "{\"VAL\":1}"); + } + { + TValue v = TValue::FromJson("{}"); + ByRefAndModify(v); + UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "{\"REF\":1,\"VAL\":1}"); + } + { + TValue v = TValue::FromJson("{foo:bar}"); + TValue w(std::move(v)); + UNIT_ASSERT(v.IsNull()); + v = static_cast<TValue&>(v); + UNIT_ASSERT(v.IsNull()); + UNIT_ASSERT_VALUES_EQUAL(w.Get("foo").GetString(), "bar"); + v = std::move(w); + UNIT_ASSERT_VALUES_EQUAL(v.Get("foo").GetString(), "bar"); + UNIT_ASSERT(w.IsNull()); + UNIT_ASSERT(w.Get("foo").IsNull()); // no crash here + w["foo"] = "baz"; // no crash here + UNIT_ASSERT(w.IsDict()); + UNIT_ASSERT_VALUES_EQUAL(w.Get("foo").GetString(), "baz"); + } + UNIT_ASSERT(NSc::TValue::DefaultValue().IsNull()); + } + + //SPI-25156 + Y_UNIT_TEST(TestMoveNotCorruptingDefault) { + using namespace NSc; + TValue w = TValue::FromJson("{foo:bar}"); + TValue v = std::move(w); + w["foo"] = "baz"; // no crash here + UNIT_ASSERT(NSc::TValue::DefaultValue().IsNull()); + } + + Y_UNIT_TEST(TestCopyFrom) { + { + TString sa = "[1,2]"; + const NSc::TValue& va = NSc::TValue::FromJson(sa); + NSc::TValue vb = va; + vb.CopyFrom(va); + UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa); + UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa); + } + { + TString sa = "[1,2]"; + NSc::TValue va = NSc::TValue::FromJson(sa); + NSc::TValue vb = va; + vb.CopyFrom(va); + UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa); + UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa); + } + { + TString sa = "[1,2]"; + NSc::TValue va = NSc::TValue::FromJson(sa); + const NSc::TValue& vb = va; + va.CopyFrom(vb); + UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa); + UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa); + } + { + TString sa = "[1,2]"; + NSc::TValue va = NSc::TValue::FromJson(sa); + NSc::TValue vb = va; + va.CopyFrom(vb); + UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa); + UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa); + } + { + NSc::TValue va = NSc::TValue::FromJson("{\"x\":\"ab\",\"y\":{\"p\":\"cd\",\"q\":\"ef\"}}"); + NSc::TValue vb = va.Get("y"); + va.CopyFrom(vb); + TString sa = "{\"p\":\"cd\",\"q\":\"ef\"}"; + UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa); + UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa); + } + { + NSc::TValue va = NSc::TValue::FromJson("{\"x\":\"ab\",\"y\":{\"p\":\"cd\",\"q\":\"ef\"}}"); + const NSc::TValue& vb = va.Get("y"); + va.CopyFrom(vb); + TString sa = "{\"p\":\"cd\",\"q\":\"ef\"}"; + UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa); + } + { + NSc::TValue va = NSc::TValue::FromJson("{\"x\":\"ab\",\"y\":{\"p\":\"cd\",\"q\":\"ef\"}}"); + NSc::TValue vb = va.Get("y"); + va = vb; + TString sa = "{\"p\":\"cd\",\"q\":\"ef\"}"; + UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa); + UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa); + } + { + NSc::TValue va = NSc::TValue::FromJson("{\"x\":\"ab\",\"y\":{\"p\":\"cd\",\"q\":\"ef\"}}"); + const NSc::TValue& vb = va.Get("y"); + va = vb; + TString sa = "{\"p\":\"cd\",\"q\":\"ef\"}"; + UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa); + UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa); + } + } + + Y_UNIT_TEST(TestCopyingDictIntoSelf) { //Found by fuzzing + NSc::TValue a; + NSc::TValue b = a.GetOrAdd("aa"); + b.CopyFrom(a); + NSc::TValue target = NSc::TValue::FromJsonThrow("{\"aa\":null}"); + UNIT_ASSERT_VALUES_EQUAL(b, target); + UNIT_ASSERT_VALUES_EQUAL(a, target); + } + + Y_UNIT_TEST(TestCopyingDictIntoSelfByRef) { //Found by fuzzing + NSc::TValue a; + NSc::TValue& b = a.GetOrAdd("aa"); + b.CopyFrom(a); + UNIT_ASSERT_VALUES_EQUAL(b, NSc::TValue::FromJsonThrow("{\"aa\":null}")); + UNIT_ASSERT_VALUES_EQUAL(a, NSc::TValue::FromJsonThrow("{\"aa\": {\"aa\": null}}")); + } + + Y_UNIT_TEST(TestGetNoAdd) { + NSc::TValue v = NSc::NUt::AssertFromJson("{a:[null,-1,2,3.4],b:3,c:{d:5}}"); + UNIT_ASSERT(v.GetNoAdd("a") != nullptr); + UNIT_ASSERT(v.GetNoAdd("b") != nullptr); + UNIT_ASSERT(v.GetNoAdd("c") != nullptr); + UNIT_ASSERT(v.GetNoAdd("d") == nullptr); + UNIT_ASSERT(v.GetNoAdd("value") == nullptr); + + NSc::TValue* child = v.GetNoAdd("c"); + UNIT_ASSERT(child != nullptr); + (*child)["e"]["f"] = 42; + const NSc::TValue expectedResult = NSc::NUt::AssertFromJson("{a:[null,-1,2,3.4],b:3,c:{d:5,e:{f:42}}}"); + UNIT_ASSERT_VALUES_EQUAL(v, expectedResult); + } +}; diff --git a/library/cpp/scheme/tests/ut/scheme_ut.proto b/library/cpp/scheme/tests/ut/scheme_ut.proto new file mode 100644 index 0000000000..7981af7eae --- /dev/null +++ b/library/cpp/scheme/tests/ut/scheme_ut.proto @@ -0,0 +1,84 @@ +package NSc; + +message TMessage { + optional double Double = 1; + optional float Float = 2; + optional int32 Int32 = 3; + optional int64 Int64 = 4; + optional uint32 UInt32 = 5; + optional uint64 UInt64 = 6; + optional sint32 SInt32 = 7; + optional sint64 SInt64 = 8; + optional fixed32 Fixed32 = 9; + optional fixed64 Fixed64 = 10; + optional sfixed32 SFixed32 = 11; + optional sfixed64 SFixed64 = 12; + optional bool Bool = 13; + optional string String = 14; + optional bytes Bytes = 15; + optional EEnum Enum = 16; + optional TMessage2 Message = 17; + + repeated double Doubles = 18; + repeated float Floats = 19; + repeated int32 Int32s = 20; + repeated int64 Int64s = 21; + repeated uint32 UInt32s = 22; + repeated uint64 UInt64s = 23; + repeated sint32 SInt32s = 24; + repeated sint64 SInt64s = 25; + repeated fixed32 Fixed32s = 26; + repeated fixed64 Fixed64s = 27; + repeated sfixed32 SFixed32s = 28; + repeated sfixed64 SFixed64s = 29; + repeated bool Bools = 30; + repeated string Strings = 31; + repeated bytes Bytess = 32; + repeated EEnum Enums = 33; + repeated TMessage2 Messages = 34; + + map<string, double> MapDoubles = 35; + map<string, int32> MapInt32s = 36; + map<string, string> MapString = 37; +} + +enum EEnum { + VALUE1 = 0; + VALUE2 = 1; +} + +message TMessage2 { + optional double Double = 1; + optional float Float = 2; + optional int32 Int32 = 3; + optional int64 Int64 = 4; + optional uint32 UInt32 = 5; + optional uint64 UInt64 = 6; + optional sint32 SInt32 = 7; + optional sint64 SInt64 = 8; + optional fixed32 Fixed32 = 9; + optional fixed64 Fixed64 = 10; + optional sfixed32 SFixed32 = 11; + optional sfixed64 SFixed64 = 12; + optional bool Bool = 13; + optional string String = 14; + optional bytes Bytes = 15; + optional EEnum Enum = 16; + + repeated double Doubles = 18; + repeated float Floats = 19; + repeated int32 Int32s = 20; + repeated int64 Int64s = 21; + repeated uint32 UInt32s = 22; + repeated uint64 UInt64s = 23; + repeated sint32 SInt32s = 24; + repeated sint64 SInt64s = 25; + repeated fixed32 Fixed32s = 26; + repeated fixed64 Fixed64s = 27; + repeated sfixed32 SFixed32s = 28; + repeated sfixed64 SFixed64s = 29; + repeated bool Bools = 30; + repeated string Strings = 31; + repeated bytes Bytess = 32; + repeated EEnum Enums = 33; +} diff --git a/library/cpp/scheme/tests/ut/ya.make b/library/cpp/scheme/tests/ut/ya.make new file mode 100644 index 0000000000..9f54791414 --- /dev/null +++ b/library/cpp/scheme/tests/ut/ya.make @@ -0,0 +1,24 @@ +UNITTEST() + +OWNER(velavokr) + +PEERDIR( + library/cpp/protobuf/util + library/cpp/scheme/tests/fuzz_ops/lib + library/cpp/scheme/ut_utils + library/cpp/string_utils/quote + library/cpp/testing/unittest +) + +SRCS( + fuzz_ops_found_bugs_ut.cpp + scheme_cast_ut.cpp + scheme_json_ut.cpp + scheme_merge_ut.cpp + scheme_path_ut.cpp + scheme_proto_ut.cpp + scheme_ut.cpp + scheme_ut.proto +) + +END() |