/* * 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 this * 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 #include #include #include #include #include #include #include "AnimGraphFixture.h" namespace EMotionFX { // Make it clear that the AnimGraphFuzzTest fixture is parameterized on a // seed value for a Random object using Seed = unsigned int; class AnimGraphFuzzTest : public AnimGraphFixture , public ::testing::WithParamInterface { void SetUp() { AnimGraphFixture::SetUp(); } void TearDown() { AnimGraphFixture::TearDown(); } bool OnPreError(const char* window, const char* fileName, int line, const char* func, const char* message) { // These error messages will cause exceptions in debug builds. // Since the fuzz tests just make sure that the process doesn't // crash, we want to ignore these errors. static const std::vector ignoredErrorMessages { std::regex("^XML parse error: RapidXML Parse error"), std::regex("^ObjectStream XML parse error\\."), std::regex("^Unknown stream tag \\(first byte\\): '\\\\0' binary, '<' xml or '\\{' json!"), std::regex("^ObjectStream JSON load error: Stream is a newer version than object stream supports\\. ObjectStream version: .*"), std::regex("^Element .* in class .* is of type .* but needs to be type .*\\."), std::regex("^Serializer failed for .* '.*'\\(0x.*\\).") }; return IsIgnored(ignoredErrorMessages, message); } bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) { // These warnings don't crash, but they make the test super chatty. // Just silence them. static const std::vector ignoredWarningMessages { std::regex("^Element .* of type .* is not registered as part of class .*\\. Data will be discarded"), std::regex("^Invalid UUID format .* \\(must be\\) \\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\\} \\(or without dashes and braces\\)") }; return IsIgnored(ignoredWarningMessages, message); } private: bool IsIgnored(const std::vector& ignoredMessages, const char* message) { for (const std::regex& ignoredMessage : ignoredMessages) { if (std::regex_search(message, ignoredMessage)) { return true; } } return false; } }; TEST_P(AnimGraphFuzzTest, TestLoad) { AZ_TEST_START_TRACE_SUPPRESSION; // Set the root state machine's Id so to ensure consistency between test runs m_animGraph->GetRootStateMachine()->SetId(9347464774972852905u); AZStd::string charBuffer; AZ::IO::ByteContainerStream charStream(&charBuffer); AZ::Utils::SaveObjectToStream(charStream, AZ::ObjectStream::ST_XML, m_animGraph.get(), GetSerializeContext()); const Seed seed = GetParam(); AZ::SimpleLcgRandom random(seed); const size_t bufSize = charBuffer.size(); for (int i = 0; i < 10; ++i) { const unsigned int positionToEdit = random.GetRandom() % bufSize; const char newValue = random.GetRandom() % 256; charBuffer[positionToEdit] = newValue; EMotionFX::AnimGraph* animGraph = EMotionFX::AnimGraph::LoadFromBuffer(&charBuffer[0], bufSize, GetSerializeContext()); if (animGraph) { delete animGraph; } } AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; } static const std::vector GetSeedsForTest(const int count) { AZ::SimpleLcgRandom random; std::vector seeds(count); for (int i = 0; i < count; ++i) { seeds[i] = random.GetRandom(); } return seeds; } const std::vector randomSeeds = GetSeedsForTest(1000); INSTANTIATE_TEST_CASE_P(InstantiationName, AnimGraphFuzzTest, ::testing::ValuesIn(randomSeeds), ::testing::PrintToStringParamName() ); } //end namespace EMotionFX