|
@@ -0,0 +1,212 @@
|
|
|
+#include "library/cpp/json/converter/converter.h"
|
|
|
+#include <library/cpp/json/json_reader.h>
|
|
|
+#include <library/cpp/json/json_writer.h>
|
|
|
+#include "library/cpp/json/writer/json_value.h"
|
|
|
+#include <library/cpp/testing/unittest/registar.h>
|
|
|
+
|
|
|
+#include <util/generic/array_ref.h>
|
|
|
+#include <util/generic/deque.h>
|
|
|
+#include <util/generic/hash.h>
|
|
|
+#include <util/generic/list.h>
|
|
|
+#include <util/generic/map.h>
|
|
|
+#include <util/generic/maybe.h>
|
|
|
+
|
|
|
+
|
|
|
+namespace NJson {
|
|
|
+ void AssertJsonsEqual(const TJsonValue& actualJson, const TJsonValue& expectedJson) {
|
|
|
+ const auto actualString = WriteJson(actualJson, /*formatOutput*/ true, /*sortkeys*/ true, /*validateUtf8*/ true);
|
|
|
+ const auto expectedString = WriteJson(expectedJson, /*formatOutput*/ true, /*sortkeys*/ true, /*validateUtf8*/ true);
|
|
|
+ UNIT_ASSERT_NO_DIFF(actualString, expectedString);
|
|
|
+ }
|
|
|
+
|
|
|
+ void AssertJsonsEqual(const TJsonValue& actualJson, TStringBuf expectedString) {
|
|
|
+ const auto expectedJson = ReadJsonFastTree(expectedString);
|
|
|
+ AssertJsonsEqual(actualJson, expectedJson);
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename T>
|
|
|
+ struct TConverterTester {
|
|
|
+ using TValues = THashMap<TStringBuf, T>;
|
|
|
+
|
|
|
+ static void TestEncoding(const TValues& values) {
|
|
|
+ for (const auto& [serializedValue, value] : values) {
|
|
|
+ {
|
|
|
+ const auto encodedValue = TConverter<T>::Encode(value);
|
|
|
+ AssertJsonsEqual(encodedValue, serializedValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static void TestDecoding(const TValues& values) {
|
|
|
+ for (const auto& [serializedValue, value] : values) {
|
|
|
+ {
|
|
|
+ const auto decodedValue = TConverter<T>::Decode(ReadJsonFastTree(serializedValue));
|
|
|
+ UNIT_ASSERT_EQUAL(decodedValue, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static void TestDecodingException(TStringBuf serializedValue) {
|
|
|
+ try {
|
|
|
+ TConverter<T>::Decode(ReadJsonFastTree(serializedValue));
|
|
|
+ UNIT_ASSERT(false);
|
|
|
+ } catch (...) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static void Test(const TValues& values) {
|
|
|
+ TestEncoding(values);
|
|
|
+ TestDecoding(values);
|
|
|
+
|
|
|
+ for (const auto& [serializedValue, value] : values) {
|
|
|
+ {
|
|
|
+ const auto encodedValue = TConverter<T>::Encode(value);
|
|
|
+ const auto decodedValue = TConverter<T>::Decode(encodedValue);
|
|
|
+ UNIT_ASSERT_EQUAL(value, decodedValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<typename T>
|
|
|
+ requires std::is_floating_point_v<T>
|
|
|
+ struct TConverterTester<T> {
|
|
|
+ using TValues = THashMap<TStringBuf, T>;
|
|
|
+
|
|
|
+ static void TestDecoding(const TValues& values) {
|
|
|
+ for (const auto& [serializedValue, value] : values) {
|
|
|
+ {
|
|
|
+ const auto decodedValue = TConverter<T>::Decode(ReadJsonFastTree(serializedValue));
|
|
|
+ UNIT_ASSERT_DOUBLES_EQUAL(decodedValue, value, 0.000001);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static void Test(const TValues& values) {
|
|
|
+ TestDecoding(values);
|
|
|
+
|
|
|
+ for (const auto& [serializedValue, value] : values) {
|
|
|
+ {
|
|
|
+ const auto encodedValue = TConverter<T>::Encode(value);
|
|
|
+ const auto decodedValue = TConverter<T>::Decode(encodedValue);
|
|
|
+ UNIT_ASSERT_DOUBLES_EQUAL(decodedValue, value, 0.000001);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ Y_UNIT_TEST_SUITE(ConversionTests) {
|
|
|
+ Y_UNIT_TEST(PrimitivesTest) {
|
|
|
+ TConverterTester<bool>::Test({{"true", true}, {"false", false}});
|
|
|
+
|
|
|
+ TConverterTester<ui8>::Test({{"0", 0}, {"255", 255}});
|
|
|
+ TConverterTester<i8>::Test({{"-128", -128}, {"127", 127}});
|
|
|
+ TConverterTester<ui16>::Test({{"0", 0}, {"65535", 65535}});
|
|
|
+ TConverterTester<i16>::Test({{"-32768", -32768}, {"32767", 32767}});
|
|
|
+ TConverterTester<ui32>::Test({{"0", 0}, {"4294967295", 4294967295}});
|
|
|
+ TConverterTester<i32>::Test({{"-2147483648", -2147483648}, {"2147483647", 2147483647}});
|
|
|
+ TConverterTester<ui64>::Test({{"0", 0}, {"18446744073709551615", 18446744073709551615u}});
|
|
|
+ TConverterTester<i64>::Test({
|
|
|
+ {"-9223372036854775808", -9223372036854775808u},
|
|
|
+ {"9223372036854775807", 9223372036854775807},
|
|
|
+ });
|
|
|
+
|
|
|
+ TConverterTester<i8>::TestDecodingException("128");
|
|
|
+ TConverterTester<i8>::TestDecodingException("-129");
|
|
|
+ TConverterTester<ui8>::TestDecodingException("256");
|
|
|
+ TConverterTester<i16>::TestDecodingException("32768");
|
|
|
+ TConverterTester<i16>::TestDecodingException("-32769");
|
|
|
+ TConverterTester<ui16>::TestDecodingException("65536");
|
|
|
+ TConverterTester<i32>::TestDecodingException("-2147483649");
|
|
|
+ TConverterTester<i32>::TestDecodingException("2147483649");
|
|
|
+ TConverterTester<ui32>::TestDecodingException("4294967296");
|
|
|
+
|
|
|
+ TConverterTester<unsigned char>::Test({{"0", 0}, {"255", 255}});
|
|
|
+ TConverterTester<signed char>::Test({{"-128", -128}, {"127", 127}});
|
|
|
+ TConverterTester<unsigned short int>::Test({{"0", 0}, {"65535", 65535}});
|
|
|
+ TConverterTester<signed short int>::Test({{"-32768", -32768}, {"32767", 32767}});
|
|
|
+ TConverterTester<unsigned int>::Test({{"0", 0}, {"65535", 65535}});
|
|
|
+ TConverterTester<signed int>::Test({{"-32768", -32768}, {"32767", 32767}});
|
|
|
+ TConverterTester<unsigned long int>::Test({{"0", 0}, {"4294967295", 4294967295}});
|
|
|
+ TConverterTester<signed long int>::Test({{"-2147483648", -2147483648}, {"2147483647", 2147483647}});
|
|
|
+ TConverterTester<unsigned long long int>::Test({{"0", 0}, {"18446744073709551615", 18446744073709551615u}});
|
|
|
+ TConverterTester<signed long long int>::Test({
|
|
|
+ {"-9223372036854775808", -9223372036854775808u},
|
|
|
+ {"9223372036854775807", 9223372036854775807},
|
|
|
+ });
|
|
|
+
|
|
|
+ TConverterTester<size_t>::Test({{"0", 0}, {"65535", 65535}});
|
|
|
+
|
|
|
+ TConverterTester<float>::Test({{"-1.12312", -1.12312}, {"3434.25674", 3434.25674}});
|
|
|
+ TConverterTester<double>::Test({{"-1.12312E+42", -1.12312E+42}, {"3.25E+120", 3.25E+120}});
|
|
|
+ }
|
|
|
+
|
|
|
+ Y_UNIT_TEST(StringsTest) {
|
|
|
+ TConverterTester<TStringBuf>::TestEncoding({
|
|
|
+ {R"("Let's permit using of Rust in Arcadia")", "Let's permit using of Rust in Arcadia"},
|
|
|
+ });
|
|
|
+ TConverterTester<TString>::Test({
|
|
|
+ {
|
|
|
+ R"("Всякое непрерывное отображение замкнутого n-мерного шара в себя обладает неподвижной точкой")",
|
|
|
+ "Всякое непрерывное отображение замкнутого n-мерного шара в себя обладает неподвижной точкой",
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ Y_UNIT_TEST(MaybeTest) {
|
|
|
+ TConverterTester<TMaybe<bool>>::Test({
|
|
|
+ {"true", TMaybe<bool>(true)},
|
|
|
+ {"null", Nothing()},
|
|
|
+ {"false", TMaybe<bool>(false)},
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ Y_UNIT_TEST(ArraysTest) {
|
|
|
+ TConverterTester<TVector<bool>>::Test({{"[true, true, false]", {true, true, false}}});
|
|
|
+ TConverterTester<TList<TString>>::Test({{R"(["a", "b"])", {"a", "b"}}});
|
|
|
+ TConverterTester<TDeque<bool>>::Test({{"[false, true, false]", {false, true, false}}});
|
|
|
+ }
|
|
|
+
|
|
|
+ Y_UNIT_TEST(MapsTest) {
|
|
|
+ TConverterTester<THashMap<TStringBuf, bool>>::TestEncoding({
|
|
|
+ {R"({"a": true, "b": false})", {{"a", true}, {"b", false}}},
|
|
|
+ });
|
|
|
+ TConverterTester<THashMap<TString, bool>>::Test({
|
|
|
+ {R"({"a": true, "b": false})", {{"a", true}, {"b", false}}},
|
|
|
+ });
|
|
|
+ TConverterTester<TMap<TStringBuf, TStringBuf>>::TestEncoding({
|
|
|
+ {R"({"a": "A", "b": "B"})", {{"a", "A"}, {"b", "B"}}},
|
|
|
+ });
|
|
|
+ TConverterTester<TMap<TString, TString>>::Test({
|
|
|
+ {R"({"a": "A", "b": "B"})", {{"a", "A"}, {"b", "B"}}},
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ Y_UNIT_TEST(NestedTest) {
|
|
|
+ TConverterTester<TVector<THashMap<TString, TVector<ui64>>>>::Test({
|
|
|
+ {
|
|
|
+ R"([
|
|
|
+ {
|
|
|
+ "Three": [0, 1, 2],
|
|
|
+ "Five": [0, 1, 2, 3, 4]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "Four": [0, 1, 2, 3],
|
|
|
+ "Six": [0, 1, 2, 3, 4, 5]
|
|
|
+ },
|
|
|
+ ])",
|
|
|
+ {
|
|
|
+ {
|
|
|
+ {"Three", {0, 1, 2}},
|
|
|
+ {"Five", {0, 1, 2, 3, 4}},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ {"Four", {0, 1, 2, 3}},
|
|
|
+ {"Six", {0, 1, 2, 3, 4, 5}},
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|