import { describe, expect, it } from "vitest"; import { AssetManager } from "@/core/AssetManager"; type FakeBundle = Record; describe("AssetSession", () => { it("deduplicates concurrent first-time bundle loads", async () => { const loadCalls: string[] = []; let resolveLoad: ((bundle: FakeBundle) => void) | null = null; const manager = new AssetManager({ init: async () => undefined, loadBundle: (name: string) => new Promise((resolve) => { loadCalls.push(name); resolveLoad = resolve; }), unloadBundle: async () => undefined, }); const sessionA = manager.createSession("scene"); const sessionB = manager.createSession("ui"); const pendingA = sessionA.loadBundle("shared"); const pendingB = sessionB.loadBundle("shared"); expect(loadCalls).toEqual(["shared"]); resolveLoad?.({ shared: true }); const [bundleA, bundleB] = await Promise.all([pendingA, pendingB]); expect(bundleA).toEqual({ shared: true }); expect(bundleB).toEqual({ shared: true }); expect(manager.getRefCount("shared")).toBe(2); }); it("tracks owner/session relationships in inspector snapshot", async () => { const loadCalls: string[] = []; const unloadCalls: string[] = []; const manager = new AssetManager({ init: async () => undefined, loadBundle: async (name: string) => { loadCalls.push(name); return { name } as FakeBundle; }, unloadBundle: async (name: string) => { unloadCalls.push(name); }, }); const sceneSessionA = manager.createSession("scene"); const sceneSessionB = manager.createSession("scene"); const uiSession = manager.createSession("ui"); await sceneSessionA.loadBundle("characters"); await sceneSessionB.loadBundle("background"); await uiSession.loadBundle("characters"); const snapshot = manager.getInspectorSnapshot(); expect(snapshot.sessions[sceneSessionA.id]?.owner).toBe("scene"); expect(snapshot.sessions[sceneSessionB.id]?.owner).toBe("scene"); expect(snapshot.sessions[uiSession.id]?.owner).toBe("ui"); expect(snapshot.owners.scene?.sessions).toContain(sceneSessionA.id); expect(snapshot.owners.scene?.sessions).toContain(sceneSessionB.id); expect(snapshot.owners.ui?.sessions).toContain(uiSession.id); expect(snapshot.activeBundles.sort()).toEqual(["background", "characters"]); expect(loadCalls).toEqual(["characters", "background"]); expect(unloadCalls).toEqual([]); }); it("clears active bundles after releaseAll", async () => { const unloadCalls: string[] = []; const manager = new AssetManager({ init: async () => undefined, loadBundle: async (name: string) => ({ name }) as FakeBundle, unloadBundle: async (name: string) => { unloadCalls.push(name); }, }); const session = manager.createSession("battle"); await session.loadBundle("fx"); await session.loadBundle("music"); expect(manager.getInspectorSnapshot().activeBundles.sort()).toEqual([ "fx", "music", ]); await session.releaseAll(); const snapshot = manager.getInspectorSnapshot(); expect(snapshot.activeBundles).toEqual([]); expect(snapshot.bundles).toEqual({}); expect(unloadCalls.sort()).toEqual(["fx", "music"]); }); it("cleans up destroyed sessions and keeps mixed default/explicit semantics consistent", async () => { const unloadCalls: string[] = []; const manager = new AssetManager({ init: async () => undefined, loadBundle: async (name: string) => ({ name }) as FakeBundle, unloadBundle: async (name: string) => { unloadCalls.push(name); }, }); const explicit = manager.createSession("scene"); await manager.loadBundle("shared"); await explicit.loadBundle("shared"); await manager.unloadBundle("shared"); expect(unloadCalls).toEqual([]); expect(manager.getInspectorSnapshot().activeBundles).toEqual(["shared"]); await explicit.destroy(); const snapshot = manager.getInspectorSnapshot(); expect(snapshot.sessions[explicit.id]).toBeUndefined(); expect(snapshot.owners.scene).toBeUndefined(); expect(snapshot.activeBundles).toEqual([]); expect(unloadCalls).toEqual(["shared"]); }); });