Skip to content

Commit

Permalink
Fix handling of allowed-values enumeration in JSON Schemas (#253)
Browse files Browse the repository at this point in the history
* Fix JSON Schema generation for #240 and add tests.

* Adapt test suite approach per PR feedback.

* Final cleanup of unused parameter.

The shift in test approach, with the shell entrypoint at
ist-metaschema-MAKE-JSON-SCHEMA.xsl and not with the previous
make-json-schema-metamap.xsl replaced means that parameter, which
was not working particularly well in the previous approach.
  • Loading branch information
aj-stein-nist authored Jan 25, 2023
1 parent f18f72f commit 5f51539
Show file tree
Hide file tree
Showing 12 changed files with 579 additions and 192 deletions.
38 changes: 38 additions & 0 deletions test-suite/metaschema-xspec/json-schema-gen/json-schema-gen.xspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<x:description xmlns:x="http://www.jenitennison.com/xslt/xspec"
xmlns:m="http://csrc.nist.gov/ns/oscal/metaschema/1.0"
xmlns:j="http://www.w3.org/2005/xpath-functions"
stylesheet="../../../toolchains/xslt-M4/nist-metaschema-MAKE-JSON-SCHEMA.xsl" run-as="external">

<x:scenario label="When generating a JSON schema from composed Metaschema definitions">
<x:scenario label="if it has a defined field with no constraint and no allowed-values">
<x:context href="json-value_unconstrained_metaschema.xml"/>
<x:expect label="the resulting JSON Schema should not have an enum to enforce it."
test="$x:result => j:json-to-xml()" select="'../json-value_unconstrained.json' => j:unparsed-text() => j:json-to-xml()"/>
</x:scenario>

<x:scenario label="if it has a defined field with a constraint, allowed-values, strict enforcement of allow-other='no' and explicit target of '.'">
<x:context href="json-value_constrained-closed_metaschema.xml"/>
<x:expect label="the resulting JSON Schema should have an enum to enforce it."
test="$x:result => j:json-to-xml()" select="'../json-value_constrained-closed.json' => j:unparsed-text() => j:json-to-xml()"/>
</x:scenario>

<x:scenario label="if it has a defined field with a constraint, allowed-values, no explicit target, and permissive enforcement of allow-other='yes'">
<x:context href="json-value_constrained-open_metaschema.xml"/>
<x:expect label="the resulting JSON Schema should not have an enum to enforce it."
test="$x:result => j:json-to-xml()" select="'../json-value_constrained-open.json' => j:unparsed-text() => j:json-to-xml()"/>
</x:scenario>

<x:scenario label="if it has a defined field with a constraint, allowed-values, strict enforcement of allow-other='no' and explicit target other than '.'">
<x:context href="json-value_constrained-narrow_metaschema.xml"/>
<x:expect label="the resulting JSON Schema should not have an enum to enforce it."
test="$x:result => j:json-to-xml()" select="'../json-value_constrained-narrow.json' => j:unparsed-text() => j:json-to-xml()"/>
</x:scenario>

<x:scenario label="if it has a defined field with a constraint, allowed-values, permissive enforcement of allow-other='yes' and explicit target other than '.'">
<x:context href="json-value_constrained-sortof_metaschema.xml"/>
<x:expect label="the resulting JSON Schema should not have an enum to enforce it."
test="$x:result => j:json-to-xml()" select="'../json-value_constrained-sortof.json' => j:unparsed-text() => j:json-to-xml()"/>
</x:scenario>
</x:scenario>
</x:description>
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://csrc.nist.gov/ns/metaschema-tests/0.1/json-schema-value-test-constrained-closed-schema.json",
"$comment": "JSON value testing mini metaschema: JSON Schema",
"type": "object",
"definitions": {
"json-schema-value-test-constrained-closed-json-schema-value-test-constrained-closed:root": {
"title": "Root",
"description": "Root root root.",
"$id": "#assembly_json-schema-value-test-constrained-closed_root",
"type": "object",
"properties": {
"constrained-closed": {
"$ref": "#field_json-schema-value-test-constrained-closed_constrained-closed"
}
},
"additionalProperties": false
},
"json-schema-value-test-constrained-closed-json-schema-value-test-constrained-closed:constrained-closed": {
"title": "Constrained closed",
"description": "Because allow-other is 'no' an enumeration can be given in the JSON Schema.",
"$id": "#field_json-schema-value-test-constrained-closed_constrained-closed",
"type": "object",
"properties": {
"some": {
"title": "Some Flag",
"description": "Some flag some flag some flag.",
"$ref": "#/definitions/StringDatatype"
},
"token-value": {
"allOf": [
{
"$ref": "#/definitions/TokenDatatype"
},
{
"enum": [
"one",
"two",
"three",
"four"
]
}
]
}
},
"required": [
"token-value"
],
"additionalProperties": false
},
"StringDatatype": {
"type": "string",
"pattern": "^\\S(.*\\S)?$"
},
"TokenDatatype": {
"type": "string",
"pattern": "^(\\p{L}|_)(\\p{L}|\\p{N}|[.\\-_])*$"
}
},
"properties": {
"root": {
"$ref": "#assembly_json-schema-value-test-constrained-closed_root"
}
},
"required": [
"root"
],
"additionalProperties": false,
"maxProperties": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="metaschema-author.css"?>
<METASCHEMA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://csrc.nist.gov/ns/oscal/metaschema/1.0 ../../../schema/xml/metaschema.xsd"
xmlns="http://csrc.nist.gov/ns/oscal/metaschema/1.0" abstract="no">
<schema-name>JSON value testing mini metaschema</schema-name>
<schema-version>0.1</schema-version>
<short-name>json-schema-value-test-constrained-closed</short-name>
<namespace>http://csrc.nist.gov/ns/metaschema-tests/1.0</namespace>
<json-base-uri>http://csrc.nist.gov/ns/metaschema-tests</json-base-uri>
<define-assembly name="root">
<formal-name>Root</formal-name>
<description>Root root root.</description>
<root-name>root</root-name>
<model>
<field ref="constrained-closed"/>
</model>
</define-assembly>
<define-field
as-type="token"
name="constrained-closed">
<formal-name>Constrained closed</formal-name>
<description>Because allow-other is 'no' an enumeration can be given in the JSON Schema.</description>
<json-value-key>token-value</json-value-key>
<define-flag name="some">
<formal-name>Some Flag</formal-name>
<description>Some flag some flag some flag.</description>
</define-flag>
<constraint>
<allowed-values target="." allow-other="no">
<enum value="one"/>
<enum value="two"/>
<enum value="three"/>
<enum value="four"/>
</allowed-values>
</constraint>
</define-field>
</METASCHEMA>
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://csrc.nist.gov/ns/metaschema-tests/0.1/json-schema-value-test-constrained-narrow-schema.json",
"$comment": "JSON value testing mini metaschema: JSON Schema",
"type": "object",
"definitions": {
"json-schema-value-test-constrained-narrow-json-schema-value-test-constrained-narrow:root": {
"title": "Root",
"description": "Root root root.",
"$id": "#assembly_json-schema-value-test-constrained-narrow_root",
"type": "object",
"properties": {
"constrained-narrow": {
"$ref": "#field_json-schema-value-test-constrained-narrow_constrained-narrow"
}
},
"additionalProperties": false
},
"json-schema-value-test-constrained-narrow-json-schema-value-test-constrained-narrow:constrained-narrow": {
"title": "Constrained narrow",
"description": "Although allow-other is 'no' an enumeration can't be given in the JSON Schema since it targets a qualified set (only a subset) of the elements in scope.",
"$id": "#field_json-schema-value-test-constrained-narrow_constrained-narrow",
"type": "object",
"properties": {
"some": {
"title": "Some Flag",
"description": "Some flag some flag some flag.",
"$ref": "#/definitions/StringDatatype"
},
"token-value": {
"$ref": "#/definitions/TokenDatatype"
}
},
"required": [
"token-value"
],
"additionalProperties": false
},
"StringDatatype": {
"type": "string",
"pattern": "^\\S(.*\\S)?$"
},
"TokenDatatype": {
"type": "string",
"pattern": "^(\\p{L}|_)(\\p{L}|\\p{N}|[.\\-_])*$"
}
},
"properties": {
"root": {
"$ref": "#assembly_json-schema-value-test-constrained-narrow_root"
}
},
"required": [
"root"
],
"additionalProperties": false,
"maxProperties": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="metaschema-author.css"?>
<METASCHEMA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://csrc.nist.gov/ns/oscal/metaschema/1.0 ../../../schema/xml/metaschema.xsd"
xmlns="http://csrc.nist.gov/ns/oscal/metaschema/1.0" abstract="no">
<schema-name>JSON value testing mini metaschema</schema-name>
<schema-version>0.1</schema-version>
<short-name>json-schema-value-test-constrained-narrow</short-name>
<namespace>http://csrc.nist.gov/ns/metaschema-tests/1.0</namespace>
<json-base-uri>http://csrc.nist.gov/ns/metaschema-tests</json-base-uri>
<define-assembly name="root">
<formal-name>Root</formal-name>
<description>Root root root.</description>
<root-name>root</root-name>
<model>
<field ref="constrained-narrow"/>
</model>
</define-assembly>

<define-field
as-type="token"
name="constrained-narrow">
<formal-name>Constrained narrow</formal-name>
<description>Although allow-other is 'no' an enumeration can't be given in the JSON Schema since it targets a qualified set (only a subset) of the elements in scope.</description>
<json-value-key>token-value</json-value-key>
<define-flag name="some">
<formal-name>Some Flag</formal-name>
<description>Some flag some flag some flag.</description>
</define-flag>
<constraint>
<allowed-values target=".[not(false())]" allow-other="no">
<enum value="one"/>
<enum value="two"/>
<enum value="three"/>
<enum value="four"/>
</allowed-values>
</constraint>
</define-field>
</METASCHEMA>
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://csrc.nist.gov/ns/metaschema-tests/0.1/json-schema-value-test-constrained-open-schema.json",
"$comment": "JSON value testing mini metaschema: JSON Schema",
"type": "object",
"definitions": {
"json-schema-value-test-constrained-open-json-schema-value-test-constrained-open:root": {
"title": "Root",
"description": "Root root root.",
"$id": "#assembly_json-schema-value-test-constrained-open_root",
"type": "object",
"properties": {
"constrained-open": {
"$ref": "#field_json-schema-value-test-constrained-open_constrained-open"
}
},
"additionalProperties": false
},
"json-schema-value-test-constrained-open-json-schema-value-test-constrained-open:constrained-open": {
"title": "Constrained open",
"description": "Because allow-other is 'yes' no enumeration can be given in the JSON Schema.",
"$id": "#field_json-schema-value-test-constrained-open_constrained-open",
"type": "object",
"properties": {
"some": {
"title": "Some Flag",
"description": "Some flag some flag some flag.",
"$ref": "#/definitions/StringDatatype"
},
"token-value": {
"anyOf": [
{
"$ref": "#/definitions/TokenDatatype"
},
{
"enum": [
"one",
"two",
"three",
"four"
]
}
]
}
},
"required": [
"token-value"
],
"additionalProperties": false
},
"StringDatatype": {
"type": "string",
"pattern": "^\\S(.*\\S)?$"
},
"TokenDatatype": {
"type": "string",
"pattern": "^(\\p{L}|_)(\\p{L}|\\p{N}|[.\\-_])*$"
}
},
"properties": {
"root": {
"$ref": "#assembly_json-schema-value-test-constrained-open_root"
}
},
"required": [
"root"
],
"additionalProperties": false,
"maxProperties": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="metaschema-author.css"?>
<METASCHEMA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://csrc.nist.gov/ns/oscal/metaschema/1.0 ../../../schema/xml/metaschema.xsd"
xmlns="http://csrc.nist.gov/ns/oscal/metaschema/1.0" abstract="no">
<schema-name>JSON value testing mini metaschema</schema-name>
<schema-version>0.1</schema-version>
<short-name>json-schema-value-test-constrained-open</short-name>
<namespace>http://csrc.nist.gov/ns/metaschema-tests/1.0</namespace>
<json-base-uri>http://csrc.nist.gov/ns/metaschema-tests</json-base-uri>
<define-assembly name="root">
<formal-name>Root</formal-name>
<description>Root root root.</description>
<root-name>root</root-name>
<model>
<field ref="constrained-open"/>
</model>
</define-assembly>
<define-field
as-type="token"
name="constrained-open">
<formal-name>Constrained open</formal-name>
<description>Because allow-other is 'yes' no enumeration can be given in the JSON Schema.</description>
<json-value-key>token-value</json-value-key>
<define-flag name="some">
<formal-name>Some Flag</formal-name>
<description>Some flag some flag some flag.</description>
</define-flag>
<constraint>
<allowed-values target="." allow-other="yes">
<enum value="one"/>
<enum value="two"/>
<enum value="three"/>
<enum value="four"/>
</allowed-values>
</constraint>
</define-field>
</METASCHEMA>
Loading

0 comments on commit 5f51539

Please sign in to comment.