Skip to content

Test cases for SDF schema and linter #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
1,646 changes: 907 additions & 739 deletions sdflint/sdf-validation.jso.json

Large diffs are not rendered by default.

52 changes: 33 additions & 19 deletions sdflint/sdflint.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ if (require.main === module) { /* run as stand-alone? */
let options = {};
let schemaFile;

process.argv.slice(3).forEach( (option) => {
process.argv.slice(3).forEach((option) => {
let name = option.substring(0, option.indexOf("="));
let value = option.substring(option.indexOf("=") + 1);
options[name] = value;
Expand All @@ -48,15 +48,20 @@ if (require.main === module) { /* run as stand-alone? */
try {
sdfFile = fs.readFileSync(inFile,
{ encoding: 'utf-8' });
} catch (err) {
console.error("Can't read input SDF file: " + err.message);
process.exit(1);
}
try {
schema = JSON.parse(fs.readFileSync(schemaFile,
{ encoding: 'utf-8' }));
} catch (err) {
res.errorCount++;
res.errors.parse = err.message;
}
} catch (err) {
console.error("Can't read schema file: " + err.message);
process.exit(1);
}

sdfLint(sdfFile, schema, res, options);
console.dir(res, {depth: null});
console.dir(res, { depth: null });

process.exit(res.errorCount);
}
Expand All @@ -68,7 +73,7 @@ if (require.main === module) { /* run as stand-alone? */
schema The filename of the JSON schema to use
license The license string to accept as valid
`
);
);
}
}

Expand All @@ -77,7 +82,7 @@ function fileNameCheck(fileName, res) {
let fileNameRe = new RegExp(FILENAME_RE);
let baseFileName = path.parse(fileName).base;

if (! baseFileName.match(fileNameRe)) {
if (!baseFileName.match(fileNameRe)) {
res.errorCount++;
res.errors.fileName = "File name " + baseFileName +
" does not match " + FILENAME_RE;
Expand All @@ -87,6 +92,11 @@ function fileNameCheck(fileName, res) {

function validCharsCheck(sdfFile, res) {
let sdfStr = JSON.stringify(sdfFile);
if (!sdfStr) {
res.errorCount++;
res.errors.file = "Invalid SDF file";
return;
};
let invalidLoc = sdfStr.search(new RegExp(VALID_CHARS_RE));
if (invalidLoc != -1) {
res.errorCount++;
Expand All @@ -97,13 +107,13 @@ function validCharsCheck(sdfFile, res) {


function licenseCheck(sdf, license, res) {
if (! sdf.info || ! sdf.info.license) {
if (!sdf.info || !sdf.info.license) {
res.errorCount++;
res.errors.license = "No license defined in model"
} else if (sdf.info.license != license) {
res.errorCount++;
res.errors.license = "Model has license '" + sdf.info.license +
"' expected '" + license + "'";
"' expected '" + license + "'";
}
}

Expand All @@ -112,25 +122,29 @@ function sdfLint(sdfFile, schema, res, options) {
let ajv = new Ajv(AJV_OPTIONS);
let sdf;

if (! res) {
if (!res) {
res = {
errorCount: 0,
errors: {}
};
}
if (! options) {
if (!options) {
options = {};
}

try {
sdf = JSON.parse(sdfFile);
} catch (err) {
res.errorCount++;
res.errors.parse = err.message;
if (options.isJSON) {
sdf = sdfFile; /* already parsed as JSON */
} else {
try {
sdf = JSON.parse(sdfFile);
} catch (err) {
res.errorCount++;
res.errors.parse = err.message;
}
validCharsCheck(sdfFile, res);
}
validCharsCheck(sdfFile, res);

if (! schema) {
if (!schema) {
schema = JSON.parse(fs.readFileSync(
DEF_SCHEMA_FILE, { encoding: 'utf-8' }));
}
Expand Down
15 changes: 15 additions & 0 deletions sdflint/tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Test cases for SDF schema and linter

This folder contains a simple test program and test cases for testing if the SDF linter program and JSO schema catch various errors in SDF documents.

The program `test-schema.js` takes at minimum two parameters: a (valid) SDF document used as basis for testing and a schema file used to validate the document.

For example: `node test-schema.js sdfobject-test.sdf.json ../sdf-validation.jso.json`

The `sdfobject-test.sdf.json` is an SDF document that exercises many of the features of SDF Object definition and is a good start for the SDF document used with testing.

For schema file the default validation schema of the linter can be used with `../sdf-validation.jso.json`.

In this mode the program changes one by one each quality in the SDF document first to a (semi random) integer value and then to a string value. If the linter does not detect this as an error, information about this is printed to console. For example `Missed change: info/title -> "FOOBAR"` indicates a change in the info block's title quality (that is in fact a change that is OK to not flag as error since title can be any string).

If further parameters are given to the program, those are assumed to be JSON merge-patch documents that alter the base SDF document. After applying each merge-patch, validation is run and if no error is detected, information about this is printed (if error is detected, nothing is printed unless verbose mode is used). Set of example merge-patch documents are available in the `schema-errors` folder. This mode also needs to have the "merge-patch" [command line program](https://rubygems.org/gems/merge-patch/versions/0.1.0) installed ("gem install merge-patch").
12 changes: 12 additions & 0 deletions sdflint/tests/schema-errors/misspell-type.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"sdfObject": {
"TestObject": {
"sdfProperty": {
"IntegerTestProperty": {
"type": null,
"typemisspelled" : "integer"
}
}
}
}
}
11 changes: 11 additions & 0 deletions sdflint/tests/schema-errors/numeric-description.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"sdfObject": {
"TestObject": {
"sdfProperty": {
"IntegerTestProperty": {
"description": 42
}
}
}
}
}
123 changes: 123 additions & 0 deletions sdflint/tests/sdfobject-test.sdf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
{
"info": {
"title": "Test object",
"copyright": "Example Test Corp 2023",
"license": "BSD-3-Clause",
"version": "2023-11-04",
"features": [],
"$comment": "Test comment",
"modified": "2023-11-05"
},
"namespace": {
"foo": "https://foo.example.com/models",
"bar": "https://foo.example.com/bar"
},
"defaultNamespace": "foo",
"sdfObject": {
"TestObject": {
"sdfProperty": {
"IntegerTestProperty": {
"description": "Integer temperature read-only",
"type": "integer",
"minimum": -3,
"maximum": 50,
"unit": "Cel",
"writable": false
},
"StringTestProperty": {
"label": "String Test Property",
"type": "string",
"readable": true
},
"BooleanTestProperty": {
"type": "boolean",
"nullable": true
},
"ArrayTestProperty": {
"type": "array",
"maxItems": 10,
"minItems": 2,
"items" : {
"type": "integer"
}
},
"FormatTestProperty": {
"type": "string",
"format": "uuid"
},
"EnumTestProperty": {
"type": "string",
"enum": ["foo", "bar", "baz"]
},
"ChoiceTestProperty": {
"type": "string",
"sdfChoice": {
"foo" : {
"description": "Foo value",
"const": 1
},
"bar": {
"description": "Bar value",
"const": 2
}
}
},
"DefaultValueTestProperty": {
"default": "foo",
"type": "string"
},
"ExclusiveLimitsTestProperty": {
"type": "integer",
"exclusiveMaximum": 50,
"exclusiveMinimum": -3
},
"RequiredTestProperty": {
"type": "boolean",
"sdfRequired": [
true
]
},
"RefTestProperty": {
"sdfRef": "#/sdfObject/TestObject/sdfData/TestData",
"description": "sdfRef test property"
}
},
"sdfRequired": [
"TestAction",
"#/sdfObject/TestObject/sdfProperty/IntegerTestProperty"
],
"sdfAction": {
"TestAction": {
"description": "Action for testing",
"sdfInputData": {
"type": "number"
},
"sdfOutputData": {
"type": "string"
}
},
"TestActionObjectOutput": {
"description": "Test action with Object output data",
"sdfOutputData": {
"type": "object",
"properties": {
"a": {
"type": "integer"
},
"b": {
"type": "string"
}
}
}
}
},
"sdfData": {
"TestData": {
"type": "string",
"sdfType": "byte-string",
"contentFormat": "60"
}
}
}
}
}
Loading