"""Tests for document management commands via Click test runner.""" import json import pytest from click.testing import CliRunner from kb_search.cli import main from kb_search.database import ( SCHEMA_VERSION, get_connection, init_schema, insert_chunk, insert_document, insert_embedding, set_db_config, tag_document, ) @pytest.fixture def kb_env(tmp_path, monkeypatch): """Set up a test KB environment.""" data_dir = tmp_path / ".kb" data_dir.mkdir() db_path = data_dir / "kb.db" conn = get_connection(db_path) init_schema(conn, 384) set_db_config(conn, "schema_version", str(SCHEMA_VERSION)) set_db_config(conn, "model_name", "all-MiniLM-L6-v2") set_db_config(conn, "embedding_dim", "384") # Add a test document doc_id = insert_document(conn, "Test Doc", "/tmp/test.pdf", "abc123", "pdf") insert_chunk(conn, doc_id, 0, "This is chunk zero about Python") insert_chunk(conn, doc_id, 1, "This is chunk one about testing") tag_document(conn, doc_id, ["test", "pdf"]) conn.commit() conn.close() monkeypatch.setenv("KB_DATA_DIR", str(data_dir)) return data_dir class TestList: def test_json_output(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["list", "--format", "json"]) assert result.exit_code == 0 data = json.loads(result.output) assert len(data) == 1 assert data[0]["title"] == "Test Doc" assert data[0]["type"] == "pdf" def test_human_output(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["list", "--format", "human"]) assert result.exit_code == 0 assert "Test Doc" in result.output def test_filter_type(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["list", "--type", "markdown", "--format", "json"]) assert result.exit_code == 0 data = json.loads(result.output) assert len(data) == 0 def test_filter_tags(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["list", "--tags", "test", "--format", "json"]) assert result.exit_code == 0 data = json.loads(result.output) assert len(data) == 1 class TestInfo: def test_json_output(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["info", "1", "--format", "json"]) assert result.exit_code == 0 data = json.loads(result.output) assert data["title"] == "Test Doc" assert data["chunk_count"] == 2 assert "test" in data["tags"] def test_not_found(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["info", "999"]) assert result.exit_code != 0 assert "not found" in result.output.lower() class TestRemove: def test_remove_with_yes(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["remove", "1", "--yes"]) assert result.exit_code == 0 assert "Removed" in result.output # Verify gone result = runner.invoke(main, ["list", "--format", "json"]) data = json.loads(result.output) assert len(data) == 0 def test_remove_not_found(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["remove", "999", "--yes"]) assert result.exit_code != 0 class TestTags: def test_list_tags(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["tags", "--format", "json"]) assert result.exit_code == 0 data = json.loads(result.output) names = [t["name"] for t in data] assert "test" in names assert "pdf" in names def test_add_tag(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["tag", "1", "--add", "new"]) assert result.exit_code == 0 assert "Added" in result.output def test_remove_tag(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["tag", "1", "--remove", "test"]) assert result.exit_code == 0 assert "Removed" in result.output class TestStatus: def test_json_output(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["status", "--format", "json"]) assert result.exit_code == 0 data = json.loads(result.output) assert data["model_name"] == "all-MiniLM-L6-v2" assert data["total_documents"] == 1 assert data["total_chunks"] == 2 def test_human_output(self, kb_env): runner = CliRunner() result = runner.invoke(main, ["status", "--format", "human"]) assert result.exit_code == 0 assert "all-MiniLM-L6-v2" in result.output def test_not_initialised(self, tmp_path, monkeypatch): monkeypatch.setenv("KB_DATA_DIR", str(tmp_path / "nonexistent")) runner = CliRunner() result = runner.invoke(main, ["status"]) assert result.exit_code != 0 assert "not initialised" in result.output.lower()