add validation tests for observation schema

This commit is contained in:
phernandez
2024-12-25 12:33:59 -06:00
parent f213ad5efa
commit fd723164ca
2 changed files with 130 additions and 1 deletions
+28 -1
View File
@@ -69,7 +69,20 @@ def validate_path_format(path: str) -> str:
return path
class ObservationCategory(str, Enum):
"""Categories for structuring observations.
Categories help organize knowledge and make it easier to find later:
- tech: Implementation details and technical notes
- design: Architecture decisions and patterns
- feature: User-facing capabilities
- note: General observations (default)
- issue: Problems or concerns
- todo: Future work items
Categories are case-insensitive for easier use.
"""
TECH = "tech"
DESIGN = "design"
FEATURE = "feature"
@@ -77,10 +90,24 @@ class ObservationCategory(str, Enum):
ISSUE = "issue"
TODO = "todo"
@classmethod
def _missing_(cls, value: str) -> "ObservationCategory":
"""Handle case-insensitive lookup."""
try:
return cls(value.lower())
except ValueError:
return None
PathId = Annotated[str, BeforeValidator(to_snake_case), BeforeValidator(validate_path_format)]
"""Unique identifier in format '{path}/{normalized_name}'."""
Observation = Annotated[str, MinLen(1), MaxLen(1000)]
Observation = Annotated[
str,
BeforeValidator(str.strip), # Clean whitespace
MinLen(1), # Ensure non-empty after stripping
MaxLen(1000) # Keep reasonable length
]
"""A single piece of information about an entity. Must be non-empty and under 1000 characters.
Best Practices:
+102
View File
@@ -0,0 +1,102 @@
"""Tests for observation schema validation and categories."""
import pytest
from pydantic import ValidationError
from basic_memory.schemas import ObservationResponse
from basic_memory.schemas.base import ObservationCategory
from basic_memory.schemas.request import ObservationCreate
def test_observation_create_minimal():
"""Test creating ObservationCreate with minimal fields."""
data = {"content": "Test observation"}
obs = ObservationCreate.model_validate(data)
assert obs.content == "Test observation"
assert obs.category == ObservationCategory.NOTE # Default category
def test_observation_create_complete():
"""Test creating ObservationCreate with all fields."""
data = {"content": "Test observation", "category": "tech", "context": "Test context"}
obs = ObservationCreate.model_validate(data)
assert obs.content == "Test observation"
assert obs.category == ObservationCategory.TECH
def test_observation_create_category_validation():
"""Test category validation in ObservationCreate."""
# Valid categories
for category in ObservationCategory:
data = {"content": "Test", "category": category.value}
obs = ObservationCreate.model_validate(data)
assert obs.category == category
# Invalid category
with pytest.raises(ValidationError):
ObservationCreate.model_validate({"content": "Test", "category": "invalid_category"})
def test_observation_response():
"""Test ObservationResponse validation and conversion."""
data = {
"id": 1,
"path_id": 1,
"content": "Test observation",
"category": "tech",
"context": "Test context",
"created_at": "2024-12-25T12:00:00",
"updated_at": "2024-12-25T12:00:00",
}
obs = ObservationResponse.model_validate(data)
assert obs.content == "Test observation"
assert obs.category == ObservationCategory.TECH
assert obs.context == "Test context"
def test_observation_create_empty_content():
"""Test validation of empty content."""
with pytest.raises(ValidationError):
ObservationCreate.model_validate({"content": "", "category": "tech"})
with pytest.raises(ValidationError):
ObservationCreate.model_validate(
{
"content": " ", # Just whitespace
"category": "tech",
}
)
def test_observation_create_content_length():
"""Test content length validation."""
# Create string just over max length
long_content = "x" * 1001
with pytest.raises(ValidationError):
ObservationCreate.model_validate({"content": long_content, "category": "tech"})
def test_observation_category_coercion():
"""Test category accepts both string and enum."""
# Test with string
obs1 = ObservationCreate.model_validate({"content": "Test", "category": "tech"})
assert obs1.category == ObservationCategory.TECH
# Test with enum
obs2 = ObservationCreate.model_validate(
{"content": "Test", "category": ObservationCategory.TECH}
)
assert obs2.category == ObservationCategory.TECH
# Both should be equal
assert obs1.category == obs2.category
def test_observation_category_case_insensitive():
"""Test category validation is case insensitive."""
variations = ["TECH", "tech", "Tech", "TEcH"]
for variant in variations:
obs = ObservationCreate.model_validate({"content": "Test", "category": variant})
assert obs.category == ObservationCategory.TECH