From 5a5eeac4247045b5811fdab39c69a2d00cc1219c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Burgd=C3=B6rfer?= Date: Fri, 28 Feb 2025 08:51:44 +0100 Subject: [PATCH] chore: adapt `runTest.js` script to allow csaf 2.1 tests --- scripts/runTest.js | 152 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 117 insertions(+), 35 deletions(-) diff --git a/scripts/runTest.js b/scripts/runTest.js index 773b668..f58f067 100755 --- a/scripts/runTest.js +++ b/scripts/runTest.js @@ -3,44 +3,126 @@ /** * @file Script to validate JSON files against given tests * - * Usage: node .js json/file/path.json mandatoryTest_6_1_1 + * Usage: node .js -f -t [-c ] * - * `mandatoryTest_6_1_1` is a sample here. You can insert any test name from lib/mandatoryTests.js, - * `lib/optionalTests.js`, `lib/schemaTests.js` and `lib/schemaTests.js`. + * -f + * Specifies the path to the csaf json file to validate the given test against. + * + * -t + * Specifies the test(s) to run. The values that you can pass here depend on the value + * of the `-c` option which specifies the used csaf version. If you use 2.0 here you + * can insert any test name from `mandatoryTests.js`, `optionalTests.js`, + * `informativeTests.js` and `schemaTests.js`. + * If you use 2.1 here you can insert any test name from `csaf_2_1/mandatoryTests.js`, + * `csaf_2_1/optionalTests.js`, `csaf_2_1/informativeTests.js` and `csaf_2_1/schemaTests.js`. + * Some presets are also allowed such as `mandatory`, `optional`, `informative`, + * `schema` and `base`. + * + * -c (default: 2.0) + * Specifies the csaf version to use. The currently allowed versions are `2.0` (the default) + * and `2.1`. */ import { readFile } from 'fs/promises' -import * as schemaTests from '../schemaTests.js' -import * as mandatoryTests from '../mandatoryTests.js' -import * as optionalTests from '../optionalTests.js' -import * as informativeTests from '../informativeTests.js' import validate from '../validate.js' +import { parseArgs } from 'node:util' +import assert from 'node:assert' + +/** + * Types a function that can lazily load a set of tests. This is used to speed up the script + * by avoiding to load unused test sets. + * + * @typedef {() => Promise>} DocumentTestLoader + */ + +/** + * This is the main function that reads the file, executes the resolved test + * and logs the result. + * + * @param {object} ctx + * @param {DocumentTestLoader} ctx.schemaTests + * @param {DocumentTestLoader} ctx.mandatoryTests + * @param {DocumentTestLoader} ctx.optionalTests + * @param {DocumentTestLoader} ctx.informativeTests + * @param {object} params + * @param {string} params.testName + * @param {string} params.filePath + */ +const main = async ( + { informativeTests, mandatoryTests, optionalTests, schemaTests }, + { testName, filePath } +) => { + const json = JSON.parse(await readFile(filePath, { encoding: 'utf-8' })) + + const matchingTests = + testName === 'mandatory' + ? Object.values(await mandatoryTests()) + : testName === 'optional' + ? Object.values(await optionalTests()) + : testName === 'informative' + ? Object.values(await informativeTests()) + : testName === 'schema' + ? Object.values(await schemaTests()) + : testName === 'base' + ? Object.values(await schemaTests()).concat( + Object.values(await mandatoryTests()) + ) + : Object.values(await mandatoryTests()) + .concat(Object.values(await optionalTests())) + .concat(Object.values(await informativeTests())) + .concat(Object.values(await schemaTests())) + .filter((t) => t.name === testName) + + if (!matchingTests.length) + throw new Error(`No test matching "${testName}" found`) + const result = await validate(matchingTests, json) + process.exitCode = result.isValid ? 0 : 1 + console.log(JSON.stringify(result, null, 2)) +} + +const { values: cliOptions } = parseArgs({ + options: { + file: { + type: 'string', + short: 'f', + }, + 'csaf-version': { + type: 'string', + short: 'c', + default: '2.0', + }, + test: { + type: 'string', + short: 't', + }, + }, +}) + +const filePath = cliOptions.file +const testName = cliOptions.test +assert(filePath) +assert(testName) -const [, , filePath, testName] = process.argv - -const json = JSON.parse(await readFile(filePath, { encoding: 'utf-8' })) - -const matchingTests = - testName === 'mandatory' - ? Object.values(mandatoryTests) - : testName === 'optional' - ? Object.values(optionalTests) - : testName === 'informative' - ? Object.values(informativeTests) - : testName === 'schema' - ? Object.values(schemaTests) - : testName === 'base' - ? Object.values(schemaTests).concat(Object.values(mandatoryTests)) - : /** @type {Array} */ ( - Object.values(mandatoryTests) - ) - .concat(Object.values(optionalTests)) - .concat(Object.values(informativeTests)) - .concat(Object.values(schemaTests)) - .filter((t) => t.name === testName) - -if (!matchingTests.length) - throw new Error(`No test matching "${testName}" found`) -const result = await validate(matchingTests, json) -process.exitCode = result.isValid ? 0 : 1 -console.log(JSON.stringify(result, null, 2)) +if (cliOptions['csaf-version'] === '2.0') { + await main( + { + mandatoryTests: () => import('../mandatoryTests.js'), + informativeTests: () => import('../informativeTests.js'), + optionalTests: () => import('../optionalTests.js'), + schemaTests: () => import('../schemaTests.js'), + }, + { filePath, testName } + ) +} else if (cliOptions['csaf-version'] === '2.1') { + await main( + { + mandatoryTests: () => import('../csaf_2_1/mandatoryTests.js'), + informativeTests: () => import('../csaf_2_1/informativeTests.js'), + optionalTests: () => import('../csaf_2_1/optionalTests.js'), + schemaTests: () => import('../csaf_2_1/schemaTests.js'), + }, + { filePath, testName } + ) +} else { + throw new Error('Unknown CSAF version') +}