tower / files / test / photos.test.ts
photos.test.ts
3cc2b5bd 2026-10-04 Pavel Safronov | 1 | import { readFileSync } from 'node:fs' |
| 2 | import { describe, expect, it } from 'vitest' | |
| 3 | import { parsePhoto, photoId } from '../src/world/photos.js' | |
| 4 | ||
| 5 | const interior = { | |
| 6 | id: 'far-cap', view: 'interior', hours: 13, dial: 'temperate', aspect: 1.5, | |
| 7 | theta: 0, z: 270_000, eyeM: 1.7, yaw: 0, pitch: 0.2, fovDeg: 60, spin: 0, | |
| 8 | } | |
| 9 | const exterior = { | |
| 10 | id: 'outside', view: 'exterior', hours: 30.5, dial: 'full', aspect: 1.47, hull: 'rock', | |
| 11 | position: [160, -360, 780], target: [0, 0, 510], phase: 1.2, fovDeg: 42, | |
| 12 | } | |
| 13 | ||
| 14 | describe('photographs (D-099)', () => { | |
| 15 | it('reads a shot of either view back as it was written', () => { | |
| 16 | expect(parsePhoto(interior)).toEqual(interior) | |
| 17 | expect(parsePhoto(exterior)).toEqual(exterior) | |
| 18 | expect(parsePhoto({ ...interior, note: 'the sun just out' }).note).toBe('the sun just out') | |
| 19 | }) | |
| 20 | ||
| 21 | it('says what is wrong with an entry typed by hand', () => { | |
| 22 | expect(() => parsePhoto({ ...interior, pitch: 2 })).toThrow('far-cap: pitch') | |
| 23 | expect(() => parsePhoto({ ...interior, z: -1 })).toThrow('far-cap: z') | |
| 24 | expect(() => parsePhoto({ ...interior, dial: 'bright' })).toThrow('dial') | |
| 25 | expect(() => parsePhoto({ ...exterior, hull: 'glass' })).toThrow('hull') | |
| 26 | expect(() => parsePhoto({ ...exterior, target: [0, 0] })).toThrow('target') | |
| 27 | expect(() => parsePhoto({ ...interior, view: 'map' })).toThrow('view') | |
| 28 | expect(() => parsePhoto({ ...interior, aspect: 0 })).toThrow('aspect') | |
| 29 | }) | |
| 30 | ||
| 31 | it('keeps an id fit to be a file name', () => { | |
| 32 | expect(photoId(' Far cap, from the Capital! ')).toBe('far-cap-from-the-capital') | |
| 33 | expect(photoId('***')).toBe('') | |
| 34 | for (const id of ['../world', 'a/b', 'Far Cap', '', 'a--b']) { | |
| 35 | expect(() => parsePhoto({ ...interior, id })).toThrow('id') | |
| 36 | } | |
| 37 | }) | |
| 38 | ||
| 39 | it('has a list every entry of which can be rendered, under names that do not collide', () => { | |
| 40 | const list = JSON.parse(readFileSync('content/photos.json', 'utf8')) as unknown[] | |
| 41 | const ids = list.map((p) => parsePhoto(p).id) | |
| 42 | expect(new Set(ids).size).toBe(ids.length) | |
| 43 | }) | |
| 44 | }) |