-
-
Notifications
You must be signed in to change notification settings - Fork 84
Expand file tree
/
Copy pathjson-schema-functional-tests.js
More file actions
118 lines (96 loc) · 3.79 KB
/
json-schema-functional-tests.js
File metadata and controls
118 lines (96 loc) · 3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"use strict";
/**
* validate all test data for a given version of CycloneDX.
* call the script via `node <this-file> -v <CDX-version>`
*/
import {readFile, stat} from 'node:fs/promises'
import {dirname, join} from 'node:path'
import {fileURLToPath} from 'node:url'
import {parseArgs} from 'node:util'
import Ajv from "ajv"
import addFormats from "ajv-formats"
import addFormats2019 from "ajv-formats-draft2019"
import {globSync} from 'glob'
const _thisDir = dirname(fileURLToPath(import.meta.url))
// region config
const testschemaVersion = (parseArgs({options: {v: {type: 'string', short: 'v'}}}).values.v ?? '').trim()
const schemaDir = join(_thisDir, '..', '..', '..', '..', 'schema')
const schemaFile = join(schemaDir, `bom-${testschemaVersion}.schema.json`)
const testdataDir = join(_thisDir, '..', 'resources', testschemaVersion)
if (testschemaVersion.length === 0) {
throw new Error('missing testschemaVersion. expected via argument')
}
console.debug('DEBUG | testschemaVersion = ', testschemaVersion);
if (!await stat(schemaFile).then(s => s.isFile()).catch(() => false)) {
throw new Error(`missing schemaFile: ${schemaFile}`);
}
console.debug('DEBUG | schemaFile = ', schemaFile);
if (!await stat(testdataDir).then(s => s.isDirectory()).catch(() => false)) {
throw new Error(`missing testdataDir: ${testdataDir}`);
}
console.debug('DEBUG | testdataDir = ', testdataDir);
// endregion config
// region validator
const [spdxSchema, jsfSchema, cryptoDefsSchema, bomSchema] = await Promise.all([
readFile(join(schemaDir, 'spdx.schema.json'), 'utf-8').then(JSON.parse),
readFile(join(schemaDir, 'jsf-0.82.schema.json'), 'utf-8').then(JSON.parse),
readFile(join(schemaDir, 'cryptography-defs.schema.json'), 'utf-8').then(JSON.parse),
readFile(schemaFile, 'utf-8').then(JSON.parse)
])
const ajv = new Ajv({
// not running in strict - this is done in the linter-test already
strict: false,
validateFormats: true,
addUsedSchema: false,
schemas: {
'http://cyclonedx.org/schema/spdx.schema.json': spdxSchema,
'http://cyclonedx.org/schema/jsf-0.82.schema.json': jsfSchema,
'http://cyclonedx.org/schema/cryptography-defs.schema.json': cryptoDefsSchema,
}
});
addFormats(ajv)
addFormats2019(ajv, {formats: ['idn-email']})
// there is just no working implementation for format "iri-reference"
// see https://github.com/luzlab/ajv-formats-draft2019/issues/22
ajv.addFormat('iri-reference', true)
if (testschemaVersion === '1.2') {
// CycloneDX 1.2 had a wrong undefined format `string`.
// Let's ignore this format only for this special version.
ajv.addFormat('string', true)
}
const _ajvValidate = ajv.compile(bomSchema)
/**
* @param {string} file - file path to validate
* @return {null|object}
*/
async function validateFile(file) {
return _ajvValidate(await readFile(file, 'utf-8').then(JSON.parse))
? null
: _ajvValidate.errors
}
// endregion validator
let errCnt = 0
for (const file of globSync(join(testdataDir, 'valid-*.json'))) {
console.log('\ntest', file, '...');
const validationErrors = await validateFile(file)
if (validationErrors === null) {
console.log('OK.')
} else {
++errCnt;
console.error('ERROR: Unexpected validation error for file:', file);
console.error(validationErrors)
}
}
for (const file of globSync(join(testdataDir, 'invalid-*.json'))) {
console.log('\ntest', file, '...');
const validationErrors = await validateFile(file)
if (validationErrors === null) {
++errCnt;
console.error('ERROR: Missing expected validation error for file:', file);
} else {
console.log('OK.')
}
}
// Exit statuses should be in the range 0 to 254.
// The status 0 is used to terminate the program successfully.
process.exitCode = Math.min(errCnt, 254)