128 lines
4.3 KiB
TypeScript
128 lines
4.3 KiB
TypeScript
import type { Texture } from 'pixi.js';
|
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
import { CreateAssetCommand } from '../../src/core/commands/assetCommands';
|
|
import { registerPictureSource } from '../../src/core/model/generated';
|
|
import {
|
|
GeneratedPictures,
|
|
projectPictureFactory,
|
|
registerPictureGenerator,
|
|
} from '../../src/viewport/generatedPictures';
|
|
import { makeSpriteScene } from '../helpers';
|
|
|
|
/** The pictures are plain strings here: what is measured is who is kept and who is let go. */
|
|
function library() {
|
|
const freed: string[] = [];
|
|
const drawn: string[] = [];
|
|
const pictures = new GeneratedPictures<string>((picture) => freed.push(picture));
|
|
let answer: (assetId: string) => string | null = (assetId) => assetId;
|
|
pictures.setFactory((assetId) => {
|
|
drawn.push(assetId);
|
|
return answer(assetId);
|
|
});
|
|
return {
|
|
pictures,
|
|
freed,
|
|
drawn,
|
|
answerWith: (fn: (assetId: string) => string | null) => {
|
|
answer = fn;
|
|
},
|
|
};
|
|
}
|
|
|
|
describe('generated pictures kept in memory', () => {
|
|
it('draws a key once and hands the same picture out again', () => {
|
|
const f = library();
|
|
f.answerWith(() => 'first');
|
|
expect(f.pictures.get('gen:a@1')).toBe('first');
|
|
expect(f.pictures.get('gen:a@1')).toBe('first');
|
|
expect(f.drawn).toEqual(['a']);
|
|
expect(f.freed).toEqual([]);
|
|
});
|
|
|
|
it('lets the old revision go the moment the new one is drawn', () => {
|
|
const f = library();
|
|
f.answerWith((id) => `${id}-one`);
|
|
f.pictures.get('gen:a@1');
|
|
f.answerWith((id) => `${id}-two`);
|
|
expect(f.pictures.get('gen:a@2')).toBe('a-two');
|
|
expect(f.freed).toEqual(['a-one']);
|
|
expect(f.pictures.keys()).toEqual(['gen:a@2']);
|
|
// Only that asset's own older picture goes; a neighbour keeps hers.
|
|
f.answerWith((id) => `${id}-b`);
|
|
f.pictures.get('gen:b@1');
|
|
f.pictures.get('gen:a@3');
|
|
expect(f.freed).toEqual(['a-one', 'a-two']);
|
|
expect(f.pictures.keys()).toEqual(['gen:b@1', 'gen:a@3']);
|
|
});
|
|
|
|
it('asks again for a picture that could not be drawn yet', () => {
|
|
const f = library();
|
|
f.answerWith(() => null);
|
|
expect(f.pictures.get('gen:a@1')).toBeNull();
|
|
expect(f.pictures.has('gen:a@1')).toBe(false);
|
|
f.answerWith(() => 'ready');
|
|
expect(f.pictures.get('gen:a@1')).toBe('ready');
|
|
expect(f.drawn).toEqual(['a', 'a']);
|
|
});
|
|
|
|
it('draws nothing for a name that is not a key', () => {
|
|
const f = library();
|
|
expect(f.pictures.get(`${'ab'.repeat(32)}.png`)).toBeNull();
|
|
expect(f.pictures.get('gen:a')).toBeNull();
|
|
expect(f.drawn).toEqual([]);
|
|
});
|
|
|
|
it('gives everything back when another session takes over', () => {
|
|
const f = library();
|
|
f.pictures.get('gen:a@1');
|
|
f.pictures.get('gen:b@1');
|
|
f.pictures.setFactory(null);
|
|
expect(f.freed).toEqual(['a', 'b']);
|
|
expect(f.pictures.keys()).toEqual([]);
|
|
expect(f.pictures.get('gen:a@1')).toBeNull();
|
|
});
|
|
|
|
it('answers peek only with what has been drawn', () => {
|
|
const f = library();
|
|
expect(f.pictures.peek('gen:a@1')).toBeNull();
|
|
f.pictures.get('gen:a@1');
|
|
expect(f.pictures.peek('gen:a@1')).toBe('a');
|
|
expect(f.drawn).toEqual(['a']);
|
|
});
|
|
});
|
|
|
|
describe('the factory the editor runs with', () => {
|
|
const registered: (() => void)[] = [];
|
|
afterEach(() => {
|
|
for (const undo of registered.splice(0)) undo();
|
|
});
|
|
|
|
it('hands an asset to the generator of its type and nothing else to anyone', () => {
|
|
const f = makeSpriteScene();
|
|
const sound = new CreateAssetCommand('sound', 'Beep');
|
|
f.stack.execute(sound);
|
|
registered.push(registerPictureSource('sound', () => ({ width: 8, height: 8, revision: 1 })));
|
|
const seen: string[] = [];
|
|
const picture = {} as Texture;
|
|
registered.push(
|
|
registerPictureGenerator('sound', (asset) => {
|
|
seen.push(asset.name);
|
|
return picture;
|
|
}),
|
|
);
|
|
|
|
const factory = projectPictureFactory(() => f.project);
|
|
expect(factory(sound.asset.id)).toBe(picture);
|
|
expect(seen).toEqual(['Beep']);
|
|
// A sprite has no generator, and an id that is gone has no asset.
|
|
expect(factory(f.spriteId)).toBeNull();
|
|
expect(factory('nobody')).toBeNull();
|
|
expect(seen).toEqual(['Beep']);
|
|
});
|
|
|
|
it('draws nothing while no project is open', () => {
|
|
const factory = projectPictureFactory(() => null);
|
|
expect(factory('a')).toBeNull();
|
|
});
|
|
});
|