compliance/tests/test_json_schema_validator.py
2025-05-16 15:18:02 +08:00

232 lines
7.5 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
JSON Schema Validator Test Module
Unit tests for ddms_compliance_suite.json_schema_validator.validator module,
validates JSON data against schema definitions.
"""
import os
import sys
import unittest
import json
from unittest import mock
from pathlib import Path
# Add project root to Python path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
# Import classes and functions to test
from ddms_compliance_suite.json_schema_validator.validator import JSONSchemaValidator
from ddms_compliance_suite.models.rule_models import JSONSchemaDefinition, RuleCategory, TargetType
class TestJSONSchemaValidator(unittest.TestCase):
"""JSON Schema Validator Test Class"""
def setUp(self):
"""Setup before tests"""
# Create validator instance
self.validator = JSONSchemaValidator()
# Test schema definition
self.well_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["wellName", "wellID", "status", "coordinates"],
"properties": {
"wellName": {
"type": "string",
"description": "Well name"
},
"wellID": {
"type": "string",
"pattern": "^W[0-9]{10}$",
"description": "Well unique identifier, must be W followed by 10 digits"
},
"status": {
"type": "string",
"enum": ["active", "inactive", "abandoned", "suspended"],
"description": "Current well status"
},
"coordinates": {
"type": "object",
"required": ["longitude", "latitude"],
"properties": {
"longitude": {
"type": "number",
"minimum": -180,
"maximum": 180,
"description": "Longitude coordinate"
},
"latitude": {
"type": "number",
"minimum": -90,
"maximum": 90,
"description": "Latitude coordinate"
}
}
}
}
}
# Create a schema rule
self.schema_rule = JSONSchemaDefinition(
id="well-data-schema",
name="Well Data Schema",
description="Defines JSON structure for well data",
category=RuleCategory.JSON_SCHEMA,
version="1.0.0",
target_type=TargetType.DATA_OBJECT,
target_identifier="Well",
schema_content=self.well_schema
)
def test_valid_data(self):
"""Test that valid data passes validation"""
# Valid test data
valid_data = {
"wellName": "Test Well-01",
"wellID": "W0123456789",
"status": "active",
"coordinates": {
"longitude": 116.3833,
"latitude": 39.9167
}
}
# Validate
result = self.validator.validate(valid_data, self.well_schema)
# Assert
self.assertTrue(result.is_valid)
self.assertEqual(len(result.errors), 0)
def test_missing_required_field(self):
"""Test missing required field scenario"""
# Data missing required field
invalid_data = {
"wellName": "Test Well-01",
"wellID": "W0123456789",
# Missing status field
"coordinates": {
"longitude": 116.3833,
"latitude": 39.9167
}
}
# Validate
result = self.validator.validate(invalid_data, self.well_schema)
# Assert
self.assertFalse(result.is_valid)
self.assertTrue(any("status" in error for error in result.errors))
def test_invalid_pattern(self):
"""Test field with invalid pattern"""
# Data with invalid wellID format
invalid_data = {
"wellName": "Test Well-01",
"wellID": "ABCDEFGHIJK", # Does not match W + 10 digits pattern
"status": "active",
"coordinates": {
"longitude": 116.3833,
"latitude": 39.9167
}
}
# Validate
result = self.validator.validate(invalid_data, self.well_schema)
# Assert
self.assertFalse(result.is_valid)
self.assertTrue(any("pattern" in error for error in result.errors))
def test_invalid_enum(self):
"""Test value not in enum"""
# Data with status not in enum list
invalid_data = {
"wellName": "Test Well-01",
"wellID": "W0123456789",
"status": "unknown", # Not in enum list
"coordinates": {
"longitude": 116.3833,
"latitude": 39.9167
}
}
# Validate
result = self.validator.validate(invalid_data, self.well_schema)
# Assert
self.assertFalse(result.is_valid)
self.assertTrue(any("enum" in error for error in result.errors))
def test_invalid_number_range(self):
"""Test number out of range"""
# Data with longitude out of range
invalid_data = {
"wellName": "Test Well-01",
"wellID": "W0123456789",
"status": "active",
"coordinates": {
"longitude": 200.0, # Outside [-180, 180] range
"latitude": 39.9167
}
}
# Validate
result = self.validator.validate(invalid_data, self.well_schema)
# Assert
self.assertFalse(result.is_valid)
self.assertTrue(any("maximum" in error for error in result.errors))
def test_validate_with_rule(self):
"""Test validation using rule object"""
# Valid test data
valid_data = {
"wellName": "Test Well-01",
"wellID": "W0123456789",
"status": "active",
"coordinates": {
"longitude": 116.3833,
"latitude": 39.9167
}
}
# Validate using rule object
result = self.validator.validate_with_rule(valid_data, self.schema_rule)
# Assert
self.assertTrue(result.is_valid)
self.assertEqual(len(result.errors), 0)
def test_additional_properties(self):
"""Test handling of additional properties"""
# Create a schema that prohibits additional properties
strict_schema = dict(self.well_schema)
strict_schema["additionalProperties"] = False
# Data with extra property
data_with_extra = {
"wellName": "Test Well-01",
"wellID": "W0123456789",
"status": "active",
"coordinates": {
"longitude": 116.3833,
"latitude": 39.9167
},
"extra_field": "Extra Field" # Extra field
}
# Validate
result = self.validator.validate(data_with_extra, strict_schema)
# Assert
self.assertFalse(result.is_valid)
self.assertTrue(any("additionalProperties" in error for error in result.errors))
if __name__ == "__main__":
unittest.main()