#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);
}
};