Skip to content

Commit 21657ff

Browse files
committed
tests: Refactor database types and improve test coverage
1 parent 4fb6d22 commit 21657ff

File tree

4 files changed

+70
-216
lines changed

4 files changed

+70
-216
lines changed

tests/subcommands/query/test_reranker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import pytest
66

77
from vectorcode.cli_utils import Config, QueryInclude
8+
from vectorcode.database.types import QueryResult
89
from vectorcode.subcommands.query.reranker import (
910
CrossEncoderReranker,
1011
NaiveReranker,
@@ -14,7 +15,6 @@
1415
get_available_rerankers,
1516
get_reranker,
1617
)
17-
from vectorcode.subcommands.query.types import QueryResult
1818

1919

2020
@pytest.fixture(scope="function")

tests/subcommands/query/test_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from tree_sitter import Point
33

44
from vectorcode.chunking import Chunk
5-
from vectorcode.subcommands.query.types import QueryResult
5+
from vectorcode.database.types import QueryResult
66

77

88
def make_dummy_chunk():

tests/subcommands/test_clean.py

Lines changed: 18 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,37 @@
11
from unittest.mock import AsyncMock, patch
22

33
import pytest
4-
from chromadb.api import AsyncClientAPI
54

65
from vectorcode.cli_utils import Config
7-
from vectorcode.subcommands.clean import clean, run_clean_on_client
6+
from vectorcode.subcommands.clean import clean
87

98

109
@pytest.mark.asyncio
11-
async def test_run_clean_on_client():
12-
mock_client = AsyncMock(spec=AsyncClientAPI)
13-
mock_collection1 = AsyncMock()
14-
mock_collection1.name = "test_collection_1"
15-
mock_collection1.metadata = {"path": "/test/path1"}
16-
mock_collection1.count.return_value = 0 # Empty collection
17-
mock_collection2 = AsyncMock()
18-
mock_collection2.name = "test_collection_2"
19-
mock_collection2.metadata = {"path": "/test/path2"}
20-
mock_collection2.count.return_value = 1 # Non-empty collection
21-
22-
async def mock_get_collections(client):
23-
yield mock_collection1
24-
yield mock_collection2
25-
26-
with (
27-
patch("vectorcode.subcommands.clean.get_collections", new=mock_get_collections),
28-
patch("os.path.isdir", return_value=lambda x: x == "/test/path2"),
29-
):
30-
await run_clean_on_client(mock_client, pipe_mode=False)
31-
32-
mock_client.delete_collection.assert_called_once_with(mock_collection1.name)
33-
34-
35-
@pytest.mark.asyncio
36-
async def test_run_clean_on_client_pipe_mode():
37-
mock_client = AsyncMock(spec=AsyncClientAPI)
38-
mock_collection1 = AsyncMock()
39-
mock_collection1.name = "test_collection_1"
40-
mock_collection1.metadata = {"path": "/test/path1"}
41-
mock_collection1.count.return_value = 0 # Empty collection
42-
43-
async def mock_get_collections(client):
44-
yield mock_collection1
10+
async def test_clean(capsys):
11+
mock_db = AsyncMock()
12+
mock_db.cleanup.return_value = ["/test/path1", "/test/path2"]
4513

4614
with patch(
47-
"vectorcode.subcommands.clean.get_collections", new=mock_get_collections
15+
"vectorcode.subcommands.clean.get_database_connector", return_value=mock_db
4816
):
49-
await run_clean_on_client(mock_client, pipe_mode=True)
17+
result = await clean(Config(pipe=False))
5018

51-
mock_client.delete_collection.assert_called_once_with(mock_collection1.name)
19+
assert result == 0
20+
captured = capsys.readouterr()
21+
assert "Deleted collection: /test/path1" in captured.out
22+
assert "Deleted collection: /test/path2" in captured.out
5223

5324

5425
@pytest.mark.asyncio
55-
async def test_run_clean_on_removed_dir():
56-
mock_client = AsyncMock(spec=AsyncClientAPI)
57-
mock_collection1 = AsyncMock()
58-
mock_collection1.name = "test_collection_1"
59-
mock_collection1.metadata = {"path": "/test/path1"}
60-
mock_collection1.count.return_value = 10
61-
62-
async def mock_get_collections(client):
63-
yield mock_collection1
26+
async def test_clean_pipe_mode(capsys):
27+
mock_db = AsyncMock()
28+
mock_db.cleanup.return_value = ["/test/path1", "/test/path2"]
6429

65-
with (
66-
patch("vectorcode.subcommands.clean.get_collections", new=mock_get_collections),
67-
patch("os.path.isdir", return_value=False),
30+
with patch(
31+
"vectorcode.subcommands.clean.get_database_connector", return_value=mock_db
6832
):
69-
await run_clean_on_client(mock_client, pipe_mode=True)
70-
71-
mock_client.delete_collection.assert_called_once_with(mock_collection1.name)
72-
73-
74-
@pytest.mark.asyncio
75-
async def test_clean():
76-
AsyncMock(spec=AsyncClientAPI)
77-
mock_config = Config(pipe=False)
78-
79-
with patch("vectorcode.subcommands.clean.ClientManager"):
80-
result = await clean(mock_config)
33+
result = await clean(Config(pipe=True))
8134

8235
assert result == 0
36+
captured = capsys.readouterr()
37+
assert captured.out == ""

tests/subcommands/test_ls.py

Lines changed: 50 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,161 +1,70 @@
11
import json
2-
import socket
3-
from unittest.mock import AsyncMock, MagicMock, patch
2+
from unittest.mock import AsyncMock, patch
43

54
import pytest
65
import tabulate
76

87
from vectorcode.cli_utils import Config
9-
from vectorcode.subcommands.ls import get_collection_list, ls
10-
11-
12-
@pytest.mark.asyncio
13-
async def test_get_collection_list():
14-
mock_client = AsyncMock()
15-
mock_collection1 = AsyncMock()
16-
mock_collection1.name = "test_collection_1"
17-
mock_collection1.metadata = {
18-
"path": "/test/path1",
19-
"username": "test_user",
20-
"embedding_function": "test_ef",
21-
}
22-
mock_collection1.count.return_value = 100
23-
mock_collection1.get.return_value = {
24-
"metadatas": [
25-
{"path": "/test/path1/file1.txt"},
26-
{"path": "/test/path1/file2.txt"},
27-
None,
28-
]
29-
}
30-
mock_collection2 = AsyncMock()
31-
mock_collection2.name = "test_collection_2"
32-
mock_collection2.metadata = {
33-
"path": "/test/path2",
34-
"username": "test_user",
35-
"embedding_function": "test_ef",
36-
}
37-
mock_collection2.count.return_value = 200
38-
mock_collection2.get.return_value = {
39-
"metadatas": [
40-
{"path": "/test/path2/file1.txt"},
41-
{"path": "/test/path2/file2.txt"},
42-
]
43-
}
44-
45-
async def mock_get_collections(client):
46-
yield mock_collection1
47-
yield mock_collection2
48-
49-
with patch("vectorcode.subcommands.ls.get_collections", new=mock_get_collections):
50-
result = await get_collection_list(mock_client)
51-
52-
assert len(result) == 2
53-
assert result[0]["project-root"] == "/test/path1"
54-
assert result[0]["user"] == "test_user"
55-
assert result[0]["hostname"] == socket.gethostname()
56-
assert result[0]["collection_name"] == "test_collection_1"
57-
assert result[0]["size"] == 100
58-
assert result[0]["embedding_function"] == "test_ef"
59-
assert result[0]["num_files"] == 2
60-
assert result[1]["num_files"] == 2
8+
from vectorcode.database.types import CollectionInfo
9+
from vectorcode.subcommands.ls import ls
10+
11+
12+
@pytest.fixture
13+
def mock_collections():
14+
return [
15+
CollectionInfo(
16+
path="/test/path1",
17+
id="test_collection_1",
18+
chunk_count=100,
19+
file_count=2,
20+
embedding_function="test_ef",
21+
database_backend="ChromaDB",
22+
),
23+
CollectionInfo(
24+
path="/test/path2",
25+
id="test_collection_2",
26+
chunk_count=200,
27+
file_count=2,
28+
embedding_function="test_ef",
29+
database_backend="ChromaDB",
30+
),
31+
]
6132

6233

6334
@pytest.mark.asyncio
64-
async def test_ls_pipe_mode(capsys):
65-
mock_client = AsyncMock()
66-
mock_collection = AsyncMock()
67-
mock_collection.name = "test_collection"
68-
mock_collection.metadata = {
69-
"path": "/test/path",
70-
"username": "test_user",
71-
"embedding_function": "test_ef",
72-
}
73-
mock_collection.count.return_value = 50
74-
mock_collection.get.return_value = {"metadatas": [{"path": "/test/path/file.txt"}]}
75-
76-
async def mock_get_collections(client):
77-
yield mock_collection
78-
79-
with (
80-
patch("vectorcode.subcommands.ls.ClientManager") as MockClientManager,
81-
patch(
82-
"vectorcode.subcommands.ls.get_collection_list",
83-
return_value=[
84-
{
85-
"project-root": "/test/path",
86-
"size": 50,
87-
"num_files": 1,
88-
"embedding_function": "test_ef",
89-
}
90-
],
91-
),
35+
async def test_ls_pipe_mode(capsys, mock_collections):
36+
mock_db = AsyncMock()
37+
mock_db.list_collections.return_value = mock_collections
38+
with patch(
39+
"vectorcode.subcommands.ls.get_database_connector", return_value=mock_db
9240
):
93-
mock_client = MagicMock()
94-
mock_client_manager = MockClientManager.return_value
95-
mock_client_manager._create_client = AsyncMock(return_value=mock_client)
96-
9741
config = Config(pipe=True)
9842
await ls(config)
9943
captured = capsys.readouterr()
100-
expected_output = (
101-
json.dumps(
102-
[
103-
{
104-
"project-root": "/test/path",
105-
"size": 50,
106-
"num_files": 1,
107-
"embedding_function": "test_ef",
108-
}
109-
]
110-
)
111-
+ "\n"
112-
)
44+
expected_output = json.dumps([c.to_dict() for c in mock_collections]) + "\n"
11345
assert captured.out == expected_output
11446

11547

11648
@pytest.mark.asyncio
117-
async def test_ls_table_mode(capsys, monkeypatch):
118-
mock_client = AsyncMock()
119-
mock_collection = AsyncMock()
120-
mock_collection.name = "test_collection"
121-
mock_collection.metadata = {
122-
"path": "/test/path",
123-
"username": "test_user",
124-
"embedding_function": "test_ef",
125-
}
126-
mock_collection.count.return_value = 50
127-
mock_collection.get.return_value = {"metadatas": [{"path": "/test/path/file.txt"}]}
128-
129-
async def mock_get_collections(client):
130-
yield mock_collection
131-
132-
with (
133-
patch("vectorcode.subcommands.ls.ClientManager") as MockClientManager,
134-
patch(
135-
"vectorcode.subcommands.ls.get_collection_list",
136-
return_value=[
137-
{
138-
"project-root": "/test/path",
139-
"size": 50,
140-
"num_files": 1,
141-
"embedding_function": "test_ef",
142-
}
143-
],
144-
),
49+
async def test_ls_table_mode(capsys, mock_collections, monkeypatch):
50+
mock_db = AsyncMock()
51+
mock_db.list_collections.return_value = mock_collections
52+
with patch(
53+
"vectorcode.subcommands.ls.get_database_connector", return_value=mock_db
14554
):
146-
mock_client = MagicMock()
147-
mock_client_manager = MockClientManager.return_value
148-
mock_client_manager._create_client = AsyncMock(return_value=mock_client)
149-
15055
config = Config(pipe=False)
15156
await ls(config)
15257
captured = capsys.readouterr()
58+
expected_table = [
59+
["/test/path1", 100, 2, "test_ef"],
60+
["/test/path2", 200, 2, "test_ef"],
61+
]
15362
expected_output = (
15463
tabulate.tabulate(
155-
[["/test/path", 50, 1, "test_ef"]],
64+
expected_table,
15665
headers=[
15766
"Project Root",
158-
"Collection Size",
67+
"Number of Embeddings",
15968
"Number of Files",
16069
"Embedding Function",
16170
],
@@ -166,32 +75,22 @@ async def mock_get_collections(client):
16675

16776
# Test with HOME environment variable set
16877
monkeypatch.setenv("HOME", "/test")
169-
with (
170-
patch("vectorcode.subcommands.ls.ClientManager") as MockClientManager,
171-
patch(
172-
"vectorcode.subcommands.ls.get_collection_list",
173-
return_value=[
174-
{
175-
"project-root": "/test/path",
176-
"size": 50,
177-
"num_files": 1,
178-
"embedding_function": "test_ef",
179-
}
180-
],
181-
),
78+
with patch(
79+
"vectorcode.subcommands.ls.get_database_connector", return_value=mock_db
18280
):
183-
mock_client = MagicMock()
184-
mock_client_manager = MockClientManager.return_value
185-
mock_client_manager._create_client = AsyncMock(return_value=mock_client)
18681
config = Config(pipe=False)
18782
await ls(config)
18883
captured = capsys.readouterr()
84+
expected_table = [
85+
["~/path1", 100, 2, "test_ef"],
86+
["~/path2", 200, 2, "test_ef"],
87+
]
18988
expected_output = (
19089
tabulate.tabulate(
191-
[["~/path", 50, 1, "test_ef"]],
90+
expected_table,
19291
headers=[
19392
"Project Root",
194-
"Collection Size",
93+
"Number of Embeddings",
19594
"Number of Files",
19695
"Embedding Function",
19796
],

0 commit comments

Comments
 (0)