1515 lines
48 KiB
C++
1515 lines
48 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#if WITH_TESTS
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Containers/AnsiString.h"
|
|
#include "Misc/AutomationTest.h"
|
|
#include "Policies/CondensedJsonPrintPolicy.h"
|
|
#include "Policies/PrettyJsonPrintPolicy.h"
|
|
#include "Serialization/JsonReader.h"
|
|
#include "Serialization/JsonSerializable.h"
|
|
#include "Serialization/JsonSerializer.h"
|
|
#include "Serialization/JsonSerializerMacros.h"
|
|
#include "Serialization/JsonTypes.h"
|
|
#include "Tests/TestHarnessAdapter.h"
|
|
|
|
#if WITH_LOW_LEVEL_TESTS
|
|
#include "TestCommon/Expectations.h"
|
|
#endif
|
|
|
|
typedef TJsonWriterFactory< TCHAR, TCondensedJsonPrintPolicy<TCHAR> > FCondensedJsonStringWriterFactory;
|
|
typedef TJsonWriter< TCHAR, TCondensedJsonPrintPolicy<TCHAR> > FCondensedJsonStringWriter;
|
|
typedef TJsonWriterFactory< ANSICHAR, TCondensedJsonPrintPolicy<ANSICHAR> > FCondensedJsonAnsiStringWriterFactory;
|
|
typedef TJsonWriter< ANSICHAR, TCondensedJsonPrintPolicy<ANSICHAR> > FCondensedJsonAnsiStringWriter;
|
|
typedef TJsonWriterFactory< UTF8CHAR, TCondensedJsonPrintPolicy<UTF8CHAR> > FCondensedJsonUtf8StringWriterFactory;
|
|
typedef TJsonWriter< UTF8CHAR, TCondensedJsonPrintPolicy<UTF8CHAR> > FCondensedJsonUtf8StringWriter;
|
|
|
|
typedef TJsonWriterFactory< TCHAR, TPrettyJsonPrintPolicy<TCHAR> > FPrettyJsonStringWriterFactory;
|
|
typedef TJsonWriter< TCHAR, TPrettyJsonPrintPolicy<TCHAR> > FPrettyJsonStringWriter;
|
|
|
|
TEST_CASE_NAMED(FJsonAutomationTest, "System::Engine::FileSystem::JSON", "[ApplicationContextMask][SmokeFilter]")
|
|
{
|
|
// Null Case
|
|
{
|
|
const FString InputString = TEXT("");
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString );
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
REQUIRE(FJsonSerializer::Deserialize( Reader, Object ) == false);
|
|
REQUIRE(!Object.IsValid());
|
|
}
|
|
|
|
// Empty Object Case
|
|
{
|
|
const FString InputString = TEXT("{}");
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString );
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
REQUIRE(FJsonSerializer::Deserialize( Reader, Object ));
|
|
REQUIRE(Object.IsValid());
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ));
|
|
REQUIRE(InputString == OutputString);
|
|
}
|
|
|
|
// Empty Array Case
|
|
{
|
|
const FString InputString = TEXT("[]");
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString );
|
|
|
|
TArray< TSharedPtr<FJsonValue> > Array;
|
|
REQUIRE(FJsonSerializer::Deserialize( Reader, Array ));
|
|
REQUIRE(Array.Num() == 0);
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize( Array, Writer ));
|
|
REQUIRE(InputString == OutputString);
|
|
}
|
|
|
|
// Empty Array with Empty Identifier Case
|
|
{
|
|
const FString ExpectedString = TEXT("[]");
|
|
FString OutputString;
|
|
TSharedRef<FJsonValueArray> EmptyValuesArray = MakeShared<FJsonValueArray>(TArray<TSharedPtr<FJsonValue>>());
|
|
TSharedRef<FCondensedJsonStringWriter> JsonWriter = FCondensedJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize(EmptyValuesArray, FString(), JsonWriter));
|
|
REQUIRE(ExpectedString == OutputString);
|
|
}
|
|
|
|
// Serializing Object Value with Empty Identifier Case
|
|
{
|
|
const FString ExpectedString = TEXT("{\"\":\"foo\"}");
|
|
FString OutputString;
|
|
TSharedRef<FJsonValue> FooValue = MakeShared<FJsonValueString>("foo");
|
|
TSharedRef<FCondensedJsonStringWriter> JsonWriter = FCondensedJsonStringWriterFactory::Create(&OutputString);
|
|
JsonWriter->WriteObjectStart();
|
|
REQUIRE(FJsonSerializer::Serialize(FooValue, FString(), JsonWriter, false));
|
|
JsonWriter->WriteObjectEnd();
|
|
JsonWriter->Close();
|
|
REQUIRE(ExpectedString == OutputString);
|
|
}
|
|
|
|
// Simple Array Case
|
|
{
|
|
const FString InputString =
|
|
TEXT(
|
|
"["
|
|
"{"
|
|
"\"Value\":\"Some String\""
|
|
"}"
|
|
"]"
|
|
);
|
|
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString );
|
|
|
|
TArray< TSharedPtr<FJsonValue> > Array;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Array);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Array.Num() == 1);
|
|
REQUIRE(Array[0].IsValid());
|
|
|
|
TSharedPtr< FJsonObject > Object = Array[0]->AsObject();
|
|
REQUIRE(Object.IsValid());
|
|
REQUIRE(Object->GetStringField( TEXT("Value") ) == TEXT("Some String"));
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize( Array, Writer ));
|
|
REQUIRE(InputString == OutputString);
|
|
}
|
|
|
|
// Object Array Case
|
|
{
|
|
const FString InputString =
|
|
TEXT(
|
|
"["
|
|
"{"
|
|
"\"Value\":\"Some String1\""
|
|
"},"
|
|
"{"
|
|
"\"Value\":\"Some String2\""
|
|
"},"
|
|
"{"
|
|
"\"Value\":\"Some String3\""
|
|
"}"
|
|
"]"
|
|
);
|
|
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(InputString);
|
|
|
|
TArray< TSharedPtr<FJsonValue> > Array;
|
|
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Array);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Array.Num() == 3);
|
|
REQUIRE(Array[0].IsValid());
|
|
REQUIRE(Array[1].IsValid());
|
|
REQUIRE(Array[2].IsValid());
|
|
|
|
TSharedPtr< FJsonObject > Object = Array[0]->AsObject();
|
|
REQUIRE(Object.IsValid());
|
|
REQUIRE(Object->GetStringField(TEXT("Value")) == TEXT("Some String1"));
|
|
|
|
Object = Array[1]->AsObject();
|
|
REQUIRE(Object.IsValid());
|
|
REQUIRE(Object->GetStringField(TEXT("Value")) == TEXT("Some String2"));
|
|
|
|
Object = Array[2]->AsObject();
|
|
REQUIRE(Object.IsValid());
|
|
REQUIRE(Object->GetStringField(TEXT("Value")) == TEXT("Some String3"));
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString);
|
|
REQUIRE(FJsonSerializer::Serialize(Array, Writer));
|
|
REQUIRE(InputString == OutputString);
|
|
}
|
|
|
|
// FJsonValue operator== Comparison Equality Test
|
|
{
|
|
/* comparing: "Type1_Type2_#" */
|
|
const FString StoredAsType1 =
|
|
TEXT(
|
|
"{"
|
|
"\"bool_string_0\" : false,"
|
|
"\"bool_string_1\" : true,"
|
|
"\"bool_string_2\" : false,"
|
|
"\"bool_string_3\" : true,"
|
|
|
|
"\"int_string_0\" : 10,"
|
|
"\"int_string_1\" : 100,"
|
|
|
|
"\"float_string_0\" : 10.123,"
|
|
"\"float_string_1\" : 100.34,"
|
|
|
|
"\"string_string_0\" : \"foo1\","
|
|
"\"string_string_1\" : \"foo2\","
|
|
|
|
"\"bool_int_0\" : true,"
|
|
"\"bool_int_1\" : false,"
|
|
|
|
"\"int_float_0\" : 10,"
|
|
"\"int_float_1\" : 100.00,"
|
|
"\"int_float_2\" : 10,"
|
|
|
|
"\"float_bool_0\" : 1.0,"
|
|
"\"float_bool_1\" : 0.0,"
|
|
"\"float_bool_2\" : 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234,"
|
|
"\"float_bool_3\" : 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234"
|
|
"}"
|
|
);
|
|
|
|
const FString StoredAsType2 =
|
|
TEXT(
|
|
"{"
|
|
"\"bool_string_0\" : \"false\","
|
|
"\"bool_string_1\" : \"true\","
|
|
"\"bool_string_2\" : \"0\","
|
|
"\"bool_string_3\" : \"1\","
|
|
|
|
"\"int_string_0\" : \"10\","
|
|
"\"int_string_1\" : \"100\","
|
|
|
|
"\"float_string_0\" : \"10.123\","
|
|
"\"float_string_1\" : \"100.34\","
|
|
|
|
"\"string_string_0\" : \"foo1\","
|
|
"\"string_string_1\" : \"foo2\","
|
|
|
|
"\"bool_int_0\" : 1,"
|
|
"\"bool_int_1\" : 0,"
|
|
|
|
"\"int_float_0\" : 10.0,"
|
|
"\"int_float_1\" : 100.00,"
|
|
"\"int_float_2\" : 10.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234,"
|
|
|
|
"\"float_bool_0\" : true,"
|
|
"\"float_bool_1\" : false,"
|
|
"\"float_bool_2\" : true,"
|
|
"\"float_bool_3\" : false"
|
|
"}"
|
|
);
|
|
|
|
TSharedRef< TJsonReader<> > TypeReader_1 = TJsonReaderFactory<>::Create(StoredAsType1);
|
|
TSharedRef< TJsonReader<> > TypeReader_2 = TJsonReaderFactory<>::Create(StoredAsType2);
|
|
|
|
TSharedPtr<FJsonObject> TypedObject_1;
|
|
REQUIRE(FJsonSerializer::Deserialize(TypeReader_1, TypedObject_1));
|
|
REQUIRE(TypedObject_1.IsValid());
|
|
|
|
TSharedPtr<FJsonObject> TypedObject_2;
|
|
REQUIRE(FJsonSerializer::Deserialize(TypeReader_2, TypedObject_2));
|
|
REQUIRE(TypedObject_2.IsValid());
|
|
|
|
REQUIRE(TypedObject_1->Values.Num() == TypedObject_2->Values.Num());
|
|
|
|
for (const TPair<FString, TSharedPtr<FJsonValue>>& KV : TypedObject_1->Values)
|
|
{
|
|
REQUIRE(TypedObject_2->Values.Contains(KV.Key));
|
|
TSharedPtr<FJsonValue> Typed1_FieldValue = KV.Value;
|
|
TSharedPtr<FJsonValue> Typed2_FieldValue = TypedObject_2->Values[KV.Key];
|
|
|
|
REQUIRE(*Typed1_FieldValue == *Typed2_FieldValue);
|
|
REQUIRE(*Typed2_FieldValue == *Typed1_FieldValue);
|
|
}
|
|
}
|
|
|
|
// FJsonValue operator!= Comparison Inequality Test
|
|
{
|
|
/* comparing: "Type1_Type2_#" */
|
|
const FString StoredAsType1 =
|
|
TEXT(
|
|
"{"
|
|
"\"bool_string_0\" : false,"
|
|
"\"bool_string_1\" : true,"
|
|
|
|
"\"int_string_0\" : 10,"
|
|
"\"int_string_1\" : 100,"
|
|
|
|
"\"float_string_0\" : 10.123,"
|
|
"\"float_string_1\" : 100.34,"
|
|
|
|
// `FJsonValue operator==` uses `FString::operator==` which uses `ESearchCase::IgnoreCase`
|
|
//"\"string_string_0\" : \"foo1\","
|
|
//"\"string_string_1\" : \"foo2\","
|
|
|
|
"\"bool_int_0\" : true,"
|
|
"\"bool_int_1\" : false,"
|
|
|
|
"\"int_float_0\" : 10,"
|
|
"\"int_float_1\" : 100.00,"
|
|
"\"int_float_2\" : 10,"
|
|
|
|
"\"float_bool_0\" : 1.0,"
|
|
"\"float_bool_1\" : 0.0,"
|
|
"\"float_bool_2\" : 2.5,"
|
|
"\"float_bool_3\" : 3.5"
|
|
"}"
|
|
);
|
|
|
|
const FString StoredAsType2 =
|
|
TEXT(
|
|
"{"
|
|
"\"bool_string_0\" : \"not_true\","
|
|
"\"bool_string_1\" : \"not_false\","
|
|
|
|
"\"int_string_0\" : \"20\","
|
|
"\"int_string_1\" : \"200\","
|
|
|
|
"\"float_string_0\" : \"20.123\","
|
|
"\"float_string_1\" : \"200.34\","
|
|
|
|
// `FJsonValue operator==` uses `FString::operator==` which uses `ESearchCase::IgnoreCase`
|
|
//"\"string_string_0\" : \"Foo1\","
|
|
//"\"string_string_1\" : \"Foo2\","
|
|
|
|
"\"bool_int_0\" : 2,"
|
|
"\"bool_int_1\" : 3,"
|
|
|
|
"\"int_float_0\" : 20.0,"
|
|
"\"int_float_1\" : 200.00,"
|
|
"\"int_float_2\" : 10.5,"
|
|
|
|
"\"float_bool_0\" : false,"
|
|
"\"float_bool_1\" : true,"
|
|
"\"float_bool_2\" : true,"
|
|
"\"float_bool_3\" : false"
|
|
"}"
|
|
);
|
|
|
|
TSharedRef< TJsonReader<> > TypeReader_1 = TJsonReaderFactory<>::Create(StoredAsType1);
|
|
TSharedRef< TJsonReader<> > TypeReader_2 = TJsonReaderFactory<>::Create(StoredAsType2);
|
|
|
|
TSharedPtr<FJsonObject> TypedObject_1;
|
|
REQUIRE(FJsonSerializer::Deserialize(TypeReader_1, TypedObject_1));
|
|
REQUIRE(TypedObject_1.IsValid());
|
|
|
|
TSharedPtr<FJsonObject> TypedObject_2;
|
|
REQUIRE(FJsonSerializer::Deserialize(TypeReader_2, TypedObject_2));
|
|
REQUIRE(TypedObject_2.IsValid());
|
|
|
|
REQUIRE(TypedObject_1->Values.Num() == TypedObject_2->Values.Num());
|
|
|
|
for (const TPair<FString, TSharedPtr<FJsonValue>>& KV : TypedObject_1->Values)
|
|
{
|
|
REQUIRE(TypedObject_2->Values.Contains(KV.Key));
|
|
TSharedPtr<FJsonValue> Typed1_FieldValue = KV.Value;
|
|
TSharedPtr<FJsonValue> Typed2_FieldValue = TypedObject_2->Values[KV.Key];
|
|
|
|
REQUIRE(*Typed1_FieldValue != *Typed2_FieldValue);
|
|
REQUIRE(*Typed2_FieldValue != *Typed1_FieldValue);
|
|
}
|
|
}
|
|
|
|
// JsonSimpleValueVariant operator== Comparison Equality Test
|
|
{
|
|
/* comparing: "Type1_Type2_#" */
|
|
const FString StoredAsType1 =
|
|
TEXT(
|
|
"{"
|
|
"\"bool_string_0\" : false,"
|
|
"\"bool_string_1\" : true,"
|
|
"\"bool_string_2\" : false,"
|
|
"\"bool_string_3\" : true,"
|
|
|
|
"\"int_string_0\" : 10,"
|
|
"\"int_string_1\" : 100,"
|
|
|
|
"\"float_string_0\" : 10.123,"
|
|
"\"float_string_1\" : 100.34,"
|
|
|
|
"\"string_string_0\" : \"foo1\","
|
|
"\"string_string_1\" : \"foo2\","
|
|
|
|
"\"bool_int_0\" : true,"
|
|
"\"bool_int_1\" : false,"
|
|
|
|
"\"int_float_0\" : 10,"
|
|
"\"int_float_1\" : 100.00,"
|
|
"\"int_float_2\" : 10,"
|
|
|
|
"\"float_bool_0\" : 1.0,"
|
|
"\"float_bool_1\" : 0.0,"
|
|
"\"float_bool_2\" : 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234,"
|
|
"\"float_bool_3\" : 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234,"
|
|
"\"float_bool_4\" : 0.9999999999999999999999999999999999999999999999999999999999999999999999999876"
|
|
"}"
|
|
);
|
|
|
|
const FString StoredAsType2 =
|
|
TEXT(
|
|
"{"
|
|
"\"bool_string_0\" : \"false\","
|
|
"\"bool_string_1\" : \"true\","
|
|
"\"bool_string_2\" : \"0\","
|
|
"\"bool_string_3\" : \"1\","
|
|
|
|
"\"int_string_0\" : \"10\","
|
|
"\"int_string_1\" : \"100\","
|
|
|
|
"\"float_string_0\" : \"10.123\","
|
|
"\"float_string_1\" : \"100.34\","
|
|
|
|
"\"string_string_0\" : \"foo1\","
|
|
"\"string_string_1\" : \"foo2\","
|
|
|
|
"\"bool_int_0\" : 1,"
|
|
"\"bool_int_1\" : 0,"
|
|
|
|
"\"int_float_0\" : 10.0,"
|
|
"\"int_float_1\" : 100.00,"
|
|
"\"int_float_2\" : 10.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234,"
|
|
|
|
"\"float_bool_0\" : true,"
|
|
"\"float_bool_1\" : false,"
|
|
"\"float_bool_2\" : true,"
|
|
"\"float_bool_3\" : false,"
|
|
"\"float_bool_4\" : true"
|
|
"}"
|
|
);
|
|
|
|
TSharedRef< TJsonReader<> > TypeReader_1 = TJsonReaderFactory<>::Create(StoredAsType1);
|
|
TSharedRef< TJsonReader<> > TypeReader_2 = TJsonReaderFactory<>::Create(StoredAsType2);
|
|
|
|
TSharedPtr<FJsonObject> TypedObject_1;
|
|
REQUIRE(FJsonSerializer::Deserialize(TypeReader_1, TypedObject_1));
|
|
REQUIRE(TypedObject_1.IsValid());
|
|
|
|
TSharedPtr<FJsonObject> TypedObject_2;
|
|
REQUIRE(FJsonSerializer::Deserialize(TypeReader_2, TypedObject_2));
|
|
REQUIRE(TypedObject_2.IsValid());
|
|
|
|
REQUIRE(TypedObject_1->Values.Num() == TypedObject_2->Values.Num());
|
|
|
|
for (const TPair<FString, TSharedPtr<FJsonValue>>& KV : TypedObject_1->Values)
|
|
{
|
|
REQUIRE(TypedObject_2->Values.Contains(KV.Key));
|
|
TSharedPtr<FJsonValue> Typed1_FieldValue = KV.Value;
|
|
TSharedPtr<FJsonValue> Typed2_FieldValue = TypedObject_2->Values[KV.Key];
|
|
|
|
REQUIRE(UE::Json::ToSimpleJsonVariant(*Typed1_FieldValue) == UE::Json::ToSimpleJsonVariant(*Typed2_FieldValue));
|
|
REQUIRE(UE::Json::ToSimpleJsonVariant(*Typed2_FieldValue) == UE::Json::ToSimpleJsonVariant(*Typed1_FieldValue));
|
|
}
|
|
}
|
|
|
|
// JsonSimpleValueVariant operator!= Comparison Inequality Test
|
|
{
|
|
/* comparing: "Type1_Type2_#" */
|
|
const FString StoredAsType1 =
|
|
TEXT(
|
|
"{"
|
|
"\"bool_string_0\" : false,"
|
|
"\"bool_string_1\" : true,"
|
|
|
|
"\"int_string_0\" : 10,"
|
|
"\"int_string_1\" : 100,"
|
|
|
|
"\"float_string_0\" : 10.123,"
|
|
"\"float_string_1\" : 100.34,"
|
|
|
|
"\"string_string_0\" : \"foo1\","
|
|
"\"string_string_1\" : \"foo2\","
|
|
|
|
"\"bool_int_0\" : true,"
|
|
"\"bool_int_1\" : false,"
|
|
|
|
"\"int_float_0\" : 10,"
|
|
"\"int_float_1\" : 100.00,"
|
|
"\"int_float_2\" : 10,"
|
|
|
|
"\"float_bool_0\" : 1.0,"
|
|
"\"float_bool_1\" : 0.0,"
|
|
"\"float_bool_2\" : 2.5,"
|
|
"\"float_bool_3\" : 3.5"
|
|
"}"
|
|
);
|
|
|
|
const FString StoredAsType2 =
|
|
TEXT(
|
|
"{"
|
|
"\"bool_string_0\" : \"not_true\","
|
|
"\"bool_string_1\" : \"not_false\","
|
|
|
|
"\"int_string_0\" : \"20\","
|
|
"\"int_string_1\" : \"200\","
|
|
|
|
"\"float_string_0\" : \"20.123\","
|
|
"\"float_string_1\" : \"200.34\","
|
|
|
|
"\"string_string_0\" : \"Foo1\","
|
|
"\"string_string_1\" : \"Foo2\","
|
|
|
|
"\"bool_int_0\" : 2,"
|
|
"\"bool_int_1\" : 3,"
|
|
|
|
"\"int_float_0\" : 20.0,"
|
|
"\"int_float_1\" : 200.00,"
|
|
"\"int_float_2\" : 10.5,"
|
|
|
|
"\"float_bool_0\" : false,"
|
|
"\"float_bool_1\" : true,"
|
|
"\"float_bool_2\" : true,"
|
|
"\"float_bool_3\" : false"
|
|
"}"
|
|
);
|
|
|
|
TSharedRef< TJsonReader<> > TypeReader_1 = TJsonReaderFactory<>::Create(StoredAsType1);
|
|
TSharedRef< TJsonReader<> > TypeReader_2 = TJsonReaderFactory<>::Create(StoredAsType2);
|
|
|
|
TSharedPtr<FJsonObject> TypedObject_1;
|
|
REQUIRE(FJsonSerializer::Deserialize(TypeReader_1, TypedObject_1));
|
|
REQUIRE(TypedObject_1.IsValid());
|
|
|
|
TSharedPtr<FJsonObject> TypedObject_2;
|
|
REQUIRE(FJsonSerializer::Deserialize(TypeReader_2, TypedObject_2));
|
|
REQUIRE(TypedObject_2.IsValid());
|
|
|
|
REQUIRE(TypedObject_1->Values.Num() == TypedObject_2->Values.Num());
|
|
|
|
for (const TPair<FString, TSharedPtr<FJsonValue>>& KV : TypedObject_1->Values)
|
|
{
|
|
REQUIRE(TypedObject_2->Values.Contains(KV.Key));
|
|
TSharedPtr<FJsonValue> Typed1_FieldValue = KV.Value;
|
|
TSharedPtr<FJsonValue> Typed2_FieldValue = TypedObject_2->Values[KV.Key];
|
|
|
|
REQUIRE(UE::Json::ToSimpleJsonVariant(*Typed1_FieldValue) != UE::Json::ToSimpleJsonVariant(*Typed2_FieldValue));
|
|
REQUIRE(UE::Json::ToSimpleJsonVariant(*Typed2_FieldValue) != UE::Json::ToSimpleJsonVariant(*Typed1_FieldValue));
|
|
}
|
|
}
|
|
|
|
// Number Array Case
|
|
{
|
|
const FString InputString =
|
|
TEXT(
|
|
"["
|
|
"10,"
|
|
"20,"
|
|
"30,"
|
|
"40"
|
|
"]"
|
|
);
|
|
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(InputString);
|
|
|
|
TArray< TSharedPtr<FJsonValue> > Array;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Array);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Array.Num() == 4);
|
|
REQUIRE(Array[0].IsValid());
|
|
REQUIRE(Array[1].IsValid());
|
|
REQUIRE(Array[2].IsValid());
|
|
REQUIRE(Array[3].IsValid());
|
|
|
|
double Number = Array[0]->AsNumber();
|
|
REQUIRE(Number == 10);
|
|
|
|
Number = Array[1]->AsNumber();
|
|
REQUIRE(Number == 20);
|
|
|
|
Number = Array[2]->AsNumber();
|
|
REQUIRE(Number == 30);
|
|
|
|
Number = Array[3]->AsNumber();
|
|
REQUIRE(Number == 40);
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString);
|
|
REQUIRE(FJsonSerializer::Serialize(Array, Writer));
|
|
REQUIRE(InputString == OutputString);
|
|
}
|
|
|
|
// String Array Case
|
|
{
|
|
const FString InputString =
|
|
TEXT(
|
|
"["
|
|
"\"Some String1\","
|
|
"\"Some String2\","
|
|
"\"Some String3\","
|
|
"\"Some String4\""
|
|
"]"
|
|
);
|
|
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(InputString);
|
|
|
|
TArray< TSharedPtr<FJsonValue> > Array;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Array);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Array.Num() == 4);
|
|
REQUIRE(Array[0].IsValid());
|
|
REQUIRE(Array[1].IsValid());
|
|
REQUIRE(Array[2].IsValid());
|
|
REQUIRE(Array[3].IsValid());
|
|
|
|
FString Text = Array[0]->AsString();
|
|
REQUIRE(Text == TEXT("Some String1"));
|
|
|
|
Text = Array[1]->AsString();
|
|
REQUIRE(Text == TEXT("Some String2"));
|
|
|
|
Text = Array[2]->AsString();
|
|
REQUIRE(Text == TEXT("Some String3"));
|
|
|
|
Text = Array[3]->AsString();
|
|
REQUIRE(Text == TEXT("Some String4"));
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString);
|
|
REQUIRE(FJsonSerializer::Serialize(Array, Writer));
|
|
REQUIRE(InputString == OutputString);
|
|
}
|
|
|
|
// Complex Array Case
|
|
{
|
|
const FString InputString =
|
|
TEXT(
|
|
"["
|
|
"\"Some String1\","
|
|
"10,"
|
|
"{"
|
|
"\"\":\"Empty Key\","
|
|
"\"Value\":\"Some String3\""
|
|
"},"
|
|
"["
|
|
"\"Some String4\","
|
|
"\"Some String5\""
|
|
"],"
|
|
"true,"
|
|
"null"
|
|
"]"
|
|
);
|
|
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(InputString);
|
|
|
|
TArray< TSharedPtr<FJsonValue> > Array;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Array);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Array.Num() == 6);
|
|
REQUIRE(Array[0].IsValid());
|
|
REQUIRE(Array[1].IsValid());
|
|
REQUIRE(Array[2].IsValid());
|
|
REQUIRE(Array[3].IsValid());
|
|
REQUIRE(Array[4].IsValid());
|
|
REQUIRE(Array[5].IsValid());
|
|
|
|
FString Text = Array[0]->AsString();
|
|
REQUIRE(Text == TEXT("Some String1"));
|
|
|
|
double Number = Array[1]->AsNumber();
|
|
REQUIRE(Number == 10);
|
|
|
|
TSharedPtr< FJsonObject > Object = Array[2]->AsObject();
|
|
REQUIRE(Object.IsValid());
|
|
REQUIRE(Object->GetStringField(TEXT("Value")) == TEXT("Some String3"));
|
|
REQUIRE(Object->GetStringField(TEXT("")) == TEXT("Empty Key"));
|
|
|
|
const TArray<TSharedPtr< FJsonValue >>& InnerArray = Array[3]->AsArray();
|
|
REQUIRE(InnerArray.Num() == 2);
|
|
REQUIRE(Array[0].IsValid());
|
|
REQUIRE(Array[1].IsValid());
|
|
|
|
Text = InnerArray[0]->AsString();
|
|
REQUIRE(Text == TEXT("Some String4"));
|
|
|
|
Text = InnerArray[1]->AsString();
|
|
REQUIRE(Text == TEXT("Some String5"));
|
|
|
|
bool Boolean = Array[4]->AsBool();
|
|
REQUIRE(Boolean == true);
|
|
|
|
REQUIRE(Array[5]->IsNull() == true);
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString);
|
|
REQUIRE(FJsonSerializer::Serialize(Array, Writer));
|
|
REQUIRE(InputString == OutputString);
|
|
}
|
|
|
|
// String Test
|
|
{
|
|
const FString InputString =
|
|
TEXT(
|
|
"{"
|
|
"\"Value\":\"Some String, Escape Chars: \\\\, \\\", \\/, \\b, \\f, \\n, \\r, \\t, \\u002B\""
|
|
"}"
|
|
);
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString );
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Object.IsValid());
|
|
|
|
const TSharedPtr<FJsonValue>* Value = Object->Values.Find(TEXT("Value"));
|
|
REQUIRE(Value);
|
|
REQUIRE((*Value)->Type == EJson::String);
|
|
const FString String = (*Value)->AsString();
|
|
REQUIRE(String == TEXT("Some String, Escape Chars: \\, \", /, \b, \f, \n, \r, \t, +"));
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ));
|
|
|
|
const FString TestOutput =
|
|
TEXT(
|
|
"{"
|
|
"\"Value\":\"Some String, Escape Chars: \\\\, \\\", /, \\b, \\f, \\n, \\r, \\t, +\""
|
|
"}"
|
|
);
|
|
REQUIRE(OutputString == TestOutput);
|
|
}
|
|
|
|
// String Test ANSI
|
|
{
|
|
const ANSICHAR* InputString =
|
|
"{" \
|
|
"\"Value\":\"Some String, Escape Chars: \\\\, \\\", \\/, \\b, \\f, \\n, \\r, \\t, \\u002B\\uD83D\\uDE10\""\
|
|
"}";
|
|
|
|
TSharedRef< TJsonReader<ANSICHAR> > Reader = TJsonReaderFactory<ANSICHAR>::CreateFromView(InputString);
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Object.IsValid());
|
|
|
|
{
|
|
const TSharedPtr<FJsonValue>* Value = Object->Values.Find(TEXT("Value"));
|
|
REQUIRE((Value && (*Value)->Type == EJson::String));
|
|
const FString String = (*Value)->AsString();
|
|
REQUIRE(String == TEXT("Some String, Escape Chars: \\, \", /, \b, \f, \n, \r, \t, +😐"));
|
|
const FUtf8String Utf8String = (*Value)->AsUtf8String();
|
|
REQUIRE(Utf8String == UTF8TEXT("Some String, Escape Chars: \\, \", /, \b, \f, \n, \r, \t, +😐"));
|
|
}
|
|
|
|
FAnsiString AnsiOutputString;
|
|
TSharedRef< FCondensedJsonAnsiStringWriter > AnsiWriter = FCondensedJsonAnsiStringWriterFactory::Create(&AnsiOutputString);
|
|
REQUIRE(FJsonSerializer::Serialize(Object.ToSharedRef(), AnsiWriter));
|
|
|
|
const FAnsiString AnsiTestOutput =
|
|
"{" \
|
|
"\"Value\":\"Some String, Escape Chars: \\\\, \\\", /, \\b, \\f, \\n, \\r, \\t, +\\ud83d\\ude10\""\
|
|
"}";
|
|
REQUIRE(AnsiOutputString == AnsiTestOutput);
|
|
}
|
|
|
|
// String Test UTF8
|
|
{
|
|
// UTF8TEXT will prepend the first u8 literal specifier
|
|
// UTF8TEXT does a cast, so we can't add it each line and still get the literals to concatenate
|
|
const UTF8CHAR* InputString = UTF8TEXT(
|
|
"{"
|
|
u8"\"Value\":\"Some String, Escape Chars: \\\\, \\\", \\/, \\b, \\f, \\n, \\r, \\t, \\u002B\\uD83D\\uDE10\","
|
|
u8"\"Value1\":\"Greek String, Σὲ γνωρίζω ἀπὸ τὴν κόψη\","
|
|
u8"\"Value2\":\"Thai String, สิบสองกษัตริย์ก่อนหน้าแลถัดไป\","
|
|
u8"\"Value3\":\"Hello world, Καλημέρα κόσμε, コンニチハ\""
|
|
u8"}"
|
|
);
|
|
|
|
TSharedRef< TJsonReader<UTF8CHAR> > Reader = TJsonReaderFactory<UTF8CHAR>::CreateFromView( InputString );
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Object.IsValid());
|
|
|
|
{
|
|
const TSharedPtr<FJsonValue>* Value = Object->Values.Find(TEXT("Value"));
|
|
REQUIRE((Value && (*Value)->Type == EJson::String));
|
|
const FString String = (*Value)->AsString();
|
|
REQUIRE(String == TEXT("Some String, Escape Chars: \\, \", /, \b, \f, \n, \r, \t, +😐"));
|
|
const FUtf8String Utf8String = (*Value)->AsUtf8String();
|
|
REQUIRE(Utf8String == UTF8TEXT("Some String, Escape Chars: \\, \", /, \b, \f, \n, \r, \t, +😐"));
|
|
}
|
|
{
|
|
const TSharedPtr<FJsonValue>* Value = Object->Values.Find(TEXT("Value1"));
|
|
REQUIRE((Value && (*Value)->Type == EJson::String));
|
|
const FString String = (*Value)->AsString();
|
|
REQUIRE(String == TEXT("Greek String, Σὲ γνωρίζω ἀπὸ τὴν κόψη"));
|
|
const FUtf8String Utf8String = (*Value)->AsUtf8String();
|
|
REQUIRE(Utf8String == UTF8TEXT("Greek String, Σὲ γνωρίζω ἀπὸ τὴν κόψη"));
|
|
}
|
|
{
|
|
const TSharedPtr<FJsonValue>* Value = Object->Values.Find(TEXT("Value2"));
|
|
REQUIRE((Value && (*Value)->Type == EJson::String));
|
|
const FString String = (*Value)->AsString();
|
|
REQUIRE(String == TEXT("Thai String, สิบสองกษัตริย์ก่อนหน้าแลถัดไป"));
|
|
const FUtf8String Utf8String = (*Value)->AsUtf8String();
|
|
REQUIRE(Utf8String == UTF8TEXT("Thai String, สิบสองกษัตริย์ก่อนหน้าแลถัดไป"));
|
|
}
|
|
{
|
|
const TSharedPtr<FJsonValue>* Value = Object->Values.Find(TEXT("Value3"));
|
|
REQUIRE((Value && (*Value)->Type == EJson::String));
|
|
const FString String = (*Value)->AsString();
|
|
REQUIRE(String == TEXT("Hello world, Καλημέρα κόσμε, コンニチハ"));
|
|
const FUtf8String Utf8String = (*Value)->AsUtf8String();
|
|
REQUIRE(Utf8String == UTF8TEXT("Hello world, Καλημέρα κόσμε, コンニチハ"));
|
|
}
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ));
|
|
|
|
// Note: The literal prefix for the string (u8, L), must be present for every concatenated string, not just the first one
|
|
const FString TestOutput =
|
|
TEXT("{")
|
|
TEXT("\"Value\":\"Some String, Escape Chars: \\\\, \\\", /, \\b, \\f, \\n, \\r, \\t, +😐\",")
|
|
TEXT("\"Value1\":\"Greek String, Σὲ γνωρίζω ἀπὸ τὴν κόψη\",")
|
|
TEXT("\"Value2\":\"Thai String, สิบสองกษัตริย์ก่อนหน้าแลถัดไป\",")
|
|
TEXT("\"Value3\":\"Hello world, Καλημέρα κόσμε, コンニチハ\"")
|
|
TEXT("}");
|
|
REQUIRE(OutputString == TestOutput);
|
|
|
|
FUtf8String Utf8OutputString;
|
|
TSharedRef< FCondensedJsonUtf8StringWriter > Utf8Writer = FCondensedJsonUtf8StringWriterFactory::Create(&Utf8OutputString);
|
|
REQUIRE(FJsonSerializer::Serialize(Object.ToSharedRef(), Utf8Writer));
|
|
|
|
// Note: The literal prefix for the string (u8, L), must be present for every concatenated string, not just the first one
|
|
const FUtf8String Utf8TestOutput =
|
|
UTF8TEXT("{"\
|
|
"\"Value\":\"Some String, Escape Chars: \\\\, \\\", /, \\b, \\f, \\n, \\r, \\t, +😐\","\
|
|
"\"Value1\":\"Greek String, Σὲ γνωρίζω ἀπὸ τὴν κόψη\","\
|
|
"\"Value2\":\"Thai String, สิบสองกษัตริย์ก่อนหน้าแลถัดไป\","\
|
|
"\"Value3\":\"Hello world, Καλημέρα κόσμε, コンニチハ\""\
|
|
"}");
|
|
REQUIRE(Utf8OutputString == Utf8TestOutput);
|
|
}
|
|
|
|
// Number Test
|
|
{
|
|
const FString InputString =
|
|
TEXT(
|
|
"{"
|
|
"\"Value1\":2.544e+15,"
|
|
"\"Value2\":-0.544E-2,"
|
|
"\"Value3\":251e3,"
|
|
"\"Value4\":-0.0,"
|
|
"\"Value5\":843"
|
|
"}"
|
|
);
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString );
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Object.IsValid());
|
|
|
|
double TestValues[] = {2.544e+15, -0.544e-2, 251e3, -0.0, 843};
|
|
for (int32 i = 0; i < 5; ++i)
|
|
{
|
|
const TSharedPtr<FJsonValue>* Value = Object->Values.Find(FString::Printf(TEXT("Value%i"), i + 1));
|
|
REQUIRE((Value && (*Value)->Type == EJson::Number));
|
|
const double Number = (*Value)->AsNumber();
|
|
REQUIRE(Number == TestValues[i]);
|
|
}
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ));
|
|
|
|
// %g isn't standardized, so we use the same %g format that is used inside PrintJson instead of hardcoding the values here
|
|
const FString TestOutput = FString::Printf(
|
|
TEXT(
|
|
"{"
|
|
"\"Value1\":%.17g,"
|
|
"\"Value2\":%.17g,"
|
|
"\"Value3\":%.17g,"
|
|
"\"Value4\":%.17g,"
|
|
"\"Value5\":%.17g"
|
|
"}"
|
|
),
|
|
TestValues[0], TestValues[1], TestValues[2], TestValues[3], TestValues[4]);
|
|
REQUIRE(OutputString == TestOutput);
|
|
}
|
|
|
|
// Test Nan
|
|
{
|
|
const FString TestNanInd = FString::Printf(TEXT("%.17g"), std::numeric_limits<double>::quiet_NaN());
|
|
CHECK(TestNanInd == TEXT("nan")); // Make sure code will not run on standard library impl which outputs nan(ind)
|
|
|
|
const FString InputString =
|
|
TEXT(
|
|
"{"
|
|
"\"Value0\":nan,"
|
|
"\"Value1\":NaN,"
|
|
"\"Value2\":-nan,"
|
|
"\"Value3\":-nan(ind)"
|
|
"}"
|
|
);
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString );
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Object.IsValid());
|
|
|
|
const TSharedPtr<FJsonValue>* Value0 = Object->Values.Find(FString::Printf(TEXT("Value%i"), 0));
|
|
const TSharedPtr<FJsonValue>* Value1 = Object->Values.Find(FString::Printf(TEXT("Value%i"), 1));
|
|
const TSharedPtr<FJsonValue>* Value2 = Object->Values.Find(FString::Printf(TEXT("Value%i"), 2));
|
|
const TSharedPtr<FJsonValue>* Value3 = Object->Values.Find(FString::Printf(TEXT("Value%i"), 3));
|
|
const double Number0 = (*Value0)->AsNumber();
|
|
const double Number1 = (*Value1)->AsNumber();
|
|
const double Number2 = (*Value2)->AsNumber();
|
|
const double Number3 = (*Value3)->AsNumber();
|
|
REQUIRE(FMath::IsNaN(Number0));
|
|
REQUIRE(FMath::IsNaN(Number1));
|
|
REQUIRE(FMath::IsNaN(Number2));
|
|
REQUIRE(FMath::IsNaN(Number3));
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ));
|
|
|
|
// %g isn't standardized, so we use the same %g format that is used inside PrintJson instead of hardcoding the values here
|
|
const FString TestOutput = FString::Printf(
|
|
TEXT(
|
|
"{"
|
|
"\"Value0\":%.17g,"
|
|
"\"Value1\":%.17g,"
|
|
"\"Value2\":%.17g,"
|
|
"\"Value3\":%.17g"
|
|
"}"
|
|
),
|
|
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), -std::numeric_limits<double>::quiet_NaN(), -std::numeric_limits<double>::quiet_NaN());
|
|
REQUIRE(OutputString == TestOutput);
|
|
}
|
|
|
|
// Boolean/Null Test
|
|
{
|
|
const FString InputString =
|
|
TEXT(
|
|
"{"
|
|
"\"Value1\":true,"
|
|
"\"Value2\":true,"
|
|
"\"Value3\":faLsE,"
|
|
"\"Value4\":null,"
|
|
"\"Value5\":NULL"
|
|
"}"
|
|
);
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString );
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Object.IsValid());
|
|
|
|
bool TestValues[] = {true, true, false};
|
|
for (int32 i = 0; i < 5; ++i)
|
|
{
|
|
const TSharedPtr<FJsonValue>* Value = Object->Values.Find(FString::Printf(TEXT("Value%i"), i + 1));
|
|
REQUIRE(Value);
|
|
if (i < 3)
|
|
{
|
|
REQUIRE((*Value)->Type == EJson::Boolean);
|
|
const bool Bool = (*Value)->AsBool();
|
|
REQUIRE(Bool == TestValues[i]);
|
|
}
|
|
else
|
|
{
|
|
REQUIRE((*Value)->Type == EJson::Null);
|
|
REQUIRE((*Value)->IsNull());
|
|
}
|
|
}
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ));
|
|
|
|
const FString TestOutput =
|
|
TEXT(
|
|
"{"
|
|
"\"Value1\":true,"
|
|
"\"Value2\":true,"
|
|
"\"Value3\":false,"
|
|
"\"Value4\":null,"
|
|
"\"Value5\":null"
|
|
"}"
|
|
);
|
|
REQUIRE(OutputString == TestOutput);
|
|
}
|
|
|
|
// Object Test && extra whitespace test
|
|
{
|
|
const FString InputStringWithExtraWhitespace =
|
|
TEXT(
|
|
" \n\r\n {"
|
|
"\"Object\":"
|
|
"{"
|
|
"\"NestedValue\":null,"
|
|
"\"NestedObject\":{}"
|
|
"},"
|
|
"\"Value\":true"
|
|
"} \n\r\n "
|
|
);
|
|
|
|
const FString InputString =
|
|
TEXT(
|
|
"{"
|
|
"\"Object\":"
|
|
"{"
|
|
"\"NestedValue\":null,"
|
|
"\"NestedObject\":{}"
|
|
"},"
|
|
"\"Value\":true"
|
|
"}"
|
|
);
|
|
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputStringWithExtraWhitespace );
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Object.IsValid());
|
|
|
|
const TSharedPtr<FJsonValue>* InnerValueFail = Object->Values.Find(TEXT("InnerValue"));
|
|
REQUIRE(!InnerValueFail);
|
|
|
|
const TSharedPtr<FJsonValue>* ObjectValue = Object->Values.Find(TEXT("Object"));
|
|
REQUIRE((ObjectValue && (*ObjectValue)->Type == EJson::Object));
|
|
const TSharedPtr<FJsonObject> InnerObject = (*ObjectValue)->AsObject();
|
|
REQUIRE(InnerObject.IsValid());
|
|
|
|
{
|
|
const TSharedPtr<FJsonValue>* NestedValueValue = InnerObject->Values.Find(TEXT("NestedValue"));
|
|
REQUIRE((NestedValueValue && (*NestedValueValue)->Type == EJson::Null));
|
|
REQUIRE((*NestedValueValue)->IsNull());
|
|
|
|
const TSharedPtr<FJsonValue>* NestedObjectValue = InnerObject->Values.Find(TEXT("NestedObject"));
|
|
REQUIRE((NestedObjectValue && (*NestedObjectValue)->Type == EJson::Object));
|
|
const TSharedPtr<FJsonObject> InnerInnerObject = (*NestedObjectValue)->AsObject();
|
|
REQUIRE(InnerInnerObject.IsValid());
|
|
|
|
{
|
|
const TSharedPtr<FJsonValue>* NestedValueValueFail = InnerInnerObject->Values.Find(TEXT("NestedValue"));
|
|
REQUIRE(!NestedValueValueFail);
|
|
}
|
|
}
|
|
|
|
const TSharedPtr<FJsonValue>* ValueValue = Object->Values.Find(TEXT("Value"));
|
|
REQUIRE((ValueValue && (*ValueValue)->Type == EJson::Boolean));
|
|
const bool Bool = (*ValueValue)->AsBool();
|
|
REQUIRE(Bool);
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ));
|
|
REQUIRE(OutputString == InputString);
|
|
}
|
|
|
|
// Array Test
|
|
{
|
|
const FString InputString =
|
|
TEXT(
|
|
"{"
|
|
"\"Array\":"
|
|
"["
|
|
"[],"
|
|
"\"Some String\","
|
|
"\"Another String\","
|
|
"null,"
|
|
"true,"
|
|
"false,"
|
|
"45,"
|
|
"{}"
|
|
"]"
|
|
"}"
|
|
);
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString );
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object);
|
|
REQUIRE(bSuccessful);
|
|
REQUIRE(Object.IsValid());
|
|
|
|
const TSharedPtr<FJsonValue>* InnerValueFail = Object->Values.Find(TEXT("InnerValue"));
|
|
REQUIRE(!InnerValueFail);
|
|
|
|
const TSharedPtr<FJsonValue>* ArrayValue = Object->Values.Find(TEXT("Array"));
|
|
REQUIRE((ArrayValue && (*ArrayValue)->Type == EJson::Array));
|
|
const TArray< TSharedPtr<FJsonValue> > Array = (*ArrayValue)->AsArray();
|
|
REQUIRE(Array.Num() == 8);
|
|
|
|
EJson ValueTypes[] = {EJson::Array, EJson::String, EJson::String, EJson::Null,
|
|
EJson::Boolean, EJson::Boolean, EJson::Number, EJson::Object};
|
|
for (int32 i = 0; i < Array.Num(); ++i)
|
|
{
|
|
const TSharedPtr<FJsonValue>& Value = Array[i];
|
|
REQUIRE(Value.IsValid());
|
|
REQUIRE(Value->Type == ValueTypes[i]);
|
|
}
|
|
|
|
const TArray< TSharedPtr<FJsonValue> >& InnerArray = Array[0]->AsArray();
|
|
REQUIRE(InnerArray.Num() == 0);
|
|
REQUIRE(Array[1]->AsString() == TEXT("Some String"));
|
|
REQUIRE(Array[2]->AsString() == TEXT("Another String"));
|
|
REQUIRE(Array[3]->IsNull());
|
|
REQUIRE(Array[4]->AsBool());
|
|
REQUIRE(!Array[5]->AsBool());
|
|
REQUIRE(FMath::Abs(Array[6]->AsNumber() - 45.f) < KINDA_SMALL_NUMBER);
|
|
const TSharedPtr<FJsonObject> InnerObject = Array[7]->AsObject();
|
|
REQUIRE(InnerObject.IsValid());
|
|
|
|
FString OutputString;
|
|
TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ));
|
|
REQUIRE(OutputString == InputString);
|
|
}
|
|
|
|
// Pretty Print Test
|
|
{
|
|
const FString InputString =
|
|
TEXT(
|
|
"{" LINE_TERMINATOR_ANSI
|
|
" \"Data1\": \"value\"," LINE_TERMINATOR_ANSI
|
|
" \"Data2\": \"value\"," LINE_TERMINATOR_ANSI
|
|
" \"Array\": [" LINE_TERMINATOR_ANSI
|
|
" {" LINE_TERMINATOR_ANSI
|
|
" \"InnerData1\": \"value\"" LINE_TERMINATOR_ANSI
|
|
" }," LINE_TERMINATOR_ANSI
|
|
" []," LINE_TERMINATOR_ANSI
|
|
" [ 1, 2, 3, 4 ]," LINE_TERMINATOR_ANSI
|
|
" {" LINE_TERMINATOR_ANSI
|
|
" }," LINE_TERMINATOR_ANSI
|
|
" \"value\"," LINE_TERMINATOR_ANSI
|
|
" \"value\"" LINE_TERMINATOR_ANSI
|
|
" ]," LINE_TERMINATOR_ANSI
|
|
" \"Object\":" LINE_TERMINATOR_ANSI
|
|
" {" LINE_TERMINATOR_ANSI
|
|
" }" LINE_TERMINATOR_ANSI
|
|
"}"
|
|
);
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString );
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
REQUIRE(FJsonSerializer::Deserialize( Reader, Object ));
|
|
REQUIRE(Object.IsValid());
|
|
|
|
FString OutputString;
|
|
TSharedRef< FPrettyJsonStringWriter > Writer = FPrettyJsonStringWriterFactory::Create( &OutputString );
|
|
REQUIRE(FJsonSerializer::Serialize( Object.ToSharedRef(), Writer ));
|
|
REQUIRE(OutputString == InputString);
|
|
}
|
|
|
|
// Line and Character # test
|
|
{
|
|
const FString InputString =
|
|
TEXT(
|
|
"{" LINE_TERMINATOR_ANSI
|
|
" \"Data1\": \"value\"," LINE_TERMINATOR_ANSI
|
|
" \"Array\":" LINE_TERMINATOR_ANSI
|
|
" [" LINE_TERMINATOR_ANSI
|
|
" 12345," LINE_TERMINATOR_ANSI
|
|
" True" LINE_TERMINATOR_ANSI
|
|
" ]," LINE_TERMINATOR_ANSI
|
|
" \"Object\":" LINE_TERMINATOR_ANSI
|
|
" {" LINE_TERMINATOR_ANSI
|
|
" }" LINE_TERMINATOR_ANSI
|
|
"}"
|
|
);
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( InputString );
|
|
|
|
EJsonNotation Notation = EJsonNotation::Null;
|
|
REQUIRE(( Reader->ReadNext( Notation ) && Notation == EJsonNotation::ObjectStart ));
|
|
REQUIRE(( Reader->GetLineNumber() == 1 && Reader->GetCharacterNumber() == 1 ));
|
|
|
|
REQUIRE(( Reader->ReadNext( Notation ) && Notation == EJsonNotation::String ));
|
|
REQUIRE(( Reader->GetLineNumber() == 2 && Reader->GetCharacterNumber() == 17 ));
|
|
|
|
REQUIRE(( Reader->ReadNext( Notation ) && Notation == EJsonNotation::ArrayStart ));
|
|
REQUIRE(( Reader->GetLineNumber() == 4 && Reader->GetCharacterNumber() == 2 ));
|
|
|
|
REQUIRE(( Reader->ReadNext( Notation ) && Notation == EJsonNotation::Number ));
|
|
REQUIRE(( Reader->GetLineNumber() == 5 && Reader->GetCharacterNumber() == 7 ));
|
|
|
|
REQUIRE(( Reader->ReadNext( Notation ) && Notation == EJsonNotation::Boolean ));
|
|
REQUIRE(( Reader->GetLineNumber() == 6 && Reader->GetCharacterNumber() == 6 ));
|
|
}
|
|
|
|
// Failure Cases
|
|
TArray<FString> FailureInputs;
|
|
|
|
// Unclosed Object
|
|
FailureInputs.Add(
|
|
TEXT("{"));
|
|
|
|
// Values in Object without identifiers
|
|
FailureInputs.Add(
|
|
TEXT(
|
|
"{"
|
|
"\"Value1\","
|
|
"\"Value2\","
|
|
"43"
|
|
"}"
|
|
)
|
|
);
|
|
|
|
// Unexpected End Of Input Found
|
|
FailureInputs.Add(
|
|
TEXT(
|
|
"{"
|
|
"\"Object\":"
|
|
"{"
|
|
"\"NestedValue\":null,")
|
|
);
|
|
|
|
// Missing first brace
|
|
FailureInputs.Add(
|
|
TEXT(
|
|
"\"Object\":"
|
|
"{"
|
|
"\"NestedValue\":null,"
|
|
"\"NestedObject\":{}"
|
|
"},"
|
|
"\"Value\":true"
|
|
"}"
|
|
)
|
|
);
|
|
|
|
// Missing last character
|
|
FailureInputs.Add(
|
|
TEXT(
|
|
"{"
|
|
"\"Object\":"
|
|
"{"
|
|
"\"NestedValue\":null,"
|
|
"\"NestedObject\":{}"
|
|
"},"
|
|
"\"Value\":true"
|
|
)
|
|
);
|
|
|
|
// Missing curly brace
|
|
FailureInputs.Add(TEXT("}"));
|
|
|
|
// Missing bracket
|
|
FailureInputs.Add(TEXT("]"));
|
|
|
|
// Extra last character
|
|
FailureInputs.Add(
|
|
TEXT(
|
|
"{"
|
|
"\"Object\":"
|
|
"{"
|
|
"\"NestedValue\":null,"
|
|
"\"NestedObject\":{}"
|
|
"},"
|
|
"\"Value\":true"
|
|
"}0"
|
|
)
|
|
);
|
|
|
|
// Missing comma
|
|
FailureInputs.Add(
|
|
TEXT(
|
|
"{"
|
|
"\"Value1\":null,"
|
|
"\"Value2\":\"string\""
|
|
"\"Value3\":65.3"
|
|
"}"
|
|
)
|
|
);
|
|
|
|
// Extra comma
|
|
FailureInputs.Add(
|
|
TEXT(
|
|
"{"
|
|
"\"Value1\":null,"
|
|
"\"Value2\":\"string\","
|
|
"\"Value3\":65.3,"
|
|
"}"
|
|
)
|
|
);
|
|
|
|
// Badly formed true/false/null
|
|
FailureInputs.Add(TEXT("{\"Value\":tru}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":full}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":nulle}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":n%ll}"));
|
|
|
|
// Floating Point Failures
|
|
FailureInputs.Add(TEXT("{\"Value\":65.3e}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":65.}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":.7}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":+6}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":01}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":00.56}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":-1.e+4}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":2e+}"));
|
|
|
|
// Bad Escape Characters
|
|
FailureInputs.Add(TEXT("{\"Value\":\"Hello\\xThere\"}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":\"Hello\\u123There\"}"));
|
|
FailureInputs.Add(TEXT("{\"Value\":\"Hello\\RThere\"}"));
|
|
|
|
for (int32 i = 0; i < FailureInputs.Num(); ++i)
|
|
{
|
|
TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create( FailureInputs[i] );
|
|
|
|
TSharedPtr<FJsonObject> Object;
|
|
REQUIRE(FJsonSerializer::Deserialize( Reader, Object ) == false);
|
|
REQUIRE(!Object.IsValid());
|
|
}
|
|
|
|
// TryGetNumber tests
|
|
{
|
|
auto JsonNumberToInt64 = [](double Val, int64& OutVal) -> bool
|
|
{
|
|
FJsonValueNumber JsonVal(Val);
|
|
return ((FJsonValue&)JsonVal).TryGetNumber(OutVal);
|
|
};
|
|
|
|
auto JsonNumberToInt32 = [](double Val, int32& OutVal) -> bool
|
|
{
|
|
FJsonValueNumber JsonVal(Val);
|
|
return ((FJsonValue&)JsonVal).TryGetNumber(OutVal);
|
|
};
|
|
|
|
auto JsonNumberToUInt32 = [](double Val, uint32& OutVal) -> bool
|
|
{
|
|
FJsonValueNumber JsonVal(Val);
|
|
return ((FJsonValue&)JsonVal).TryGetNumber(OutVal);
|
|
};
|
|
|
|
// TryGetNumber-Int64 tests
|
|
{
|
|
int64 IntVal;
|
|
bool bOk = JsonNumberToInt64(9007199254740991.0, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int64 Big Float64 succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int64 Big Float64"), IntVal, 9007199254740991LL);
|
|
}
|
|
|
|
{
|
|
int64 IntVal;
|
|
bool bOk = JsonNumberToInt64(-9007199254740991.0, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int64 Small Float64 succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int64 Small Float64"), IntVal, -9007199254740991LL);
|
|
}
|
|
|
|
{
|
|
int64 IntVal;
|
|
bool bOk = JsonNumberToInt64(0.4999999999999997, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int64 Lesser than near half succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int64 Lesser than near half rounds to zero"), IntVal, 0LL);
|
|
}
|
|
|
|
{
|
|
int64 IntVal;
|
|
bool bOk = JsonNumberToInt64(-0.4999999999999997, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int64 Greater than near negative half succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int64 Greater than near negative half rounds to zero"), IntVal, 0LL);
|
|
}
|
|
|
|
{
|
|
int64 IntVal;
|
|
bool bOk = JsonNumberToInt64(0.5, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int64 Half rounds to next integer succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int64 Half rounds to next integer"), IntVal, 1LL);
|
|
}
|
|
|
|
{
|
|
int64 IntVal;
|
|
bool bOk = JsonNumberToInt64(-0.5, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int64 Negative half rounds to next negative integer succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int64 Negative half rounds to next negative integer succeeds"), IntVal, -1LL);
|
|
}
|
|
|
|
// TryGetNumber-Int32 tests
|
|
{
|
|
int32 IntVal;
|
|
bool bOk = JsonNumberToInt32(2147483647.000001, IntVal);
|
|
TestFalse(TEXT("TryGetNumber-Int32 Number greater than max Int32 fails"), bOk);
|
|
}
|
|
|
|
{
|
|
int32 IntVal;
|
|
bool bOk = JsonNumberToInt32(-2147483648.000001, IntVal);
|
|
TestFalse(TEXT("TryGetNumber-Int32 Number lesser than min Int32 fails"), bOk);
|
|
}
|
|
|
|
{
|
|
int32 IntVal;
|
|
bool bOk = JsonNumberToInt32(2147483647.0, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int32 Max Int32 succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int32 Max Int32"), IntVal, INT_MAX);
|
|
}
|
|
|
|
{
|
|
int32 IntVal;
|
|
bool bOk = JsonNumberToInt32(2147483646.5, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int32 Round up to max Int32 succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int32 Round up to max Int32"), IntVal, INT_MAX);
|
|
}
|
|
|
|
{
|
|
int32 IntVal;
|
|
bool bOk = JsonNumberToInt32(-2147483648.0, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int32 Min Int32 succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int32 Min Int32"), IntVal, INT_MIN);
|
|
}
|
|
|
|
{
|
|
int32 IntVal;
|
|
bool bOk = JsonNumberToInt32(-2147483647.5, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int32 Round down to min Int32 succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int32 Round down to min Int32"), IntVal, INT_MIN);
|
|
}
|
|
|
|
{
|
|
int32 IntVal;
|
|
bool bOk = JsonNumberToInt32(0.4999999999999997, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int32 Lesser than near half succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int32 Lesser than near half rounds to zero"), IntVal, 0);
|
|
}
|
|
|
|
{
|
|
int32 IntVal;
|
|
bool bOk = JsonNumberToInt32(-0.4999999999999997, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int32 Greater than near negative half succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int32 Greater than near negative half rounds to zero"), IntVal, 0);
|
|
}
|
|
|
|
{
|
|
int32 IntVal;
|
|
bool bOk = JsonNumberToInt32(0.5, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int32 Half rounds to next integer succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int32 Half rounds to next integer"), IntVal, 1);
|
|
}
|
|
|
|
{
|
|
int32 IntVal;
|
|
bool bOk = JsonNumberToInt32(-0.5, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-Int32 Negative half rounds to next negative integer succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-Int32 Negative half rounds to next negative integer succeeds"), IntVal, -1);
|
|
}
|
|
|
|
// TryGetNumber-UInt32 tests
|
|
{
|
|
uint32 IntVal;
|
|
bool bOk = JsonNumberToUInt32(4294967295.000001, IntVal);
|
|
TestFalse(TEXT("TryGetNumber-UInt32 Number greater than max Uint32 fails"), bOk);
|
|
}
|
|
|
|
{
|
|
uint32 IntVal;
|
|
bool bOk = JsonNumberToUInt32(-0.000000000000001, IntVal);
|
|
TestFalse(TEXT("TryGetNumber-UInt32 Negative number fails"), bOk);
|
|
}
|
|
|
|
{
|
|
uint32 IntVal;
|
|
bool bOk = JsonNumberToUInt32(4294967295.0, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-UInt32 Max UInt32 succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-UInt32 Max UInt32"), IntVal, UINT_MAX);
|
|
}
|
|
|
|
{
|
|
uint32 IntVal;
|
|
bool bOk = JsonNumberToUInt32(4294967294.5, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-UInt32 Round up to max UInt32 succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-UInt32 Round up to max UInt32"), IntVal, UINT_MAX);
|
|
}
|
|
|
|
{
|
|
uint32 IntVal;
|
|
bool bOk = JsonNumberToUInt32(0.4999999999999997, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-UInt32 Lesser than near half succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-UInt32 Lesser than near half rounds to zero"), IntVal, 0U);
|
|
}
|
|
|
|
{
|
|
uint32 IntVal;
|
|
bool bOk = JsonNumberToUInt32(0.5, IntVal);
|
|
TestTrue(TEXT("TryGetNumber-UInt32 Half rounds to next integer succeeds"), bOk);
|
|
TestEqual(TEXT("TryGetNumber-UInt32 Half rounds to next integer"), IntVal, 1U);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE_NAMED(FJsonSerializerMacrosTest, "System::Engine::FileSystem::JSON::MacroToSerializeMembers", "[ApplicationContextMask][SmokeFilter]")
|
|
{
|
|
struct FJsonStruct : public FJsonSerializable
|
|
{
|
|
struct FSubJsonStruct : public FJsonSerializable
|
|
{
|
|
int32 SubVarInt;
|
|
FString SubVarString;
|
|
|
|
FSubJsonStruct(int32 InSubVarInt = 0, FStringView InSubVarString = TEXTVIEW(""))
|
|
: SubVarInt(InSubVarInt)
|
|
, SubVarString(InSubVarString)
|
|
{
|
|
}
|
|
|
|
BEGIN_JSON_SERIALIZER
|
|
JSON_SERIALIZE("sub_var_int", SubVarInt);
|
|
JSON_SERIALIZE("sub_var_string", SubVarString);
|
|
END_JSON_SERIALIZER
|
|
};
|
|
|
|
int32 VarInt = 0;
|
|
FSubJsonStruct VarSerializable;
|
|
|
|
BEGIN_JSON_SERIALIZER
|
|
JSON_SERIALIZE("var_int", VarInt);
|
|
JSON_SERIALIZE_MEMBERS_OF(VarSerializable);
|
|
END_JSON_SERIALIZER;
|
|
};
|
|
|
|
const TCHAR* SourceJsonString = TEXT("{\"var_int\":2,\"sub_var_int\":10,\"sub_var_string\":\"abc\"}");
|
|
|
|
FJsonStruct JsonStructTarget;
|
|
JsonStructTarget.FromJson(SourceJsonString);
|
|
|
|
CHECK(JsonStructTarget.VarInt == 2);
|
|
CHECK(JsonStructTarget.VarSerializable.SubVarInt == 10);
|
|
CHECK(JsonStructTarget.VarSerializable.SubVarString == TEXT("abc"));
|
|
|
|
FString ToJsonResult = JsonStructTarget.ToJson(/*bPrettyPrint*/false);
|
|
CHECK(ToJsonResult == SourceJsonString);
|
|
}
|
|
|
|
#endif // WITH_TESTS
|