From b409ce49a566d188590fcf52887db7d905deb792 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sat, 19 Apr 2025 17:23:38 -0300 Subject: [PATCH] Fixes Validation of JsonSchema --- jambo/schema_converter.py | 5 +- tests/parser/test_type_parser.py | 31 ++++++++++++ tests/test_schema_converter.py | 85 ++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 tests/parser/test_type_parser.py diff --git a/jambo/schema_converter.py b/jambo/schema_converter.py index 1f9834f..728a2a2 100644 --- a/jambo/schema_converter.py +++ b/jambo/schema_converter.py @@ -2,7 +2,7 @@ from jambo.parser import GenericTypeParser from jambo.types.json_schema_type import JSONSchema from jsonschema.exceptions import SchemaError -from jsonschema.protocols import Validator +from jsonschema.validators import validator_for from pydantic import create_model from pydantic.fields import Field from pydantic.main import ModelT @@ -42,7 +42,8 @@ class SchemaConverter: """ try: - Validator.check_schema(schema) + validator = validator_for(schema) + validator.check_schema(schema) except SchemaError as e: raise ValueError(f"Invalid JSON Schema: {e}") diff --git a/tests/parser/test_type_parser.py b/tests/parser/test_type_parser.py new file mode 100644 index 0000000..38bb6a1 --- /dev/null +++ b/tests/parser/test_type_parser.py @@ -0,0 +1,31 @@ +from jambo.parser._type_parser import GenericTypeParser + +from unittest import TestCase + + +class InvalidGenericTypeParser(GenericTypeParser): + mapped_type = str + json_schema_type = "invalid" + + def from_properties( + self, name: str, properties: dict[str, any], required: bool = False + ): ... + + +class TestGenericTypeParser(TestCase): + def test_invalid_get_impl(self): + # Assuming GenericTypeParser is imported from the module + with self.assertRaises(ValueError): + GenericTypeParser.get_impl("another_invalid_type") + + def test_invalid_json_schema_type(self): + InvalidGenericTypeParser.json_schema_type = None + + # This is more for the developer's sanity check + with self.assertRaises(RuntimeError): + GenericTypeParser.get_impl("another_invalid_type") + + def test_invalid_mappings_properties_builder(self): + parser = InvalidGenericTypeParser() + with self.assertRaises(NotImplementedError): + parser.mappings_properties_builder({}, required=False) diff --git a/tests/test_schema_converter.py b/tests/test_schema_converter.py index 4cfd9b5..7f85d3f 100644 --- a/tests/test_schema_converter.py +++ b/tests/test_schema_converter.py @@ -10,6 +10,59 @@ def is_pydantic_model(cls): class TestSchemaConverter(TestCase): + def test_build_expects_title(self): + schema = { + "description": "A person", + "type": "object", + "properties": { + "name": {"type": "string"}, + "age": {"type": "integer"}, + }, + } + + with self.assertRaises(ValueError): + SchemaConverter.build(schema) + + def test_build_expects_valid_schema(self): + invalid_schema = { + "type": "object", + "properties": { + "name": { + "type": "strng" + } # typo: "strng" is not a valid JSON Schema type + }, + "required": ["name"], + } + + with self.assertRaises(ValueError): + SchemaConverter.build_object("placeholder", invalid_schema) + + def test_build_expects_object(self): + schema = { + "title": "Person", + "description": "A person", + "type": "string", + } + + with self.assertRaises(TypeError): + SchemaConverter.build(schema) + + def test_is_invalid_field(self): + schema = { + "title": "Person", + "description": "A person", + "type": "object", + "properties": { + "id": { + "notType": "string", + } + }, + # 'required': ['name', 'age', 'is_active', 'friends', 'address'], + } + + with self.assertRaises(ValueError): + SchemaConverter.build(schema) + def test_jsonschema_to_pydantic(self): schema = { "title": "Person", @@ -312,3 +365,35 @@ class TestSchemaConverter(TestCase): with self.assertRaises(ValueError): Model(name="") + + def test_any_of(self): + schema = { + "title": "Person", + "description": "A person", + "type": "object", + "properties": { + "id": { + "anyOf": [ + {"type": "string", "maxLength": 11, "minLength": 1}, + {"type": "integer", "maximum": 10}, + ] + }, + }, + } + + Model = SchemaConverter.build(schema) + + obj = Model(id=1) + self.assertEqual(obj.id, 1) + + obj = Model(id="12345678901") + self.assertEqual(obj.id, "12345678901") + + with self.assertRaises(ValueError): + Model(id="") + + with self.assertRaises(ValueError): + Model(id="12345678901234567890") + + with self.assertRaises(ValueError): + Model(id=11)