Files
o3de/Gems/Atom/RPI/Code/Tests/Common/ErrorMessageFinder.cpp
T
santorac 1a99103999 Overhauled the .materialtype file format to group all related properties data together. This prepares the way for a number of possible improvements, especially unlocking the ability to factor out material type configuration to be shared by multiple material types.
Here we formalize the concept of a Property Set, which replaces property "groups", containing the group name and description, properties, and functors all in one place.
The Property Set structure will allow arbitrarily deep nesting, whereas before you only had one level of grouping. This nesting is not fully supported yet throughout the system, particularly in the Material Editor. It was easier to go ahead and put in some of the nesting mechanims, parituclar in the implementation of MaterialTypeSourceData.
This change is backward compatible, which is proved with unit tests, and by the fact that only MinimalPBR.materialtype has been updated to the new format. StandardPBR, EnhancedPBR, and others are still using the old format. (In a subsequent commit I'll update these as well, to prove that the new format works correctly).

Other changes and improvements...
- A new constructor for MaterialPropertyId
- Improved API for MaterialTypeSourceData that hides a good deal more of it's data as private, with clear and convenient APIs. Especially AddProperty, AddPropertySet, FindProperty, FindPropertySet, EnumerateProperties, EnumeratePropertySets.
- Added lots of new unit tests
- Updated MinimalPBR.materialtype to the new format.

Testing:
- Updated unit tests.
- Reprocessed Atom material assets.
- Ran AtomSampleViewer material screenshot test.
- Opened, edited, saved material in the Material Editor.
- Opened a level, edited material property overrides, saved and reloaded.

Signed-off-by: santorac <55155825+santorac@users.noreply.github.com>
2021-09-30 01:30:28 -07:00

171 lines
5.1 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 "ErrorMessageFinder.h"
#include <gtest/gtest.h>
#include <AzCore/UnitTest/UnitTest.h>
#include <AzFramework/StringFunc/StringFunc.h>
namespace UnitTest
{
ErrorMessageFinder::ErrorMessageFinder()
{
m_reportFailure = &ErrorMessageFinder::ReportFailure;
AZ::Debug::TraceMessageBus::Handler::BusConnect();
UnitTest::TestRunner::Instance().StartAssertTests();
}
ErrorMessageFinder::ErrorMessageFinder(AZStd::string_view message, uint32_t expectedCount)
: ErrorMessageFinder()
{
AddExpectedErrorMessage(message, expectedCount);
}
ErrorMessageFinder::~ErrorMessageFinder()
{
if (!m_disabled)
{
Disable();
}
}
void ErrorMessageFinder::Disable()
{
AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
UnitTest::TestRunner::Instance().StopAssertTests();
if (!m_checked)
{
CheckExpectedErrorsFound();
}
m_disabled = true;
}
void ErrorMessageFinder::AddExpectedErrorMessage(AZStd::string_view message, uint32_t expectedCount)
{
EXPECT_FALSE(m_disabled);
if (expectedCount > 0)
{
ExpectedError expectedError;
expectedError.m_message = message;
expectedError.m_expectedCount = expectedCount;
m_expectedErrors.push_back(expectedError);
m_checked = false;
}
}
void ErrorMessageFinder::AddIgnoredErrorMessage(AZStd::string_view message, bool matchSubstring)
{
EXPECT_FALSE(m_disabled);
OptionalError optionalError;
optionalError.m_message = message;
optionalError.m_allowSubstring = matchSubstring;
m_optionalErrors.push_back(optionalError);
}
void ErrorMessageFinder::CheckExpectedErrorsFound()
{
EXPECT_FALSE(m_disabled);
for (auto expectedError : m_expectedErrors)
{
if (expectedError.m_expectedCount != expectedError.m_gotCount)
{
AZStd::string message = AZStd::string::format("Expected error %d time(s) but got %d time(s): '%s'", expectedError.m_expectedCount, expectedError.m_gotCount, expectedError.m_message.c_str());
m_reportFailure(message);
}
}
m_checked = true;
}
void ErrorMessageFinder::ReportFailure(const AZStd::string& failureMessage)
{
FAIL() << failureMessage.c_str();
}
void ErrorMessageFinder::Reset()
{
EXPECT_FALSE(m_disabled);
m_expectedErrors.clear();
m_optionalErrors.clear();
m_checked = false;
}
void ErrorMessageFinder::ResetCounts()
{
EXPECT_FALSE(m_disabled);
AZStd::for_each(m_expectedErrors.begin(), m_expectedErrors.end(), [](ExpectedError& expectedError) { expectedError.m_gotCount = 0; });
m_checked = false;
}
bool ErrorMessageFinder::OnPreAssert(const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message)
{
return OnTrace(message);
}
bool ErrorMessageFinder::OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message)
{
return OnTrace(message);
}
bool ErrorMessageFinder::OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message)
{
return OnTrace(message);
}
bool ErrorMessageFinder::OnTrace(AZStd::string_view message)
{
bool found = false;
for (auto expectedErrorIter = m_expectedErrors.begin(); expectedErrorIter != m_expectedErrors.end(); ++expectedErrorIter)
{
if (AzFramework::StringFunc::Find(message, expectedErrorIter->m_message) != AZStd::string::npos)
{
found = true;
++expectedErrorIter->m_gotCount;
}
}
if (!found)
{
for (auto& optionalError : m_optionalErrors)
{
if (optionalError.m_message == message)
{
found = true;
break;
}
else if (optionalError.m_allowSubstring && message.find(optionalError.m_message) != AZStd::string::npos)
{
found = true;
break;
}
}
}
if (!found)
{
// We will return false below, but there are been times in the past when that did not trigger gtest failures
// as expected, so we report the failure directly here. It might get reported again by another trace hander.
AZStd::string fullMessage = AZStd::string::format("Detected unexpected error message: '%.*s'", AZ_STRING_ARG(message));
m_reportFailure(fullMessage);
}
m_checked = false;
return found;
}
}