#include #include #include #include using namespace XCEngine::Resources; namespace Containers = XCEngine::Containers; namespace Core = XCEngine::Core; namespace { void FillPayload(Containers::Array& payload, std::initializer_list bytes) { payload.Clear(); payload.Reserve(bytes.size()); for (const Core::uint8 value : bytes) { payload.PushBack(value); } } } // namespace TEST(ArtifactContainer, WritesAndReadsMultipleEntries) { namespace fs = std::filesystem; const fs::path projectRoot = fs::temp_directory_path() / "xc_artifact_container_test"; fs::remove_all(projectRoot); fs::create_directories(projectRoot); ArtifactContainerWriter writer; ArtifactContainerEntry mainEntry; mainEntry.name = "main"; mainEntry.resourceType = ResourceType::Model; mainEntry.localID = kMainAssetLocalID; FillPayload(mainEntry.payload, { 1, 2, 3, 4 }); writer.AddEntry(mainEntry); ArtifactContainerEntry meshEntry; meshEntry.name = "mesh/0"; meshEntry.resourceType = ResourceType::Mesh; meshEntry.localID = 42; meshEntry.flags = 7; FillPayload(meshEntry.payload, { 9, 8, 7 }); writer.AddEntry(std::move(meshEntry)); Containers::String errorMessage; const fs::path artifactPath = projectRoot / "Library" / "Artifacts" / "ab" / "artifact.xca"; ASSERT_TRUE(writer.WriteToFile(artifactPath.string().c_str(), &errorMessage)) << errorMessage.CStr(); ASSERT_TRUE(fs::exists(artifactPath)); ArtifactContainerReader reader; ASSERT_TRUE(reader.Open(artifactPath.string().c_str(), &errorMessage)) << errorMessage.CStr(); EXPECT_EQ(reader.GetEntryCount(), 2u); const ArtifactContainerEntryView* mainView = reader.FindEntryByName("main"); ASSERT_NE(mainView, nullptr); EXPECT_EQ(mainView->resourceType, ResourceType::Model); EXPECT_EQ(mainView->localID, kMainAssetLocalID); const ArtifactContainerEntryView* meshView = reader.FindEntry(ResourceType::Mesh, 42); ASSERT_NE(meshView, nullptr); EXPECT_EQ(meshView->name, Containers::String("mesh/0")); EXPECT_EQ(meshView->flags, 7u); Containers::Array payload; ASSERT_TRUE(reader.ReadEntryPayload(*meshView, payload, &errorMessage)) << errorMessage.CStr(); ASSERT_EQ(payload.Size(), 3u); EXPECT_EQ(payload[0], 9u); EXPECT_EQ(payload[1], 8u); EXPECT_EQ(payload[2], 7u); } TEST(ArtifactContainer, RejectsCorruptFileHeader) { namespace fs = std::filesystem; const fs::path projectRoot = fs::temp_directory_path() / "xc_artifact_container_corrupt_test"; fs::remove_all(projectRoot); fs::create_directories(projectRoot); const fs::path artifactPath = projectRoot / "broken.xca"; { std::ofstream output(artifactPath, std::ios::binary | std::ios::trunc); output << "broken"; } ArtifactContainerReader reader; Containers::String errorMessage; EXPECT_FALSE(reader.Open(artifactPath.string().c_str(), &errorMessage)); EXPECT_FALSE(errorMessage.Empty()); } TEST(ArtifactContainer, ResolvesEntryVirtualPaths) { namespace fs = std::filesystem; const fs::path projectRoot = fs::temp_directory_path() / "xc_artifact_container_entry_path_test"; fs::remove_all(projectRoot); fs::create_directories(projectRoot); ArtifactContainerWriter writer; ArtifactContainerEntry mainEntry; mainEntry.name = "main"; mainEntry.resourceType = ResourceType::Model; mainEntry.localID = kMainAssetLocalID; FillPayload(mainEntry.payload, { 1, 2, 3 }); writer.AddEntry(mainEntry); ArtifactContainerEntry meshEntry; meshEntry.name = "mesh_0.xcmesh"; meshEntry.resourceType = ResourceType::Mesh; meshEntry.localID = 77; FillPayload(meshEntry.payload, { 5, 6, 7, 8 }); writer.AddEntry(meshEntry); const Containers::String containerPath = (projectRoot / "Library" / "Artifacts" / "ab" / "artifact.xcmodel").string().c_str(); Containers::String errorMessage; ASSERT_TRUE(writer.WriteToFile(containerPath, &errorMessage)) << errorMessage.CStr(); const Containers::String virtualPath = BuildArtifactContainerEntryPath(containerPath, "mesh_0.xcmesh"); Containers::String parsedContainerPath; Containers::String parsedEntryName; ASSERT_TRUE(TryParseArtifactContainerEntryPath( virtualPath, parsedContainerPath, parsedEntryName)); EXPECT_EQ(parsedContainerPath, containerPath); EXPECT_EQ(parsedEntryName, "mesh_0.xcmesh"); Containers::Array payload; ASSERT_TRUE(ReadArtifactContainerPayloadByPath( virtualPath, ResourceType::Mesh, payload, &errorMessage)) << errorMessage.CStr(); ASSERT_EQ(payload.Size(), 4u); EXPECT_EQ(payload[0], 5u); EXPECT_EQ(payload[3], 8u); }