diff --git a/tests/test_dataforge_type_check.py b/tests/test_dataforge_type_check.py new file mode 100644 index 0000000..62723d2 --- /dev/null +++ b/tests/test_dataforge_type_check.py @@ -0,0 +1,170 @@ +"""Tests for type_check module.""" + +import pytest + +from dataforge.type_check import ( + infer_type, + parse_type_spec, + check_type, + validate_types, + infer_schema_from_data, +) + + +class TestInferType: + """Tests for type inference.""" + + def test_infer_null(self): + assert infer_type(None) == "null" + + def test_infer_boolean(self): + assert infer_type(True) == "boolean" + assert infer_type(False) == "boolean" + + def test_infer_integer(self): + assert infer_type(42) == "integer" + assert infer_type(-10) == "integer" + + def test_infer_float(self): + assert infer_type(3.14) == "number" + assert infer_type(0.0) == "number" + + def test_infer_string(self): + assert infer_type("hello") == "string" + + def test_infer_array(self): + assert infer_type([1, 2, 3]) == "array" + + def test_infer_object(self): + assert infer_type({"key": "value"}) == "object" + + +class TestParseTypeSpec: + """Tests for type specification parsing.""" + + def test_parse_string_type(self): + type_name, type_info = parse_type_spec("string") + assert type_name == "string" + assert type_info is None + + def test_parse_object_type(self): + type_spec = {"type": "object", "properties": {"name": {"type": "string"}}} + type_name, type_info = parse_type_spec(type_spec) + assert type_name == "object" + assert type_info == type_spec + + +class TestCheckType: + """Tests for type checking.""" + + def test_check_string_type_valid(self): + valid, error = check_type("hello", "string") + assert valid is True + assert error is None + + def test_check_string_type_invalid(self): + valid, error = check_type(123, "string") + assert valid is False + assert "Expected string" in error + + def test_check_integer_type(self): + valid, error = check_type(42, "integer") + assert valid is True + + def test_check_object_type(self): + type_spec = {"type": "object", "properties": {"name": {"type": "string"}}} + valid, error = check_type({"name": "John"}, type_spec) + assert valid is True + + def test_check_object_type_missing_property(self): + type_spec = {"type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"]} + valid, error = check_type({}, type_spec) + assert valid is False + assert "Missing required property" in error + + def test_check_array_type(self): + type_spec = {"type": "array", "items": {"type": "integer"}} + valid, error = check_type([1, 2, 3], type_spec) + assert valid is True + + def test_check_array_type_invalid_item(self): + type_spec = {"type": "array", "items": {"type": "integer"}} + valid, error = check_type([1, "two", 3], type_spec) + assert valid is False + assert "Array item 1" in error + + def test_check_any_type(self): + valid, error = check_type("anything", "any") + assert valid is True + + +class TestValidateTypes: + """Tests for comprehensive type validation.""" + + def test_validate_valid_types(self): + type_spec = {"type": "object", "properties": {"name": {"type": "string"}}} + errors = validate_types({"name": "John"}, type_spec) + assert len(errors) == 0 + + def test_validate_invalid_types(self): + type_spec = {"type": "object", "properties": {"name": {"type": "string"}}} + errors = validate_types({"name": 123}, type_spec) + assert len(errors) > 0 + + def test_validate_nested_object(self): + type_spec = { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": {"name": {"type": "string"}} + } + } + } + errors = validate_types({"user": {"name": "John"}}, type_spec) + assert len(errors) == 0 + + def test_validate_required_properties(self): + type_spec = { + "type": "object", + "properties": {"name": {"type": "string"}}, + "required": ["name"] + } + errors = validate_types({}, type_spec) + assert len(errors) > 0 + + +class TestInferSchemaFromData: + """Tests for schema inference.""" + + def test_infer_simple_object_schema(self): + data = {"name": "John", "age": 30} + schema = infer_schema_from_data(data) + assert schema["type"] == "object" + assert "properties" in schema + assert schema["properties"]["name"]["type"] == "string" + assert schema["properties"]["age"]["type"] == "integer" + + def test_infer_nested_object_schema(self): + data = {"user": {"name": "John", "address": {"city": "NYC"}}} + schema = infer_schema_from_data(data) + assert schema["type"] == "object" + assert schema["properties"]["user"]["type"] == "object" + assert schema["properties"]["user"]["properties"]["address"]["type"] == "object" + + def test_infer_array_schema(self): + data = [1, 2, 3] + schema = infer_schema_from_data(data) + assert schema["type"] == "array" + assert "items" in schema + assert schema["items"]["type"] == "integer" + + def test_infer_empty_object_schema(self): + data = {} + schema = infer_schema_from_data(data) + assert schema["type"] == "object" + + def test_infer_empty_array_schema(self): + data = [] + schema = infer_schema_from_data(data) + assert schema["type"] == "array"