// Le prove nel browser a sezioni (scripts/verify.mjs): ogni file del gioco finisce negli ingressi delle prove giuste, // e l'impronta cambia solo se cambia un ingresso. import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readdirSync } from 'node:fs'; import { SUITES, ENGINE, inputsOf, ignored, fingerprint, plan } from '../scripts/verify.mjs'; const FILES = ['index.html', 'style.css', 'src/main.js', 'src/version.js', 'package.json', 'package-lock.json', 'Makefile', 'README.md', 'src/engine/game.js', 'src/engine/render.js', 'src/engine/ambient.js', 'src/engine/bocce.js', 'src/engine/nuovo.js', 'src/engine/briscola.js', 'src/engine/briscola-render.js', 'src/engine/flipper.js', 'src/engine/corsa.js', 'src/story/piloti.js', 'src/story/story.js', 'src/story/solution.js', 'assets/scenes/piazza.png', 'assets/closeups/micro-parcheggio.png', 'assets/closeups/gp/boccino.png', 'assets/muro/index.html', 'assets/video/briscola.mp4', 'docs/BRISCOLA.md', 'docs/STATO.md', 'tests/helpers.mjs', 'tests/browser.mjs', 'tests/briscola.browser.mjs', 'tests/briscola.test.mjs', 'tests/story.test.mjs', 'scripts/verify.mjs', 'scripts/bump.sh', 'tools/slice_sprites.py', '.verify-ok.json']; const suitesWith = path => Object.keys(SUITES).filter(n => inputsOf(n, FILES).includes(path)); const islands = Object.keys(SUITES).filter(n => !SUITES[n].core), cores = Object.keys(SUITES).filter(n => SUITES[n].core); test('ogni prova nel browser di tests/ ha la sua voce, e una sola', () => { const runs = Object.values(SUITES).map(s => s.run[0]); for (const f of readdirSync('tests').filter(f => f.endsWith('.browser.mjs'))) { if (f === 'multimedia.browser.mjs') continue; // la chiama la parte «telefoni» di browser.mjs const n = runs.filter(r => r === `tests/${f}`).length; assert.equal(n, f === 'browser.mjs' ? 3 : 1, `tests/${f} è in ${n} prove`); } }); test('la briscola si riprova solo se cambia la briscola o il motore', () => { assert.deepEqual(suitesWith('src/engine/briscola.js'), ['briscola']); assert.deepEqual(suitesWith('src/engine/briscola-render.js'), ['briscola']); assert.deepEqual(suitesWith('assets/video/briscola.mp4'), ['briscola']); assert.deepEqual(suitesWith('tests/briscola.browser.mjs'), ['briscola']); assert.deepEqual(suitesWith('docs/BRISCOLA.md'), [], 'i documenti non fanno rifare niente'); assert.ok(!inputsOf('briscola', FILES).includes('src/story/story.js'), 'la storia non fa riprovare la briscola'); assert.deepEqual(suitesWith('src/engine/corsa.js'), ['gara']); assert.deepEqual(suitesWith('src/story/piloti.js'), ['gara']); assert.deepEqual(suitesWith('assets/closeups/gp/boccino.png'), ['gara']); assert.deepEqual(suitesWith('assets/muro/index.html'), ['telefono']); assert.deepEqual(suitesWith('assets/closeups/micro-parcheggio.png'), ['micro']); }); test('la storia, le scene, i minigiochi dentro la partita e un modulo nuovo fanno rifare la partita intera, non i minigiochi a sé', () => { for (const path of ['src/story/story.js', 'src/story/solution.js', 'assets/scenes/piazza.png', 'src/engine/bocce.js', 'src/engine/ambient.js', 'src/engine/nuovo.js', 'tests/browser.mjs']) { assert.deepEqual(suitesWith(path), cores, path); } }); test('il motore comune fa rifare tutto', () => { for (const path of ENGINE) assert.deepEqual(suitesWith(path), Object.keys(SUITES), path); assert.ok(islands.length >= 10 && cores.length >= 3); }); test('versione, package.json, Makefile, documenti, strumenti e test unitari non fanno rifare niente', () => { for (const path of ['src/version.js', 'package.json', 'Makefile', 'README.md', 'docs/STATO.md', 'scripts/bump.sh', 'tools/slice_sprites.py', 'tests/briscola.test.mjs', 'tests/story.test.mjs', '.verify-ok.json']) { assert.ok(ignored(path), `${path} dovrebbe essere ignorato`); assert.deepEqual(suitesWith(path), [], path); } }); test("l'impronta cambia solo se cambia un ingresso, e il piano dice quali", () => { const hashes = new Map(FILES.map(p => [p, 'h-' + p])); const before = plan(hashes, {}); assert.ok(before.every(p => !p.green), 'mai provate: tutte da rifare'); const ok = Object.fromEntries(before.map(p => [p.name, { fingerprint: p.fp, hashes: Object.fromEntries(p.inputs.map(f => [f, hashes.get(f)])) }])); assert.ok(plan(hashes, ok).every(p => p.green), 'niente cambiato: tutte verdi'); hashes.set('docs/STATO.md', 'altro'); assert.ok(plan(hashes, ok).every(p => p.green), 'un documento non cambia niente'); hashes.set('src/engine/briscola.js', 'altro'); const after = plan(hashes, ok); assert.deepEqual(after.filter(p => !p.green).map(p => p.name), ['briscola']); assert.deepEqual(after.find(p => p.name === 'briscola').changed, ['src/engine/briscola.js']); assert.notEqual(fingerprint(['a'], () => '1'), fingerprint(['a'], () => '2')); });