/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of thistoolsApp * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #include using namespace AzToolsFramework; using namespace AzToolsFramework::Fingerprinting; namespace UnitTest { class ReflectedTestClass { public: AZ_TYPE_INFO(ReflectedTestClass, "{AE55A3D4-845B-457F-94BA-A708BBDD6307}"); AZ_CLASS_ALLOCATOR(ReflectedTestClass, AZ::SystemAllocator, 0); ~ReflectedTestClass() { delete m_property1AsPointer; } int m_property1; bool m_property1AsBool; int *m_property1AsPointer = nullptr; int m_property2; static void ReflectDefault(AZ::SerializeContext& context) { context.Class() ->Field("Property1", &ReflectedTestClass::m_property1); } static void ReflectHigherVersion(AZ::SerializeContext& context) { context.Class() ->Version(2) ->Field("Property1", &ReflectedTestClass::m_property1); } static void ReflectRenamedProperty(AZ::SerializeContext& context) { context.Class() ->Field("Property1Renamed", &ReflectedTestClass::m_property1); } static void ReflectPropertyWithDifferentType(AZ::SerializeContext& context) { context.Class() ->Field("Property", &ReflectedTestClass::m_property1AsBool); } static void ReflectPropertyAsPointer(AZ::SerializeContext& context) { context.Class() ->Field("Property1", &ReflectedTestClass::m_property1AsPointer); } static void ReflectTwoProperties(AZ::SerializeContext& context) { context.Class() ->Field("Property1", &ReflectedTestClass::m_property1) ->Field("Property2", &ReflectedTestClass::m_property2); } }; class ReflectedBaseClass { public: AZ_TYPE_INFO(ReflectedBaseClass, "{B53DC61E-6E8A-4F0A-82E4-864FA50326E5}"); virtual ~ReflectedBaseClass() = default; static void ReflectDefault(AZ::SerializeContext& context) { context.Class(); } }; class ReflectedSubClass : public ReflectedBaseClass { public: AZ_TYPE_INFO(ReflectedSubClass, "{B95E143C-D97E-44F3-8F38-BAB6F317A03C}"); static void ReflectWithInheritance(AZ::SerializeContext& context) { context.Class(); } static void ReflectWithoutInheritance(AZ::SerializeContext& context) { context.Class(); } }; class ReflectedClassWithPointer { public: AZ_TYPE_INFO(ReflectedClassWithPointer, "{03DE24B9-288B-41B5-952D-4749F8F400D2}"); ~ReflectedClassWithPointer() { delete m_pointer; } ReflectedTestClass* m_pointer = nullptr; static void Reflect(AZ::SerializeContext& context) { context.Class() ->Field("Pointer", &ReflectedClassWithPointer::m_pointer); } }; TEST(FingerprintTests, IntFingerprint_IsValid) { AZ::SerializeContext serializeContext; TypeFingerprinter fingerprinter{ serializeContext }; EXPECT_NE(InvalidTypeFingerprint, fingerprinter.GetFingerprint()); } TEST(FingerprintTests, ClassFingerprint_IsValid) { AZ::SerializeContext serializeContext; ReflectedTestClass::ReflectDefault(serializeContext); TypeFingerprinter fingerprinter{ serializeContext }; EXPECT_NE(InvalidTypeFingerprint, fingerprinter.GetFingerprint()); } TEST(FingerprintTests, ClassWithNewVersionNumber_ChangesFingerprint) { AZ::SerializeContext serializeContext1; ReflectedTestClass::ReflectDefault(serializeContext1); TypeFingerprinter fingerprinter1{ serializeContext1 }; AZ::SerializeContext serializeContext2; ReflectedTestClass::ReflectHigherVersion(serializeContext2); TypeFingerprinter fingerprinter2{ serializeContext2 }; EXPECT_NE(fingerprinter1.GetFingerprint(), fingerprinter2.GetFingerprint()); } TEST(FingerprintTests, ClassWithRenamedProperty_ChangesFingerprint) { AZ::SerializeContext serializeContext1; ReflectedTestClass::ReflectDefault(serializeContext1); TypeFingerprinter fingerprinter1{ serializeContext1 }; AZ::SerializeContext serializeContext2; ReflectedTestClass::ReflectRenamedProperty(serializeContext2); TypeFingerprinter fingerprinter2{ serializeContext2 }; EXPECT_NE(fingerprinter1.GetFingerprint(), fingerprinter2.GetFingerprint()); } TEST(FingerprintTests, ClassWithPropertyThatChangesType_ChangesFingerprint) { AZ::SerializeContext serializeContext1; ReflectedTestClass::ReflectDefault(serializeContext1); TypeFingerprinter fingerprinter1{ serializeContext1 }; AZ::SerializeContext serializeContext2; ReflectedTestClass::ReflectPropertyWithDifferentType(serializeContext2); TypeFingerprinter fingerprinter2{ serializeContext2 }; EXPECT_NE(fingerprinter1.GetFingerprint(), fingerprinter2.GetFingerprint()); } TEST(FingerprintTests, ClassWithPropertyThatChangesToPointer_ChangesFingerprint) { AZ::SerializeContext serializeContext1; ReflectedTestClass::ReflectDefault(serializeContext1); TypeFingerprinter fingerprinter1{ serializeContext1 }; AZ::SerializeContext serializeContext2; ReflectedTestClass::ReflectPropertyAsPointer(serializeContext2); TypeFingerprinter fingerprinter2{ serializeContext2 }; EXPECT_NE(fingerprinter1.GetFingerprint(), fingerprinter2.GetFingerprint()); } TEST(FingerprintTests, ClassWithNewProperty_ChangesFingerprint) { AZ::SerializeContext serializeContext1; ReflectedTestClass::ReflectDefault(serializeContext1); TypeFingerprinter fingerprinter1{ serializeContext1 }; AZ::SerializeContext serializeContext2; ReflectedTestClass::ReflectTwoProperties(serializeContext2); TypeFingerprinter fingerprinter2{ serializeContext2 }; EXPECT_NE(fingerprinter1.GetFingerprint(), fingerprinter2.GetFingerprint()); } TEST(FingerprintTests, ClassGainingBaseClass_ChangesFingerprint) { AZ::SerializeContext serializeContext1; ReflectedBaseClass::ReflectDefault(serializeContext1); ReflectedSubClass::ReflectWithoutInheritance(serializeContext1); TypeFingerprinter fingerprinter1{ serializeContext1 }; AZ::SerializeContext serializeContext2; ReflectedBaseClass::ReflectDefault(serializeContext2); ReflectedSubClass::ReflectWithInheritance(serializeContext2); TypeFingerprinter fingerprinter2{ serializeContext2 }; EXPECT_NE(fingerprinter1.GetFingerprint(), fingerprinter2.GetFingerprint()); } TEST(FingerprintTests, GatherAllTypesInObject_FindsCorrectTypes) { AZ::SerializeContext serializeContext; ReflectedTestClass::ReflectDefault(serializeContext); TypeFingerprinter fingerprinter{ serializeContext }; ReflectedTestClass object; TypeCollection typesInObject; fingerprinter.GatherAllTypesInObject(&object, typesInObject); EXPECT_EQ(2, typesInObject.size()); EXPECT_EQ(1, typesInObject.count(AZ::SerializeTypeInfo::GetUuid())); EXPECT_EQ(1, typesInObject.count(AZ::SerializeTypeInfo::GetUuid())); } TEST(FingerprintTests, GatherAllTypesInObjectWithBaseClass_FindsCorrectTypes) { AZ::SerializeContext serializeContext; ReflectedBaseClass::ReflectDefault(serializeContext); ReflectedSubClass::ReflectWithInheritance(serializeContext); TypeFingerprinter fingerprinter{ serializeContext }; ReflectedSubClass object; TypeCollection typesInObject; fingerprinter.GatherAllTypesInObject(&object, typesInObject); EXPECT_EQ(2, typesInObject.size()); EXPECT_EQ(1, typesInObject.count(AZ::SerializeTypeInfo::GetUuid())); EXPECT_EQ(1, typesInObject.count(AZ::SerializeTypeInfo::GetUuid())); } TEST(FingerprintTests, GatherTypesInObjectWithNullPointer_FindsCorrectTypes) { AZ::SerializeContext serializeContext; ReflectedClassWithPointer::Reflect(serializeContext); ReflectedTestClass::ReflectDefault(serializeContext); TypeFingerprinter fingerprinter{ serializeContext }; ReflectedClassWithPointer classWithPointer; classWithPointer.m_pointer = nullptr; TypeCollection typesInObject; fingerprinter.GatherAllTypesInObject(&classWithPointer, typesInObject); // shouldn't gather types from ReflectedTestClass, since m_pointer is null EXPECT_EQ(1, typesInObject.size()); EXPECT_EQ(1, typesInObject.count(AZ::SerializeTypeInfo::GetUuid())); } TEST(FingerprintTests, GatherTypesInObjectWithValidPointer_FindsCorrectTypes) { AZ::SerializeContext serializeContext; ReflectedClassWithPointer::Reflect(serializeContext); ReflectedTestClass::ReflectDefault(serializeContext); TypeFingerprinter fingerprinter{ serializeContext }; ReflectedClassWithPointer classWithPointer; classWithPointer.m_pointer = aznew ReflectedTestClass(); TypeCollection typesInObject; fingerprinter.GatherAllTypesInObject(&classWithPointer, typesInObject); // should have followed m_pointer and gathered types from ReflectedTestClass EXPECT_EQ(3, typesInObject.size()); EXPECT_EQ(1, typesInObject.count(AZ::SerializeTypeInfo::GetUuid())); EXPECT_EQ(1, typesInObject.count(AZ::SerializeTypeInfo::GetUuid())); EXPECT_EQ(1, typesInObject.count(AZ::SerializeTypeInfo::GetUuid())); } TEST(FingerprintTests, GenerateFingerprintForAllTypesInObject_Works) { AZ::SerializeContext serializeContext; ReflectedTestClass::ReflectDefault(serializeContext); TypeFingerprinter fingerprinter{ serializeContext }; ReflectedTestClass object; EXPECT_NE(InvalidTypeFingerprint, fingerprinter.GenerateFingerprintForAllTypesInObject(&object)); } } // namespace UnitTest