/** Which asset a reference field points at – what "Open texture" and the inspector link open (#221). */ import { describe, expect, it } from 'vitest'; import { CreateAssetCommand, CreateSoundCommand, CreateTextureCommand, CreateVideoCommand, } from '../../src/core/commands/assetCommands'; import { AddClipCommand } from '../../src/core/commands/clipCommands'; import { AddFrameCommand } from '../../src/core/commands/frameCommands'; import type { PixelArtAsset } from '../../src/core/model/Asset'; import { findAsset } from '../../src/core/model/Project'; import { type PropertyDef, schemaForAsset } from '../../src/core/properties/PropertySchema'; import { referencedAssetId, referencedTarget, referencesOf } from '../../src/core/properties/references'; import { resolveAssetProps } from '../../src/core/properties/resolve'; import { SHADER_KEY } from '../../src/core/properties/shaders'; import { makeSpriteScene } from '../helpers'; const FILE = `${'ab'.repeat(32)}.png`; const TEXTURE: PropertyDef = { key: 'texture', label: 'Texture', kind: 'texture', default: '' }; const SHADER: PropertyDef = { key: SHADER_KEY, label: 'Shader', kind: 'asset', default: '', assetTypes: ['shader'], }; const SOUND: PropertyDef = { key: 'sound', label: 'Sound', kind: 'sound', default: '' }; function withClips() { const f = setup(); const video = new CreateVideoCommand('Film', `${'cd'.repeat(32)}.mp4`, { width: 320, height: 180, duration: 4, fps: 30, audio: false, }); const sound = new CreateSoundCommand('Kick', `${'ef'.repeat(32)}.ogg`); f.stack.execute(video); f.stack.execute(sound); const videoClip = new AddClipCommand(video.asset.id, { start: 1, end: 2 }); const soundClip = new AddClipCommand(sound.asset.id, { start: 0.1, end: 0.2 }); f.stack.execute(videoClip); f.stack.execute(soundClip); return { ...f, videoId: video.asset.id, soundId: sound.asset.id, videoClip: videoClip.clipId, soundClip: soundClip.clipId, }; } function setup() { const fixture = makeSpriteScene(); const texture = new CreateTextureCommand('Sheet', { file: FILE, width: 64, height: 32 }); fixture.stack.execute(texture); const frame = new AddFrameCommand(texture.asset.id, { x: 0, y: 0, w: 16, h: 16 }, 'Idle'); fixture.stack.execute(frame); const shader = new CreateAssetCommand('shader', 'Glow'); fixture.stack.execute(shader); const art = new CreateAssetCommand('pixelart', 'Art'); fixture.stack.execute(art); return { ...fixture, textureId: texture.asset.id, frameId: frame.frameId, shaderId: shader.asset.id, art: art.asset as PixelArtAsset, }; } describe('referencedAssetId', () => { it('is the asset a reference names', () => { const f = setup(); expect(referencedAssetId(f.project, TEXTURE, f.textureId)).toBe(f.textureId); expect(referencedAssetId(f.project, SHADER, f.shaderId)).toBe(f.shaderId); }); it('is the sheet for a frame of a texture or of pixel art', () => { const f = setup(); expect(referencedAssetId(f.project, TEXTURE, f.frameId)).toBe(f.textureId); f.art.frames.push({ id: 'second', cels: {} }); expect(referencedAssetId(f.project, TEXTURE, 'second')).toBe(f.art.id); }); it('is nothing for an empty or dangling reference', () => { const f = setup(); expect(referencedAssetId(f.project, TEXTURE, '')).toBeNull(); expect(referencedAssetId(f.project, SHADER, 'gone')).toBeNull(); }); it('only resolves frames in a texture field', () => { const f = setup(); expect(referencedAssetId(f.project, SHADER, f.frameId)).toBeNull(); }); it('is nothing for a field that names no asset, whatever it holds', () => { const f = setup(); const text: PropertyDef = { key: 'name', label: 'Name', kind: 'text', default: '' }; expect(referencedAssetId(f.project, text, f.textureId)).toBeNull(); }); it('is the video for a clip of one in a texture field (#425)', () => { const f = withClips(); expect(referencedAssetId(f.project, TEXTURE, f.videoClip)).toBe(f.videoId); expect(referencedAssetId(f.project, SOUND, f.soundClip)).toBe(f.soundId); }); }); describe('referencedTarget (#425)', () => { it('is the clip itself for a clip of a video or a sound, the asset for anything else', () => { const f = withClips(); expect(referencedTarget(f.project, TEXTURE, f.videoClip)).toBe(f.videoClip); expect(referencedTarget(f.project, SOUND, f.soundClip)).toBe(f.soundClip); expect(referencedTarget(f.project, TEXTURE, f.videoId)).toBe(f.videoId); expect(referencedTarget(f.project, TEXTURE, f.frameId)).toBe(f.textureId); expect(referencedTarget(f.project, SHADER, f.videoClip)).toBeNull(); }); }); describe('referencesOf', () => { it("lists a sprite asset's texture and shader in schema order, and nothing unset", () => { const f = setup(); const sprite = findAsset(f.project, f.spriteId)!; const refs = () => referencesOf(f.project, schemaForAsset(f.project, sprite), resolveAssetProps(f.project, sprite)); sprite.props.texture = ''; expect(refs()).toEqual([]); sprite.props[SHADER_KEY] = f.shaderId; sprite.props.texture = f.frameId; expect(refs()).toEqual([ { label: 'Texture', assetId: f.textureId }, { label: 'Shader', assetId: f.shaderId }, ]); }); });