/** * @file test_asset_service.cpp * @brief AssetService 单元测试 * * 测试资源服务的加载、缓存、异步加载等功能。 */ #include "test_framework.h" #include #include #include #include #include #include using namespace extra2d; using namespace extra2d::test; // --------------------------------------------------------------------------- // 测试辅助函数 // --------------------------------------------------------------------------- namespace { std::string testDir = "test_temp_service"; void setupTestDir() { std::filesystem::create_directories(testDir); } void cleanupTestDir() { std::filesystem::remove_all(testDir); } std::string getTestPath(const std::string& name) { return testDir + "/" + name; } void writeTestFile(const std::string& path, const std::vector& data) { std::ofstream file(path, std::ios::binary); file.write(reinterpret_cast(data.data()), data.size()); } } // --------------------------------------------------------------------------- // 测试用资源类和加载器 // --------------------------------------------------------------------------- /** * @brief 测试用资源类 */ class TestResource : public Asset { public: AssetType type() const override { return AssetType::Data; } bool loaded() const override { return state_.load(std::memory_order_acquire) == AssetState::Loaded; } size_t memSize() const override { return data_.size(); } const std::vector& data() const { return data_; } void setData(const std::vector& data) { data_ = data; setState(AssetState::Loaded); } void initId(const std::string& path) { setId(AssetID(path)); setPath(path); } private: std::vector data_; }; /** * @brief 测试用资源加载器 */ class TestResourceLoader : public AssetLoader { public: Ref load(const std::string& path) override { std::ifstream file(path, std::ios::binary | std::ios::ate); if (!file.is_open()) { return nullptr; } size_t size = static_cast(file.tellg()); file.seekg(0); std::vector data(size); file.read(reinterpret_cast(data.data()), size); auto resource = std::make_shared(); resource->initId(path); resource->setData(data); return resource; } Ref loadFromMemory(const u8* data, size_t size) override { auto resource = std::make_shared(); resource->setData(std::vector(data, data + size)); return resource; } bool canLoad(const std::string& path) const override { return path.find(".test") != std::string::npos; } AssetType type() const override { return AssetType::Data; } std::vector extensions() const override { return {".test"}; } }; // --------------------------------------------------------------------------- // AssetService 基本测试 // --------------------------------------------------------------------------- TEST(AssetService, Create) { AssetService service; TEST_ASSERT_FALSE(service.isLoaded("nonexistent")); TEST_ASSERT_FALSE(service.isLoading("nonexistent")); TEST_ASSERT_EQ(0u, service.size()); } TEST(AssetService, InitShutdown) { AssetService service; bool initResult = service.init(); TEST_ASSERT_TRUE(initResult); service.shutdown(); } TEST(AssetService, SetRoot) { AssetService service; service.init(); service.setRoot("assets"); TEST_ASSERT_EQ("assets", service.root()); service.shutdown(); } TEST(AssetService, SetLimit) { AssetService service; service.init(); service.setLimit(1024 * 1024); service.shutdown(); } // --------------------------------------------------------------------------- // 加载器注册测试 // --------------------------------------------------------------------------- TEST(AssetService, RegisterLoader) { AssetService service; service.init(); service.registerLoader(std::make_unique()); service.shutdown(); } // --------------------------------------------------------------------------- // 资源加载测试 // --------------------------------------------------------------------------- TEST(AssetService, LoadNonExistent) { setupTestDir(); AssetService service; service.init(); service.setRoot(testDir); service.registerLoader(std::make_unique()); auto handle = service.load("nonexistent.test"); TEST_ASSERT_FALSE(handle.valid()); service.shutdown(); cleanupTestDir(); } TEST(AssetService, LoadFromMemory) { AssetService service; service.init(); service.registerLoader(std::make_unique()); std::vector testData = createTestData(256); service.shutdown(); } TEST(AssetService, IsLoaded) { setupTestDir(); std::string filePath = getTestPath("resource.test"); writeTestFile(filePath, createTestData(256)); AssetService service; service.init(); service.setRoot(testDir); service.registerLoader(std::make_unique()); TEST_ASSERT_FALSE(service.isLoaded("resource.test")); auto handle = service.load("resource.test"); TEST_ASSERT_TRUE(service.isLoaded("resource.test")); service.shutdown(); cleanupTestDir(); } // --------------------------------------------------------------------------- // 缓存测试 // --------------------------------------------------------------------------- TEST(AssetService, CacheHit) { setupTestDir(); std::string filePath = getTestPath("cached.test"); writeTestFile(filePath, createTestData(256)); AssetService service; service.init(); service.setRoot(testDir); service.registerLoader(std::make_unique()); auto handle1 = service.load("cached.test"); auto handle2 = service.get("cached.test"); TEST_ASSERT_TRUE(handle1.valid()); TEST_ASSERT_TRUE(handle2.valid()); TEST_ASSERT_EQ(handle1.get().get(), handle2.get().get()); auto stats = service.stats(); TEST_ASSERT_GE(stats.hits, 1u); service.shutdown(); cleanupTestDir(); } TEST(AssetService, CacheMiss) { AssetService service; service.init(); auto handle = service.get("not_in_cache.test"); TEST_ASSERT_FALSE(handle.valid()); auto stats = service.stats(); TEST_ASSERT_GE(stats.misses, 1u); service.shutdown(); } TEST(AssetService, Purge) { setupTestDir(); std::string filePath = getTestPath("purge.test"); writeTestFile(filePath, createTestData(256)); AssetService service; service.init(); service.setRoot(testDir); service.registerLoader(std::make_unique()); { auto handle = service.load("purge.test"); } service.purge(); TEST_ASSERT_EQ(0u, service.size()); service.shutdown(); cleanupTestDir(); } TEST(AssetService, Clear) { setupTestDir(); std::string filePath = getTestPath("clear.test"); writeTestFile(filePath, createTestData(256)); AssetService service; service.init(); service.setRoot(testDir); service.registerLoader(std::make_unique()); auto handle = service.load("clear.test"); TEST_ASSERT_GT(service.size(), 0u); service.clear(); TEST_ASSERT_EQ(0u, service.size()); service.shutdown(); cleanupTestDir(); } // --------------------------------------------------------------------------- // 卸载测试 // --------------------------------------------------------------------------- TEST(AssetService, Unload) { setupTestDir(); std::string filePath = getTestPath("unload.test"); writeTestFile(filePath, createTestData(256)); AssetService service; service.init(); service.setRoot(testDir); service.registerLoader(std::make_unique()); auto handle = service.load("unload.test"); TEST_ASSERT_TRUE(service.isLoaded("unload.test")); service.unload("unload.test"); TEST_ASSERT_FALSE(service.isLoaded("unload.test")); service.shutdown(); cleanupTestDir(); } // --------------------------------------------------------------------------- // 资源包挂载测试 // --------------------------------------------------------------------------- TEST(AssetService, MountPack) { setupTestDir(); AssetPackBuilder builder; builder.add("packed.test", createTestData(256)); builder.build(getTestPath("service.pack")); AssetService service; service.init(); service.registerLoader(std::make_unique()); bool mounted = service.mount(getTestPath("service.pack")); TEST_ASSERT_TRUE(mounted); service.shutdown(); cleanupTestDir(); } TEST(AssetService, UnmountPack) { setupTestDir(); AssetPackBuilder builder; builder.add("packed.test", createTestData(256)); builder.build(getTestPath("unmount.pack")); AssetService service; service.init(); service.registerLoader(std::make_unique()); service.mount(getTestPath("unmount.pack")); service.unmount(getTestPath("unmount.pack")); service.shutdown(); cleanupTestDir(); } // --------------------------------------------------------------------------- // 统计测试 // --------------------------------------------------------------------------- TEST(AssetService, Stats) { AssetService service; service.init(); auto stats = service.stats(); TEST_ASSERT_EQ(0u, stats.hits); TEST_ASSERT_EQ(0u, stats.misses); TEST_ASSERT_EQ(0u, stats.count); service.shutdown(); } // --------------------------------------------------------------------------- // 数据处理管道测试 // --------------------------------------------------------------------------- TEST(AssetService, SetPipe) { AssetService service; service.init(); DataPipe pipe; pipe.encrypt("key", Decryptor::Type::XOR); service.setPipe(std::move(pipe)); service.shutdown(); } // --------------------------------------------------------------------------- // 异步加载测试 // --------------------------------------------------------------------------- TEST(AssetService, AsyncLoad) { setupTestDir(); std::string filePath = getTestPath("async.test"); writeTestFile(filePath, createTestData(512)); AssetService service; service.init(); service.setRoot(testDir); service.registerLoader(std::make_unique()); std::atomic callbackCalled{false}; AssetHandle resultHandle; service.loadAsync("async.test", [&](AssetHandle handle) { resultHandle = handle; callbackCalled = true; }); for (int i = 0; i < 100 && !callbackCalled; ++i) { service.process(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } service.process(); TEST_ASSERT_TRUE(callbackCalled); TEST_ASSERT_TRUE(resultHandle.valid()); service.shutdown(); cleanupTestDir(); } TEST(AssetService, Preload) { setupTestDir(); std::string filePath = getTestPath("preload.test"); writeTestFile(filePath, createTestData(256)); AssetService service; service.init(); service.setRoot(testDir); service.registerLoader(std::make_unique()); service.preload("preload.test"); for (int i = 0; i < 50; ++i) { service.process(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } service.shutdown(); cleanupTestDir(); } // --------------------------------------------------------------------------- // 多资源测试 // --------------------------------------------------------------------------- TEST(AssetService, LoadMultiple) { setupTestDir(); for (int i = 0; i < 5; ++i) { std::string filePath = getTestPath("multi" + std::to_string(i) + ".test"); writeTestFile(filePath, createTestData(100 * (i + 1))); } AssetService service; service.init(); service.setRoot(testDir); service.registerLoader(std::make_unique()); for (int i = 0; i < 5; ++i) { auto handle = service.load("multi" + std::to_string(i) + ".test"); TEST_ASSERT_TRUE(handle.valid()); } TEST_ASSERT_GT(service.size(), 0u); service.shutdown(); cleanupTestDir(); }