|
|
|
@@ -32,6 +32,7 @@ class SchemagenEnumTest(unittest.TestCase):
|
|
|
|
|
def test_colliding_enum_values_deduplicate(self):
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {"role": {"enum": ["foo-bar", "foo_bar"]}},
|
|
|
|
|
}
|
|
|
|
|
rc, stdout, stderr = self.run_schemagen(schema)
|
|
|
|
@@ -45,6 +46,7 @@ class SchemagenEnumTest(unittest.TestCase):
|
|
|
|
|
def test_distinct_enum_values_generate(self):
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {"role": {"enum": ["admin", "user", "guest"]}},
|
|
|
|
|
}
|
|
|
|
|
rc, stdout, stderr = self.run_schemagen(schema)
|
|
|
|
@@ -80,7 +82,7 @@ class SchemagenKeywordTest(unittest.TestCase):
|
|
|
|
|
"module",
|
|
|
|
|
"import",
|
|
|
|
|
]
|
|
|
|
|
schema = {"type": "object", "properties": {}}
|
|
|
|
|
schema = {"type": "object", "additionalProperties": False, "properties": {}}
|
|
|
|
|
for kw in keywords:
|
|
|
|
|
schema["properties"][kw] = {"type": "string"}
|
|
|
|
|
rc, stdout, stderr = self.run_schemagen(schema)
|
|
|
|
@@ -164,11 +166,18 @@ class SchemagenCollisionTest(unittest.TestCase):
|
|
|
|
|
def test_kind_enum_does_not_duplicate_arr0(self):
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {
|
|
|
|
|
"arr": {"type": "array", "items": {"type": "string"}},
|
|
|
|
|
"obj": {"$ref": "#/$defs/Arr0"},
|
|
|
|
|
},
|
|
|
|
|
"$defs": {"Arr0": {"type": "object", "properties": {}}},
|
|
|
|
|
"$defs": {
|
|
|
|
|
"Arr0": {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
out = self.generate_and_compile(schema)
|
|
|
|
|
self.assertIn("struct Arr0", out)
|
|
|
|
@@ -183,7 +192,13 @@ class SchemagenCollisionTest(unittest.TestCase):
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "array",
|
|
|
|
|
"items": {"$ref": "#/$defs/Skip"},
|
|
|
|
|
"$defs": {"Skip": {"type": "object", "properties": {}}},
|
|
|
|
|
"$defs": {
|
|
|
|
|
"Skip": {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
out = self.generate_and_compile(schema)
|
|
|
|
|
self.assertIn("struct Skip", out)
|
|
|
|
@@ -199,6 +214,7 @@ class SchemagenCollisionTest(unittest.TestCase):
|
|
|
|
|
"""Regression test for issue #17: enum and array $defs must be reused."""
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {
|
|
|
|
|
"role1": {"$ref": "#/$defs/Role"},
|
|
|
|
|
"role2": {"$ref": "#/$defs/Role"},
|
|
|
|
@@ -252,17 +268,14 @@ class SchemagenAdditionalPropertiesTest(unittest.TestCase):
|
|
|
|
|
self.assertNotEqual(rc, 0)
|
|
|
|
|
self.assertIn("additionalProperties: true is not supported", stderr)
|
|
|
|
|
|
|
|
|
|
def test_additional_properties_absent_defaults_to_strict(self):
|
|
|
|
|
def test_additional_properties_absent_rejected(self):
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"properties": {"name": {"type": "string"}},
|
|
|
|
|
}
|
|
|
|
|
rc, stdout, stderr = self.run_schemagen(schema)
|
|
|
|
|
self.assertEqual(rc, 0, msg=stderr)
|
|
|
|
|
# The generated parser should reject unknown keys. Verify the key-matching
|
|
|
|
|
# helper returns -1 for an unknown key and cbKeyData rejects it.
|
|
|
|
|
self.assertIn("int matchKey(Kind k, std::string_view key) const {", stdout)
|
|
|
|
|
self.assertNotIn("bool isStrict(Kind k) const", stdout)
|
|
|
|
|
self.assertNotEqual(rc, 0)
|
|
|
|
|
self.assertIn("additionalProperties is required for object schemas", stderr)
|
|
|
|
|
|
|
|
|
|
def test_additional_properties_false_accepted(self):
|
|
|
|
|
schema = {
|
|
|
|
@@ -310,6 +323,7 @@ class SchemagenCyclicArrayTest(unittest.TestCase):
|
|
|
|
|
def test_object_field_to_self_referential_array_rejected(self):
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {"items": {"$ref": "#/$defs/Items"}},
|
|
|
|
|
"$defs": {
|
|
|
|
|
"Items": {
|
|
|
|
@@ -326,6 +340,7 @@ class SchemagenCyclicArrayTest(unittest.TestCase):
|
|
|
|
|
def test_chain_of_array_refs_rejected(self):
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {"x": {"$ref": "#/$defs/A"}},
|
|
|
|
|
"$defs": {
|
|
|
|
|
"A": {"type": "array", "items": {"$ref": "#/$defs/B"}},
|
|
|
|
@@ -339,6 +354,7 @@ class SchemagenCyclicArrayTest(unittest.TestCase):
|
|
|
|
|
def test_non_recursive_array_refs_still_allowed(self):
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {"roles": {"$ref": "#/$defs/Roles"}},
|
|
|
|
|
"$defs": {
|
|
|
|
|
"Role": {"enum": ["admin", "user"]},
|
|
|
|
@@ -439,10 +455,12 @@ class SchemagenCyclicNullableObjectTest(unittest.TestCase):
|
|
|
|
|
self.skipTest("C++ compiler not available")
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {"self": {"$ref": "#/$defs/Self"}},
|
|
|
|
|
"$defs": {
|
|
|
|
|
"Self": {
|
|
|
|
|
"type": ["object", "null"],
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {"self": {"$ref": "#/$defs/Self"}},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
@@ -670,6 +688,7 @@ class SchemagenIntegerBoundaryTest(unittest.TestCase):
|
|
|
|
|
)
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {"age": {"type": "integer"}},
|
|
|
|
|
"required": ["age"],
|
|
|
|
|
}
|
|
|
|
@@ -785,14 +804,22 @@ class SchemagenStringEscapeTest(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
def test_newline_in_property_key(self):
|
|
|
|
|
"""A JSON key containing a newline must become a valid C++ literal."""
|
|
|
|
|
schema = {"type": "object", "properties": {"a\nb": {"type": "string"}}}
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {"a\nb": {"type": "string"}},
|
|
|
|
|
}
|
|
|
|
|
out = self.generate_and_compile(schema)
|
|
|
|
|
self.assertIn('// "a\\nb"', out)
|
|
|
|
|
self.assertIn('if (key == "a\\nb") return 0;', out)
|
|
|
|
|
|
|
|
|
|
def test_newline_in_enum_value(self):
|
|
|
|
|
"""An enum value containing a newline must become a valid C++ literal."""
|
|
|
|
|
schema = {"type": "object", "properties": {"x": {"enum": ["a\nb"]}}}
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {"x": {"enum": ["a\nb"]}},
|
|
|
|
|
}
|
|
|
|
|
out = self.generate_and_compile(schema)
|
|
|
|
|
self.assertIn('static constexpr const char *X_names[] = { "a\\nb" };', out)
|
|
|
|
|
|
|
|
|
@@ -800,6 +827,7 @@ class SchemagenStringEscapeTest(unittest.TestCase):
|
|
|
|
|
"""Mixed control characters in an enum value must be escaped."""
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {
|
|
|
|
|
"x": {"enum": ["x\ny\rz\tw\vq\x00\x01"]},
|
|
|
|
|
},
|
|
|
|
@@ -812,7 +840,11 @@ class SchemagenStringEscapeTest(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
def test_backslash_and_quote_still_escaped(self):
|
|
|
|
|
"""Existing escaping for backslash and double quote must remain correct."""
|
|
|
|
|
schema = {"type": "object", "properties": {'a"b\\c': {"type": "string"}}}
|
|
|
|
|
schema = {
|
|
|
|
|
"type": "object",
|
|
|
|
|
"additionalProperties": False,
|
|
|
|
|
"properties": {'a"b\\c': {"type": "string"}},
|
|
|
|
|
}
|
|
|
|
|
out = self.generate_and_compile(schema)
|
|
|
|
|
self.assertIn('// "a\\"b\\\\c"', out)
|
|
|
|
|
self.assertIn('if (key == "a\\"b\\\\c") return 0;', out)
|
|
|
|
|