""" Unit tests for Information Space models. Tests the core domain models: InformationSpace, SpaceDocument, SpaceConfig, SpaceMetadata. """ import pytest from datetime import datetime from markitect.spaces.models import ( InformationSpace, SpaceDocument, SpaceConfig, SpaceMetadata, SpaceVariable, TransclusionReference, SpaceStatus, ) class TestSpaceMetadata: """Tests for SpaceMetadata dataclass.""" def test_default_metadata(self): """Test default metadata values.""" metadata = SpaceMetadata() assert metadata.tags == [] assert metadata.author is None assert metadata.custom == {} def test_metadata_with_values(self): """Test metadata with custom values.""" metadata = SpaceMetadata( tags=["api", "docs"], author="test-user", custom={"version": "1.0"} ) assert metadata.tags == ["api", "docs"] assert metadata.author == "test-user" assert metadata.custom["version"] == "1.0" def test_metadata_to_dict(self): """Test metadata serialization.""" metadata = SpaceMetadata(tags=["test"], author="user") data = metadata.to_dict() assert data["tags"] == ["test"] assert data["author"] == "user" def test_metadata_from_dict(self): """Test metadata deserialization.""" data = {"tags": ["api"], "author": "admin", "custom": {"key": "value"}} metadata = SpaceMetadata.from_dict(data) assert metadata.tags == ["api"] assert metadata.author == "admin" assert metadata.custom["key"] == "value" class TestSpaceConfig: """Tests for SpaceConfig dataclass.""" def test_default_config(self): """Test default configuration values.""" config = SpaceConfig() assert config.default_variant == "hierarchical" assert config.enable_caching is True assert config.theme is None assert config.history_enabled is False assert config.history_backend == "git" def test_config_with_history_enabled(self): """Test config with git history enabled.""" config = SpaceConfig(history_enabled=True, history_backend="git") assert config.history_enabled is True assert config.history_backend == "git" def test_config_to_dict(self): """Test config serialization.""" config = SpaceConfig(theme="dark", enable_caching=False) data = config.to_dict() assert data["theme"] == "dark" assert data["enable_caching"] is False def test_config_from_dict(self): """Test config deserialization.""" data = {"default_variant": "flat", "history_enabled": True} config = SpaceConfig.from_dict(data) assert config.default_variant == "flat" assert config.history_enabled is True class TestSpaceDocument: """Tests for SpaceDocument dataclass.""" def test_default_document(self): """Test default document values.""" doc = SpaceDocument() assert doc.id is not None assert doc.space_path == "" assert doc.order_index == 0 assert doc.metadata == {} def test_document_with_values(self): """Test document with custom values.""" doc = SpaceDocument( space_id="space-1", document_id="doc-1", space_path="/intro.md", order_index=1, content_hash="abc123" ) assert doc.space_id == "space-1" assert doc.space_path == "/intro.md" assert doc.content_hash == "abc123" def test_document_to_dict(self): """Test document serialization.""" doc = SpaceDocument(space_path="/test.md") data = doc.to_dict() assert data["space_path"] == "/test.md" assert "id" in data assert "added_at" in data def test_document_from_dict(self): """Test document deserialization.""" data = { "id": "doc-123", "space_id": "space-1", "space_path": "/api.md", "order_index": 5 } doc = SpaceDocument.from_dict(data) assert doc.id == "doc-123" assert doc.space_path == "/api.md" assert doc.order_index == 5 class TestInformationSpace: """Tests for InformationSpace dataclass.""" def test_space_requires_name(self): """Test that space name is required.""" with pytest.raises(ValueError, match="Space name is required"): InformationSpace(name="") def test_space_default_values(self): """Test default space values.""" space = InformationSpace(name="test-space") assert space.name == "test-space" assert space.id is not None assert space.status == SpaceStatus.DRAFT assert space.description is None assert space.parent_space_id is None def test_space_with_config(self): """Test space with custom config.""" config = SpaceConfig(theme="minimal", history_enabled=True) space = InformationSpace( name="docs", description="Documentation space", config=config ) assert space.config.theme == "minimal" assert space.config.history_enabled is True def test_space_activation(self): """Test space lifecycle transitions.""" space = InformationSpace(name="test") assert space.status == SpaceStatus.DRAFT space.activate() assert space.status == SpaceStatus.ACTIVE space.archive() assert space.status == SpaceStatus.ARCHIVED def test_space_touch_updates_timestamp(self): """Test that touch() updates the timestamp.""" space = InformationSpace(name="test") original_updated = space.updated_at import time time.sleep(0.01) # Small delay to ensure timestamp changes space.touch() assert space.updated_at >= original_updated def test_space_to_dict(self): """Test space serialization.""" space = InformationSpace( name="api-docs", description="API Documentation" ) data = space.to_dict() assert data["name"] == "api-docs" assert data["description"] == "API Documentation" assert data["status"] == "draft" assert "id" in data assert "created_at" in data def test_space_from_dict(self): """Test space deserialization.""" data = { "id": "space-123", "name": "my-space", "description": "Test space", "status": "active", "config": {"history_enabled": True}, "metadata": {"tags": ["test"]} } space = InformationSpace.from_dict(data) assert space.id == "space-123" assert space.name == "my-space" assert space.status == SpaceStatus.ACTIVE assert space.config.history_enabled is True assert space.metadata.tags == ["test"] def test_space_roundtrip_serialization(self): """Test that to_dict and from_dict are inverse operations.""" original = InformationSpace( name="roundtrip-test", description="Testing serialization", config=SpaceConfig(theme="dark", history_enabled=True), metadata=SpaceMetadata(tags=["test", "roundtrip"]) ) original.activate() data = original.to_dict() restored = InformationSpace.from_dict(data) assert restored.name == original.name assert restored.description == original.description assert restored.status == original.status assert restored.config.theme == original.config.theme assert restored.metadata.tags == original.metadata.tags class TestSpaceVariable: """Tests for SpaceVariable dataclass.""" def test_variable_creation(self): """Test variable creation.""" var = SpaceVariable( space_id="space-1", name="version", value="1.0.0" ) assert var.name == "version" assert var.value == "1.0.0" assert var.scope == "space" def test_variable_to_dict(self): """Test variable serialization.""" var = SpaceVariable( space_id="space-1", name="config", value={"key": "value"}, scope="document" ) data = var.to_dict() assert data["name"] == "config" assert data["scope"] == "document" class TestTransclusionReference: """Tests for TransclusionReference dataclass.""" def test_reference_creation(self): """Test transclusion reference creation.""" ref = TransclusionReference( source_doc_id="doc-1", target_doc_id="doc-2", space_id="space-1" ) assert ref.source_doc_id == "doc-1" assert ref.target_doc_id == "doc-2" assert ref.created_at is not None def test_reference_to_dict(self): """Test reference serialization.""" ref = TransclusionReference( source_doc_id="a", target_doc_id="b", space_id="s" ) data = ref.to_dict() assert "created_at" in data assert data["source_doc_id"] == "a" class TestSpaceStatus: """Tests for SpaceStatus enum.""" def test_status_values(self): """Test status enum values.""" assert SpaceStatus.DRAFT.value == "draft" assert SpaceStatus.ACTIVE.value == "active" assert SpaceStatus.ARCHIVED.value == "archived" assert SpaceStatus.DELETED.value == "deleted"