You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/EMotionFX/Code/Tests/AnimGraphFuzzTests.cpp

139 lines
4.9 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <vector>
#include <regex>
#include <AzCore/Math/Random.h>
#include <EMotionFX/Source/AnimGraph.h>
#include <EMotionFX/Source/AnimGraphStateMachine.h>
#include <AzCore/IO/ByteContainerStream.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/UnitTest/UnitTest.h>
#include "AnimGraphFixture.h"
#include "EMotionFX_Traits_Platform.h"
namespace EMotionFX
{
// Control the load for the AnimGraphFuzzTest
static constexpr int s_AnimGraphFuzzTestLoad = 100;
// 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<Seed>
{
void SetUp()
{
AnimGraphFixture::SetUp();
}
void TearDown()
{
AnimGraphFixture::TearDown();
}
bool OnPreError([[maybe_unused]] const char* window, [[maybe_unused]] const char* fileName, [[maybe_unused]] int line, [[maybe_unused]] 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<std::regex> 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<std::regex> 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<std::regex>& 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<AZStd::string > 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<Seed> GetSeedsForTest(const int count)
{
AZ::SimpleLcgRandom random;
std::vector<Seed> seeds(count);
for (int i = 0; i < count; ++i)
{
seeds[i] = random.GetRandom();
}
return seeds;
}
const std::vector<Seed> randomSeeds = GetSeedsForTest(s_AnimGraphFuzzTestLoad);
INSTANTIATE_TEST_CASE_P(InstantiationName,
AnimGraphFuzzTest,
::testing::ValuesIn(randomSeeds),
::testing::PrintToStringParamName()
);
} //end namespace EMotionFX