Merge branch 'upstream/development' into LYN-8514_AutomatedReviewServerLogChecks
This commit is contained in:
@@ -148,6 +148,7 @@ class TestAutomation(EditorTestSuite):
|
||||
class test_SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes(EditorParallelTest):
|
||||
from .EditorScripts import SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope as test_module
|
||||
|
||||
@pytest.mark.xfail(reason="Intermittently fails to create level")
|
||||
class test_DynamicSliceInstanceSpawner_Embedded_E2E_Editor(EditorSingleTest):
|
||||
from .EditorScripts import DynamicSliceInstanceSpawner_Embedded_E2E as test_module
|
||||
|
||||
@@ -156,6 +157,7 @@ class TestAutomation(EditorTestSuite):
|
||||
file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "Levels", "tmp_level")],
|
||||
True, True)
|
||||
|
||||
@pytest.mark.xfail(reason="Intermittently fails to create level")
|
||||
class test_DynamicSliceInstanceSpawner_External_E2E_Editor(EditorSingleTest):
|
||||
from .EditorScripts import DynamicSliceInstanceSpawner_External_E2E as test_module
|
||||
|
||||
@@ -163,7 +165,8 @@ class TestAutomation(EditorTestSuite):
|
||||
def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "Levels", "tmp_level")],
|
||||
True, True)
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Intermittently fails to create level")
|
||||
class test_LayerBlender_E2E_Editor(EditorSingleTest):
|
||||
from .EditorScripts import LayerBlender_E2E_Editor as test_module
|
||||
|
||||
|
||||
@@ -325,13 +325,13 @@ namespace AZ
|
||||
|
||||
T& operator*() const
|
||||
{
|
||||
AZ_Assert(m_assetData, "Asset is not loaded");
|
||||
AZ_Assert(m_assetData, "Asset %s (%s) is not loaded", m_assetId.ToString<AZStd::string>().c_str(), m_assetHint.c_str());
|
||||
return *Get();
|
||||
}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
AZ_Assert(m_assetData, "Asset is not loaded");
|
||||
AZ_Assert(m_assetData, "Asset %s (%s) is not loaded", m_assetId.ToString<AZStd::string>().c_str(), m_assetHint.c_str());
|
||||
return Get();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
//
|
||||
// When AZ_CRC("My string") is used by default it will map to AZ::Crc32("My string").
|
||||
// We do have a pro-processor program which will precompute the crc for you and
|
||||
// transform that macro to AZ_CRC("My string",0xabcdef00) this will expand to just 0xabcdef00.
|
||||
// transform that macro to AZ_CRC("My string", 0x18fbd270) this will expand to just 0x18fbd270.
|
||||
// This will remove completely the "My string" from your executable, it will add it to a database and so on.
|
||||
// WHen you want to update the string, just change the string.
|
||||
// If you don't run the precompile step the code should still run fine, except it will be slower,
|
||||
@@ -24,7 +24,7 @@
|
||||
// a constant expression.
|
||||
// For example
|
||||
// switch(id) {
|
||||
// case AZ_CRC("My string",0xabcdef00): {} break; // this will compile fine
|
||||
// case AZ_CRC("My string",0x18fbd270): {} break; // this will compile fine
|
||||
// case AZ_CRC("My string"): {} break; // this will cause "error C2051: case expression not constant"
|
||||
// }
|
||||
// So it's you choice what you do, depending on your needs.
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/parallel/condition_variable.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/UnitTest/Mocks/MockFileIOBase.h>
|
||||
#include <AZTestShared/Utils/Utils.h>
|
||||
#include <Streamer/IStreamerMock.h>
|
||||
#include <Tests/Asset/BaseAssetManagerTest.h>
|
||||
@@ -131,8 +132,8 @@ namespace UnitTest
|
||||
* This will test the aspect of the system where ObjectStreams and asset jobs loading dependent
|
||||
* assets will do the work in their own thread.
|
||||
*/
|
||||
class AssetJobsFloodTest
|
||||
: public BaseAssetManagerTest
|
||||
|
||||
class AssetJobsFloodTest : public DisklessAssetManagerBase
|
||||
{
|
||||
public:
|
||||
TestAssetManager* m_testAssetManager{ nullptr };
|
||||
@@ -183,15 +184,14 @@ namespace UnitTest
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BaseAssetManagerTest::SetUp();
|
||||
DisklessAssetManagerBase::SetUp();
|
||||
SetupTest();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
TearDownTest();
|
||||
AssetManager::Destroy();
|
||||
BaseAssetManagerTest::TearDown();
|
||||
DisklessAssetManagerBase::TearDown();
|
||||
}
|
||||
|
||||
void SetupAssets()
|
||||
@@ -257,9 +257,9 @@ namespace UnitTest
|
||||
AssetWithSerializedData ap2;
|
||||
AssetWithSerializedData ap3;
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset4.txt", AZ::DataStream::ST_XML, &ap1, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset5.txt", AZ::DataStream::ST_XML, &ap2, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset6.txt", AZ::DataStream::ST_XML, &ap3, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset4.txt", &ap1, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset5.txt", &ap2, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset6.txt", &ap3, m_serializeContext));
|
||||
|
||||
AssetWithAssetReference assetWithPreload1;
|
||||
AssetWithAssetReference assetWithPreload2;
|
||||
@@ -273,11 +273,11 @@ namespace UnitTest
|
||||
noLoadAsset.m_asset = m_testAssetManager->CreateAsset<AssetWithSerializedData>(MyAsset2Id, AssetLoadBehavior::NoLoad);
|
||||
EXPECT_EQ(m_assetHandlerAndCatalog->m_numCreations, 4);
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset1.txt", AZ::DataStream::ST_XML, &assetWithPreload1, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset2.txt", AZ::DataStream::ST_XML, &assetWithPreload2, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset3.txt", AZ::DataStream::ST_XML, &assetWithPreload3, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "DelayLoadAsset.txt", AZ::DataStream::ST_XML, &delayedAsset, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "NoLoadAsset.txt", AZ::DataStream::ST_XML, &noLoadAsset, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset1.txt", &assetWithPreload1, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset2.txt", &assetWithPreload2, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset3.txt", &assetWithPreload3, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("DelayLoadAsset.txt", &delayedAsset, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("NoLoadAsset.txt", &noLoadAsset, m_serializeContext));
|
||||
|
||||
AssetWithQueueAndPreLoadReferences preLoadRoot;
|
||||
AssetWithQueueAndPreLoadReferences preLoadA;
|
||||
@@ -297,16 +297,16 @@ namespace UnitTest
|
||||
preLoadBrokenA.m_preLoad = m_testAssetManager->CreateAsset<AssetWithAssetReference>(PreloadBrokenDepBId, AssetLoadBehavior::PreLoad);
|
||||
preLoadBrokenB.m_preLoad = m_testAssetManager->CreateAsset<AssetWithAssetReference>(PreloadAssetNoDataId, AssetLoadBehavior::PreLoad);
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadRoot.txt", AZ::DataStream::ST_XML, &preLoadRoot, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadA.txt", AZ::DataStream::ST_XML, &preLoadA, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadB.txt", AZ::DataStream::ST_XML, &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadC.txt", AZ::DataStream::ST_XML, &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "QueueLoadA.txt", AZ::DataStream::ST_XML, &queueLoadA, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "QueueLoadB.txt", AZ::DataStream::ST_XML, &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "QueueLoadC.txt", AZ::DataStream::ST_XML, &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadBrokenA.txt", AZ::DataStream::ST_XML, &preLoadBrokenA, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadBrokenB.txt", AZ::DataStream::ST_XML, &preLoadBrokenB, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "PreLoadNoData.txt", AZ::DataStream::ST_XML, &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadRoot.txt", &preLoadRoot, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadA.txt", &preLoadA, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadB.txt", &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadC.txt", &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("QueueLoadA.txt", &queueLoadA, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("QueueLoadB.txt", &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("QueueLoadC.txt", &noRefs, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadBrokenA.txt", &preLoadBrokenA, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadBrokenB.txt", &preLoadBrokenB, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("PreLoadNoData.txt", &noRefs, m_serializeContext));
|
||||
|
||||
AssetWithQueueAndPreLoadReferences circularA;
|
||||
AssetWithQueueAndPreLoadReferences circularB;
|
||||
@@ -318,43 +318,15 @@ namespace UnitTest
|
||||
circularC.m_preLoad = m_testAssetManager->CreateAsset<AssetWithAssetReference>(CircularBId, AssetLoadBehavior::PreLoad);
|
||||
circularD.m_preLoad = circularC.m_preLoad;
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "CircularA.txt", AZ::DataStream::ST_XML, &circularA, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "CircularB.txt", AZ::DataStream::ST_XML, &circularB, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "CircularC.txt", AZ::DataStream::ST_XML, &circularC, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "CircularD.txt", AZ::DataStream::ST_XML, &circularD, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("CircularA.txt", &circularA, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("CircularB.txt", &circularB, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("CircularC.txt", &circularC, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("CircularD.txt", &circularD, m_serializeContext));
|
||||
|
||||
m_assetHandlerAndCatalog->m_numCreations = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TearDownTest()
|
||||
{
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset4.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset5.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset6.txt");
|
||||
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset1.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset2.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "TestAsset3.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "DelayLoadAsset.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "NoLoadAsset.txt");
|
||||
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadRoot.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadA.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadB.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadC.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "QueueLoadA.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "QueueLoadB.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "QueueLoadC.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadBrokenA.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadBrokenB.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "PreLoadNoData.txt");
|
||||
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "CircularA.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "CircularB.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "CircularC.txt");
|
||||
DeleteAssetFromDisk(GetTestFolderPath() + "CircularD.txt");
|
||||
}
|
||||
|
||||
void CheckFinishedCreationsAndDestructions()
|
||||
{
|
||||
// Make sure asset jobs have finished before validating the number of destroyed assets, because it's possible that the asset job
|
||||
@@ -367,7 +339,7 @@ namespace UnitTest
|
||||
};
|
||||
|
||||
static constexpr AZStd::chrono::seconds MaxDispatchTimeoutSeconds = BaseAssetManagerTest::DefaultTimeoutSeconds * 12;
|
||||
|
||||
|
||||
template <typename Pred>
|
||||
bool DispatchEventsUntilCondition(AZ::Data::AssetManager& assetManager, Pred&& conditionPredicate,
|
||||
AZStd::chrono::seconds logIntervalSeconds = BaseAssetManagerTest::DefaultTimeoutSeconds,
|
||||
@@ -608,7 +580,7 @@ namespace UnitTest
|
||||
AZ::Data::AssetData::AssetStatus expected_base_status = AZ::Data::AssetData::AssetStatus::Ready;
|
||||
EXPECT_EQ(baseStatus, expected_base_status);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(AssetJobsFloodTest, RapidAcquireAndRelease)
|
||||
{
|
||||
auto assetUuids = {
|
||||
@@ -641,7 +613,7 @@ namespace UnitTest
|
||||
{
|
||||
Asset<AssetWithAssetReference> asset1 =
|
||||
m_testAssetManager->GetAsset(assetUuid, azrtti_typeid<AssetWithAssetReference>(), AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
|
||||
|
||||
if (checkLoaded)
|
||||
{
|
||||
asset1.BlockUntilLoadComplete();
|
||||
@@ -714,8 +686,8 @@ namespace UnitTest
|
||||
|
||||
AssetWithSerializedData ap;
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "a.txt", AZ::DataStream::ST_XML, &ap, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "b.txt", AZ::DataStream::ST_XML, &ap, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("a.txt", &ap, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("b.txt", &ap, m_serializeContext));
|
||||
}
|
||||
|
||||
auto& assetManager = AssetManager::Instance();
|
||||
@@ -778,7 +750,7 @@ namespace UnitTest
|
||||
* Verify that loads without using the Asset Container still work correctly
|
||||
*/
|
||||
class AssetContainerDisableTest
|
||||
: public BaseAssetManagerTest
|
||||
: public DisklessAssetManagerBase
|
||||
{
|
||||
public:
|
||||
static inline const AZ::Uuid MyAsset1Id{ "{5B29FE2B-6B41-48C9-826A-C723951B0560}" };
|
||||
@@ -797,7 +769,7 @@ namespace UnitTest
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BaseAssetManagerTest::SetUp();
|
||||
DisklessAssetManagerBase::SetUp();
|
||||
SetupTest();
|
||||
|
||||
}
|
||||
@@ -807,7 +779,7 @@ namespace UnitTest
|
||||
AssetManager::Instance().UnregisterHandler(m_assetHandlerAndCatalog);
|
||||
delete m_assetHandlerAndCatalog;
|
||||
AssetManager::Destroy();
|
||||
BaseAssetManagerTest::TearDown();
|
||||
DisklessAssetManagerBase::TearDown();
|
||||
}
|
||||
|
||||
void SetupAssets()
|
||||
@@ -849,9 +821,9 @@ namespace UnitTest
|
||||
AssetWithSerializedData ap2;
|
||||
AssetWithSerializedData ap3;
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset4.txt", AZ::DataStream::ST_XML, &ap1, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset5.txt", AZ::DataStream::ST_XML, &ap2, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset6.txt", AZ::DataStream::ST_XML, &ap3, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset4.txt", &ap1, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset5.txt", &ap2, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset6.txt", &ap3, m_serializeContext));
|
||||
|
||||
AssetWithAssetReference assetWithPreload1;
|
||||
AssetWithAssetReference assetWithPreload2;
|
||||
@@ -862,9 +834,9 @@ namespace UnitTest
|
||||
assetWithPreload3.m_asset = m_testAssetManager->CreateAsset<AssetWithSerializedData>(MyAsset6Id, AssetLoadBehavior::PreLoad);
|
||||
EXPECT_EQ(m_assetHandlerAndCatalog->m_numCreations, 3);
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset1.txt", AZ::DataStream::ST_XML, &assetWithPreload1, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset2.txt", AZ::DataStream::ST_XML, &assetWithPreload2, m_serializeContext));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset3.txt", AZ::DataStream::ST_XML, &assetWithPreload3, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset1.txt", &assetWithPreload1, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset2.txt", &assetWithPreload2, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset3.txt", &assetWithPreload3, m_serializeContext));
|
||||
|
||||
m_assetHandlerAndCatalog->m_numCreations = 0;
|
||||
}
|
||||
@@ -2014,11 +1986,12 @@ namespace UnitTest
|
||||
CheckFinishedCreationsAndDestructions();
|
||||
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run multiple threads that get and release assets simultaneously to test AssetManager's thread safety
|
||||
*/
|
||||
class AssetJobsMultithreadedTest
|
||||
: public BaseAssetManagerTest
|
||||
: public DisklessAssetManagerBase
|
||||
{
|
||||
public:
|
||||
static inline const AZ::Uuid MyAsset1Id{ "{5B29FE2B-6B41-48C9-826A-C723951B0560}" };
|
||||
@@ -2028,6 +2001,7 @@ namespace UnitTest
|
||||
static inline const AZ::Uuid MyAsset5Id{ "{D9CDAB04-D206-431E-BDC0-1DD615D56197}" };
|
||||
static inline const AZ::Uuid MyAsset6Id{ "{B2F139C3-5032-4B52-ADCA-D52A8F88E043}" };
|
||||
|
||||
|
||||
// Initialize the Job Manager with 2 threads for the Asset Manager to use.
|
||||
size_t GetNumJobManagerThreads() const override { return 2; }
|
||||
|
||||
@@ -2078,9 +2052,9 @@ namespace UnitTest
|
||||
AssetWithSerializedData ap2;
|
||||
AssetWithSerializedData ap3;
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset4.txt", AZ::DataStream::ST_XML, &ap1, &context));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset5.txt", AZ::DataStream::ST_XML, &ap2, &context));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset6.txt", AZ::DataStream::ST_XML, &ap3, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset4.txt", &ap1, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset5.txt", &ap2, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset6.txt", &ap3, &context));
|
||||
|
||||
AssetWithAssetReference assetWithPreload1;
|
||||
AssetWithAssetReference assetWithPreload2;
|
||||
@@ -2089,9 +2063,9 @@ namespace UnitTest
|
||||
assetWithPreload2.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset5Id, AssetLoadBehavior::PreLoad);
|
||||
assetWithPreload3.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset6Id, AssetLoadBehavior::PreLoad);
|
||||
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset1.txt", AZ::DataStream::ST_XML, &assetWithPreload1, &context));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset2.txt", AZ::DataStream::ST_XML, &assetWithPreload2, &context));
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset3.txt", AZ::DataStream::ST_XML, &assetWithPreload3, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset1.txt", &assetWithPreload1, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset2.txt", &assetWithPreload2, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset3.txt", &assetWithPreload3, &context));
|
||||
|
||||
EXPECT_TRUE(assetHandlerAndCatalog->m_numCreations == 3);
|
||||
assetHandlerAndCatalog->m_numCreations = 0;
|
||||
@@ -2191,22 +2165,22 @@ namespace UnitTest
|
||||
// A will be saved to disk with MyAsset1Id
|
||||
AssetWithAssetReference a;
|
||||
a.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset2Id);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset1.txt", AZ::DataStream::ST_XML, &a, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset1.txt", &a, &context));
|
||||
AssetWithAssetReference b;
|
||||
b.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset3Id);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset2.txt", AZ::DataStream::ST_XML, &b, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset2.txt", &b, &context));
|
||||
AssetWithAssetReference c;
|
||||
c.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset4Id);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset3.txt", AZ::DataStream::ST_XML, &c, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset3.txt", &c, &context));
|
||||
AssetWithAssetReference d;
|
||||
d.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset5Id);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset4.txt", AZ::DataStream::ST_XML, &d, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset4.txt", &d, &context));
|
||||
AssetWithAssetReference e;
|
||||
e.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset6Id);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset5.txt", AZ::DataStream::ST_XML, &e, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset5.txt", &e, &context));
|
||||
AssetWithAssetReference f;
|
||||
f.m_asset = AssetManager::Instance().CreateAsset<AssetWithSerializedData>(MyAsset1Id); // refer back to asset1
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset6.txt", AZ::DataStream::ST_XML, &f, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset6.txt", &f, &context));
|
||||
|
||||
EXPECT_TRUE(assetHandlerAndCatalog->m_numCreations == 6);
|
||||
assetHandlerAndCatalog->m_numCreations = 0;
|
||||
@@ -2347,26 +2321,26 @@ namespace UnitTest
|
||||
// AssetD is MYASSETD
|
||||
AssetWithSerializedData d;
|
||||
d.m_data = 42;
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset4.txt", AZ::DataStream::ST_XML, &d, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset4.txt", &d, &context));
|
||||
|
||||
// AssetC is MYASSETC
|
||||
AssetWithAssetReference c;
|
||||
c.m_asset = db.CreateAsset<AssetWithSerializedData>(AssetId(MyAssetDId)); // point at D
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset3.txt", AZ::DataStream::ST_XML, &c, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset3.txt", &c, &context));
|
||||
|
||||
// AssetB is MYASSETB
|
||||
AssetWithAssetReference b;
|
||||
b.m_asset = db.CreateAsset<AssetWithAssetReference>(AssetId(MyAssetCId)); // point at C
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset2.txt", AZ::DataStream::ST_XML, &b, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset2.txt", &b, &context));
|
||||
|
||||
// AssetA will be written to disk as MYASSETA
|
||||
AssetWithAssetReference a;
|
||||
a.m_asset = db.CreateAsset<AssetWithAssetReference>(AssetId(MyAssetBId)); // point at B
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset1.txt", AZ::DataStream::ST_XML, &a, &context));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("TestAsset1.txt", &a, &context));
|
||||
}
|
||||
|
||||
const size_t numThreads = 4;
|
||||
AZStd::atomic_int threadCount(numThreads);
|
||||
constexpr size_t NumThreads = 4;
|
||||
AZStd::atomic_int threadCount(NumThreads);
|
||||
AZStd::condition_variable cv;
|
||||
AZStd::vector<AZStd::thread> threads;
|
||||
AZStd::atomic_bool keepDispatching(true);
|
||||
@@ -2381,7 +2355,7 @@ namespace UnitTest
|
||||
|
||||
AZStd::thread dispatchThread(dispatch);
|
||||
|
||||
for (size_t threadIdx = 0; threadIdx < numThreads; ++threadIdx)
|
||||
for (size_t threadIdx = 0; threadIdx < NumThreads; ++threadIdx)
|
||||
{
|
||||
threads.emplace_back([&threadCount, &db, &cv]()
|
||||
{
|
||||
@@ -2569,7 +2543,6 @@ namespace UnitTest
|
||||
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
TEST_F(AssetJobsMultithreadedTest, DISABLED_ParallelDeepAssetReferences)
|
||||
#else
|
||||
// temporarily disabled until sporadic failures can be root caused
|
||||
TEST_F(AssetJobsMultithreadedTest, ParallelDeepAssetReferences)
|
||||
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
{
|
||||
@@ -2577,7 +2550,7 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
class AssetManagerTests
|
||||
: public BaseAssetManagerTest
|
||||
: public DisklessAssetManagerBase
|
||||
{
|
||||
protected:
|
||||
static inline const AZ::Uuid MyAsset1Id{ "{5B29FE2B-6B41-48C9-826A-C723951B0560}" };
|
||||
@@ -2592,7 +2565,7 @@ namespace UnitTest
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BaseAssetManagerTest::SetUp();
|
||||
DisklessAssetManagerBase::SetUp();
|
||||
|
||||
m_console = AZStd::make_unique<AZ::Console>();
|
||||
AZ::Interface<AZ::IConsole>::Register(m_console.get());
|
||||
@@ -2631,7 +2604,7 @@ namespace UnitTest
|
||||
AssetManager::Destroy();
|
||||
AZ::Interface<AZ::IConsole>::Unregister(m_console.get());
|
||||
m_console = nullptr;
|
||||
BaseAssetManagerTest::TearDown();
|
||||
DisklessAssetManagerBase::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2982,7 +2955,7 @@ namespace UnitTest
|
||||
* the middle of loading. The tests help ensure that assets can't get stuck in perpetual loading states.
|
||||
**/
|
||||
class AssetManagerClearAssetReferenceTests
|
||||
: public BaseAssetManagerTest
|
||||
: public DisklessAssetManagerBase
|
||||
{
|
||||
protected:
|
||||
static inline const AZ::Uuid RootAssetId{ "{AB13F568-C676-41FE-A7E9-341F71A78104}" };
|
||||
@@ -3001,7 +2974,7 @@ namespace UnitTest
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BaseAssetManagerTest::SetUp();
|
||||
DisklessAssetManagerBase::SetUp();
|
||||
|
||||
// create the database
|
||||
AssetManager::Descriptor desc;
|
||||
@@ -3039,21 +3012,18 @@ namespace UnitTest
|
||||
|
||||
// Create and save the dependent asset first, so that we can get a reference to it.
|
||||
AssetWithSerializedData dependentBlockingAsset;
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "DependentPreloadBlockingAsset.txt",
|
||||
AZ::DataStream::ST_XML, &dependentBlockingAsset, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("DependentPreloadBlockingAsset.txt", &dependentBlockingAsset, m_serializeContext));
|
||||
|
||||
AssetWithAssetReference dependentAsset;
|
||||
dependentAsset.m_asset = AssetManager::Instance().CreateAsset<AssetWithAssetReference>(
|
||||
NestedDependentPreloadBlockingAssetId, AssetLoadBehavior::PreLoad);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "DependentPreloadAsset.txt",
|
||||
AZ::DataStream::ST_XML, &dependentAsset, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("DependentPreloadAsset.txt", &dependentAsset, m_serializeContext));
|
||||
|
||||
// Create and save the top-level asset.
|
||||
AssetWithAssetReference rootAsset;
|
||||
rootAsset.m_asset = AssetManager::Instance().CreateAsset<AssetWithAssetReference>(
|
||||
DependentPreloadAssetId, AssetLoadBehavior::PreLoad);
|
||||
EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "RootAsset.txt",
|
||||
AZ::DataStream::ST_XML, &rootAsset, m_serializeContext));
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile("RootAsset.txt", &rootAsset, m_serializeContext));
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
@@ -3065,7 +3035,7 @@ namespace UnitTest
|
||||
delete m_assetHandlerAndCatalog;
|
||||
|
||||
AssetManager::Destroy();
|
||||
BaseAssetManagerTest::TearDown();
|
||||
DisklessAssetManagerBase::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -165,4 +165,254 @@ namespace UnitTest
|
||||
|
||||
EXPECT_FALSE(AssetManager::Instance().HasActiveJobsOrStreamerRequests());
|
||||
}
|
||||
|
||||
MemoryStreamerWrapper::MemoryStreamerWrapper()
|
||||
{
|
||||
using ::testing::_;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::Return;
|
||||
|
||||
ON_CALL(m_mockStreamer, SuspendProcessing()).WillByDefault([this]()
|
||||
{
|
||||
m_suspended = true;
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, ResumeProcessing()).WillByDefault([this]()
|
||||
{
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
|
||||
m_suspended = false;
|
||||
|
||||
while (!m_processingQueue.empty())
|
||||
{
|
||||
FileRequestHandle requestHandle = m_processingQueue.front();
|
||||
m_processingQueue.pop();
|
||||
|
||||
const auto& onCompleteCallback = GetReadRequest(requestHandle)->m_callback;
|
||||
|
||||
if (onCompleteCallback)
|
||||
{
|
||||
onCompleteCallback(requestHandle);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, Read(_, ::testing::An<IStreamerTypes::RequestMemoryAllocator&>(), _, _, _, _))
|
||||
.WillByDefault(
|
||||
[this](
|
||||
[[maybe_unused]] AZStd::string_view relativePath, IStreamerTypes::RequestMemoryAllocator& allocator, size_t size,
|
||||
AZStd::chrono::microseconds deadline, IStreamerTypes::Priority priority, [[maybe_unused]] size_t offset)
|
||||
{
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
|
||||
ReadRequest request;
|
||||
|
||||
// Save off the requested deadline and priority
|
||||
request.m_deadline = deadline;
|
||||
request.m_priority = priority;
|
||||
request.m_data = allocator.Allocate(size, size, 8);
|
||||
|
||||
const auto* virtualFile = FindFile(relativePath);
|
||||
|
||||
AZ_Assert(
|
||||
virtualFile->size() == size, "Streamer read request size did not match size of saved file: %d vs %d (%.*s)",
|
||||
virtualFile->size(), size,
|
||||
relativePath.size(), relativePath.data());
|
||||
AZ_Assert(size > 0, "Size is zero %.*s", relativePath.size(), relativePath.data());
|
||||
|
||||
memcpy(request.m_data.m_address, virtualFile->data(), size);
|
||||
|
||||
// Create a real file request result and return it
|
||||
request.m_request = m_context.GetNewExternalRequest();
|
||||
|
||||
m_readRequests.push_back(request);
|
||||
|
||||
return request.m_request;
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, SetRequestCompleteCallback(_, _))
|
||||
.WillByDefault([this](FileRequestPtr& request, AZ::IO::IStreamer::OnCompleteCallback callback) -> FileRequestPtr&
|
||||
{
|
||||
// Save off the callback just so that we can call it when the request is "done"
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
ReadRequest* readRequest = GetReadRequest(request);
|
||||
readRequest->m_callback = callback;
|
||||
|
||||
return request;
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, QueueRequest(_))
|
||||
.WillByDefault([this](const auto& fileRequest)
|
||||
{
|
||||
if (!m_suspended)
|
||||
{
|
||||
decltype(ReadRequest::m_callback) onCompleteCallback;
|
||||
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
ReadRequest* readRequest = GetReadRequest(fileRequest);
|
||||
onCompleteCallback = readRequest->m_callback;
|
||||
|
||||
if (onCompleteCallback)
|
||||
{
|
||||
onCompleteCallback(fileRequest);
|
||||
|
||||
m_readRequests.erase(readRequest);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
|
||||
m_processingQueue.push(fileRequest);
|
||||
}
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, GetRequestStatus(_))
|
||||
.WillByDefault([]([[maybe_unused]] FileRequestHandle request)
|
||||
{
|
||||
// Return whatever request status has been set in this class
|
||||
return IO::IStreamerTypes::RequestStatus::Completed;
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, GetReadRequestResult(_, _, _, _))
|
||||
.WillByDefault([this](
|
||||
[[maybe_unused]] FileRequestHandle request, void*& buffer, AZ::u64& numBytesRead,
|
||||
IStreamerTypes::ClaimMemory claimMemory)
|
||||
{
|
||||
// Make sure the requestor plans to free the data buffer we allocated.
|
||||
EXPECT_EQ(claimMemory, IStreamerTypes::ClaimMemory::Yes);
|
||||
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
|
||||
ReadRequest* readRequest = GetReadRequest(request);
|
||||
|
||||
// Provide valid data buffer results.
|
||||
numBytesRead = readRequest->m_data.m_size;
|
||||
buffer = readRequest->m_data.m_address;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
ON_CALL(m_mockStreamer, RescheduleRequest(_, _, _))
|
||||
.WillByDefault([this](IO::FileRequestPtr target, AZStd::chrono::microseconds newDeadline, IO::IStreamerTypes::Priority newPriority)
|
||||
{
|
||||
AZStd::unique_lock lock(m_mutex);
|
||||
ReadRequest* readRequest = GetReadRequest(target);
|
||||
|
||||
readRequest->m_deadline = newDeadline;
|
||||
readRequest->m_priority = newPriority;
|
||||
|
||||
return target;
|
||||
});
|
||||
}
|
||||
|
||||
ReadRequest* MemoryStreamerWrapper::GetReadRequest(FileRequestHandle request)
|
||||
{
|
||||
auto itr = AZStd::find_if(
|
||||
m_readRequests.begin(), m_readRequests.end(),
|
||||
[request](const ReadRequest& searchItem) -> bool
|
||||
{
|
||||
return (searchItem.m_request == request);
|
||||
});
|
||||
|
||||
return itr;
|
||||
}
|
||||
|
||||
AZStd::vector<char>* MemoryStreamerWrapper::FindFile(AZStd::string_view path)
|
||||
{
|
||||
auto itr = m_virtualFiles.find(path);
|
||||
|
||||
if (itr == m_virtualFiles.end())
|
||||
{
|
||||
// Path didn't work as-is, does it have the test folder prefixed? If so try removing it
|
||||
if (AZ::StringFunc::StartsWith(path, GetTestFolderPath()))
|
||||
{
|
||||
AZStd::string_view pathWithoutFolder = path;
|
||||
|
||||
pathWithoutFolder = AZ::StringFunc::LStrip(pathWithoutFolder, GetTestFolderPath().c_str());
|
||||
itr = m_virtualFiles.find(pathWithoutFolder);
|
||||
}
|
||||
else // Path isn't prefixed, so try adding it
|
||||
{
|
||||
itr = m_virtualFiles.find(GetTestFolderPath().append(path));
|
||||
}
|
||||
}
|
||||
|
||||
if (itr != m_virtualFiles.end())
|
||||
{
|
||||
return &itr->second;
|
||||
}
|
||||
|
||||
// Currently no test expects a file not to exist so we assert to make it easy to quickly find where something went wrong
|
||||
// If we ever need to test for a non-existent file this assert should just be conditionally disabled for that specific test
|
||||
AZ_Assert(false, "Failed to find virtual file %*.s", path.size(), path.data())
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DisklessAssetManagerBase::SetUp()
|
||||
{
|
||||
using ::testing::_;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::Return;
|
||||
|
||||
BaseAssetManagerTest::SetUp();
|
||||
|
||||
ON_CALL(m_fileIO, Size(::testing::Matcher<const char*>(::testing::_), _))
|
||||
.WillByDefault(
|
||||
[this](const char* path, u64& size)
|
||||
{
|
||||
AZStd::scoped_lock lock(m_streamerWrapper->m_mutex);
|
||||
|
||||
const auto* file = m_streamerWrapper->FindFile(path);
|
||||
|
||||
if (file)
|
||||
{
|
||||
size = file->size();
|
||||
return ResultCode::Success;
|
||||
}
|
||||
|
||||
AZ_Error("DisklessAssetManagerBase", false, "Failed to find virtual file %.*s", path);
|
||||
|
||||
return ResultCode::Error;
|
||||
});
|
||||
|
||||
m_prevFileIO = IO::FileIOBase::GetInstance();
|
||||
IO::FileIOBase::SetInstance(nullptr);
|
||||
IO::FileIOBase::SetInstance(&m_fileIO);
|
||||
}
|
||||
|
||||
void DisklessAssetManagerBase::TearDown()
|
||||
{
|
||||
IO::FileIOBase::SetInstance(nullptr);
|
||||
IO::FileIOBase::SetInstance(m_prevFileIO);
|
||||
|
||||
BaseAssetManagerTest::TearDown();
|
||||
}
|
||||
|
||||
IO::IStreamer* DisklessAssetManagerBase::CreateStreamer()
|
||||
{
|
||||
m_streamerWrapper = AZStd::make_unique<MemoryStreamerWrapper>();
|
||||
|
||||
return &(m_streamerWrapper->m_mockStreamer);
|
||||
}
|
||||
|
||||
void DisklessAssetManagerBase::DestroyStreamer(IO::IStreamer*)
|
||||
{
|
||||
m_streamerWrapper = nullptr;
|
||||
}
|
||||
|
||||
void DisklessAssetManagerBase::WriteAssetToDisk(const AZStd::string& assetName, const AZStd::string&)
|
||||
{
|
||||
AZStd::string assetFileName = GetTestFolderPath() + assetName;
|
||||
|
||||
AssetWithCustomData asset;
|
||||
|
||||
EXPECT_TRUE(m_streamerWrapper->WriteMemoryFile(assetFileName, &asset, m_serializeContext));
|
||||
}
|
||||
|
||||
void DisklessAssetManagerBase::DeleteAssetFromDisk(const AZStd::string&)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
#include <Tests/Asset/TestAssetTypes.h>
|
||||
#include <Tests/SerializeContextFixture.h>
|
||||
#include <Tests/TestCatalog.h>
|
||||
|
||||
#include <AzCore/UnitTest/Mocks/MockFileIOBase.h>
|
||||
#include <Streamer/IStreamerMock.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
@@ -58,7 +59,11 @@ namespace UnitTest
|
||||
|
||||
// Subclasses can optionally override the streamer creation and destruction
|
||||
virtual IO::IStreamer* CreateStreamer() { return aznew IO::Streamer(AZStd::thread_desc{}, StreamerComponent::CreateStreamerStack()); }
|
||||
virtual void DestroyStreamer(IO::IStreamer* streamer) { delete streamer; }
|
||||
virtual void DestroyStreamer(IO::IStreamer* streamer)
|
||||
{
|
||||
delete streamer;
|
||||
streamer = nullptr;
|
||||
}
|
||||
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
@@ -66,8 +71,8 @@ namespace UnitTest
|
||||
static void SuppressTraceOutput(bool suppress);
|
||||
|
||||
// Helper methods to create and destroy actual assets on the disk for true end-to-end asset loading.
|
||||
void WriteAssetToDisk(const AZStd::string& assetName, const AZStd::string& assetIdGuid);
|
||||
void DeleteAssetFromDisk(const AZStd::string& assetName);
|
||||
virtual void WriteAssetToDisk(const AZStd::string& assetName, const AZStd::string& assetIdGuid);
|
||||
virtual void DeleteAssetFromDisk(const AZStd::string& assetName);
|
||||
|
||||
void BlockUntilAssetJobsAreComplete();
|
||||
|
||||
@@ -82,4 +87,57 @@ namespace UnitTest
|
||||
AZStd::vector<AZStd::string> m_assetsWritten;
|
||||
};
|
||||
|
||||
|
||||
struct ReadRequest
|
||||
{
|
||||
AZStd::chrono::milliseconds m_deadline{};
|
||||
AZ::IO::IStreamerTypes::Priority m_priority{};
|
||||
IO::IStreamerTypes::RequestMemoryAllocatorResult m_data{ nullptr, 0, IO::IStreamerTypes::MemoryType::ReadWrite };
|
||||
AZ::IO::IStreamer::OnCompleteCallback m_callback;
|
||||
IO::FileRequestPtr m_request;
|
||||
};
|
||||
|
||||
struct MemoryStreamerWrapper
|
||||
{
|
||||
MemoryStreamerWrapper();
|
||||
~MemoryStreamerWrapper() = default;
|
||||
|
||||
ReadRequest* GetReadRequest(IO::FileRequestHandle request);
|
||||
|
||||
template<typename TObject>
|
||||
bool WriteMemoryFile(const AZStd::string& filePath, TObject* object, AZ::SerializeContext* context)
|
||||
{
|
||||
auto& buffer = m_virtualFiles[filePath];
|
||||
ByteContainerStream stream(&buffer);
|
||||
|
||||
return AZ::Utils::SaveObjectToStream(stream, DataStream::StreamType::ST_XML, object, context);
|
||||
}
|
||||
|
||||
AZStd::vector<char>* FindFile(AZStd::string_view path);
|
||||
|
||||
::testing::NiceMock<StreamerMock> m_mockStreamer;
|
||||
IO::StreamerContext m_context;
|
||||
AZStd::atomic_bool m_suspended{ false };
|
||||
|
||||
AZStd::recursive_mutex m_mutex;
|
||||
AZStd::queue<FileRequestHandle> m_processingQueue; // Keeps tracks of requests that have been queued while processing is suspended
|
||||
AZStd::vector<ReadRequest> m_readRequests;
|
||||
AZStd::unordered_map<AZStd::string, AZStd::vector<char>> m_virtualFiles;
|
||||
};
|
||||
|
||||
struct DisklessAssetManagerBase : BaseAssetManagerTest
|
||||
{
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
IO::IStreamer* CreateStreamer() override;
|
||||
void DestroyStreamer(IO::IStreamer*) override;
|
||||
|
||||
void WriteAssetToDisk(const AZStd::string& assetName, const AZStd::string& assetIdGuid) override;
|
||||
void DeleteAssetFromDisk(const AZStd::string& assetName) override;
|
||||
|
||||
AZStd::unique_ptr<MemoryStreamerWrapper> m_streamerWrapper;
|
||||
::testing::NiceMock<MockFileIOBase> m_fileIO;
|
||||
IO::FileIOBase* m_prevFileIO{};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -167,7 +167,8 @@ namespace UnitTest
|
||||
if (!info.m_streamName.empty())
|
||||
{
|
||||
AZStd::string fullName = GetTestFolderPath() + info.m_streamName;
|
||||
info.m_dataLen = static_cast<size_t>(IO::SystemFile::Length(fullName.c_str()));
|
||||
IO::FileIOBase* io = IO::FileIOBase::GetInstance();
|
||||
io->Size(fullName.c_str(), info.m_dataLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -187,8 +188,11 @@ namespace UnitTest
|
||||
|
||||
if (!info.m_streamName.empty())
|
||||
{
|
||||
IO::FileIOBase* io = AZ::IO::FileIOBase::GetInstance();
|
||||
|
||||
AZStd::string fullName = GetTestFolderPath() + info.m_streamName;
|
||||
info.m_dataLen = static_cast<size_t>(IO::SystemFile::Length(fullName.c_str()));
|
||||
|
||||
io->Size(fullName.c_str(), info.m_dataLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -23,11 +23,11 @@ namespace AzToolsFramework
|
||||
/// @name Reverse URLs.
|
||||
/// Used to identify common actions and override them when necessary.
|
||||
//@{
|
||||
static const AZ::Crc32 s_backAction = AZ_CRC("com.o3de.action.common.back", 0xd772a2af);
|
||||
static const AZ::Crc32 s_deleteAction = AZ_CRC("com.o3de.action.common.delete", 0x5731f6cb);
|
||||
static const AZ::Crc32 s_duplicateAction = AZ_CRC("com.o3de.action.common.duplicate", 0x08ccf461);
|
||||
static const AZ::Crc32 s_nextComponentMode = AZ_CRC("com.o3de.action.common.nextComponentMode", 0xcc26094f);
|
||||
static const AZ::Crc32 s_previousComponentMode = AZ_CRC("com.o3de.action.common.previousComponentMode", 0x0d18ff39);
|
||||
static const AZ::Crc32 s_backAction = AZ_CRC("com.o3de.action.common.back", 0x80c3030f);
|
||||
static const AZ::Crc32 s_deleteAction = AZ_CRC("com.o3de.action.common.delete", 0x58e78eed);
|
||||
static const AZ::Crc32 s_duplicateAction = AZ_CRC("com.o3de.action.common.duplicate", 0xbc5a4a23);
|
||||
static const AZ::Crc32 s_nextComponentMode = AZ_CRC("com.o3de.action.common.nextComponentMode", 0xf9aca3a8);
|
||||
static const AZ::Crc32 s_previousComponentMode = AZ_CRC("com.o3de.action.common.previousComponentMode", 0x0580eaec);
|
||||
//@}
|
||||
|
||||
/// Specific Action properties to be sent to a type implementing
|
||||
|
||||
@@ -132,6 +132,12 @@ namespace AssetProcessor
|
||||
// calls PrintStat on each element in the vector.
|
||||
void PrintStatsArray(AZStd::vector<AZStd::string>& keys, int maxToPrint, const char* header)
|
||||
{
|
||||
// don't print anything out at all, not even a header, if the keys are empty.
|
||||
if (keys.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_dumpHumanReadableStats)&&(header))
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel,"Top %i %s\n", maxToPrint, header);
|
||||
|
||||
@@ -1182,7 +1182,11 @@ namespace AssetUtilities
|
||||
}
|
||||
}
|
||||
|
||||
// keep track of how much time we spend actually hashing files.
|
||||
AZStd::string statName = AZStd::string::format("HashFile,%s", filePath);
|
||||
AssetProcessor::StatsCapture::BeginCaptureStat(statName.c_str());
|
||||
hash = AssetBuilderSDK::GetFileHash(filePath, bytesReadOut, hashMsDelay);
|
||||
AssetProcessor::StatsCapture::EndCaptureStat(statName.c_str());
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
AZ::AzTest
|
||||
AZ::AzFramework
|
||||
AZ::AzFrameworkTestShared
|
||||
AZ::AzQtComponents
|
||||
AZ::ProjectManager.Static
|
||||
)
|
||||
|
||||
|
||||
@@ -73,10 +73,10 @@ namespace O3DE::ProjectManager
|
||||
|
||||
QString m_path;
|
||||
QString m_name = "Unknown Gem Name";
|
||||
QString m_displayName = "Unknown Gem Name";
|
||||
QString m_displayName;
|
||||
QString m_creator = "Unknown Creator";
|
||||
GemOrigin m_gemOrigin = Local;
|
||||
bool m_isAdded = false; //! Is the gem currently added and enabled in the project?
|
||||
bool m_isAdded = false; //! Is the gem explicitly added (not a dependency) and enabled in the project?
|
||||
QString m_summary = "No summary provided.";
|
||||
Platforms m_platforms;
|
||||
Types m_types; //! Asset and/or Code and/or Tool
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzTest/Utils.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -17,14 +17,22 @@ namespace O3DE::ProjectManager
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
m_gemModel.reset(new GemModel());
|
||||
}
|
||||
|
||||
GemCatalogTests() = default;
|
||||
void TearDown() override
|
||||
{
|
||||
m_gemModel.release();
|
||||
}
|
||||
|
||||
protected:
|
||||
AZStd::unique_ptr<GemModel> m_gemModel;
|
||||
};
|
||||
|
||||
TEST_F(GemCatalogTests, GemCatalog_Displays_But_Does_Not_Add_Dependencies)
|
||||
TEST_F(GemCatalogTests, GemCatalog_GemWithDependencies_DisplaysButDoesNotAddDependencies)
|
||||
{
|
||||
GemModel* gemModel = new GemModel();
|
||||
|
||||
// given 3 gems a,b,c where a depends on b which depends on c
|
||||
GemInfo gemA, gemB, gemC;
|
||||
QModelIndex indexA, indexB, indexC;
|
||||
@@ -35,30 +43,531 @@ namespace O3DE::ProjectManager
|
||||
gemA.m_dependencies = QStringList({ "b" });
|
||||
gemB.m_dependencies = QStringList({ "c" });
|
||||
|
||||
gemModel->AddGem(gemA);
|
||||
indexA = gemModel->FindIndexByNameString(gemA.m_name);
|
||||
indexA = m_gemModel->AddGem(gemA);
|
||||
indexB = m_gemModel->AddGem(gemB);
|
||||
indexC = m_gemModel->AddGem(gemC);
|
||||
|
||||
gemModel->AddGem(gemB);
|
||||
indexB = gemModel->FindIndexByNameString(gemB.m_name);
|
||||
|
||||
gemModel->AddGem(gemC);
|
||||
indexC = gemModel->FindIndexByNameString(gemC.m_name);
|
||||
|
||||
gemModel->UpdateGemDependencies();
|
||||
m_gemModel->UpdateGemDependencies();
|
||||
|
||||
EXPECT_FALSE(GemModel::IsAdded(indexA));
|
||||
EXPECT_FALSE(GemModel::IsAddedDependency(indexB) || GemModel::IsAddedDependency(indexC));
|
||||
|
||||
// when a is added
|
||||
GemModel::SetIsAdded(*gemModel, indexA, true);
|
||||
GemModel::SetIsAdded(*m_gemModel, indexA, true);
|
||||
|
||||
// expect b and c are now dependencies of an added gem but not themselves added
|
||||
// cmake will handle dependencies
|
||||
EXPECT_TRUE(GemModel::IsAddedDependency(indexB) && GemModel::IsAddedDependency(indexC));
|
||||
EXPECT_TRUE(!GemModel::IsAdded(indexB) && !GemModel::IsAdded(indexC));
|
||||
EXPECT_FALSE(GemModel::IsAdded(indexB) || GemModel::IsAdded(indexC));
|
||||
|
||||
QVector<QModelIndex> gemsToAdd = gemModel->GatherGemsToBeAdded();
|
||||
const QVector<QModelIndex>& gemsToAdd = m_gemModel->GatherGemsToBeAdded();
|
||||
EXPECT_TRUE(gemsToAdd.size() == 1);
|
||||
EXPECT_EQ(GemModel::GetName(gemsToAdd.at(0)), gemA.m_name);
|
||||
}
|
||||
|
||||
class GemCatalogFilterTests
|
||||
: public GemCatalogTests
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
GemCatalogTests::SetUp();
|
||||
m_proxyModel.reset(new GemSortFilterProxyModel(m_gemModel.get()));
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_proxyModel.release();
|
||||
GemCatalogTests::TearDown();
|
||||
}
|
||||
|
||||
protected:
|
||||
AZStd::unique_ptr<GemSortFilterProxyModel> m_proxyModel;
|
||||
};
|
||||
|
||||
class GemCatalogSearchFilterTests
|
||||
: public GemCatalogFilterTests
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
GemCatalogFilterTests::SetUp();
|
||||
|
||||
GemInfo gemfilterName, gemfilterDisplayName, gemfilterCreator, gemfilterSummary, gemfilterFeature;
|
||||
|
||||
gemfilterName.m_name = "Name";
|
||||
gemfilterDisplayName.m_name = "D";
|
||||
gemfilterCreator.m_name = "C";
|
||||
gemfilterSummary.m_name = "S";
|
||||
gemfilterFeature.m_name = "F";
|
||||
|
||||
gemfilterDisplayName.m_displayName = "Display Name";
|
||||
gemfilterCreator.m_creator = "Johnathon Doe";
|
||||
gemfilterSummary.m_summary = "Unique Summary";
|
||||
gemfilterFeature.m_features.append("Creative Feature");
|
||||
|
||||
m_gemRows.append(m_gemModel->AddGem(gemfilterName).row());
|
||||
m_gemRows.append(m_gemModel->AddGem(gemfilterDisplayName).row());
|
||||
m_gemRows.append(m_gemModel->AddGem(gemfilterCreator).row());
|
||||
m_gemRows.append(m_gemModel->AddGem(gemfilterSummary).row());
|
||||
m_gemRows.append(m_gemModel->AddGem(gemfilterFeature).row());
|
||||
}
|
||||
|
||||
protected:
|
||||
enum RowOrder
|
||||
{
|
||||
Name,
|
||||
DisplayName,
|
||||
Creator,
|
||||
Summary,
|
||||
Features
|
||||
};
|
||||
|
||||
QVector<int> m_gemRows;
|
||||
};
|
||||
|
||||
TEST_F(GemCatalogSearchFilterTests, GemCatalogFilters_SearchStringName_ShowsNameGems)
|
||||
{
|
||||
m_proxyModel->SetSearchString("Name");
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Name], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DisplayName], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Creator], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Summary], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Features], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSearchFilterTests, GemCatalogFilters_SearchStringDisplayName_ShowsDisplayNameGem)
|
||||
{
|
||||
m_proxyModel->SetSearchString("Display Name");
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Name], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DisplayName], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Creator], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Summary], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Features], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSearchFilterTests, GemCatalogFilters_SearchStringCreator_ShowsCreatorGem)
|
||||
{
|
||||
m_proxyModel->SetSearchString("Johnathon Doe");
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Name], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DisplayName], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Creator], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Summary], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Features], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSearchFilterTests, GemCatalogFilters_SearchStringSummary_ShowsSummaryGem)
|
||||
{
|
||||
m_proxyModel->SetSearchString("Unique Summary");
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Name], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DisplayName], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Creator], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Summary], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Features], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSearchFilterTests, GemCatalogFilters_SearchStringFeatures_ShowsFeatureGem)
|
||||
{
|
||||
m_proxyModel->SetSearchString("Creative");
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Name], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DisplayName], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Creator], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Summary], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Features], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSearchFilterTests, GemCatalogFilters_SearchStringEmpty_ShowsAll)
|
||||
{
|
||||
m_proxyModel->SetSearchString("");
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Name], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DisplayName], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Creator], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Summary], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Features], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSearchFilterTests, GemCatalogFilters_SearchStringCommonCharacter_ShowsAll)
|
||||
{
|
||||
// All gems contain "a" in a searchable field so all should be shown
|
||||
m_proxyModel->SetSearchString("a");
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Name], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DisplayName], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Creator], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Summary], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Features], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSearchFilterTests, GemCatalogFilters_SearchStringDifferentCaseCommonCharacter_ShowsAll)
|
||||
{
|
||||
// No gems contain the character "A" but search should be case insensitive
|
||||
m_proxyModel->SetSearchString("A");
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Name], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DisplayName], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Creator], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Summary], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[Features], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSearchFilterTests, GemCatalogFilters_SearchStringNoneContainCharacter_ShowsNone)
|
||||
{
|
||||
// No gems contain the character "z" or "Z" so none should be shown
|
||||
m_proxyModel->SetSearchString("z");
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Name], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DisplayName], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Creator], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Summary], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Features], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSearchFilterTests, GemCatalogFilters_SearchStringPartialMatchString_ShowsNone)
|
||||
{
|
||||
// Token matching is currently not supported
|
||||
// The whole string must match a substring
|
||||
m_proxyModel->SetSearchString("Name Token");
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Name], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DisplayName], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Creator], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Summary], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[Features], QModelIndex()));
|
||||
}
|
||||
|
||||
class GemCatalogSelectedActiveFilterTests
|
||||
: public GemCatalogFilterTests
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
GemCatalogFilterTests::SetUp();
|
||||
|
||||
GemInfo gemSelected, gemSelectedDep, gemUnselected, gemUnselectedDep, gemActive, gemInactive;
|
||||
|
||||
gemSelected.m_name = "selected";
|
||||
gemSelectedDep.m_name = "selectedDep";
|
||||
gemUnselected.m_name = "unselected";
|
||||
gemUnselectedDep.m_name = "unselectedDep";
|
||||
gemActive.m_name = "active";
|
||||
gemInactive.m_name = "inactive";
|
||||
|
||||
gemSelected.m_dependencies = QStringList({ "selectedDep" });
|
||||
gemUnselected.m_dependencies = QStringList({ "unselectedDep" });
|
||||
|
||||
m_gemIndices.append(m_gemModel->AddGem(gemSelected));
|
||||
m_gemIndices.append(m_gemModel->AddGem(gemSelectedDep));
|
||||
m_gemIndices.append(m_gemModel->AddGem(gemUnselected));
|
||||
m_gemIndices.append(m_gemModel->AddGem(gemUnselectedDep));
|
||||
m_gemIndices.append(m_gemModel->AddGem(gemActive));
|
||||
m_gemIndices.append(m_gemModel->AddGem(gemInactive));
|
||||
|
||||
m_gemModel->UpdateGemDependencies();
|
||||
|
||||
// Set intial state of catalog with the to be unselected gem currently added along with active gem
|
||||
GemModel::SetIsAdded(*m_gemModel, m_gemIndices[Unselected], true);
|
||||
GemModel::SetWasPreviouslyAdded(*m_gemModel, m_gemIndices[Unselected], true);
|
||||
GemModel::SetIsAdded(*m_gemModel, m_gemIndices[Active], true);
|
||||
GemModel::SetWasPreviouslyAdded(*m_gemModel, m_gemIndices[Active], true);
|
||||
|
||||
// Add selected gem and remove unselected gem
|
||||
GemModel::SetIsAdded(*m_gemModel, m_gemIndices[Selected], true);
|
||||
GemModel::SetIsAdded(*m_gemModel, m_gemIndices[Unselected], false);
|
||||
}
|
||||
|
||||
protected:
|
||||
enum IndexOrder
|
||||
{
|
||||
Selected,
|
||||
SelectedDep,
|
||||
Unselected,
|
||||
UnselectedDep,
|
||||
Active,
|
||||
Inactive
|
||||
};
|
||||
|
||||
QVector<QModelIndex> m_gemIndices;
|
||||
};
|
||||
|
||||
TEST_F(GemCatalogSelectedActiveFilterTests, GemCatalogFilters_SelectedActiveIntialState_AddedGemsAndDependenciesAreAdded)
|
||||
{
|
||||
// Check if gems are all in expected state
|
||||
// if this test fails all other Selected/Active tests are invalid
|
||||
EXPECT_TRUE(GemModel::IsAdded(m_gemIndices[Selected]));
|
||||
EXPECT_TRUE(GemModel::IsAddedDependency(m_gemIndices[SelectedDep]));
|
||||
EXPECT_FALSE(GemModel::IsAdded(m_gemIndices[Unselected]));
|
||||
EXPECT_FALSE(GemModel::IsAddedDependency(m_gemIndices[UnselectedDep]));
|
||||
EXPECT_TRUE(GemModel::IsAdded(m_gemIndices[Active]));
|
||||
EXPECT_FALSE(GemModel::IsAdded(m_gemIndices[Inactive]));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSelectedActiveFilterTests, GemCatalogFilters_SelectedActiveNoFilter_ShowsAll)
|
||||
{
|
||||
// Filter is clear
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Selected].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[SelectedDep].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Unselected].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[UnselectedDep].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Active].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Inactive].row(), QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSelectedActiveFilterTests, GemCatalogFilters_FilterSelected_ShowsSelectedAndDependencies)
|
||||
{
|
||||
// Check selected filter
|
||||
// Selected dependencies should also be shown
|
||||
m_proxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Selected);
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Selected].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[SelectedDep].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Unselected].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[UnselectedDep].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Active].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Inactive].row(), QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSelectedActiveFilterTests, GemCatalogFilters_FilterUnselected_ShowsUnselectedAndDependencies)
|
||||
{
|
||||
// Check unselected filter
|
||||
// Unselected dependencies should also be shown
|
||||
m_proxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Unselected);
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Selected].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[SelectedDep].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Unselected].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[UnselectedDep].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Active].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Inactive].row(), QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSelectedActiveFilterTests, GemCatalogFilters_FilterSelectedAndUnselected_ShowsAllChangesAndDependencies)
|
||||
{
|
||||
// Check both un/selected filter
|
||||
m_proxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Both);
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Selected].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[SelectedDep].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Unselected].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[UnselectedDep].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Active].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Inactive].row(), QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSelectedActiveFilterTests, GemCatalogFilters_FilterActive_ShowsActive)
|
||||
{
|
||||
// Check active filter
|
||||
// Active dependencies should also be shown
|
||||
m_proxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Active);
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Selected].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[SelectedDep].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Unselected].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[UnselectedDep].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Active].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Inactive].row(), QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogSelectedActiveFilterTests, GemCatalogFilters_FilterActive_ShowsInactive)
|
||||
{
|
||||
// Check inactive filter
|
||||
m_proxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Inactive);
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Selected].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[SelectedDep].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Unselected].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[UnselectedDep].row(), QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemIndices[Active].row(), QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemIndices[Inactive].row(), QModelIndex()));
|
||||
}
|
||||
|
||||
class GemCatalogMiscFilterTests
|
||||
: public GemCatalogFilterTests
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
GemCatalogFilterTests::SetUp();
|
||||
|
||||
GemInfo gemA, gemB, gemC;
|
||||
|
||||
gemA.m_name = "Default Audio";
|
||||
gemB.m_name = "Mobile UX";
|
||||
gemC.m_name = "City Props";
|
||||
|
||||
gemA.m_gemOrigin = GemInfo::GemOrigin::Open3DEngine;
|
||||
gemB.m_gemOrigin = GemInfo::GemOrigin::Local;
|
||||
gemC.m_gemOrigin = GemInfo::GemOrigin::Remote;
|
||||
|
||||
gemA.m_types = GemInfo::Type::Code;
|
||||
gemB.m_types = GemInfo::Type::Code | GemInfo::Type::Tool;
|
||||
gemC.m_types = GemInfo::Type::Asset;
|
||||
|
||||
using Plat = GemInfo::Platform;
|
||||
gemA.m_platforms = Plat::Windows;
|
||||
gemB.m_platforms = Plat::Android | Plat::iOS;
|
||||
gemC.m_platforms = Plat::Android | Plat::iOS | Plat::Linux | Plat::macOS | Plat::Windows;
|
||||
|
||||
gemA.m_features = QStringList({ "Audio", "Framework", "SDK" });
|
||||
gemB.m_features = QStringList({ "Framework", "Tools", "UI" });
|
||||
gemC.m_features = QStringList({ "Assets", "Content", "Environment" });
|
||||
|
||||
m_gemRows.append(m_gemModel->AddGem(gemA).row());
|
||||
m_gemRows.append(m_gemModel->AddGem(gemB).row());
|
||||
m_gemRows.append(m_gemModel->AddGem(gemC).row());
|
||||
}
|
||||
|
||||
protected:
|
||||
enum RowOrder
|
||||
{
|
||||
DefaultAudio,
|
||||
MobileUX,
|
||||
CityProps
|
||||
};
|
||||
|
||||
QVector<int> m_gemRows;
|
||||
};
|
||||
|
||||
TEST_F(GemCatalogMiscFilterTests, GemCatalogFilters_MiscNoFilter_ShowsAll)
|
||||
{
|
||||
// No filter
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogMiscFilterTests, GemCatalogFilters_FilterSingleOrigin_ShowsOriginMatch)
|
||||
{
|
||||
m_proxyModel->SetGemOrigins(GemInfo::GemOrigin::Open3DEngine);
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
|
||||
m_proxyModel->SetGemOrigins(GemInfo::GemOrigin::Local);
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
|
||||
m_proxyModel->SetGemOrigins(GemInfo::GemOrigin::Remote);
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogMiscFilterTests, GemCatalogFilters_FilterMultipleOrigins_ShowsMultipleOriginMatches)
|
||||
{
|
||||
m_proxyModel->SetGemOrigins(GemInfo::GemOrigin::Open3DEngine | GemInfo::GemOrigin::Local);
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogMiscFilterTests, GemCatalogFilters_FilterSingleType_ShowsTypeMatch)
|
||||
{
|
||||
m_proxyModel->SetTypes(GemInfo::Type::Code);
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
|
||||
m_proxyModel->SetTypes(GemInfo::Type::Tool);
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
|
||||
m_proxyModel->SetTypes(GemInfo::Type::Asset);
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogMiscFilterTests, GemCatalogFilters_FilterMultipleTypes_ShowsMultipleTypeMatches)
|
||||
{
|
||||
m_proxyModel->SetTypes(GemInfo::Type::Tool | GemInfo::Type::Asset);
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogMiscFilterTests, GemCatalogFilters_FilterSinglePlatform_ShowsPlatformMatch)
|
||||
{
|
||||
m_proxyModel->SetPlatforms(GemInfo::Platform::Windows);
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
|
||||
m_proxyModel->SetPlatforms(GemInfo::Platform::Android);
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
|
||||
m_proxyModel->SetPlatforms(GemInfo::Platform::macOS);
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogMiscFilterTests, GemCatalogFilters_FilterMultiplePlatforms_ShowsMultiplePlatformMatches)
|
||||
{
|
||||
m_proxyModel->SetPlatforms(GemInfo::Platform::Android | GemInfo::Platform::iOS);
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogMiscFilterTests, GemCatalogFilters_FilterSingleFeature_ShowsFeatureMatch)
|
||||
{
|
||||
m_proxyModel->SetFeatures({ "Audio" });
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
|
||||
m_proxyModel->SetFeatures({ "Tools", });
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
|
||||
m_proxyModel->SetFeatures({ "Environment" });
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogMiscFilterTests, GemCatalogFilters_FilterMultipleFeatures_ShowsMultipleFeatureMatches)
|
||||
{
|
||||
m_proxyModel->SetFeatures({ "Assets", "Framework" });
|
||||
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_TRUE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
}
|
||||
|
||||
TEST_F(GemCatalogMiscFilterTests, GemCatalogFilters_FilterPartialMatchFeature_ShowsNone)
|
||||
{
|
||||
// Features must be an exact match to filter by them directly
|
||||
m_proxyModel->SetFeatures({ "Frame" });
|
||||
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[DefaultAudio], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[MobileUX], QModelIndex()));
|
||||
EXPECT_FALSE(m_proxyModel->filterAcceptsRow(m_gemRows[CityProps], QModelIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace AZ
|
||||
if (lodCount > 0)
|
||||
{
|
||||
rule->AddLod();
|
||||
selection.CopyTo(rule->GetNodeSelectionList(index));
|
||||
selection.CopyTo(rule->GetNodeSelectionList(lodLevel));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
|
||||
#include <SceneAPI/SceneCore/Events/GraphMetaInfoBus.h>
|
||||
#include <SceneAPI/SceneCore/Events/ManifestMetaInfoBus.h>
|
||||
#include <SceneAPI/SceneData/SceneDataConfiguration.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -27,7 +28,7 @@ namespace AZ
|
||||
{
|
||||
class LodRule;
|
||||
|
||||
class LodRuleBehavior
|
||||
class SCENE_DATA_CLASS LodRuleBehavior
|
||||
: public SceneCore::BehaviorComponent
|
||||
, public Events::ManifestMetaInfoBus::Handler
|
||||
, public Events::AssetImportRequestBus::Handler
|
||||
@@ -36,18 +37,19 @@ namespace AZ
|
||||
public:
|
||||
AZ_COMPONENT(LodRuleBehavior, "{D2E19864-9A4B-41FD-8ACC-DA6756728CB3}", SceneCore::BehaviorComponent);
|
||||
|
||||
~LodRuleBehavior() override = default;
|
||||
SCENE_DATA_API ~LodRuleBehavior() override = default;
|
||||
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
SCENE_DATA_API void Activate() override;
|
||||
SCENE_DATA_API void Deactivate() override;
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
void InitializeObject(const Containers::Scene& scene, DataTypes::IManifestObject& target) override;
|
||||
Events::ProcessingResult UpdateManifest(Containers::Scene& scene, ManifestAction action,
|
||||
SCENE_DATA_API void InitializeObject(const Containers::Scene& scene, DataTypes::IManifestObject& target) override;
|
||||
SCENE_DATA_API Events::ProcessingResult UpdateManifest(
|
||||
Containers::Scene& scene, ManifestAction action,
|
||||
RequestingApplication requester) override;
|
||||
|
||||
void GetVirtualTypeName(AZStd::string& name, Crc32 type) override;
|
||||
void GetAllVirtualTypes(AZStd::set<Crc32>& types) override;
|
||||
SCENE_DATA_API void GetVirtualTypeName(AZStd::string& name, Crc32 type) override;
|
||||
SCENE_DATA_API void GetAllVirtualTypes(AZStd::set<Crc32>& types) override;
|
||||
|
||||
private:
|
||||
size_t SelectLodMeshes(const Containers::Scene& scene, DataTypes::ISceneNodeSelectionList& selection, size_t lodLevel) const;
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace AZ
|
||||
{
|
||||
const size_t LodRule::m_maxLods;
|
||||
|
||||
AZ_CLASS_ALLOCATOR_IMPL(LodRule, SystemAllocator, 0)
|
||||
|
||||
SceneNodeSelectionList& LodRule::GetNodeSelectionList(size_t index)
|
||||
{
|
||||
|
||||
@@ -25,26 +25,26 @@ namespace AZ
|
||||
}
|
||||
namespace SceneData
|
||||
{
|
||||
class LodRule
|
||||
class SCENE_DATA_CLASS LodRule
|
||||
: public DataTypes::ILodRule
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(LodRule, "{6E796AC8-1484-4909-860A-6D3F22A7346F}", DataTypes::ILodRule);
|
||||
AZ_CLASS_ALLOCATOR_DECL
|
||||
AZ_CLASS_ALLOCATOR(LodRule, AZ::SystemAllocator, 0)
|
||||
|
||||
~LodRule() override = default;
|
||||
SCENE_DATA_API ~LodRule() override = default;
|
||||
|
||||
SceneNodeSelectionList& GetNodeSelectionList(size_t index);
|
||||
SCENE_DATA_API SceneNodeSelectionList& GetNodeSelectionList(size_t index);
|
||||
|
||||
DataTypes::ISceneNodeSelectionList& GetSceneNodeSelectionList(size_t index) override;
|
||||
const DataTypes::ISceneNodeSelectionList& GetSceneNodeSelectionList(size_t index) const override;
|
||||
size_t GetLodCount() const override;
|
||||
SCENE_DATA_API DataTypes::ISceneNodeSelectionList& GetSceneNodeSelectionList(size_t index) override;
|
||||
SCENE_DATA_API const DataTypes::ISceneNodeSelectionList& GetSceneNodeSelectionList(size_t index) const override;
|
||||
SCENE_DATA_API size_t GetLodCount() const override;
|
||||
|
||||
void AddLod();
|
||||
SCENE_DATA_API void AddLod();
|
||||
|
||||
static void Reflect(ReflectContext* context);
|
||||
//The engine supports 6 total lods. 1 for the base model then 5 more lods.
|
||||
//The rule only captures lods past level 0 so this is set to 5.
|
||||
//The engine supports 6 total lods. 1 for the base model then 5 more lods.
|
||||
//The rule only captures lods past level 0 so this is set to 5.
|
||||
static const size_t m_maxLods = 5;
|
||||
protected:
|
||||
|
||||
|
||||
@@ -11,5 +11,6 @@ set(FILES
|
||||
Tests/GraphData/MeshDataTests.cpp
|
||||
Tests/GraphData/MeshDataPrimitiveUtilsTests.cpp
|
||||
Tests/GraphData/GraphDataBehaviorTests.cpp
|
||||
Tests/GraphData/RulesTests.cpp
|
||||
Tests/SceneManifest/SceneManifestRuleTests.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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 <AzTest/AzTest.h>
|
||||
#include <SceneAPI/SceneCore/Containers/Scene.h>
|
||||
#include <SceneAPI/SceneData/GraphData/MeshData.h>
|
||||
#include <SceneAPI/SceneData/Behaviors/LodRuleBehavior.h>
|
||||
#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
|
||||
#include <SceneAPI/SceneData/Behaviors/Registry.h>
|
||||
#include <SceneAPI/SceneData/Groups/MeshGroup.h>
|
||||
#include <SceneAPI/SceneData/Rules/LodRule.h>
|
||||
#include <SceneAPI/SceneData/Rules/TangentsRule.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace SceneData
|
||||
{
|
||||
struct SoftNameMock
|
||||
: SceneAPI::Events::GraphMetaInfoBus::Handler
|
||||
{
|
||||
SoftNameMock()
|
||||
{
|
||||
BusConnect();
|
||||
}
|
||||
|
||||
~SoftNameMock() override
|
||||
{
|
||||
BusDisconnect();
|
||||
}
|
||||
|
||||
void GetVirtualTypes(AZStd::set<Crc32>& types, const SceneAPI::Containers::Scene&, SceneAPI::Containers::SceneGraph::NodeIndex) override
|
||||
{
|
||||
// Indicate this node is a LOD1 type
|
||||
types.emplace(AZ_CRC_CE("LODMesh1"));
|
||||
}
|
||||
};
|
||||
|
||||
TEST(LOD, LODRuleTest)
|
||||
{
|
||||
// Test that UpdateManifest doesn't crash when trying to auto-add new LOD levels
|
||||
SoftNameMock softNameMock;
|
||||
|
||||
SceneAPI::SceneData::LodRuleBehavior lod;
|
||||
SceneAPI::Containers::Scene scene("test");
|
||||
|
||||
auto lodRule = AZStd::shared_ptr<SceneAPI::SceneData::LodRule>(aznew SceneAPI::SceneData::LodRule());
|
||||
scene.GetManifest().AddEntry(lodRule);
|
||||
|
||||
auto group = AZStd::shared_ptr<SceneAPI::SceneData::MeshGroup>(aznew SceneAPI::SceneData::MeshGroup());
|
||||
|
||||
// Add a bunch of other rules first
|
||||
// This is necessary to replicate the bug condition where the index of the rule is used instead of the index of the LOD
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
auto tangentsRule = AZStd::shared_ptr<SceneAPI::SceneData::TangentsRule>(aznew SceneAPI::SceneData::TangentsRule());
|
||||
group->GetRuleContainer().AddRule(tangentsRule);
|
||||
}
|
||||
|
||||
group->GetRuleContainer().AddRule(lodRule);
|
||||
scene.GetManifest().AddEntry(group);
|
||||
|
||||
auto meshData = AZStd::shared_ptr<GraphData::MeshData>(new GraphData::MeshData());
|
||||
scene.GetGraph().AddChild(scene.GetGraph().GetRoot(), "test", meshData);
|
||||
|
||||
EXPECT_EQ(lodRule->GetLodCount(), 0);
|
||||
|
||||
// This should auto-add 1 LOD because of the "test" node we added above along with the SoftNameMock which will report it as an LOD1
|
||||
lod.UpdateManifest(scene, SceneAPI::Events::AssetImportRequest::Update, SceneAPI::Events::AssetImportRequest::Generic);
|
||||
|
||||
EXPECT_EQ(lodRule->GetLodCount(), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,9 +140,18 @@ namespace AZ
|
||||
m_drawData.push_back(drawData);
|
||||
}
|
||||
|
||||
int ImGuiPass::GetTickOrder()
|
||||
{
|
||||
// We have to call ImGui::NewFrame (which happens in ImGuiPass::OnTick) after setting
|
||||
// ImGui::GetIO().NavInputs (which happens in ImGuiPass::OnInputChannelEventFiltered),
|
||||
// but before ImGui::Render (which happens in ImGuiPass::SetupFrameGraphDependencies).
|
||||
return AZ::ComponentTickBus::TICK_PRE_RENDER;
|
||||
}
|
||||
|
||||
void ImGuiPass::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
|
||||
{
|
||||
auto imguiContextScope = ImguiContextScope(m_imguiContext);
|
||||
ImGui::NewFrame();
|
||||
|
||||
auto& io = ImGui::GetIO();
|
||||
io.DeltaTime = deltaTime;
|
||||
@@ -413,6 +422,7 @@ namespace AZ
|
||||
|
||||
void ImGuiPass::Init()
|
||||
{
|
||||
auto imguiContextScope = ImguiContextScope(m_imguiContext);
|
||||
auto& io = ImGui::GetIO();
|
||||
|
||||
// ImGui IO Setup
|
||||
@@ -421,7 +431,6 @@ namespace AZ
|
||||
{
|
||||
io.KeyMap[static_cast<ImGuiKey_>(i)] = static_cast<int>(i);
|
||||
}
|
||||
io.NavActive = true;
|
||||
|
||||
// Touch input
|
||||
const AzFramework::InputDevice* inputDevice = nullptr;
|
||||
@@ -434,6 +443,17 @@ namespace AZ
|
||||
io.ConfigFlags |= ImGuiConfigFlags_IsTouchScreen;
|
||||
}
|
||||
|
||||
// Gamepad input
|
||||
inputDevice = nullptr;
|
||||
AzFramework::InputDeviceRequestBus::EventResult(inputDevice,
|
||||
AzFramework::InputDeviceGamepad::IdForIndex0,
|
||||
&AzFramework::InputDeviceRequests::GetInputDevice);
|
||||
if (inputDevice && inputDevice->IsSupported())
|
||||
{
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||
}
|
||||
|
||||
// Set initial display size to something reasonable (this will be updated in FramePrepare)
|
||||
io.DisplaySize.x = 1920;
|
||||
io.DisplaySize.y = 1080;
|
||||
@@ -571,7 +591,6 @@ namespace AZ
|
||||
auto imguiContextScope = ImguiContextScope(m_imguiContext);
|
||||
ImGui::GetIO().MouseWheel = m_lastFrameMouseWheel;
|
||||
m_lastFrameMouseWheel = 0.0;
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
void ImGuiPass::BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context)
|
||||
|
||||
@@ -77,6 +77,7 @@ namespace AZ
|
||||
void RenderImguiDrawData(const ImDrawData& drawData);
|
||||
|
||||
// TickBus::Handler overrides...
|
||||
int GetTickOrder() override;
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint timePoint) override;
|
||||
|
||||
// AzFramework::InputTextEventListener overrides...
|
||||
|
||||
@@ -67,12 +67,12 @@ namespace AZ
|
||||
|
||||
void AtomBridgeSystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("AtomBridgeService", 0xdb816a99));
|
||||
provided.push_back(AZ_CRC("AtomBridgeService", 0x92d990b5));
|
||||
}
|
||||
|
||||
void AtomBridgeSystemComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("AtomBridgeService", 0xdb816a99));
|
||||
incompatible.push_back(AZ_CRC("AtomBridgeService", 0x92d990b5));
|
||||
}
|
||||
|
||||
void AtomBridgeSystemComponent::GetRequiredServices(ComponentDescriptor::DependencyArrayType& required)
|
||||
|
||||
+2
-2
@@ -109,12 +109,12 @@ namespace AZ
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
{
|
||||
services.push_back(AZ_CRC("AssetCollectionAsyncLoaderTest", 0xdd5ab934));
|
||||
services.push_back(AZ_CRC("AssetCollectionAsyncLoaderTest", 0x66d04369));
|
||||
}
|
||||
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
{
|
||||
services.push_back(AZ_CRC("AssetCollectionAsyncLoaderTest", 0xdd5ab934));
|
||||
services.push_back(AZ_CRC("AssetCollectionAsyncLoaderTest", 0x66d04369));
|
||||
}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ namespace AZ::Render
|
||||
void AtomViewportDisplayIconsSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC("RPISystem", 0xf2add773));
|
||||
required.push_back(AZ_CRC("AtomBridgeService", 0xdb816a99));
|
||||
required.push_back(AZ_CRC("AtomBridgeService", 0x92d990b5));
|
||||
}
|
||||
|
||||
void AtomViewportDisplayIconsSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
|
||||
+2
-2
@@ -59,12 +59,12 @@ namespace AZ
|
||||
|
||||
void OcclusionCullingPlaneComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("OcclusionCullingPlaneService", 0x9123f33d));
|
||||
provided.push_back(AZ_CRC("OcclusionCullingPlaneService", 0x7d036c2e));
|
||||
}
|
||||
|
||||
void OcclusionCullingPlaneComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("OcclusionCullingPlaneService", 0x9123f33d));
|
||||
incompatible.push_back(AZ_CRC("OcclusionCullingPlaneService", 0x7d036c2e));
|
||||
}
|
||||
|
||||
void OcclusionCullingPlaneComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
|
||||
@@ -31,12 +31,12 @@ namespace Blast
|
||||
private:
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("BlastEditorService", 0x0a61cda5));
|
||||
provided.push_back(AZ_CRC("BlastEditorService", 0xeddfed0d));
|
||||
}
|
||||
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC("BlastService", 0x75beae2d));
|
||||
required.push_back(AZ_CRC("BlastService", 0x46927a9f));
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<EditorBlastChunksAssetHandler> m_editorBlastChunksAssetHandler;
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ namespace GraphModelIntegration
|
||||
|
||||
//! Constructor
|
||||
//! \param nodeName Name of the node that will show up in the Palette
|
||||
//! \param editorId Unique name of the client system editor (ex: AZ_CRC("ShaderCanvas", 0xa6d1a85a))
|
||||
//! \param editorId Unique name of the client system editor (ex: AZ_CRC("ShaderCanvas", 0x0a1dff96))
|
||||
//! \param dataType The type of data that the InputGraphNode or OutputGraphNode will represent
|
||||
InputOutputNodePaletteItem(AZStd::string_view nodeName, GraphCanvas::EditorId editorId, GraphModel::DataTypePtr dataType)
|
||||
: DraggableNodePaletteTreeItem(nodeName, editorId)
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ namespace GraphModelIntegration
|
||||
AZ_CLASS_ALLOCATOR(ModuleNodePaletteItem, AZ::SystemAllocator, 0);
|
||||
|
||||
//! Constructor
|
||||
//! \param editorId Unique name of the client system editor (ex: AZ_CRC("ShaderCanvas", 0xa6d1a85a))
|
||||
//! \param editorId Unique name of the client system editor (ex: AZ_CRC("ShaderCanvas", 0x0a1dff96))
|
||||
//! \param sourceFileId The unique id for the module node graph source file.
|
||||
//! \param sourceFilePath The path to the module node graph source file. This will be used for node naming and debug output.
|
||||
ModuleNodePaletteItem(GraphCanvas::EditorId editorId, AZ::Uuid sourceFileId, AZStd::string_view sourceFilePath)
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ namespace GraphModelIntegration
|
||||
|
||||
//! Constructor
|
||||
//! \param nodeName Name of the node that will show up in the Palette
|
||||
//! \param editorId Unique name of the client system editor (ex: AZ_CRC("ShaderCanvas", 0xa6d1a85a))
|
||||
//! \param editorId Unique name of the client system editor (ex: AZ_CRC("ShaderCanvas", 0x0a1dff96))
|
||||
StandardNodePaletteItem(AZStd::string_view nodeName, GraphCanvas::EditorId editorId)
|
||||
: DraggableNodePaletteTreeItem(nodeName, editorId)
|
||||
{
|
||||
|
||||
@@ -172,7 +172,6 @@ void ImGuiManager::Initialize()
|
||||
|
||||
// Broadcast ImGui Ready to Listeners
|
||||
ImGuiUpdateListenerBus::Broadcast(&IImGuiUpdateListener::OnImGuiInitialize);
|
||||
m_currentControllerIndex = -1;
|
||||
m_button1Pressed = m_button2Pressed = false;
|
||||
m_menuBarStatusChanged = false;
|
||||
|
||||
@@ -227,6 +226,7 @@ void ImGui::ImGuiManager::RestoreRenderWindowSizeToDefault()
|
||||
|
||||
void ImGui::ImGuiManager::SetDpiScalingFactor(float dpiScalingFactor)
|
||||
{
|
||||
ImGui::ImGuiContextScope contextScope(m_imguiContext);
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
// Set the global font scale to size our UI to the scaling factor
|
||||
// Note: Currently we use the default, 13px fixed-size IMGUI font, so this can get somewhat blurry
|
||||
@@ -235,6 +235,7 @@ void ImGui::ImGuiManager::SetDpiScalingFactor(float dpiScalingFactor)
|
||||
|
||||
float ImGui::ImGuiManager::GetDpiScalingFactor() const
|
||||
{
|
||||
ImGui::ImGuiContextScope contextScope(m_imguiContext);
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
return io.FontGlobalScale;
|
||||
}
|
||||
@@ -406,7 +407,7 @@ bool ImGuiManager::OnInputChannelEventFiltered(const InputChannel& inputChannel)
|
||||
// Cycle through ImGui Menu Bar States on Home button press
|
||||
if (inputChannelId == InputDeviceKeyboard::Key::NavigationHome)
|
||||
{
|
||||
ToggleThroughImGuiVisibleState(-1);
|
||||
ToggleThroughImGuiVisibleState();
|
||||
}
|
||||
|
||||
// Cycle through Standalone Editor Window States
|
||||
@@ -453,19 +454,10 @@ bool ImGuiManager::OnInputChannelEventFiltered(const InputChannel& inputChannel)
|
||||
}
|
||||
|
||||
// Handle Controller Inputs
|
||||
int inputControllerIndex = -1;
|
||||
bool controllerInput = false;
|
||||
if (InputDeviceGamepad::IsGamepadDevice(inputDeviceId))
|
||||
{
|
||||
inputControllerIndex = inputDeviceId.GetIndex();
|
||||
controllerInput = true;
|
||||
}
|
||||
|
||||
|
||||
if (controllerInput)
|
||||
{
|
||||
// Only pipe in Controller Nav Inputs if we are the current Controller Index and at least 1 of the two controller modes are enabled.
|
||||
if (m_currentControllerIndex == inputControllerIndex && m_controllerModeFlags)
|
||||
// Only pipe in Controller Nav Inputs when at least 1 of the two controller modes are enabled.
|
||||
if (m_controllerModeFlags)
|
||||
{
|
||||
const auto lyButtonToImGuiNav = s_lyInputToImGuiNavIndexMap.find(inputChannelId);
|
||||
if (lyButtonToImGuiNav != s_lyInputToImGuiNavIndexMap.end())
|
||||
@@ -476,7 +468,7 @@ bool ImGuiManager::OnInputChannelEventFiltered(const InputChannel& inputChannel)
|
||||
}
|
||||
|
||||
//Switch menu bar display only if two buttons are pressed at the same time
|
||||
if (inputChannelId == InputDeviceGamepad::Button::L3)
|
||||
if (inputChannelId == InputDeviceGamepad::Button::L1)
|
||||
{
|
||||
if (inputChannel.IsStateBegan())
|
||||
{
|
||||
@@ -488,7 +480,7 @@ bool ImGuiManager::OnInputChannelEventFiltered(const InputChannel& inputChannel)
|
||||
m_menuBarStatusChanged = false;
|
||||
}
|
||||
}
|
||||
if (inputChannelId == InputDeviceGamepad::Button::R3)
|
||||
if (inputChannelId == InputDeviceGamepad::Button::R1)
|
||||
{
|
||||
if (inputChannel.IsStateBegan())
|
||||
{
|
||||
@@ -502,7 +494,7 @@ bool ImGuiManager::OnInputChannelEventFiltered(const InputChannel& inputChannel)
|
||||
}
|
||||
if (!m_menuBarStatusChanged && m_button1Pressed && m_button2Pressed)
|
||||
{
|
||||
ToggleThroughImGuiVisibleState(inputControllerIndex);
|
||||
ToggleThroughImGuiVisibleState();
|
||||
}
|
||||
|
||||
// If we have the Discrete Input Mode Enabled.. and we are in the Visible State, then consume input here
|
||||
@@ -627,14 +619,13 @@ bool ImGuiManager::OnInputTextEventFiltered(const AZStd::string& textUTF8)
|
||||
return io.WantTextInput && m_clientMenuBarState == DisplayState::Visible;;
|
||||
}
|
||||
|
||||
void ImGuiManager::ToggleThroughImGuiVisibleState(int controllerIndex)
|
||||
void ImGuiManager::ToggleThroughImGuiVisibleState()
|
||||
{
|
||||
ImGui::ImGuiContextScope contextScope(m_imguiContext);
|
||||
|
||||
switch (m_clientMenuBarState)
|
||||
{
|
||||
case DisplayState::Hidden:
|
||||
m_currentControllerIndex = controllerIndex;
|
||||
m_clientMenuBarState = DisplayState::Visible;
|
||||
|
||||
// Draw the ImGui Mouse cursor if either the hardware mouse is connected, or the controller mouse is enabled.
|
||||
@@ -669,7 +660,6 @@ void ImGuiManager::ToggleThroughImGuiVisibleState(int controllerIndex)
|
||||
|
||||
default:
|
||||
m_clientMenuBarState = DisplayState::Hidden;
|
||||
m_currentControllerIndex = -1;
|
||||
|
||||
// Enable system cursor if it's in editor and it's not editor game mode
|
||||
if (gEnv->IsEditor() && !gEnv->IsEditorGameMode())
|
||||
@@ -686,12 +676,6 @@ void ImGuiManager::ToggleThroughImGuiVisibleState(int controllerIndex)
|
||||
m_setEnabledEvent.Signal(m_clientMenuBarState == DisplayState::Hidden);
|
||||
}
|
||||
|
||||
void ImGuiManager::ToggleThroughImGuiVisibleState()
|
||||
{
|
||||
ToggleThroughImGuiVisibleState(-1);
|
||||
}
|
||||
|
||||
|
||||
void ImGuiManager::RenderImGuiBuffers(const ImVec2& scaleRects)
|
||||
{
|
||||
ImGui::ImGuiContextScope contextScope(m_imguiContext);
|
||||
|
||||
@@ -76,9 +76,6 @@ namespace ImGui
|
||||
// Sets up initial window size and listens for changes
|
||||
void InitWindowSize();
|
||||
|
||||
// A function to toggle through the available ImGui Visibility States
|
||||
void ToggleThroughImGuiVisibleState(int controllerIndex);
|
||||
|
||||
private:
|
||||
ImGuiContext* m_imguiContext = nullptr;
|
||||
DisplayState m_clientMenuBarState = DisplayState::Hidden;
|
||||
@@ -96,8 +93,6 @@ namespace ImGui
|
||||
std::vector<uint16> m_idxBuffer;
|
||||
|
||||
//Controller navigation
|
||||
static const int MaxControllerNumber = 4;
|
||||
int m_currentControllerIndex;
|
||||
bool m_button1Pressed, m_button2Pressed, m_menuBarStatusChanged;
|
||||
|
||||
bool m_hardwardeMouseConnected = false;
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace LmbrCentral
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR_IMPL(EditorTubeShapeComponentMode, AZ::SystemAllocator, 0)
|
||||
|
||||
static const AZ::Crc32 s_resetVariableRadii = AZ_CRC("com.o3de.action.tubeshape.reset_radii", 0x0f2ef8e2);
|
||||
static const AZ::Crc32 s_resetVariableRadii = AZ_CRC("com.o3de.action.tubeshape.reset_radii", 0xa987659c);
|
||||
static const char* const s_resetRadiiTitle = "Reset Radii";
|
||||
static const char* const s_resetRadiiDesc = "Reset all variable radius values to the default";
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class PropertyHandlerUiParticleColorKeyframe
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PropertyHandlerUiParticleColorKeyframe, AZ::SystemAllocator, 0);
|
||||
|
||||
AZ::u32 GetHandlerName(void) const override { return AZ_CRC("UiParticleColorKeyframeCtrl", 0x8cb3a9f1); }
|
||||
AZ::u32 GetHandlerName(void) const override { return AZ_CRC("UiParticleColorKeyframeCtrl", 0xe3ef28b6); }
|
||||
bool IsDefaultHandler() const override { return true; }
|
||||
QWidget* CreateGUI(QWidget* pParent) override;
|
||||
void ConsumeAttribute(PropertyUiParticleColorKeyframeCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
|
||||
@@ -50,7 +50,7 @@ class PropertyHandlerUiParticleFloatKeyframe
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PropertyHandlerUiParticleFloatKeyframe, AZ::SystemAllocator, 0);
|
||||
|
||||
AZ::u32 GetHandlerName(void) const override { return AZ_CRC("UiParticleFloatKeyframeCtrl", 0xba9359a2); }
|
||||
AZ::u32 GetHandlerName(void) const override { return AZ_CRC("UiParticleFloatKeyframeCtrl", 0x448a90ec); }
|
||||
bool IsDefaultHandler() const override { return true; }
|
||||
QWidget* CreateGUI(QWidget* pParent) override;
|
||||
void ConsumeAttribute(PropertyUiParticleFloatKeyframeCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
|
||||
@@ -31,12 +31,12 @@ namespace LyShine
|
||||
|
||||
void LyShineLoadScreenComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.emplace_back(AZ_CRC("LyShineLoadScreenService", 0xBB5EAB17));
|
||||
provided.emplace_back(AZ_CRC("LyShineLoadScreenService", 0xbb5eab17));
|
||||
}
|
||||
|
||||
void LyShineLoadScreenComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.emplace_back(AZ_CRC("LyShineLoadScreenService", 0xBB5EAB17));
|
||||
incompatible.emplace_back(AZ_CRC("LyShineLoadScreenService", 0xbb5eab17));
|
||||
}
|
||||
|
||||
void LyShineLoadScreenComponent::Init()
|
||||
|
||||
@@ -27,10 +27,10 @@ namespace PhysX
|
||||
namespace
|
||||
{
|
||||
//! Uri's for shortcut actions.
|
||||
const AZ::Crc32 SetDimensionsSubModeActionUri = AZ_CRC("com.o3de.action.physx.setdimensionssubmode", 0x77b70dd6);
|
||||
const AZ::Crc32 SetOffsetSubModeActionUri = AZ_CRC("com.o3de.action.physx.setoffsetsubmode", 0xc06132e5);
|
||||
const AZ::Crc32 SetRotationSubModeActionUri = AZ_CRC("com.o3de.action.physx.setrotationsubmode", 0xc4225918);
|
||||
const AZ::Crc32 ResetSubModeActionUri = AZ_CRC("com.o3de.action.physx.resetsubmode", 0xb70b120e);
|
||||
const AZ::Crc32 SetDimensionsSubModeActionUri = AZ_CRC("com.o3de.action.physx.setdimensionssubmode", 0x508b1781);
|
||||
const AZ::Crc32 SetOffsetSubModeActionUri = AZ_CRC("com.o3de.action.physx.setoffsetsubmode", 0x777ac743);
|
||||
const AZ::Crc32 SetRotationSubModeActionUri = AZ_CRC("com.o3de.action.physx.setrotationsubmode", 0xf1a8f3ff);
|
||||
const AZ::Crc32 ResetSubModeActionUri = AZ_CRC("com.o3de.action.physx.resetsubmode", 0x599d1594);
|
||||
} // namespace
|
||||
|
||||
AZ_CLASS_ALLOCATOR_IMPL(ColliderComponentMode, AZ::SystemAllocator, 0);
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace PhysXDebug
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("PhysXDebugEditorService", 0xe3dde7d8));
|
||||
provided.push_back(AZ_CRC("PhysXDebugEditorService", 0xf8611967));
|
||||
}
|
||||
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace WhiteBox
|
||||
AZ::Color, cl_whiteBoxVertexIndicatorColor, AZ::Color::CreateFromRgba(0, 0, 0, 102), nullptr,
|
||||
AZ::ConsoleFunctorFlags::Null, "The color of the vertex indicator");
|
||||
|
||||
static const AZ::Crc32 HideEdge = AZ_CRC("com.o3de.action.whitebox.hide_edge", 0x6a60ae23);
|
||||
static const AZ::Crc32 HideVertex = AZ_CRC("com.o3de.action.whitebox.hide_vertex", 0x4a4bd092);
|
||||
static const AZ::Crc32 HideEdge = AZ_CRC("com.o3de.action.whitebox.hide_edge", 0x84f6a9b9);
|
||||
static const AZ::Crc32 HideVertex = AZ_CRC("com.o3de.action.whitebox.hide_vertex", 0x5f81c937);
|
||||
|
||||
static const char* const HideEdgeTitle = "Hide Edge";
|
||||
static const char* const HideEdgeDesc = "Hide the selected edge to merge the two connected polygons";
|
||||
|
||||
@@ -16,7 +16,6 @@ if(LY_MONOLITHIC_GAME)
|
||||
ly_set(PAL_TRAIT_BUILD_HOST_TOOLS FALSE)
|
||||
ly_set(PAL_TRAIT_BUILD_HOST_GUI_TOOLS FALSE)
|
||||
ly_set(PAL_TRAIT_BUILD_TESTS_SUPPORTED FALSE)
|
||||
ly_set(PAL_TRAIT_BUILD_SERVER_SUPPORTED FALSE)
|
||||
else()
|
||||
ly_set(PAL_TRAIT_MONOLITHIC_DRIVEN_LIBRARY_TYPE SHARED)
|
||||
ly_set(PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE GEM_MODULE)
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import sys
|
||||
try:
|
||||
import six
|
||||
except ImportError:
|
||||
import pip
|
||||
pip.main(['install', 'six', '--ignore-installed', '-q'])
|
||||
import six
|
||||
from pathlib import Path
|
||||
|
||||
this_file_path = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
# resolve symlinks and eliminate ".." components
|
||||
engine_root_path = Path(__file__).resolve().parents[3]
|
||||
|
||||
def convert_glob_pattern_to_regex_pattern(glob_pattern):
|
||||
# switch to forward slashes because way easier to pattern match against
|
||||
pattern = re.sub(r'\\', r'/', glob_pattern)
|
||||
|
||||
# Replace the dots and question marks
|
||||
pattern = re.sub(r'\.', r'\\.', pattern)
|
||||
pattern = re.sub(r'\?', r'.', pattern)
|
||||
|
||||
# Handle the * vs ** expansions
|
||||
pattern = re.sub(r'([^*])\*($|[^*])', r'\1[^/\\\\]*\2', pattern)
|
||||
pattern = re.sub(r'\*\*/', r'(.*/)?', pattern)
|
||||
pattern = re.sub(r'\*\*', r'.*', pattern)
|
||||
|
||||
# replace the forward slashes with [/\\] so it works on PC/unix
|
||||
pattern = re.sub(r'([^^])/', r'\1[/\\\\]', pattern)
|
||||
return pattern
|
||||
|
||||
# Convert the package json into a pair of regexes we can use to look for includes and excludes
|
||||
def convert_glob_list_to_regex_list(filelist, prefix):
|
||||
includes = []
|
||||
excludes = []
|
||||
for key, value in six.iteritems(filelist):
|
||||
glob_pattern = os.path.join(prefix, key)
|
||||
if isinstance(value, dict):
|
||||
(sub_includes, sub_excludes) = convert_glob_list_to_regex_list(value, glob_pattern)
|
||||
includes.extend(sub_includes)
|
||||
excludes.extend(sub_excludes)
|
||||
else:
|
||||
# Simulate what glob would do with file walking to scope the * within a directory
|
||||
# and ** across directories
|
||||
regex_pattern = convert_glob_pattern_to_regex_pattern(os.path.normpath(glob_pattern))
|
||||
|
||||
# Deal with the commands. include/exclude are straight forward. Moves/renames are to be considered
|
||||
# includes, and we will stick with validating the original contents for now
|
||||
if value == "#include":
|
||||
includes.append(regex_pattern)
|
||||
elif value == "#exclude":
|
||||
excludes.append(regex_pattern)
|
||||
elif value.startswith('#move:'):
|
||||
includes.append(regex_pattern)
|
||||
elif value.startswith('#rename:'):
|
||||
includes.append(regex_pattern)
|
||||
else:
|
||||
pass
|
||||
return (includes, excludes)
|
||||
|
||||
def generate_excludes_for_platform(root, platform):
|
||||
if platform == 'all':
|
||||
platform_exclusions_filename = os.path.join(this_file_path, 'platform_exclusions.json')
|
||||
with open(platform_exclusions_filename, 'r') as platform_exclusions_file:
|
||||
platform_exclusions = json.load(platform_exclusions_file)
|
||||
else:
|
||||
# Use real path in case root is a symlink path
|
||||
if os.name == 'posix' and os.path.islink(root):
|
||||
root = os.readlink(root)
|
||||
# "root" is the root of the folder structure we're validating
|
||||
# "engine_root_path" is the engine root where the restricted platform folder is linked
|
||||
relative_folder = os.path.relpath(this_file_path, engine_root_path)
|
||||
platform_exclusions_filename = os.path.join(engine_root_path, 'restricted', platform, relative_folder, platform.lower() + '_exclusions.json')
|
||||
with open(platform_exclusions_filename, 'r') as platform_exclusions_file:
|
||||
platform_exclusions = json.load(platform_exclusions_file)
|
||||
|
||||
if platform not in platform_exclusions:
|
||||
raise KeyError('No {} found in {}'.format(platform, platform_exclusions_filename))
|
||||
if '@lyengine' not in platform_exclusions[platform]:
|
||||
raise KeyError('No {}/@lyengine found in {}'.format(platform, package_file_list))
|
||||
(_, excludes) = convert_glob_list_to_regex_list(platform_exclusions[platform]['@lyengine'], root)
|
||||
del _
|
||||
return excludes
|
||||
|
||||
def generate_include_exclude_regexes(package_platform, package_type, root, prohibited_platforms):
|
||||
# The general contents will be indicated by the package file
|
||||
if package_type == 'all':
|
||||
package_file_list = os.path.join(this_file_path, 'package_filelists', 'all.json')
|
||||
else:
|
||||
# Search non-restricted platform first
|
||||
package_file_list = os.path.join(this_file_path, 'Platform', package_platform, 'package_filelists', f'{package_type}.json')
|
||||
if not os.path.exists(filelist):
|
||||
# Use real path in case root is a symlink path
|
||||
if os.name == 'posix' and os.path.islink(root):
|
||||
root = os.readlink(root)
|
||||
# "root" is the root of the folder structure we're validating
|
||||
# "engine_root_path" is the engine root where the restricted platform folder is linked
|
||||
rel_path = os.path.relpath(this_file_path, engine_root_path)
|
||||
package_file_list = os.path.join(engine_root_path, 'restricted', package_platform, rel_path, 'package_filelists',
|
||||
f'{package_type}.json')
|
||||
with open(package_file_list, 'r') as package_file:
|
||||
package = json.load(package_file)
|
||||
|
||||
if '@lyengine' not in package:
|
||||
raise KeyError('No @lyengine found in {}'.format(package_file_list))
|
||||
|
||||
(includes_list, excludes_list) = convert_glob_list_to_regex_list(package['@lyengine'], root)
|
||||
prohibited_platforms.append('all')
|
||||
|
||||
# Add the exclusions of each prohibited platform
|
||||
for p in prohibited_platforms:
|
||||
excludes_list.extend(generate_excludes_for_platform(root, p))
|
||||
|
||||
includes = re.compile('|'.join(includes_list), re.IGNORECASE)
|
||||
excludes = re.compile('|'.join(excludes_list), re.IGNORECASE)
|
||||
return (includes, excludes)
|
||||
|
||||
def generate_exclude_regexes_for_platform(root, platform):
|
||||
return re.compile('|'.join(generate_excludes_for_platform(root, platform)), re.IGNORECASE)
|
||||
@@ -6,10 +6,8 @@
|
||||
#
|
||||
#
|
||||
|
||||
# this ctest makes sure that the commit validation function
|
||||
# also runs its tests during commit validation!
|
||||
ly_add_pytest(
|
||||
NAME test_commit_validation
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/commit_validation/tests
|
||||
TEST_SUITE smoke
|
||||
)
|
||||
|
||||
|
||||
@@ -181,4 +181,6 @@ EXCLUDED_VALIDATION_PATTERNS = [
|
||||
'restricted/*/Tools/*RemoteControl',
|
||||
'*/user/Cache/*',
|
||||
'*/user/log/*',
|
||||
'*/user/log_test_1/*',
|
||||
'*/user/log_test_2/*',
|
||||
]
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
|
||||
import unittest
|
||||
from unittest.mock import patch, mock_open
|
||||
|
||||
from commit_validation.tests.mocks.mock_commit import MockCommit
|
||||
from commit_validation.validators.crc_validator import CrcValidator
|
||||
|
||||
|
||||
class CrcValidatorTests(unittest.TestCase):
|
||||
|
||||
@patch('builtins.open', mock_open(read_data='This file does not contain an AZ_CRC macro'))
|
||||
def test_fileWithNoCrc_passes(self):
|
||||
commit = MockCommit(files=['/someCppFile.cpp'])
|
||||
error_list = []
|
||||
self.assertTrue(CrcValidator().run(commit, error_list))
|
||||
self.assertEqual(len(error_list), 0, f"Unexpected errors: {error_list}")
|
||||
|
||||
@patch('builtins.open', mock_open(read_data='This file contains an invalid CRC macro AZ_CRC("My string", 0xabcdef00)'))
|
||||
def test_fileWithInvalidCrc_fails(self):
|
||||
commit = MockCommit(files=['/someCppFile.cpp'])
|
||||
error_list = []
|
||||
self.assertFalse(CrcValidator().run(commit, error_list))
|
||||
self.assertNotEqual(len(error_list), 0, f"Errors were expected but none were returned.")
|
||||
|
||||
@patch('builtins.open', mock_open(read_data='This file contains a valid CRC macro AZ_CRC("My string", 0x18fbd270)'))
|
||||
def test_fileWithValidCrc_fails(self):
|
||||
commit = MockCommit(files=['/someCppFile.cpp'])
|
||||
error_list = []
|
||||
self.assertTrue(CrcValidator().run(commit, error_list))
|
||||
self.assertEqual(len(error_list), 0, f"Unexpected errors: {error_list}")
|
||||
|
||||
@patch('builtins.open', mock_open(read_data='This file contains an invalid CRC macro AZ_CRC("My string", 0xabcdef00)'))
|
||||
def test_fileExtensionIgnored_passes(self):
|
||||
commit = MockCommit(files=['/someCppFile.somerandomextension'])
|
||||
error_list = []
|
||||
self.assertTrue(CrcValidator().run(commit, error_list))
|
||||
self.assertEqual(len(error_list), 0, f"Unexpected errors: {error_list}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,48 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
|
||||
import binascii
|
||||
import fnmatch
|
||||
import pathlib
|
||||
import re
|
||||
from typing import Type, List
|
||||
|
||||
from commit_validation.commit_validation import Commit, CommitValidator, SOURCE_FILE_EXTENSIONS, EXCLUDED_VALIDATION_PATTERNS, VERBOSE
|
||||
|
||||
class CrcValidator(CommitValidator):
|
||||
"""A file-level validator that makes sure a file does not contain an invalid CRC"""
|
||||
|
||||
def run(self, commit: Commit, errors: List[str]) -> bool:
|
||||
for file_name in commit.get_files():
|
||||
for pattern in EXCLUDED_VALIDATION_PATTERNS:
|
||||
if fnmatch.fnmatch(file_name, pattern):
|
||||
if VERBOSE: print(f'{file_name}::{self.__class__.__name__} SKIPPED - Validation pattern excluded on path.')
|
||||
break
|
||||
else:
|
||||
if pathlib.Path(file_name).suffix.lower() not in SOURCE_FILE_EXTENSIONS:
|
||||
if VERBOSE: print(f'{file_name}::{self.__class__.__name__} SKIPPED - File excluded based on extension.')
|
||||
continue
|
||||
|
||||
with open(file_name, mode='r', encoding='utf8') as fh:
|
||||
fileContents = fh.read()
|
||||
matchesFound = re.findall(r'AZ_CRC\("([^"]+)",([^)]*)\)', fileContents)
|
||||
for element in matchesFound:
|
||||
stringInCode = element[0]
|
||||
valueInCode = element[1].strip()
|
||||
expectedValue = "{0:#0{1}x}".format(binascii.crc32(stringInCode.lower().encode('utf8')), 10)
|
||||
if expectedValue != valueInCode:
|
||||
error_message = str(f'{file_name}::{self.__class__.__name__} FAILED - Source file contains a CRC mismatch!\n'
|
||||
f' AZ_CRC("{stringInCode}", {valueInCode}), expected value {expectedValue}')
|
||||
if VERBOSE: print(error_message)
|
||||
errors.append(error_message)
|
||||
return (not errors)
|
||||
|
||||
|
||||
def get_validator() -> Type[CrcValidator]:
|
||||
"""Returns the validator class for this module"""
|
||||
return CrcValidator
|
||||
@@ -1,29 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
cur_dir = cur_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.abspath(f'{cur_dir}/../build/package'))
|
||||
import util
|
||||
|
||||
# Run validator
|
||||
success = True
|
||||
validator_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'validator.py')
|
||||
engine_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
|
||||
if sys.platform == 'win32':
|
||||
python = os.path.join(engine_root, 'python', 'python.cmd')
|
||||
else:
|
||||
python = os.path.join(engine_root, 'python', 'python.sh')
|
||||
args = [python, validator_path, '--package_platform', 'Windows', '--package_type', 'all', engine_root]
|
||||
return_code = util.safe_execute_system_call(args)
|
||||
if return_code != 0:
|
||||
success = False
|
||||
if not success:
|
||||
util.error('Restricted file validator failed.')
|
||||
print('Restricted file validator completed successfully.')
|
||||
@@ -29,8 +29,6 @@ else:
|
||||
from io import StringIO
|
||||
|
||||
import validator_data_LEGAL_REVIEW_REQUIRED # pull in the data we need to configure this tool
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'build', 'package'))
|
||||
from glob_to_regex import generate_include_exclude_regexes
|
||||
|
||||
class Validator(object):
|
||||
"""Class to contain the validator program"""
|
||||
@@ -212,9 +210,6 @@ class Validator(object):
|
||||
# TODO: Perhaps the directories to skip should become a parameter so we can use the validator
|
||||
# on non-Lumberyard trees.
|
||||
def validate_directory_tree(self, root, platform):
|
||||
prohibited_platforms = validator_data_LEGAL_REVIEW_REQUIRED.get_prohibited_platforms_for_package(self.options.package_platform)
|
||||
(includes, excludes) = generate_include_exclude_regexes(self.options.package_platform, self.options.package_type, root, prohibited_platforms)
|
||||
|
||||
"""Walk from root to find all files to validate and call the validator on each file.
|
||||
Return 0 if no problems where found, and 1 if any validation failures occured."""
|
||||
counter = 0
|
||||
@@ -227,28 +222,22 @@ class Validator(object):
|
||||
# First deal with the files in the current directory
|
||||
for filename in filenames:
|
||||
filepath = os.path.join(dirname, filename)
|
||||
include_match = includes.match(filepath)
|
||||
exclude_match = excludes.match(filepath)
|
||||
allowed = include_match and not exclude_match
|
||||
|
||||
if self.options.all or allowed:
|
||||
scanned += 1
|
||||
file_failed = self.validate_file(os.path.normpath(filepath))
|
||||
if file_failed:
|
||||
platform_failed = file_failed
|
||||
else:
|
||||
validations += 1
|
||||
counter += 1
|
||||
scanned += 1
|
||||
file_failed = self.validate_file(os.path.normpath(filepath))
|
||||
if file_failed:
|
||||
platform_failed = file_failed
|
||||
else:
|
||||
validations += 1
|
||||
|
||||
# Trim out allowlisted subdirectories in the current directory if allowed
|
||||
for name in bypassed_directories:
|
||||
if name in dirnames:
|
||||
dirnames.remove(name)
|
||||
if counter == 0 or scanned == 0:
|
||||
if scanned == 0:
|
||||
logging.error('No files scanned at target search directory: %s', root)
|
||||
platform_failed = 1
|
||||
else:
|
||||
print('validated {} of {} package files ({} non-package files skipped)'.format(validations, scanned, counter - scanned))
|
||||
print('validated {} of {} files'.format(validations, scanned))
|
||||
return platform_failed
|
||||
|
||||
|
||||
@@ -387,8 +376,6 @@ def parse_options():
|
||||
choices=platform_choices,
|
||||
dest='package_platform',
|
||||
help='Package platform to validate. Must be one of {}.'.format(platform_choices))
|
||||
parser.add_option('--package_type', action='store', type='string', default='all', dest='package_type',
|
||||
help='Package type to validate.')
|
||||
parser.add_option('-s', '--store-exceptions', action='store', type='string', default='',
|
||||
dest='exception_file',
|
||||
help='Store list of lines that the validator gave exceptions to by matching accepted use patterns. These can be diffed with prior runs to see what is changing.')
|
||||
@@ -430,7 +417,6 @@ def main():
|
||||
|
||||
package_failed = 0
|
||||
package_platform = validator.options.package_platform
|
||||
package_type = validator.options.package_type
|
||||
prohibited_platforms = validator_data_LEGAL_REVIEW_REQUIRED.get_prohibited_platforms_for_package(package_platform)
|
||||
|
||||
if validator.options.exception_file != '':
|
||||
@@ -441,19 +427,20 @@ def main():
|
||||
sys.exit(1)
|
||||
|
||||
for platform in prohibited_platforms:
|
||||
print('validating {} against {} for package platform {} package type {}'.format(args[0], platform, package_platform, package_type))
|
||||
print('validating {} against {} for package platform {}'.format(args[0], platform, package_platform))
|
||||
platform_failed = validator.validate(platform)
|
||||
if platform_failed:
|
||||
print('{} FAILED validation against {} for package platform {} package type {}'.format(args[0], platform, package_platform, package_type))
|
||||
print('{} FAILED validation against {} for package platform {}'.format(args[0], platform, package_platform))
|
||||
package_failed = platform_failed
|
||||
else:
|
||||
print('{} is VALIDATED against {} for package platform {} package type {}'.format(args[0], platform, package_platform, package_type))
|
||||
print('{} is VALIDATED against {} for package platform {}'.format(args[0], platform, package_platform))
|
||||
|
||||
if validator.options.exception_file != '':
|
||||
validator.exceptions_output.close()
|
||||
|
||||
return package_failed
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# pylint: disable-msg=C0103
|
||||
main_results = main()
|
||||
|
||||
Reference in New Issue
Block a user