113 lines
4.6 KiB
JavaScript
113 lines
4.6 KiB
JavaScript
// Verificacao de consistencia documental, nao validacao funcional do portal.
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFile } from 'node:fs/promises';
|
|
const root = new URL('../', import.meta.url);
|
|
async function csv(name) {
|
|
const text = await readFile(new URL(name, root), 'utf8');
|
|
const lines = text.trim().split(/\r?\n/);
|
|
const parse = (line) =>
|
|
[...line.matchAll(/"((?:[^"]|"")*)"(?:,|$)/g)].map((match) =>
|
|
match[1].replaceAll('""', '"'),
|
|
);
|
|
const header = parse(lines.shift());
|
|
return lines.map((line) => {
|
|
const cells = parse(line);
|
|
assert.equal(cells.length, header.length, name + ': numero de colunas');
|
|
return Object.fromEntries(header.map((key, i) => [key, cells[i]]));
|
|
});
|
|
}
|
|
await test('33 requirements retain IDs and resolve entities, rules, risks and acceptance tests', async () => {
|
|
const rows = await csv('requirements.csv');
|
|
const entities = new Set(
|
|
(await csv('entities.csv')).map((e) => e.entidade),
|
|
);
|
|
const spec = await readFile(new URL('specification.md', root), 'utf8');
|
|
assert.equal(rows.length, 33);
|
|
assert.equal(new Set(rows.map((r) => r.id)).size, rows.length);
|
|
for (const [index, row] of rows.entries()) {
|
|
assert.equal(row.id, 'RF-EDU-' + String(index + 1).padStart(3, '0'));
|
|
for (const entity of row.dados_entidades.split(';'))
|
|
assert.ok(entities.has(entity), entity);
|
|
for (const rule of row.regra_negocio.split(';'))
|
|
assert.ok(spec.includes(rule), rule);
|
|
assert.ok(spec.includes(row.risco), row.risco);
|
|
assert.ok(row.criterio_aceitacao.length > 20);
|
|
assert.ok(row.endpoint_proposto.startsWith('/api/v1/education/'));
|
|
assert.equal(row.estado, 'Proposta');
|
|
}
|
|
});
|
|
await test('entities, RNF, indicators and conformity matrices are complete and explicitly proposed', async () => {
|
|
assert.equal((await csv('entities.csv')).length, 44);
|
|
assert.equal((await csv('nonfunctional.csv')).length, 18);
|
|
const indicators = await csv('indicators.csv');
|
|
assert.equal(indicators.length, 25);
|
|
for (const indicator of indicators)
|
|
assert.match(indicator.meta, /Pendente/);
|
|
const conformity = await csv('conformity.csv');
|
|
assert.equal(
|
|
conformity.filter((r) => r.categoria.startsWith('Módulo ')).length,
|
|
20,
|
|
);
|
|
for (const item of conformity)
|
|
assert.ok(
|
|
[
|
|
'Conforme',
|
|
'Parcialmente conforme',
|
|
'Não conforme',
|
|
'Pendente de validação',
|
|
].includes(item.classificacao),
|
|
);
|
|
});
|
|
await test('OpenAPI proposal resolves local refs and guards all modifying operations', async () => {
|
|
const api = JSON.parse(
|
|
await readFile(new URL('openapi.proposed.json', root), 'utf8'),
|
|
);
|
|
assert.equal(api.openapi, '3.1.0');
|
|
assert.equal(api['x-artifact-status'], 'Proposta');
|
|
const operations = new Set();
|
|
function walk(value) {
|
|
if (!value || typeof value !== 'object') return;
|
|
if (value.$ref) {
|
|
assert.ok(value.$ref.startsWith('#/'));
|
|
let target = api;
|
|
for (const part of value.$ref.slice(2).split('/'))
|
|
target =
|
|
target?.[part.replaceAll('~1', '/').replaceAll('~0', '~')];
|
|
assert.ok(target, value.$ref);
|
|
}
|
|
for (const nested of Object.values(value)) walk(nested);
|
|
}
|
|
walk(api);
|
|
for (const [path, methods] of Object.entries(api.paths)) {
|
|
assert.ok(path.startsWith('/api/v1/education/'));
|
|
for (const method of ['get', 'post', 'patch']) {
|
|
const operation = methods[method];
|
|
if (!operation) continue;
|
|
assert.ok(!operations.has(operation.operationId));
|
|
operations.add(operation.operationId);
|
|
assert.ok(operation.responses['401']);
|
|
if (method !== 'get')
|
|
assert.ok(
|
|
operation.parameters.some((p) =>
|
|
p.$ref.endsWith('/Idempotency'),
|
|
),
|
|
);
|
|
if (method === 'patch' || path.endsWith('/decisions'))
|
|
assert.ok(
|
|
operation.parameters.some((p) => p.$ref.endsWith('/Match')),
|
|
);
|
|
}
|
|
}
|
|
});
|
|
await test('all thirty requested numbered sections exist in order', async () => {
|
|
const text = await readFile(new URL('specification.md', root), 'utf8');
|
|
const numbers = [...text.matchAll(/^## (\d+)\. /gm)].map((m) =>
|
|
Number(m[1]),
|
|
);
|
|
assert.deepEqual(
|
|
numbers,
|
|
Array.from({ length: 30 }, (_, i) => i + 1),
|
|
);
|
|
});
|