diff options
| author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 | 
|---|---|---|
| committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 | 
| commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
| tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/scheme/tests/ut | |
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 00000000000..a445b0f87c7 --- /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 00000000000..4f907157e92 --- /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 00000000000..daeb2654f9a --- /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 00000000000..2a06cf110da --- /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 00000000000..0d4d79d4833 --- /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 00000000000..e711a0d0925 --- /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 00000000000..1a5d07c31bc --- /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 00000000000..7981af7eae0 --- /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 00000000000..9f547914146 --- /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()  | 
