Skip to content

Commit 10a4369

Browse files
committed
feat(tests): add comprehensive test suite and coverage
* Implement unit tests for utility functions * Add validation tests for input constraints * Create integration tests for SQLiteVecClient operations * Establish security tests for SQL injection prevention * Configure pytest with coverage reporting * Update README and TESTING.md with testing instructions
1 parent ef5cad5 commit 10a4369

File tree

13 files changed

+1021
-135
lines changed

13 files changed

+1021
-135
lines changed

.coveragerc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[run]
2+
source = sqlite_vec_client
3+
omit =
4+
*/tests/*
5+
*/test_*.py
6+
*/__pycache__/*
7+
*/site-packages/*
8+
9+
[report]
10+
exclude_lines =
11+
pragma: no cover
12+
def __repr__
13+
raise AssertionError
14+
raise NotImplementedError
15+
if __name__ == .__main__.:
16+
if TYPE_CHECKING:
17+
@abstractmethod

.vscode/settings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"python.testing.pytestArgs": [
3+
"tests"
4+
],
5+
"python.testing.unittestEnabled": false,
6+
"python.testing.pytestEnabled": true
7+
}

README.md

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,26 +62,81 @@ client.close()
6262
## How it works
6363
`SQLiteVecClient` stores data in `{table}` and mirrors embeddings in `{table}_vec` (a `vec0` virtual table). SQLite triggers keep both in sync when rows are inserted, updated, or deleted. Embeddings are serialized as packed float32 bytes for compact storage.
6464

65+
## Testing
66+
67+
The project has comprehensive test coverage (91%+) with 75 tests covering:
68+
- Unit tests for utilities and validation
69+
- Integration tests for all client operations
70+
- Security tests for SQL injection prevention
71+
- Edge cases and error handling
72+
73+
See [TESTING.md](TESTING.md) for detailed testing documentation.
74+
6575
## Development
6676

77+
### Setup
78+
6779
Install development dependencies:
6880
```bash
6981
pip install -r requirements-dev.txt
7082
pre-commit install
7183
```
7284

73-
Run tests:
85+
### Testing
86+
87+
The project uses pytest with comprehensive test coverage (89%+).
88+
89+
**Run all tests:**
7490
```bash
75-
pytest --cov=sqlite_vec_client
91+
pytest
7692
```
7793

78-
Format and lint:
94+
**Run with verbose output:**
95+
```bash
96+
pytest -v
97+
```
98+
99+
**Run specific test categories:**
100+
```bash
101+
pytest -m unit # Unit tests only
102+
pytest -m integration # Integration tests only
103+
```
104+
105+
**Run with coverage report:**
106+
```bash
107+
pytest --cov=sqlite_vec_client --cov-report=html
108+
```
109+
110+
**Run specific test file:**
111+
```bash
112+
pytest tests/test_client.py
113+
pytest tests/test_validation.py
114+
pytest tests/test_security.py
115+
pytest tests/test_utils.py
116+
```
117+
118+
### Code Quality
119+
120+
**Format code:**
79121
```bash
80-
ruff check .
81122
ruff format .
123+
```
124+
125+
**Lint code:**
126+
```bash
127+
ruff check .
128+
```
129+
130+
**Type checking:**
131+
```bash
82132
mypy sqlite_vec_client/
83133
```
84134

135+
**Run all quality checks:**
136+
```bash
137+
ruff check . && ruff format . && mypy sqlite_vec_client/ && pytest
138+
```
139+
85140
## Contributing
86141
Contributions are very welcome—issues, ideas, and PRs help this project grow!
87142

TESTING.md

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# Testing Guide
2+
3+
This document provides comprehensive information about testing sqlite-vec-client.
4+
5+
## Test Structure
6+
7+
```
8+
tests/
9+
├── __init__.py # Test package initialization
10+
├── conftest.py # Pytest fixtures and configuration
11+
├── test_utils.py # Unit tests for utility functions
12+
├── test_validation.py # Unit tests for validation functions
13+
├── test_security.py # Security tests (SQL injection, validation)
14+
└── test_client.py # Integration tests for SQLiteVecClient
15+
```
16+
17+
## Test Categories
18+
19+
### Unit Tests
20+
Tests for individual functions and modules in isolation.
21+
22+
**Markers:** `@pytest.mark.unit`
23+
24+
**Files:**
25+
- `test_utils.py` - Tests for serialization/deserialization functions
26+
- `test_validation.py` - Tests for input validation functions
27+
- `test_security.py` - Security tests for SQL injection prevention and input validation
28+
29+
**Run unit tests only:**
30+
```bash
31+
pytest -m unit
32+
```
33+
34+
### Integration Tests
35+
Tests for complete workflows and client operations.
36+
37+
**Markers:** `@pytest.mark.integration`
38+
39+
**Files:**
40+
- `test_client.py` - Tests for SQLiteVecClient methods
41+
42+
**Run integration tests only:**
43+
```bash
44+
pytest -m integration
45+
```
46+
47+
## Fixtures
48+
49+
Common fixtures available in `conftest.py`:
50+
51+
- **temp_db**: Provides a temporary database file path
52+
- **client**: Provides a SQLiteVecClient instance with temp database
53+
- **client_with_table**: Provides a client with table already created (dim=3)
54+
- **sample_embeddings**: 3D sample embeddings for testing
55+
- **sample_texts**: Sample text strings
56+
- **sample_metadata**: Sample metadata dictionaries
57+
58+
**Example usage:**
59+
```python
60+
def test_example(client_with_table, sample_texts, sample_embeddings):
61+
rowids = client_with_table.add(texts=sample_texts, embeddings=sample_embeddings)
62+
assert len(rowids) == 3
63+
```
64+
65+
## Running Tests
66+
67+
### Basic Commands
68+
69+
```bash
70+
# Run all tests
71+
pytest
72+
73+
# Run with verbose output
74+
pytest -v
75+
76+
# Run specific test file
77+
pytest tests/test_client.py
78+
79+
# Run specific test class
80+
pytest tests/test_client.py::TestAddRecords
81+
82+
# Run specific test method
83+
pytest tests/test_client.py::TestAddRecords::test_add_single_record
84+
```
85+
86+
### Coverage Reports
87+
88+
```bash
89+
# Run with coverage (terminal output)
90+
pytest --cov=sqlite_vec_client
91+
92+
# Generate HTML coverage report
93+
pytest --cov=sqlite_vec_client --cov-report=html
94+
95+
# Generate XML coverage report (for CI)
96+
pytest --cov=sqlite_vec_client --cov-report=xml
97+
98+
# Show missing lines
99+
pytest --cov=sqlite_vec_client --cov-report=term-missing
100+
```
101+
102+
View HTML coverage report:
103+
```bash
104+
# Open htmlcov/index.html in your browser
105+
```
106+
107+
### Test Markers
108+
109+
```bash
110+
# Run only unit tests
111+
pytest -m unit
112+
113+
# Run only integration tests
114+
pytest -m integration
115+
116+
# Run slow tests
117+
pytest -m slow
118+
119+
# Exclude slow tests
120+
pytest -m "not slow"
121+
```
122+
123+
## Writing Tests
124+
125+
### Test Naming Convention
126+
127+
- Test files: `test_*.py`
128+
- Test classes: `Test*`
129+
- Test functions: `test_*`
130+
131+
### Example Test
132+
133+
```python
134+
import pytest
135+
from sqlite_vec_client import SQLiteVecClient
136+
137+
@pytest.mark.integration
138+
class TestMyFeature:
139+
"""Tests for my feature."""
140+
141+
def test_basic_functionality(self, client_with_table):
142+
"""Test basic functionality."""
143+
# Arrange
144+
texts = ["test"]
145+
embeddings = [[1.0, 2.0, 3.0]]
146+
147+
# Act
148+
rowids = client_with_table.add(texts=texts, embeddings=embeddings)
149+
150+
# Assert
151+
assert len(rowids) == 1
152+
assert client_with_table.count() == 1
153+
```
154+
155+
### Testing Exceptions
156+
157+
```python
158+
def test_invalid_input(self, client):
159+
"""Test that invalid input raises error."""
160+
with pytest.raises(ValidationError, match="positive integer"):
161+
client.create_table(dim=0)
162+
```
163+
164+
## Coverage Goals
165+
166+
- **Target:** 80%+ overall coverage
167+
- **Current:** 91% coverage
168+
- **Critical paths:** 100% coverage for validation and security functions
169+
170+
## Continuous Integration
171+
172+
Tests are automatically run on:
173+
- Every commit (via pre-commit hooks)
174+
- Pull requests (via GitHub Actions)
175+
- Before releases
176+
177+
## Troubleshooting
178+
179+
### Common Issues
180+
181+
**Issue:** Tests fail with "no such table" error
182+
```
183+
Solution: Ensure client_with_table fixture is used for tests requiring a table
184+
```
185+
186+
**Issue:** Coverage report not generated
187+
```
188+
Solution: Install pytest-cov: pip install pytest-cov
189+
```
190+
191+
**Issue:** Tests hang or timeout
192+
```
193+
Solution: Check for unclosed database connections, use fixtures properly
194+
```
195+
196+
## Best Practices
197+
198+
1. **Use fixtures** for common setup/teardown
199+
2. **Test one thing** per test function
200+
3. **Use descriptive names** for test functions
201+
4. **Add docstrings** to explain what is being tested
202+
5. **Test edge cases** (empty lists, None values, invalid inputs)
203+
6. **Clean up resources** (fixtures handle this automatically)
204+
7. **Mock external dependencies** when appropriate
205+
206+
## Performance Testing
207+
208+
For performance-critical operations, use the `@pytest.mark.slow` marker:
209+
210+
```python
211+
@pytest.mark.slow
212+
def test_large_batch_insert(client_with_table):
213+
"""Test inserting 10,000 records."""
214+
texts = [f"text_{i}" for i in range(10000)]
215+
embeddings = [[0.1, 0.2, 0.3] for _ in range(10000)]
216+
rowids = client_with_table.add(texts=texts, embeddings=embeddings)
217+
assert len(rowids) == 10000
218+
```
219+
220+
Run without slow tests:
221+
```bash
222+
pytest -m "not slow"
223+
```

TODO

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
## 🟡 High Priority (Quality & Reliability)
1717

1818
### Test Suite
19-
- [ ] Setup pytest and configuration
20-
- [ ] Unit tests (utils, types)
21-
- [ ] Integration tests (SQLiteVecClient)
22-
- [ ] Edge case tests
23-
- [ ] Create fixtures
24-
- [ ] Target 80%+ test coverage
19+
- [x] Setup pytest and configuration
20+
- [x] Unit tests (utils, types)
21+
- [x] Integration tests (SQLiteVecClient)
22+
- [x] Edge case tests
23+
- [x] Create fixtures
24+
- [x] Target 80%+ test coverage
2525
- [ ] Mock tests (sqlite-vec extension)
2626

2727
### Examples

pytest.ini

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[pytest]
2+
testpaths = tests
3+
python_files = test_*.py
4+
python_classes = Test*
5+
python_functions = test_*
6+
addopts =
7+
--verbose
8+
--strict-markers
9+
--cov=sqlite_vec_client
10+
--cov-report=term-missing
11+
--cov-report=html
12+
--cov-report=xml
13+
--cov-branch
14+
markers =
15+
unit: Unit tests for individual functions/classes
16+
integration: Integration tests for full workflows
17+
slow: Tests that take longer to run

0 commit comments

Comments
 (0)