tests: improved coverage to 97%
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
"""Behave steps for context manager coverage."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from behave import given, then, when
|
||||
|
||||
from cleveragents.reactive.context_manager import ContextManager
|
||||
|
||||
|
||||
def _write_json(path: Path, data: object) -> None:
|
||||
path.write_text(json.dumps(data), encoding="utf-8")
|
||||
|
||||
|
||||
@given("a context manager storage directory with valid JSON files")
|
||||
def step_valid_storage_directory(context):
|
||||
temp_dir = Path(tempfile.mkdtemp())
|
||||
context.context_name = "valid_context"
|
||||
context.temp_dir = temp_dir
|
||||
context.context_root = temp_dir / context.context_name
|
||||
context.context_root.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
context.expected_messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "hello",
|
||||
"timestamp": "2024-01-01T00:00:00",
|
||||
"metadata": {},
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "hi",
|
||||
"timestamp": "2024-01-01T00:00:01",
|
||||
"metadata": {"tone": "friendly"},
|
||||
},
|
||||
]
|
||||
context.expected_metadata = {
|
||||
"created_at": "2024-01-01T00:00:00",
|
||||
"last_updated": "2024-01-02T00:00:00",
|
||||
"context_name": context.context_name,
|
||||
}
|
||||
context.expected_state = {"stage": "draft"}
|
||||
context.expected_global = {"topic": "coverage"}
|
||||
|
||||
_write_json(context.context_root / "messages.json", context.expected_messages)
|
||||
_write_json(context.context_root / "metadata.json", context.expected_metadata)
|
||||
_write_json(context.context_root / "state.json", context.expected_state)
|
||||
_write_json(context.context_root / "global_context.json", context.expected_global)
|
||||
|
||||
|
||||
@given("a context manager storage directory with invalid JSON files")
|
||||
def step_invalid_storage_directory(context):
|
||||
temp_dir = Path(tempfile.mkdtemp())
|
||||
context.context_name = "invalid_context"
|
||||
context.temp_dir = temp_dir
|
||||
context.context_root = temp_dir / context.context_name
|
||||
context.context_root.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for filename in (
|
||||
"messages.json",
|
||||
"metadata.json",
|
||||
"state.json",
|
||||
"global_context.json",
|
||||
):
|
||||
(context.context_root / filename).write_text("{", encoding="utf-8")
|
||||
|
||||
|
||||
@when("I initialize the context manager from that directory")
|
||||
def step_initialize_context_manager(context):
|
||||
context.manager = ContextManager(context.context_name, context_dir=context.temp_dir)
|
||||
|
||||
|
||||
@then("the stored context data should be loaded")
|
||||
def step_verify_loaded_context(context):
|
||||
assert context.manager.messages == context.expected_messages
|
||||
assert context.manager.metadata == context.expected_metadata
|
||||
assert context.manager.state == context.expected_state
|
||||
assert context.manager.global_context == context.expected_global
|
||||
|
||||
|
||||
@then("invalid context files should load as empty defaults")
|
||||
def step_verify_invalid_defaults(context):
|
||||
assert context.manager.messages == []
|
||||
assert context.manager.metadata == {}
|
||||
assert context.manager.state == {}
|
||||
assert context.manager.global_context == {}
|
||||
|
||||
|
||||
@given("a temporary home directory for the context manager")
|
||||
def step_temporary_home(context):
|
||||
context.temp_home = Path(tempfile.mkdtemp())
|
||||
context.context_name = "home_context"
|
||||
|
||||
|
||||
@when("I initialize the context manager without a context directory")
|
||||
def step_initialize_default_context(context):
|
||||
with patch("pathlib.Path.home", return_value=context.temp_home):
|
||||
context.manager = ContextManager(context.context_name)
|
||||
|
||||
|
||||
@then("the context manager should use the default home context path")
|
||||
def step_verify_default_path(context):
|
||||
expected = context.temp_home / ".cleveragents" / "context" / context.context_name
|
||||
assert context.manager.context_dir == expected
|
||||
assert context.manager.context_dir.exists()
|
||||
|
||||
|
||||
@then("deleting the context should remove the directory")
|
||||
def step_verify_delete(context):
|
||||
context.manager.delete()
|
||||
assert not context.manager.context_dir.exists()
|
||||
|
||||
|
||||
@given("a context manager for state and metadata updates")
|
||||
def step_state_metadata_manager(context):
|
||||
context.temp_dir = Path(tempfile.mkdtemp())
|
||||
context.context_name = "state_meta_context"
|
||||
context.manager = ContextManager(context.context_name, context_dir=context.temp_dir)
|
||||
|
||||
|
||||
@when("I update state and metadata in the context manager")
|
||||
def step_update_state_metadata(context):
|
||||
context.manager.update_state("mode", "active")
|
||||
context.manager.update_metadata({"owner": "qa"})
|
||||
context.state_value = context.manager.get_state("mode")
|
||||
context.default_state = context.manager.get_state("missing", "default")
|
||||
context.exists_value = context.manager.exists()
|
||||
|
||||
|
||||
@then("the context manager should return the updated values")
|
||||
def step_verify_updated_values(context):
|
||||
assert context.state_value == "active"
|
||||
assert context.default_state == "default"
|
||||
assert context.manager.metadata["owner"] == "qa"
|
||||
|
||||
|
||||
@then("the context should report it exists on disk")
|
||||
def step_verify_exists(context):
|
||||
assert context.exists_value is True
|
||||
|
||||
|
||||
@given("a context manager with stored messages")
|
||||
def step_context_with_messages(context):
|
||||
context.temp_dir = Path(tempfile.mkdtemp())
|
||||
context.context_name = "message_context"
|
||||
context.manager = ContextManager(context.context_name, context_dir=context.temp_dir)
|
||||
context.manager.add_message("user", "Hello")
|
||||
context.manager.add_message("assistant", "Hi")
|
||||
context.manager.update_state("counter", 2)
|
||||
context.manager.global_context = {"mode": "chat"}
|
||||
|
||||
|
||||
@when("I request the last message and clear the context")
|
||||
def step_last_message_and_clear(context):
|
||||
context.last_messages = context.manager.get_last_n_messages(1)
|
||||
context.manager.clear()
|
||||
|
||||
|
||||
@then("the last message should be returned and the context reset")
|
||||
def step_verify_last_and_clear(context):
|
||||
assert len(context.last_messages) == 1
|
||||
assert context.last_messages[0]["role"] == "assistant"
|
||||
assert context.manager.messages == []
|
||||
assert context.manager.state == {}
|
||||
assert context.manager.global_context == {}
|
||||
assert context.manager.metadata["context_name"] == context.context_name
|
||||
assert "created_at" in context.manager.metadata
|
||||
assert "last_updated" in context.manager.metadata
|
||||
|
||||
|
||||
@given("a context manager with exportable data")
|
||||
def step_exportable_context(context):
|
||||
context.temp_dir = Path(tempfile.mkdtemp())
|
||||
context.context_name = "export_context"
|
||||
context.manager = ContextManager(context.context_name, context_dir=context.temp_dir)
|
||||
context.manager.add_message("user", "Export this")
|
||||
context.manager.update_state("flag", True)
|
||||
context.manager.global_context = {"mode": "full"}
|
||||
context.manager.metadata["tag"] = "export"
|
||||
context.export_file = context.temp_dir / "exports" / "context.json"
|
||||
|
||||
|
||||
@when("I export and import the context")
|
||||
def step_export_import_context(context):
|
||||
context.manager.export_context(context.export_file)
|
||||
context.import_manager = ContextManager(
|
||||
"import_context", context_dir=context.temp_dir
|
||||
)
|
||||
context.import_manager.import_context(context.export_file)
|
||||
|
||||
|
||||
@then("the imported context should match the exported data")
|
||||
def step_verify_imported_data(context):
|
||||
assert context.export_file.exists()
|
||||
assert context.import_manager.messages == context.manager.messages
|
||||
assert context.import_manager.state == context.manager.state
|
||||
assert context.import_manager.global_context == context.manager.global_context
|
||||
assert (
|
||||
context.import_manager.metadata["context_name"]
|
||||
== context.manager.metadata["context_name"]
|
||||
)
|
||||
assert context.import_manager.metadata.get("tag") == "export"
|
||||
Reference in New Issue
Block a user