3
0

AnimGraphFuzzTests.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <vector>
  9. #include <regex>
  10. #include <AzCore/Math/Random.h>
  11. #include <EMotionFX/Source/AnimGraph.h>
  12. #include <EMotionFX/Source/AnimGraphStateMachine.h>
  13. #include <AzCore/IO/ByteContainerStream.h>
  14. #include <AzCore/Serialization/Utils.h>
  15. #include <AzCore/UnitTest/UnitTest.h>
  16. #include "AnimGraphFixture.h"
  17. #include "EMotionFX_Traits_Platform.h"
  18. namespace EMotionFX
  19. {
  20. // Control the load for the AnimGraphFuzzTest
  21. static constexpr int s_AnimGraphFuzzTestLoad = 1;
  22. // Make it clear that the AnimGraphFuzzTest fixture is parameterized on a
  23. // seed value for a Random object
  24. using Seed = unsigned int;
  25. class AnimGraphFuzzTest
  26. : public AnimGraphFixture
  27. , public ::testing::WithParamInterface<Seed>
  28. {
  29. void SetUp()
  30. {
  31. AnimGraphFixture::SetUp();
  32. }
  33. void TearDown()
  34. {
  35. AnimGraphFixture::TearDown();
  36. }
  37. bool OnPreError([[maybe_unused]] const char* window, [[maybe_unused]] const char* fileName, [[maybe_unused]] int line, [[maybe_unused]] const char* func, const char* message)
  38. {
  39. // These error messages will cause exceptions in debug builds.
  40. // Since the fuzz tests just make sure that the process doesn't
  41. // crash, we want to ignore these errors.
  42. static const std::vector<std::regex> ignoredErrorMessages
  43. {
  44. std::regex("^XML parse error: RapidXML Parse error"),
  45. std::regex("^ObjectStream XML parse error\\."),
  46. std::regex("^Unknown stream tag \\(first byte\\): '\\\\0' binary, '<' xml or '\\{' json!"),
  47. std::regex("^ObjectStream JSON load error: Stream is a newer version than object stream supports\\. ObjectStream version: .*"),
  48. std::regex("^Element .* in class .* is of type .* but needs to be type .*\\."),
  49. std::regex("^Serializer failed for .* '.*'\\(0x.*\\).")
  50. };
  51. return IsIgnored(ignoredErrorMessages, message);
  52. }
  53. bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message)
  54. {
  55. // These warnings don't crash, but they make the test super chatty.
  56. // Just silence them.
  57. static const std::vector<std::regex> ignoredWarningMessages
  58. {
  59. std::regex("^Element .* of type .* is not registered as part of class .*\\. Data will be discarded"),
  60. std::regex("^Invalid UUID format .* \\(must be\\) \\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\\} \\(or without dashes and braces\\)")
  61. };
  62. return IsIgnored(ignoredWarningMessages, message);
  63. }
  64. private:
  65. bool IsIgnored(const std::vector<std::regex>& ignoredMessages, const char* message)
  66. {
  67. for (const std::regex& ignoredMessage : ignoredMessages)
  68. {
  69. if (std::regex_search(message, ignoredMessage))
  70. {
  71. return true;
  72. }
  73. }
  74. return false;
  75. }
  76. };
  77. TEST_P(AnimGraphFuzzTest, TestLoad)
  78. {
  79. AZ_TEST_START_TRACE_SUPPRESSION;
  80. // Set the root state machine's Id so to ensure consistency between test runs
  81. m_animGraph->GetRootStateMachine()->SetId(9347464774972852905u);
  82. AZStd::string charBuffer;
  83. AZ::IO::ByteContainerStream<AZStd::string > charStream(&charBuffer);
  84. AZ::Utils::SaveObjectToStream(charStream, AZ::ObjectStream::ST_XML, m_animGraph.get(), GetSerializeContext());
  85. const Seed seed = GetParam();
  86. AZ::SimpleLcgRandom random(seed);
  87. const size_t bufSize = charBuffer.size();
  88. for (int i = 0; i < 1000; ++i)
  89. {
  90. const unsigned int positionToEdit = random.GetRandom() % bufSize;
  91. const char newValue = random.GetRandom() % 256;
  92. charBuffer[positionToEdit] = newValue;
  93. EMotionFX::AnimGraph* animGraph = EMotionFX::AnimGraph::LoadFromBuffer(&charBuffer[0], bufSize, GetSerializeContext());
  94. if (animGraph)
  95. {
  96. delete animGraph;
  97. }
  98. }
  99. AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
  100. }
  101. static const std::vector<Seed> GetSeedsForTest(const int count)
  102. {
  103. AZ::SimpleLcgRandom random;
  104. std::vector<Seed> seeds(count);
  105. for (int i = 0; i < count; ++i)
  106. {
  107. seeds[i] = random.GetRandom();
  108. }
  109. return seeds;
  110. }
  111. const std::vector<Seed> randomSeeds = GetSeedsForTest(s_AnimGraphFuzzTestLoad);
  112. INSTANTIATE_TEST_CASE_P(InstantiationName,
  113. AnimGraphFuzzTest,
  114. ::testing::ValuesIn(randomSeeds),
  115. ::testing::PrintToStringParamName()
  116. );
  117. } //end namespace EMotionFX