From 7115f60b91b5717d90f643fd692010905c7004db Mon Sep 17 00:00:00 2001 From: Bryan Galdrikian Date: Thu, 31 May 2018 11:36:08 -0700 Subject: Blast 1.1.3. See docs/release_notes.txt. --- test/src/unit/AssetTests.cpp | 1716 +++++++++++++++++++++--------------------- 1 file changed, 858 insertions(+), 858 deletions(-) mode change 100644 => 100755 test/src/unit/AssetTests.cpp (limited to 'test/src/unit/AssetTests.cpp') diff --git a/test/src/unit/AssetTests.cpp b/test/src/unit/AssetTests.cpp old mode 100644 new mode 100755 index 9bd8aa0..6511f60 --- a/test/src/unit/AssetTests.cpp +++ b/test/src/unit/AssetTests.cpp @@ -1,858 +1,858 @@ -// This code contains NVIDIA Confidential Information and is disclosed to you -// under a form of NVIDIA software license agreement provided separately to you. -// -// Notice -// NVIDIA Corporation and its licensors retain all intellectual property and -// proprietary rights in and to this software and related documentation and -// any modifications thereto. Any use, reproduction, disclosure, or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA Corporation is strictly prohibited. -// -// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES -// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO -// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, -// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. -// -// Information and code furnished is believed to be accurate and reliable. -// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such -// information or for any infringement of patents or other rights of third parties that may -// result from its use. No license is granted by implication or otherwise under any patent -// or patent rights of NVIDIA Corporation. Details are subject to change without notice. -// This code supersedes and replaces all information previously supplied. -// NVIDIA Corporation products are not authorized for use as critical -// components in life support devices or systems without express written approval of -// NVIDIA Corporation. -// -// Copyright (c) 2016-2018 NVIDIA Corporation. All rights reserved. - - -#include "NvBlastAsset.h" -#include "NvBlastMath.h" - -#include "BlastBaseTest.h" - -#include "NvBlastTkFramework.h" - -#include - - -// all supported platform now provide serialization -// keep the define for future platforms that won't -#define ENABLE_SERIALIZATION_TESTS 1 - -#pragma warning( push ) -#pragma warning( disable : 4267 ) -// NOTE: Instead of excluding serialization and the tests when on VC12, should break the tests out into a separate C++ file. - -#if ENABLE_SERIALIZATION_TESTS -#include "NvBlastExtSerialization.h" -#include "NvBlastExtLlSerialization.h" -#include "NvBlastExtSerializationInternal.h" -#endif - -#include "NvBlastExtAssetUtils.h" - -#pragma warning( pop ) - -#include -#include - -#ifdef WIN32 -#include -#endif - -template -class AssetTest : public BlastBaseTest -{ -public: - - AssetTest() - { - NvBlastTkFrameworkCreate(); - } - - ~AssetTest() - { - NvBlastTkFrameworkGet()->release(); - } - - static void messageLog(int type, const char* msg, const char* file, int line) - { - BlastBaseTest::messageLog(type, msg, file, line); - } - - static void* alloc(size_t size) - { - return BlastBaseTest::alignedZeroedAlloc(size); - } - - static void free(void* mem) - { - BlastBaseTest::alignedFree(mem); - } - - void testSubtreeLeafChunkCounts(const Nv::Blast::Asset& a) - { - const NvBlastChunk* chunks = a.getChunks(); - const uint32_t* subtreeLeafChunkCounts = a.getSubtreeLeafChunkCounts(); - uint32_t totalLeafChunkCount = 0; - for (uint32_t chunkIndex = 0; chunkIndex < a.m_chunkCount; ++chunkIndex) - { - const NvBlastChunk& chunk = chunks[chunkIndex]; - if (Nv::Blast::isInvalidIndex(chunk.parentChunkIndex)) - { - totalLeafChunkCount += subtreeLeafChunkCounts[chunkIndex]; - } - const bool isLeafChunk = chunk.firstChildIndex >= chunk.childIndexStop; - uint32_t subtreeLeafChunkCount = isLeafChunk ? 1 : 0; - for (uint32_t childIndex = chunk.firstChildIndex; childIndex < chunk.childIndexStop; ++childIndex) - { - subtreeLeafChunkCount += subtreeLeafChunkCounts[childIndex]; - } - EXPECT_EQ(subtreeLeafChunkCount, subtreeLeafChunkCounts[chunkIndex]); - } - EXPECT_EQ(totalLeafChunkCount, a.m_leafChunkCount); - } - - void testChunkToNodeMap(const Nv::Blast::Asset& a) - { - for (uint32_t chunkIndex = 0; chunkIndex < a.m_chunkCount; ++chunkIndex) - { - const uint32_t nodeIndex = a.getChunkToGraphNodeMap()[chunkIndex]; - if (!Nv::Blast::isInvalidIndex(nodeIndex)) - { - EXPECT_LT(nodeIndex, a.m_graph.m_nodeCount); - EXPECT_EQ(chunkIndex, a.m_graph.getChunkIndices()[nodeIndex]); - } - else - { - const uint32_t* chunkIndexStop = a.m_graph.getChunkIndices() + a.m_graph.m_nodeCount; - const uint32_t* it = std::find(a.m_graph.getChunkIndices(), chunkIndexStop, chunkIndex); - EXPECT_EQ(chunkIndexStop, it); - } - } - } - - NvBlastAsset* buildAsset(const ExpectedAssetValues& expected, const NvBlastAssetDesc* desc) - { - std::vector scratch; - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(desc, messageLog)); - void* mem = alloc(NvBlastGetAssetMemorySize(desc, messageLog)); - NvBlastAsset* asset = NvBlastCreateAsset(mem, desc, scratch.data(), messageLog); - EXPECT_TRUE(asset != nullptr); - if (asset == nullptr) - { - free(mem); - return nullptr; - } - Nv::Blast::Asset& a = *(Nv::Blast::Asset*)asset; - EXPECT_EQ(expected.totalChunkCount, a.m_chunkCount); - EXPECT_EQ(expected.graphNodeCount, a.m_graph.m_nodeCount); - EXPECT_EQ(expected.bondCount, a.m_graph.getAdjacencyPartition()[a.m_graph.m_nodeCount] / 2); - EXPECT_EQ(expected.leafChunkCount, a.m_leafChunkCount); - EXPECT_EQ(expected.subsupportChunkCount, a.m_chunkCount - a.m_firstSubsupportChunkIndex); - testSubtreeLeafChunkCounts(a); - testChunkToNodeMap(a); - return asset; - } - - void checkAssetsExpected(Nv::Blast::Asset& asset, const ExpectedAssetValues& expected) - { - EXPECT_EQ(expected.totalChunkCount, asset.m_chunkCount); - EXPECT_EQ(expected.graphNodeCount, asset.m_graph.m_nodeCount); - EXPECT_EQ(expected.bondCount, asset.m_graph.getAdjacencyPartition()[asset.m_graph.m_nodeCount] / 2); - EXPECT_EQ(expected.leafChunkCount, asset.m_leafChunkCount); - EXPECT_EQ(expected.subsupportChunkCount, asset.m_chunkCount - asset.m_firstSubsupportChunkIndex); - testSubtreeLeafChunkCounts(asset); - testChunkToNodeMap(asset); - } - - // expects that the bond normal points from the lower indexed chunk to higher index chunk - // uses chunk.centroid - // convention, requirement from findClosestNode - void checkNormalDir(NvBlastChunkDesc* chunkDescs, size_t chunkDescCount, NvBlastBondDesc* bondDescs, size_t bondDescCount) - { - for (size_t bondIndex = 0; bondIndex < bondDescCount; ++bondIndex) - { - NvBlastBondDesc& bond = bondDescs[bondIndex]; - uint32_t chunkIndex0 = bond.chunkIndices[0]; - uint32_t chunkIndex1 = bond.chunkIndices[1]; - - bool swap = chunkIndex0 > chunkIndex1; - uint32_t testIndex0 = swap ? chunkIndex1 : chunkIndex0; - uint32_t testIndex1 = swap ? chunkIndex0 : chunkIndex1; - - EXPECT_TRUE(testIndex0 < testIndex1); - - // no convention for world chunks - if (!Nv::Blast::isInvalidIndex(testIndex0) && !Nv::Blast::isInvalidIndex(testIndex1)) - { - NvBlastChunkDesc& chunk0 = chunkDescs[testIndex0]; - NvBlastChunkDesc& chunk1 = chunkDescs[testIndex1]; - - float dir[3]; - Nv::Blast::VecMath::sub(chunk1.centroid, chunk0.centroid, dir); - bool meetsConvention = Nv::Blast::VecMath::dot(bond.bond.normal, dir) > 0; - EXPECT_TRUE(meetsConvention); - if (!meetsConvention) - { - printf("bond %zd chunks(%d,%d): %.2f %.2f %.2f %.2f %.2f %.2f %d\n", - bondIndex, chunkIndex0, chunkIndex1, - bond.bond.normal[0], bond.bond.normal[1], bond.bond.normal[2], - dir[0], dir[1], dir[2], - Nv::Blast::VecMath::dot(bond.bond.normal, dir) > 0); - } - } - } - } - - // expects that the bond normal points from the lower indexed node to higher index node - // uses chunk.centroid - // convention, requirement from findClosestNode - void checkNormalDir(const NvBlastSupportGraph graph, const NvBlastChunk* assetChunks, const NvBlastBond* assetBonds) - { - for (uint32_t nodeIndex = 0; nodeIndex < graph.nodeCount; nodeIndex++) - { - uint32_t adjStart = graph.adjacencyPartition[nodeIndex]; - uint32_t adjStop = graph.adjacencyPartition[nodeIndex + 1]; - for (uint32_t adj = adjStart; adj < adjStop; ++adj) - { - uint32_t adjNodeIndex = graph.adjacentNodeIndices[adj]; - - bool swap = nodeIndex > adjNodeIndex; - uint32_t testIndex0 = swap ? adjNodeIndex : nodeIndex; - uint32_t testIndex1 = swap ? nodeIndex : adjNodeIndex; - - // no convention for world chunks - if (!Nv::Blast::isInvalidIndex(graph.chunkIndices[testIndex0]) && !Nv::Blast::isInvalidIndex(graph.chunkIndices[testIndex1])) - { - const NvBlastChunk& chunk0 = assetChunks[graph.chunkIndices[testIndex0]]; - const NvBlastChunk& chunk1 = assetChunks[graph.chunkIndices[testIndex1]]; - - uint32_t bondIndex = graph.adjacentBondIndices[adj]; - const NvBlastBond& bond = assetBonds[bondIndex]; - - float dir[3]; - Nv::Blast::VecMath::sub(chunk1.centroid, chunk0.centroid, dir); - bool meetsConvention = Nv::Blast::VecMath::dot(bond.normal, dir) > 0; - EXPECT_TRUE(meetsConvention); - if (!meetsConvention) - { - printf("bond %d nodes(%d,%d): %.2f %.2f %.2f %.2f %.2f %.2f %d\n", - bondIndex, nodeIndex, adjNodeIndex, - bond.normal[0], bond.normal[1], bond.normal[2], - dir[0], dir[1], dir[2], - Nv::Blast::VecMath::dot(bond.normal, dir) > 0); - } - } - } - } - } - - void checkNormalDir(const NvBlastAsset* asset) - { - const NvBlastChunk* assetChunks = NvBlastAssetGetChunks(asset, nullptr); - const NvBlastBond* assetBonds = NvBlastAssetGetBonds(asset, nullptr); - const NvBlastSupportGraph graph = NvBlastAssetGetSupportGraph(asset, nullptr); - checkNormalDir(graph, assetChunks, assetBonds); - } - - void buildAssetShufflingDescriptors(const NvBlastAssetDesc* desc, const ExpectedAssetValues& expected, uint32_t shuffleCount, bool useTk) - { - NvBlastAssetDesc shuffledDesc = *desc; - std::vector chunkDescs(desc->chunkDescs, desc->chunkDescs + desc->chunkCount); - shuffledDesc.chunkDescs = chunkDescs.data(); - std::vector bondDescs(desc->bondDescs, desc->bondDescs + desc->bondCount); - shuffledDesc.bondDescs = bondDescs.data(); - if (!useTk) - { - std::vector scratch(desc->chunkCount); - NvBlastEnsureAssetExactSupportCoverage(chunkDescs.data(), desc->chunkCount, scratch.data(), messageLog); - } - else - { - NvBlastTkFrameworkGet()->ensureAssetExactSupportCoverage(chunkDescs.data(), desc->chunkCount); - } - for (uint32_t i = 0; i < shuffleCount; ++i) - { - checkNormalDir(chunkDescs.data(), chunkDescs.size(), bondDescs.data(), bondDescs.size()); - shuffleAndFixChunkDescs(chunkDescs.data(), desc->chunkCount, bondDescs.data(), desc->bondCount, useTk); - checkNormalDir(chunkDescs.data(), chunkDescs.size(), bondDescs.data(), bondDescs.size()); - - NvBlastAsset* asset = buildAsset(expected, &shuffledDesc); - EXPECT_TRUE(asset != nullptr); - checkNormalDir(asset); - if (asset) - { - free(asset); - } - } - } - - void shuffleAndFixChunkDescs(NvBlastChunkDesc* chunkDescs, uint32_t chunkDescCount, NvBlastBondDesc* bondDescs, uint32_t bondDescCount, bool useTk) - { - // Create reorder array and fill with identity map - std::vector shuffledOrder(chunkDescCount); - for (uint32_t i = 0; i < chunkDescCount; ++i) - { - shuffledOrder[i] = i; - } - - // An array into which to copy the reordered descs - std::vector shuffledChunkDescs(chunkDescCount); - - std::vector scratch; - const uint32_t trials = 30; - uint32_t attempt = 0; - while(1) - { - // Shuffle the reorder array - std::random_shuffle(shuffledOrder.begin(), shuffledOrder.end()); - - // Save initial bonds - std::vector savedBondDescs(bondDescs, bondDescs + bondDescCount); - - // Shuffle chunks and bonds - NvBlastApplyAssetDescChunkReorderMap(shuffledChunkDescs.data(), chunkDescs, chunkDescCount, bondDescs, bondDescCount, shuffledOrder.data(), true, nullptr); - - // All the normals are pointing in the expected direction (they have been swapped) - checkNormalDir(shuffledChunkDescs.data(), chunkDescCount, bondDescs, bondDescCount); - checkNormalDir(chunkDescs, chunkDescCount, savedBondDescs.data(), bondDescCount); - - // Check the results - for (uint32_t i = 0; i < chunkDescCount; ++i) - { - EXPECT_EQ(chunkDescs[i].userData, shuffledChunkDescs[shuffledOrder[i]].userData); - EXPECT_TRUE(chunkDescs[i].parentChunkIndex > chunkDescCount || shuffledChunkDescs[shuffledOrder[i]].parentChunkIndex == shuffledOrder[chunkDescs[i].parentChunkIndex]); - } - for (uint32_t i = 0; i < bondDescCount; ++i) - { - for (uint32_t k = 0; k < 2; ++k) - { - if (!Nv::Blast::isInvalidIndex(savedBondDescs[i].chunkIndices[k])) - { - EXPECT_EQ(shuffledOrder[savedBondDescs[i].chunkIndices[k]], bondDescs[i].chunkIndices[k]); - } - } - } - - // Try creating asset, usually it should fail (otherwise make another attempt) - NvBlastAssetDesc desc = { chunkDescCount, shuffledChunkDescs.data(), bondDescCount, bondDescs }; - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&desc, nullptr)); - void* mem = alloc(NvBlastGetAssetMemorySize(&desc, nullptr)); - NvBlastAsset* asset = NvBlastCreateAsset(mem, &desc, scratch.data(), nullptr); - if (asset == nullptr) - { - free(mem); - break; - } - else - { - free(asset); - memcpy(bondDescs, savedBondDescs.data(), sizeof(NvBlastBondDesc) * bondDescCount); - attempt++; - if (attempt >= trials) - { - GTEST_NONFATAL_FAILURE_("Shuffled chunk descs should fail asset creation (most of the time)."); - break; - } - } - } - - // Now we want to fix that order - if (!useTk) - { - std::vector chunkReorderMap(chunkDescCount); - std::vector scratch2(2 * chunkDescCount * sizeof(uint32_t)); - const bool isIdentity = NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), shuffledChunkDescs.data(), chunkDescCount, scratch2.data(), messageLog); - EXPECT_FALSE(isIdentity); - NvBlastApplyAssetDescChunkReorderMap(chunkDescs, shuffledChunkDescs.data(), chunkDescCount, bondDescs, bondDescCount, chunkReorderMap.data(), true, messageLog); - } - else - { - memcpy(chunkDescs, shuffledChunkDescs.data(), chunkDescCount * sizeof(NvBlastChunkDesc)); - const bool isIdentity = NvBlastTkFrameworkGet()->reorderAssetDescChunks(chunkDescs, chunkDescCount, bondDescs, bondDescCount, nullptr, true); - EXPECT_FALSE(isIdentity); - } - } - - void mergeAssetTest(const NvBlastAssetDesc& desc, bool fail) - { - std::vector scratch; - - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&desc, messageLog)); - void* mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&desc, messageLog)); - NvBlastAsset* asset = NvBlastCreateAsset(mem, &desc, scratch.data(), messageLog); - EXPECT_TRUE(asset != nullptr); - if (asset == nullptr) - { - free(mem); - return; - } - - // Merge two copies of this asset together - const NvBlastAsset* components[2] = { asset, asset }; - const NvcVec3 translations[2] = { { 0, 0, 0 },{ 2, 0, 0 } }; - - const NvBlastBond bond = { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 }; - - NvBlastExtAssetUtilsBondDesc newBondDescs[4]; - for (int i = 0; i < 4; ++i) - { - newBondDescs[i].bond = bond; - newBondDescs[i].chunkIndices[0] = 2 * (i + 1); - newBondDescs[i].chunkIndices[1] = 2 * i + 1; - newBondDescs[i].componentIndices[0] = 0; - newBondDescs[i].componentIndices[1] = 1; - } - - // Create a merged descriptor - std::vector chunkIndexOffsets(2); - std::vector chunkReorderMap(2 * desc.chunkCount); - - NvBlastAssetDesc mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), chunkReorderMap.data(), 2 * desc.chunkCount); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - for (uint32_t i = 0; i < 2 * desc.chunkCount; ++i) - { - EXPECT_LT(chunkReorderMap[i], 2 * desc.chunkCount); - } - EXPECT_EQ(0, chunkIndexOffsets[0]); - EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]); - - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - NvBlastAsset* mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset != nullptr); - if (mergedAsset == nullptr) - { - free(mem); - return; - } - - NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); - NVBLAST_FREE(mergedAsset); - - if (!fail) - { - mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, chunkReorderMap.data(), 2 * desc.chunkCount); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - for (uint32_t i = 0; i < 2 * desc.chunkCount; ++i) - { - EXPECT_LT(chunkReorderMap[i], 2 * desc.chunkCount); - } - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset != nullptr); - free(mem); - NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); - } - else - { - // We don't pass in a valid chunkReorderMap so asset creation should fail - mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), nullptr, 0); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - EXPECT_EQ(0, chunkIndexOffsets[0]); - EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]); - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset == nullptr); - free(mem); - NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); - - mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, nullptr, 0); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset == nullptr); - free(mem); - NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); - - // We lie and say the chunkReorderMap is not large enough. It should be filled with 0xFFFFFFFF up to the size we gave - mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, chunkReorderMap.data(), desc.chunkCount); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - for (uint32_t i = 0; i < desc.chunkCount; ++i) - { - EXPECT_TRUE(Nv::Blast::isInvalidIndex(chunkReorderMap[i])); - } - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset == nullptr); - free(mem); - NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); - - mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), chunkReorderMap.data(), desc.chunkCount); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - for (uint32_t i = 0; i < desc.chunkCount; ++i) - { - EXPECT_TRUE(Nv::Blast::isInvalidIndex(chunkReorderMap[i])); - } - EXPECT_EQ(0, chunkIndexOffsets[0]); - EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]); - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset == nullptr); - free(mem); - NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); - } - - // Finally free the original asset - NVBLAST_FREE(asset); - } -}; - -typedef AssetTest<-1, 0> AssetTestAllowErrorsSilently; -typedef AssetTest AssetTestAllowWarningsSilently; -typedef AssetTest AssetTestAllowWarnings; -typedef AssetTest AssetTestStrict; - - -TEST_F(AssetTestStrict, BuildAssets) -{ - const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); - - std::vector assets(assetDescCount); - - // Build - for (uint32_t i = 0; i < assetDescCount; ++i) - { - assets[i] = buildAsset(g_assetExpectedValues[i], &g_assetDescs[i]); - } - - // Destroy - for (uint32_t i = 0; i < assetDescCount; ++i) - { - if (assets[i]) - { - free(assets[i]); - } - } -} - -#if ENABLE_SERIALIZATION_TESTS -TEST_F(AssetTestStrict, SerializeAssets) -{ - Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate(); - EXPECT_TRUE(ser != nullptr); - - const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); - - std::vector assets(assetDescCount); - - // Build - for (uint32_t i = 0; i < assetDescCount; ++i) - { - assets[i] = reinterpret_cast(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i])); - } - - // Serialize them - for (Nv::Blast::Asset* asset : assets) - { - void* buffer; - const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, asset); - EXPECT_TRUE(size != 0); - - uint32_t objectTypeID; - uint32_t encodingID; - uint64_t dataSize = 0; - EXPECT_TRUE(ser->peekHeader(&objectTypeID, &encodingID, &dataSize, buffer, size)); - EXPECT_EQ(objectTypeID, Nv::Blast::LlObjectTypeID::Asset); - EXPECT_EQ(encodingID, ser->getSerializationEncoding()); - EXPECT_EQ(dataSize + Nv::Blast::ExtSerializationInternal::HeaderSize, size); - } - - // Destroy - for (uint32_t i = 0; i < assetDescCount; ++i) - { - if (assets[i]) - { - free(assets[i]); - } - } - - ser->release(); -} - -TEST_F(AssetTestStrict, SerializeAssetsRoundTrip) -{ - Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate(); - EXPECT_TRUE(ser != nullptr); - - const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); - - std::vector assets(assetDescCount); - - // Build - for (uint32_t i = 0; i < assetDescCount; ++i) - { - assets[i] = reinterpret_cast(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i])); - } - - const uint32_t encodings[] = - { - Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary, - Nv::Blast::ExtSerialization::EncodingID::RawBinary - }; - - for (auto encoding : encodings) - { - ser->setSerializationEncoding(encoding); - - // Serialize them - for (uint32_t i = 0; i < assetDescCount; ++i) - { - Nv::Blast::Asset* asset = assets[i]; - - void* buffer; - const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, asset); - EXPECT_TRUE(size != 0); - - Nv::Blast::Asset* rtAsset = reinterpret_cast(ser->deserializeFromBuffer(buffer, size)); - - //TODO: Compare assets - checkAssetsExpected(*rtAsset, g_assetExpectedValues[i]); - - free(static_cast(rtAsset)); - } - } - - // Destroy - for (uint32_t i = 0; i < assetDescCount; ++i) - { - if (assets[i]) - { - free(assets[i]); - } - } - - ser->release(); -} - -TEST_F(AssetTestStrict, SerializeAssetsRoundTripWithSkipping) -{ - Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate(); - EXPECT_TRUE(ser != nullptr); - - std::vector stream; - - class StreamBufferProvider : public Nv::Blast::ExtSerialization::BufferProvider - { - public: - StreamBufferProvider(std::vector& stream) : m_stream(stream), m_cursor(0) {} - - virtual void* requestBuffer(size_t size) override - { - m_stream.resize(m_cursor + size); - void* data = m_stream.data() + m_cursor; - m_cursor += size; - return data; - } - - private: - std::vector& m_stream; - size_t m_cursor; - } myStreamProvider(stream); - - ser->setBufferProvider(&myStreamProvider); - - const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); - - std::vector assets(assetDescCount); - - // Build - for (uint32_t i = 0; i < assetDescCount; ++i) - { - assets[i] = reinterpret_cast(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i])); - } - - const uint32_t encodings[] = - { - Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary, - Nv::Blast::ExtSerialization::EncodingID::RawBinary - }; - - for (auto encoding : encodings) - { - ser->setSerializationEncoding(encoding); - - // Serialize them - for (uint32_t i = 0; i < assetDescCount; ++i) - { - void* buffer; - const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, assets[i]); - EXPECT_TRUE(size != 0); - } - } - - // Deserialize from stream - const void* buffer = stream.data(); - uint64_t bufferSize = stream.size(); - for (uint32_t assetCount = 0; bufferSize; ++assetCount) - { - uint32_t objectTypeID; - uint32_t encodingID; - const bool peekSuccess = ser->peekHeader(&objectTypeID, &encodingID, nullptr, buffer, bufferSize); - EXPECT_TRUE(peekSuccess); - if (!peekSuccess) - { - break; - } - - EXPECT_EQ(Nv::Blast::LlObjectTypeID::Asset, objectTypeID); - if (assetCount < assetDescCount) - { - EXPECT_EQ(Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary, encodingID); - } - else - { - EXPECT_EQ(Nv::Blast::ExtSerialization::EncodingID::RawBinary, encodingID); - } - - const bool skip = (assetCount & 1) != 0; - - if (!skip) - { - const uint32_t assetnum = assetCount % assetDescCount; - Nv::Blast::Asset* rtAsset = reinterpret_cast(ser->deserializeFromBuffer(buffer, bufferSize)); - EXPECT_TRUE(rtAsset != nullptr); - if (rtAsset == nullptr) - { - break; - } - - //TODO: Compare assets - checkAssetsExpected(*rtAsset, g_assetExpectedValues[assetnum]); - - free(static_cast(rtAsset)); - } - - buffer = ser->skipObject(bufferSize, buffer); - } - - // Destroy - for (uint32_t i = 0; i < assetDescCount; ++i) - { - if (assets[i]) - { - free(assets[i]); - } - } - - ser->release(); -} -#endif // ENABLE_SERIALIZATION_TESTS - -TEST_F(AssetTestAllowWarnings, BuildAssetsMissingCoverage) -{ - const uint32_t assetDescCount = sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); - - std::vector assets(assetDescCount); - - // Build - for (uint32_t i = 0; i < assetDescCount; ++i) - { - const NvBlastAssetDesc* desc = &g_assetDescsMissingCoverage[i]; - NvBlastAssetDesc fixedDesc = *desc; - std::vector chunkDescs(desc->chunkDescs, desc->chunkDescs + desc->chunkCount); - std::vector bondDescs(desc->bondDescs, desc->bondDescs + desc->bondCount); - std::vector chunkReorderMap(desc->chunkCount); - std::vector scratch(desc->chunkCount * sizeof(NvBlastChunkDesc)); - const bool changedCoverage = !NvBlastEnsureAssetExactSupportCoverage(chunkDescs.data(), fixedDesc.chunkCount, scratch.data(), messageLog); - EXPECT_TRUE(changedCoverage); - NvBlastReorderAssetDescChunks(chunkDescs.data(), fixedDesc.chunkCount, bondDescs.data(), fixedDesc.bondCount, chunkReorderMap.data(), true, scratch.data(), messageLog); - fixedDesc.chunkDescs = chunkDescs.data(); - fixedDesc.bondDescs = bondDescs.data(); - assets[i] = buildAsset(g_assetsFromMissingCoverageExpectedValues[i], &fixedDesc); - } - - // Destroy - for (uint32_t i = 0; i < assetDescCount; ++i) - { - if (assets[i]) - { - free(assets[i]); - } - } -} - -TEST_F(AssetTestAllowWarningsSilently, BuildAssetsShufflingChunkDescriptors) -{ - for (uint32_t i = 0; i < sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); ++i) - { - buildAssetShufflingDescriptors(&g_assetDescs[i], g_assetExpectedValues[i], 10, false); - } - - for (uint32_t i = 0; i < sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); ++i) - { - buildAssetShufflingDescriptors(&g_assetDescsMissingCoverage[i], g_assetsFromMissingCoverageExpectedValues[i], 10, false); - } -} - -TEST_F(AssetTestAllowWarningsSilently, BuildAssetsShufflingChunkDescriptorsUsingTk) -{ - for (uint32_t i = 0; i < sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); ++i) - { - buildAssetShufflingDescriptors(&g_assetDescs[i], g_assetExpectedValues[i], 10, true); - } - - for (uint32_t i = 0; i < sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); ++i) - { - buildAssetShufflingDescriptors(&g_assetDescsMissingCoverage[i], g_assetsFromMissingCoverageExpectedValues[i], 10, true); - } -} - -TEST_F(AssetTestStrict, MergeAssetsUpperSupportOnly) -{ - mergeAssetTest(g_assetDescs[0], false); -} - -TEST_F(AssetTestStrict, MergeAssetsWithSubsupport) -{ - mergeAssetTest(g_assetDescs[1], false); -} - -TEST_F(AssetTestStrict, MergeAssetsWithWorldBondsUpperSupportOnly) -{ - mergeAssetTest(g_assetDescs[3], false); -} - -TEST_F(AssetTestStrict, MergeAssetsWithWorldBondsWithSubsupport) -{ - mergeAssetTest(g_assetDescs[4], false); -} - -TEST_F(AssetTestAllowErrorsSilently, MergeAssetsUpperSupportOnlyExpectFail) -{ - mergeAssetTest(g_assetDescs[0], true); -} - -TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithSubsupportExpectFail) -{ - mergeAssetTest(g_assetDescs[1], true); -} - -TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithWorldBondsUpperSupportOnlyExpectFail) -{ - mergeAssetTest(g_assetDescs[3], true); -} - -TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithWorldBondsWithSubsupportExpectFail) -{ - mergeAssetTest(g_assetDescs[4], true); -} +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2016-2018 NVIDIA Corporation. All rights reserved. + + +#include "NvBlastAsset.h" +#include "NvBlastMath.h" + +#include "BlastBaseTest.h" + +#include "NvBlastTkFramework.h" + +#include + + +// all supported platform now provide serialization +// keep the define for future platforms that won't +#define ENABLE_SERIALIZATION_TESTS 1 + +#pragma warning( push ) +#pragma warning( disable : 4267 ) +// NOTE: Instead of excluding serialization and the tests when on VC12, should break the tests out into a separate C++ file. + +#if ENABLE_SERIALIZATION_TESTS +#include "NvBlastExtSerialization.h" +#include "NvBlastExtLlSerialization.h" +#include "NvBlastExtSerializationInternal.h" +#endif + +#include "NvBlastExtAssetUtils.h" + +#pragma warning( pop ) + +#include +#include + +#ifdef WIN32 +#include +#endif + +template +class AssetTest : public BlastBaseTest +{ +public: + + AssetTest() + { + NvBlastTkFrameworkCreate(); + } + + ~AssetTest() + { + NvBlastTkFrameworkGet()->release(); + } + + static void messageLog(int type, const char* msg, const char* file, int line) + { + BlastBaseTest::messageLog(type, msg, file, line); + } + + static void* alloc(size_t size) + { + return BlastBaseTest::alignedZeroedAlloc(size); + } + + static void free(void* mem) + { + BlastBaseTest::alignedFree(mem); + } + + void testSubtreeLeafChunkCounts(const Nv::Blast::Asset& a) + { + const NvBlastChunk* chunks = a.getChunks(); + const uint32_t* subtreeLeafChunkCounts = a.getSubtreeLeafChunkCounts(); + uint32_t totalLeafChunkCount = 0; + for (uint32_t chunkIndex = 0; chunkIndex < a.m_chunkCount; ++chunkIndex) + { + const NvBlastChunk& chunk = chunks[chunkIndex]; + if (Nv::Blast::isInvalidIndex(chunk.parentChunkIndex)) + { + totalLeafChunkCount += subtreeLeafChunkCounts[chunkIndex]; + } + const bool isLeafChunk = chunk.firstChildIndex >= chunk.childIndexStop; + uint32_t subtreeLeafChunkCount = isLeafChunk ? 1 : 0; + for (uint32_t childIndex = chunk.firstChildIndex; childIndex < chunk.childIndexStop; ++childIndex) + { + subtreeLeafChunkCount += subtreeLeafChunkCounts[childIndex]; + } + EXPECT_EQ(subtreeLeafChunkCount, subtreeLeafChunkCounts[chunkIndex]); + } + EXPECT_EQ(totalLeafChunkCount, a.m_leafChunkCount); + } + + void testChunkToNodeMap(const Nv::Blast::Asset& a) + { + for (uint32_t chunkIndex = 0; chunkIndex < a.m_chunkCount; ++chunkIndex) + { + const uint32_t nodeIndex = a.getChunkToGraphNodeMap()[chunkIndex]; + if (!Nv::Blast::isInvalidIndex(nodeIndex)) + { + EXPECT_LT(nodeIndex, a.m_graph.m_nodeCount); + EXPECT_EQ(chunkIndex, a.m_graph.getChunkIndices()[nodeIndex]); + } + else + { + const uint32_t* chunkIndexStop = a.m_graph.getChunkIndices() + a.m_graph.m_nodeCount; + const uint32_t* it = std::find(a.m_graph.getChunkIndices(), chunkIndexStop, chunkIndex); + EXPECT_EQ(chunkIndexStop, it); + } + } + } + + NvBlastAsset* buildAsset(const ExpectedAssetValues& expected, const NvBlastAssetDesc* desc) + { + std::vector scratch; + scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(desc, messageLog)); + void* mem = alloc(NvBlastGetAssetMemorySize(desc, messageLog)); + NvBlastAsset* asset = NvBlastCreateAsset(mem, desc, scratch.data(), messageLog); + EXPECT_TRUE(asset != nullptr); + if (asset == nullptr) + { + free(mem); + return nullptr; + } + Nv::Blast::Asset& a = *(Nv::Blast::Asset*)asset; + EXPECT_EQ(expected.totalChunkCount, a.m_chunkCount); + EXPECT_EQ(expected.graphNodeCount, a.m_graph.m_nodeCount); + EXPECT_EQ(expected.bondCount, a.m_graph.getAdjacencyPartition()[a.m_graph.m_nodeCount] / 2); + EXPECT_EQ(expected.leafChunkCount, a.m_leafChunkCount); + EXPECT_EQ(expected.subsupportChunkCount, a.m_chunkCount - a.m_firstSubsupportChunkIndex); + testSubtreeLeafChunkCounts(a); + testChunkToNodeMap(a); + return asset; + } + + void checkAssetsExpected(Nv::Blast::Asset& asset, const ExpectedAssetValues& expected) + { + EXPECT_EQ(expected.totalChunkCount, asset.m_chunkCount); + EXPECT_EQ(expected.graphNodeCount, asset.m_graph.m_nodeCount); + EXPECT_EQ(expected.bondCount, asset.m_graph.getAdjacencyPartition()[asset.m_graph.m_nodeCount] / 2); + EXPECT_EQ(expected.leafChunkCount, asset.m_leafChunkCount); + EXPECT_EQ(expected.subsupportChunkCount, asset.m_chunkCount - asset.m_firstSubsupportChunkIndex); + testSubtreeLeafChunkCounts(asset); + testChunkToNodeMap(asset); + } + + // expects that the bond normal points from the lower indexed chunk to higher index chunk + // uses chunk.centroid + // convention, requirement from findClosestNode + void checkNormalDir(NvBlastChunkDesc* chunkDescs, size_t chunkDescCount, NvBlastBondDesc* bondDescs, size_t bondDescCount) + { + for (size_t bondIndex = 0; bondIndex < bondDescCount; ++bondIndex) + { + NvBlastBondDesc& bond = bondDescs[bondIndex]; + uint32_t chunkIndex0 = bond.chunkIndices[0]; + uint32_t chunkIndex1 = bond.chunkIndices[1]; + + bool swap = chunkIndex0 > chunkIndex1; + uint32_t testIndex0 = swap ? chunkIndex1 : chunkIndex0; + uint32_t testIndex1 = swap ? chunkIndex0 : chunkIndex1; + + EXPECT_TRUE(testIndex0 < testIndex1); + + // no convention for world chunks + if (!Nv::Blast::isInvalidIndex(testIndex0) && !Nv::Blast::isInvalidIndex(testIndex1)) + { + NvBlastChunkDesc& chunk0 = chunkDescs[testIndex0]; + NvBlastChunkDesc& chunk1 = chunkDescs[testIndex1]; + + float dir[3]; + Nv::Blast::VecMath::sub(chunk1.centroid, chunk0.centroid, dir); + bool meetsConvention = Nv::Blast::VecMath::dot(bond.bond.normal, dir) > 0; + EXPECT_TRUE(meetsConvention); + if (!meetsConvention) + { + printf("bond %zd chunks(%d,%d): %.2f %.2f %.2f %.2f %.2f %.2f %d\n", + bondIndex, chunkIndex0, chunkIndex1, + bond.bond.normal[0], bond.bond.normal[1], bond.bond.normal[2], + dir[0], dir[1], dir[2], + Nv::Blast::VecMath::dot(bond.bond.normal, dir) > 0); + } + } + } + } + + // expects that the bond normal points from the lower indexed node to higher index node + // uses chunk.centroid + // convention, requirement from findClosestNode + void checkNormalDir(const NvBlastSupportGraph graph, const NvBlastChunk* assetChunks, const NvBlastBond* assetBonds) + { + for (uint32_t nodeIndex = 0; nodeIndex < graph.nodeCount; nodeIndex++) + { + uint32_t adjStart = graph.adjacencyPartition[nodeIndex]; + uint32_t adjStop = graph.adjacencyPartition[nodeIndex + 1]; + for (uint32_t adj = adjStart; adj < adjStop; ++adj) + { + uint32_t adjNodeIndex = graph.adjacentNodeIndices[adj]; + + bool swap = nodeIndex > adjNodeIndex; + uint32_t testIndex0 = swap ? adjNodeIndex : nodeIndex; + uint32_t testIndex1 = swap ? nodeIndex : adjNodeIndex; + + // no convention for world chunks + if (!Nv::Blast::isInvalidIndex(graph.chunkIndices[testIndex0]) && !Nv::Blast::isInvalidIndex(graph.chunkIndices[testIndex1])) + { + const NvBlastChunk& chunk0 = assetChunks[graph.chunkIndices[testIndex0]]; + const NvBlastChunk& chunk1 = assetChunks[graph.chunkIndices[testIndex1]]; + + uint32_t bondIndex = graph.adjacentBondIndices[adj]; + const NvBlastBond& bond = assetBonds[bondIndex]; + + float dir[3]; + Nv::Blast::VecMath::sub(chunk1.centroid, chunk0.centroid, dir); + bool meetsConvention = Nv::Blast::VecMath::dot(bond.normal, dir) > 0; + EXPECT_TRUE(meetsConvention); + if (!meetsConvention) + { + printf("bond %d nodes(%d,%d): %.2f %.2f %.2f %.2f %.2f %.2f %d\n", + bondIndex, nodeIndex, adjNodeIndex, + bond.normal[0], bond.normal[1], bond.normal[2], + dir[0], dir[1], dir[2], + Nv::Blast::VecMath::dot(bond.normal, dir) > 0); + } + } + } + } + } + + void checkNormalDir(const NvBlastAsset* asset) + { + const NvBlastChunk* assetChunks = NvBlastAssetGetChunks(asset, nullptr); + const NvBlastBond* assetBonds = NvBlastAssetGetBonds(asset, nullptr); + const NvBlastSupportGraph graph = NvBlastAssetGetSupportGraph(asset, nullptr); + checkNormalDir(graph, assetChunks, assetBonds); + } + + void buildAssetShufflingDescriptors(const NvBlastAssetDesc* desc, const ExpectedAssetValues& expected, uint32_t shuffleCount, bool useTk) + { + NvBlastAssetDesc shuffledDesc = *desc; + std::vector chunkDescs(desc->chunkDescs, desc->chunkDescs + desc->chunkCount); + shuffledDesc.chunkDescs = chunkDescs.data(); + std::vector bondDescs(desc->bondDescs, desc->bondDescs + desc->bondCount); + shuffledDesc.bondDescs = bondDescs.data(); + if (!useTk) + { + std::vector scratch(desc->chunkCount); + NvBlastEnsureAssetExactSupportCoverage(chunkDescs.data(), desc->chunkCount, scratch.data(), messageLog); + } + else + { + NvBlastTkFrameworkGet()->ensureAssetExactSupportCoverage(chunkDescs.data(), desc->chunkCount); + } + for (uint32_t i = 0; i < shuffleCount; ++i) + { + checkNormalDir(chunkDescs.data(), chunkDescs.size(), bondDescs.data(), bondDescs.size()); + shuffleAndFixChunkDescs(chunkDescs.data(), desc->chunkCount, bondDescs.data(), desc->bondCount, useTk); + checkNormalDir(chunkDescs.data(), chunkDescs.size(), bondDescs.data(), bondDescs.size()); + + NvBlastAsset* asset = buildAsset(expected, &shuffledDesc); + EXPECT_TRUE(asset != nullptr); + checkNormalDir(asset); + if (asset) + { + free(asset); + } + } + } + + void shuffleAndFixChunkDescs(NvBlastChunkDesc* chunkDescs, uint32_t chunkDescCount, NvBlastBondDesc* bondDescs, uint32_t bondDescCount, bool useTk) + { + // Create reorder array and fill with identity map + std::vector shuffledOrder(chunkDescCount); + for (uint32_t i = 0; i < chunkDescCount; ++i) + { + shuffledOrder[i] = i; + } + + // An array into which to copy the reordered descs + std::vector shuffledChunkDescs(chunkDescCount); + + std::vector scratch; + const uint32_t trials = 30; + uint32_t attempt = 0; + while(1) + { + // Shuffle the reorder array + std::random_shuffle(shuffledOrder.begin(), shuffledOrder.end()); + + // Save initial bonds + std::vector savedBondDescs(bondDescs, bondDescs + bondDescCount); + + // Shuffle chunks and bonds + NvBlastApplyAssetDescChunkReorderMap(shuffledChunkDescs.data(), chunkDescs, chunkDescCount, bondDescs, bondDescCount, shuffledOrder.data(), true, nullptr); + + // All the normals are pointing in the expected direction (they have been swapped) + checkNormalDir(shuffledChunkDescs.data(), chunkDescCount, bondDescs, bondDescCount); + checkNormalDir(chunkDescs, chunkDescCount, savedBondDescs.data(), bondDescCount); + + // Check the results + for (uint32_t i = 0; i < chunkDescCount; ++i) + { + EXPECT_EQ(chunkDescs[i].userData, shuffledChunkDescs[shuffledOrder[i]].userData); + EXPECT_TRUE(chunkDescs[i].parentChunkIndex > chunkDescCount || shuffledChunkDescs[shuffledOrder[i]].parentChunkIndex == shuffledOrder[chunkDescs[i].parentChunkIndex]); + } + for (uint32_t i = 0; i < bondDescCount; ++i) + { + for (uint32_t k = 0; k < 2; ++k) + { + if (!Nv::Blast::isInvalidIndex(savedBondDescs[i].chunkIndices[k])) + { + EXPECT_EQ(shuffledOrder[savedBondDescs[i].chunkIndices[k]], bondDescs[i].chunkIndices[k]); + } + } + } + + // Try creating asset, usually it should fail (otherwise make another attempt) + NvBlastAssetDesc desc = { chunkDescCount, shuffledChunkDescs.data(), bondDescCount, bondDescs }; + scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&desc, nullptr)); + void* mem = alloc(NvBlastGetAssetMemorySize(&desc, nullptr)); + NvBlastAsset* asset = NvBlastCreateAsset(mem, &desc, scratch.data(), nullptr); + if (asset == nullptr) + { + free(mem); + break; + } + else + { + free(asset); + memcpy(bondDescs, savedBondDescs.data(), sizeof(NvBlastBondDesc) * bondDescCount); + attempt++; + if (attempt >= trials) + { + GTEST_NONFATAL_FAILURE_("Shuffled chunk descs should fail asset creation (most of the time)."); + break; + } + } + } + + // Now we want to fix that order + if (!useTk) + { + std::vector chunkReorderMap(chunkDescCount); + std::vector scratch2(2 * chunkDescCount * sizeof(uint32_t)); + const bool isIdentity = NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), shuffledChunkDescs.data(), chunkDescCount, scratch2.data(), messageLog); + EXPECT_FALSE(isIdentity); + NvBlastApplyAssetDescChunkReorderMap(chunkDescs, shuffledChunkDescs.data(), chunkDescCount, bondDescs, bondDescCount, chunkReorderMap.data(), true, messageLog); + } + else + { + memcpy(chunkDescs, shuffledChunkDescs.data(), chunkDescCount * sizeof(NvBlastChunkDesc)); + const bool isIdentity = NvBlastTkFrameworkGet()->reorderAssetDescChunks(chunkDescs, chunkDescCount, bondDescs, bondDescCount, nullptr, true); + EXPECT_FALSE(isIdentity); + } + } + + void mergeAssetTest(const NvBlastAssetDesc& desc, bool fail) + { + std::vector scratch; + + scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&desc, messageLog)); + void* mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&desc, messageLog)); + NvBlastAsset* asset = NvBlastCreateAsset(mem, &desc, scratch.data(), messageLog); + EXPECT_TRUE(asset != nullptr); + if (asset == nullptr) + { + free(mem); + return; + } + + // Merge two copies of this asset together + const NvBlastAsset* components[2] = { asset, asset }; + const NvcVec3 translations[2] = { { 0, 0, 0 },{ 2, 0, 0 } }; + + const NvBlastBond bond = { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 }; + + NvBlastExtAssetUtilsBondDesc newBondDescs[4]; + for (int i = 0; i < 4; ++i) + { + newBondDescs[i].bond = bond; + newBondDescs[i].chunkIndices[0] = 2 * (i + 1); + newBondDescs[i].chunkIndices[1] = 2 * i + 1; + newBondDescs[i].componentIndices[0] = 0; + newBondDescs[i].componentIndices[1] = 1; + } + + // Create a merged descriptor + std::vector chunkIndexOffsets(2); + std::vector chunkReorderMap(2 * desc.chunkCount); + + NvBlastAssetDesc mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), chunkReorderMap.data(), 2 * desc.chunkCount); + EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); + EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); + for (uint32_t i = 0; i < 2 * desc.chunkCount; ++i) + { + EXPECT_LT(chunkReorderMap[i], 2 * desc.chunkCount); + } + EXPECT_EQ(0, chunkIndexOffsets[0]); + EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]); + + scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); + mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); + NvBlastAsset* mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); + EXPECT_TRUE(mergedAsset != nullptr); + if (mergedAsset == nullptr) + { + free(mem); + return; + } + + NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); + NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); + NVBLAST_FREE(mergedAsset); + + if (!fail) + { + mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, chunkReorderMap.data(), 2 * desc.chunkCount); + EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); + EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); + for (uint32_t i = 0; i < 2 * desc.chunkCount; ++i) + { + EXPECT_LT(chunkReorderMap[i], 2 * desc.chunkCount); + } + scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); + mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); + mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); + EXPECT_TRUE(mergedAsset != nullptr); + free(mem); + NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); + NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); + } + else + { + // We don't pass in a valid chunkReorderMap so asset creation should fail + mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), nullptr, 0); + EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); + EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); + EXPECT_EQ(0, chunkIndexOffsets[0]); + EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]); + scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); + mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); + mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); + EXPECT_TRUE(mergedAsset == nullptr); + free(mem); + NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); + NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); + + mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, nullptr, 0); + EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); + EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); + scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); + mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); + mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); + EXPECT_TRUE(mergedAsset == nullptr); + free(mem); + NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); + NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); + + // We lie and say the chunkReorderMap is not large enough. It should be filled with 0xFFFFFFFF up to the size we gave + mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, chunkReorderMap.data(), desc.chunkCount); + EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); + EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); + for (uint32_t i = 0; i < desc.chunkCount; ++i) + { + EXPECT_TRUE(Nv::Blast::isInvalidIndex(chunkReorderMap[i])); + } + scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); + mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); + mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); + EXPECT_TRUE(mergedAsset == nullptr); + free(mem); + NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); + NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); + + mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), chunkReorderMap.data(), desc.chunkCount); + EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); + EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); + for (uint32_t i = 0; i < desc.chunkCount; ++i) + { + EXPECT_TRUE(Nv::Blast::isInvalidIndex(chunkReorderMap[i])); + } + EXPECT_EQ(0, chunkIndexOffsets[0]); + EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]); + scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); + mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); + mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); + EXPECT_TRUE(mergedAsset == nullptr); + free(mem); + NVBLAST_FREE(const_cast(mergedDesc.bondDescs)); + NVBLAST_FREE(const_cast(mergedDesc.chunkDescs)); + } + + // Finally free the original asset + NVBLAST_FREE(asset); + } +}; + +typedef AssetTest<-1, 0> AssetTestAllowErrorsSilently; +typedef AssetTest AssetTestAllowWarningsSilently; +typedef AssetTest AssetTestAllowWarnings; +typedef AssetTest AssetTestStrict; + + +TEST_F(AssetTestStrict, BuildAssets) +{ + const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); + + std::vector assets(assetDescCount); + + // Build + for (uint32_t i = 0; i < assetDescCount; ++i) + { + assets[i] = buildAsset(g_assetExpectedValues[i], &g_assetDescs[i]); + } + + // Destroy + for (uint32_t i = 0; i < assetDescCount; ++i) + { + if (assets[i]) + { + free(assets[i]); + } + } +} + +#if ENABLE_SERIALIZATION_TESTS +TEST_F(AssetTestStrict, SerializeAssets) +{ + Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate(); + EXPECT_TRUE(ser != nullptr); + + const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); + + std::vector assets(assetDescCount); + + // Build + for (uint32_t i = 0; i < assetDescCount; ++i) + { + assets[i] = reinterpret_cast(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i])); + } + + // Serialize them + for (Nv::Blast::Asset* asset : assets) + { + void* buffer; + const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, asset); + EXPECT_TRUE(size != 0); + + uint32_t objectTypeID; + uint32_t encodingID; + uint64_t dataSize = 0; + EXPECT_TRUE(ser->peekHeader(&objectTypeID, &encodingID, &dataSize, buffer, size)); + EXPECT_EQ(objectTypeID, Nv::Blast::LlObjectTypeID::Asset); + EXPECT_EQ(encodingID, ser->getSerializationEncoding()); + EXPECT_EQ(dataSize + Nv::Blast::ExtSerializationInternal::HeaderSize, size); + } + + // Destroy + for (uint32_t i = 0; i < assetDescCount; ++i) + { + if (assets[i]) + { + free(assets[i]); + } + } + + ser->release(); +} + +TEST_F(AssetTestStrict, SerializeAssetsRoundTrip) +{ + Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate(); + EXPECT_TRUE(ser != nullptr); + + const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); + + std::vector assets(assetDescCount); + + // Build + for (uint32_t i = 0; i < assetDescCount; ++i) + { + assets[i] = reinterpret_cast(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i])); + } + + const uint32_t encodings[] = + { + Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary, + Nv::Blast::ExtSerialization::EncodingID::RawBinary + }; + + for (auto encoding : encodings) + { + ser->setSerializationEncoding(encoding); + + // Serialize them + for (uint32_t i = 0; i < assetDescCount; ++i) + { + Nv::Blast::Asset* asset = assets[i]; + + void* buffer; + const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, asset); + EXPECT_TRUE(size != 0); + + Nv::Blast::Asset* rtAsset = reinterpret_cast(ser->deserializeFromBuffer(buffer, size)); + + //TODO: Compare assets + checkAssetsExpected(*rtAsset, g_assetExpectedValues[i]); + + free(static_cast(rtAsset)); + } + } + + // Destroy + for (uint32_t i = 0; i < assetDescCount; ++i) + { + if (assets[i]) + { + free(assets[i]); + } + } + + ser->release(); +} + +TEST_F(AssetTestStrict, SerializeAssetsRoundTripWithSkipping) +{ + Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate(); + EXPECT_TRUE(ser != nullptr); + + std::vector stream; + + class StreamBufferProvider : public Nv::Blast::ExtSerialization::BufferProvider + { + public: + StreamBufferProvider(std::vector& stream) : m_stream(stream), m_cursor(0) {} + + virtual void* requestBuffer(size_t size) override + { + m_stream.resize(m_cursor + size); + void* data = m_stream.data() + m_cursor; + m_cursor += size; + return data; + } + + private: + std::vector& m_stream; + size_t m_cursor; + } myStreamProvider(stream); + + ser->setBufferProvider(&myStreamProvider); + + const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); + + std::vector assets(assetDescCount); + + // Build + for (uint32_t i = 0; i < assetDescCount; ++i) + { + assets[i] = reinterpret_cast(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i])); + } + + const uint32_t encodings[] = + { + Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary, + Nv::Blast::ExtSerialization::EncodingID::RawBinary + }; + + for (auto encoding : encodings) + { + ser->setSerializationEncoding(encoding); + + // Serialize them + for (uint32_t i = 0; i < assetDescCount; ++i) + { + void* buffer; + const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, assets[i]); + EXPECT_TRUE(size != 0); + } + } + + // Deserialize from stream + const void* buffer = stream.data(); + uint64_t bufferSize = stream.size(); + for (uint32_t assetCount = 0; bufferSize; ++assetCount) + { + uint32_t objectTypeID; + uint32_t encodingID; + const bool peekSuccess = ser->peekHeader(&objectTypeID, &encodingID, nullptr, buffer, bufferSize); + EXPECT_TRUE(peekSuccess); + if (!peekSuccess) + { + break; + } + + EXPECT_EQ(Nv::Blast::LlObjectTypeID::Asset, objectTypeID); + if (assetCount < assetDescCount) + { + EXPECT_EQ(Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary, encodingID); + } + else + { + EXPECT_EQ(Nv::Blast::ExtSerialization::EncodingID::RawBinary, encodingID); + } + + const bool skip = (assetCount & 1) != 0; + + if (!skip) + { + const uint32_t assetnum = assetCount % assetDescCount; + Nv::Blast::Asset* rtAsset = reinterpret_cast(ser->deserializeFromBuffer(buffer, bufferSize)); + EXPECT_TRUE(rtAsset != nullptr); + if (rtAsset == nullptr) + { + break; + } + + //TODO: Compare assets + checkAssetsExpected(*rtAsset, g_assetExpectedValues[assetnum]); + + free(static_cast(rtAsset)); + } + + buffer = ser->skipObject(bufferSize, buffer); + } + + // Destroy + for (uint32_t i = 0; i < assetDescCount; ++i) + { + if (assets[i]) + { + free(assets[i]); + } + } + + ser->release(); +} +#endif // ENABLE_SERIALIZATION_TESTS + +TEST_F(AssetTestAllowWarnings, BuildAssetsMissingCoverage) +{ + const uint32_t assetDescCount = sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); + + std::vector assets(assetDescCount); + + // Build + for (uint32_t i = 0; i < assetDescCount; ++i) + { + const NvBlastAssetDesc* desc = &g_assetDescsMissingCoverage[i]; + NvBlastAssetDesc fixedDesc = *desc; + std::vector chunkDescs(desc->chunkDescs, desc->chunkDescs + desc->chunkCount); + std::vector bondDescs(desc->bondDescs, desc->bondDescs + desc->bondCount); + std::vector chunkReorderMap(desc->chunkCount); + std::vector scratch(desc->chunkCount * sizeof(NvBlastChunkDesc)); + const bool changedCoverage = !NvBlastEnsureAssetExactSupportCoverage(chunkDescs.data(), fixedDesc.chunkCount, scratch.data(), messageLog); + EXPECT_TRUE(changedCoverage); + NvBlastReorderAssetDescChunks(chunkDescs.data(), fixedDesc.chunkCount, bondDescs.data(), fixedDesc.bondCount, chunkReorderMap.data(), true, scratch.data(), messageLog); + fixedDesc.chunkDescs = chunkDescs.data(); + fixedDesc.bondDescs = bondDescs.data(); + assets[i] = buildAsset(g_assetsFromMissingCoverageExpectedValues[i], &fixedDesc); + } + + // Destroy + for (uint32_t i = 0; i < assetDescCount; ++i) + { + if (assets[i]) + { + free(assets[i]); + } + } +} + +TEST_F(AssetTestAllowWarningsSilently, BuildAssetsShufflingChunkDescriptors) +{ + for (uint32_t i = 0; i < sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); ++i) + { + buildAssetShufflingDescriptors(&g_assetDescs[i], g_assetExpectedValues[i], 10, false); + } + + for (uint32_t i = 0; i < sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); ++i) + { + buildAssetShufflingDescriptors(&g_assetDescsMissingCoverage[i], g_assetsFromMissingCoverageExpectedValues[i], 10, false); + } +} + +TEST_F(AssetTestAllowWarningsSilently, BuildAssetsShufflingChunkDescriptorsUsingTk) +{ + for (uint32_t i = 0; i < sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); ++i) + { + buildAssetShufflingDescriptors(&g_assetDescs[i], g_assetExpectedValues[i], 10, true); + } + + for (uint32_t i = 0; i < sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); ++i) + { + buildAssetShufflingDescriptors(&g_assetDescsMissingCoverage[i], g_assetsFromMissingCoverageExpectedValues[i], 10, true); + } +} + +TEST_F(AssetTestStrict, MergeAssetsUpperSupportOnly) +{ + mergeAssetTest(g_assetDescs[0], false); +} + +TEST_F(AssetTestStrict, MergeAssetsWithSubsupport) +{ + mergeAssetTest(g_assetDescs[1], false); +} + +TEST_F(AssetTestStrict, MergeAssetsWithWorldBondsUpperSupportOnly) +{ + mergeAssetTest(g_assetDescs[3], false); +} + +TEST_F(AssetTestStrict, MergeAssetsWithWorldBondsWithSubsupport) +{ + mergeAssetTest(g_assetDescs[4], false); +} + +TEST_F(AssetTestAllowErrorsSilently, MergeAssetsUpperSupportOnlyExpectFail) +{ + mergeAssetTest(g_assetDescs[0], true); +} + +TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithSubsupportExpectFail) +{ + mergeAssetTest(g_assetDescs[1], true); +} + +TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithWorldBondsUpperSupportOnlyExpectFail) +{ + mergeAssetTest(g_assetDescs[3], true); +} + +TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithWorldBondsWithSubsupportExpectFail) +{ + mergeAssetTest(g_assetDescs[4], true); +} -- cgit v1.2.3