The time budget of § 14.14 had no enforcement: a reporter now prints the total and the ten slowest tests, and fails a run whose node project exceeds 30 s or node-long 60 s. Two guards parsed imports with two patterns, one blind past an apostrophe in a comment; both now use one parser anchored on « from ». The determinism guard refuses key-order walks, and one test binds the application name across its three declarations. The end-to-end generations drop to 100 000 moves. Checked: each ceiling, the apostrophe case and a key walk are shown failing before the guard that catches them. --- FR --- [ADD] épreuves : rapporteur de budget, imports, ordre des clés Le budget de temps du § 14.14 n'avait aucune garde : un rapporteur imprime désormais la durée totale et les dix épreuves les plus lentes, et fait échouer une exécution dont le projet node dépasse 30 s ou node-long 60 s. Deux gardes lisaient les imports par deux motifs, l'un aveugle après une apostrophe en commentaire ; les deux passent par un seul analyseur ancré sur « from ». La garde de déterminisme refuse les parcours de clés, et une épreuve lie le nom de l'application à ses trois déclarations. Les générations de bout en bout passent à 100 000. Vérifié : chaque plafond, le cas de l'apostrophe et un parcours de clés sont montrés en échec avant la garde qui les attrape. Assisted-by: Claude Opus 5.5
91 lines
3.3 KiB
JavaScript
91 lines
3.3 KiB
JavaScript
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
||
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||
|
||
// L'analyseur des chargements, test/chargements.js, que lisent les gardes de
|
||
// l'arborescence et du livrable. Chaque épreuve donne un texte et les
|
||
// chargements qu'il demande, dans l'ordre du texte. Les spécificateurs nus
|
||
// des données sont des paquets de devDependencies ou des modules de Node :
|
||
// la garde des dépendances lit aussi ce fichier.
|
||
import assert from 'node:assert/strict';
|
||
import { chargements } from './chargements.js';
|
||
import { describe, test } from './lanceur.js';
|
||
|
||
// Numéro, à partir de 1, de la ligne qui porte le caractère d'indice donné.
|
||
const ligneDe = (texte, indice) => texte.slice(0, indice).split('\n').length;
|
||
|
||
// Chaque chargement d'un texte, en « ligne spécificateur », ou en « ligne
|
||
// calculé argument » pour un argument qui n'est pas une chaîne littérale.
|
||
const lus = (texte) =>
|
||
chargements(texte).map(({ indice, specificateur, argument }) =>
|
||
specificateur === undefined
|
||
? `${ligneDe(texte, indice)} calculé ${argument}`
|
||
: `${ligneDe(texte, indice)} ${specificateur}`,
|
||
);
|
||
|
||
describe('chargements', () => {
|
||
test("un import dont les accolades portent un commentaire à apostrophe se relève, comme celui qui le suit", () => {
|
||
const texte = [
|
||
'import {',
|
||
" // l'écran d'accueil",
|
||
' App,',
|
||
"} from '../interface/App.svelte';",
|
||
"import { a } from './a.js';",
|
||
].join('\n');
|
||
assert.deepEqual(
|
||
chargements(texte).map(({ specificateur }) => specificateur),
|
||
['../interface/App.svelte', './a.js'],
|
||
);
|
||
});
|
||
|
||
test('import et export à from, import seul, import() et require() de chaîne, avec ou sans options, se relèvent à leur ligne, dans l’ordre du texte', () => {
|
||
const texte = [
|
||
"import { a } from './a.js';",
|
||
'import b, { c } from "../b.js";',
|
||
"export * from './c.js';",
|
||
"export { d } from'./d.js';",
|
||
"import 'svelte';",
|
||
'const e = require("electron");',
|
||
"const f = await import('node:fs', { with: {} });",
|
||
'const g = await import(`vitest`);',
|
||
"import * as h from 'svelte/store'; const i = require('./i.cjs');",
|
||
].join('\n');
|
||
assert.deepEqual(lus(texte), [
|
||
'1 ./a.js',
|
||
'2 ../b.js',
|
||
'3 ./c.js',
|
||
'4 ./d.js',
|
||
'5 svelte',
|
||
'6 electron',
|
||
'7 node:fs',
|
||
'8 vitest',
|
||
'9 svelte/store',
|
||
'9 ./i.cjs',
|
||
]);
|
||
});
|
||
|
||
test("un argument qui n'est pas une chaîne littérale se relève comme calculé, sans spécificateur", () => {
|
||
const texte = [
|
||
'const a = require(nom);',
|
||
'const b = await import(`./${module}.js`);',
|
||
"const c = require('./' + nom);",
|
||
'const d = await import( cible );',
|
||
].join('\n');
|
||
assert.deepEqual(lus(texte), [
|
||
'1 calculé nom',
|
||
'2 calculé `./${module}.js`',
|
||
"3 calculé './' + nom",
|
||
'4 calculé cible',
|
||
]);
|
||
});
|
||
|
||
test("ni une chaîne qui finit sur « import », ni la règle @import d'une feuille de style ne sont des chargements", () => {
|
||
const texte = [
|
||
"spawnSync(process.execPath, ['--import', 'chargeur.js']);",
|
||
'<style>',
|
||
" @import 'jetons.css';",
|
||
'</style>',
|
||
"const mot = 'import';",
|
||
].join('\n');
|
||
assert.deepEqual(lus(texte), []);
|
||
});
|
||
});
|