This document describes how to run tests and measure coverage for the Lash project.
Run all tests across the workspace:
cargo test --workspaceRun only unit tests (library tests):
cargo test --workspace --libRun integration tests for a specific crate:
cargo test -p lash-core --test '*'
cargo test -p lash-db --test '*'
cargo test -p lash --test '*'Run E2E tests that exercise the actual binary:
cargo test -p lash --test e2e_cli_testsRun documentation examples:
cargo test --workspace --docRun performance benchmarks:
cargo bench --workspaceSpecific benchmarks:
# Parser benchmarks
cargo bench -p lash-core --bench parser_bench
# Graph benchmarks
cargo bench -p lash-core --bench graph_bench
# Indexing benchmarks
cargo bench -p lash-db --bench indexing
# Search benchmarks
cargo bench -p lash-db --bench search_benchInstall cargo-llvm-cov:
cargo install cargo-llvm-covGenerate HTML coverage report:
cargo llvm-cov --workspace --htmlThis creates a report in target/llvm-cov/html/index.html. Open it in your browser:
open target/llvm-cov/html/index.htmlGet a text summary:
cargo llvm-cov --workspaceFor CI integration or editor plugins:
cargo llvm-cov --workspace --lcov --output-path lcov.infocargo llvm-cov -p lash-core --htmlCoverage is already configured to exclude:
- Test files (
tests/,benches/) - Generated code
- The binary entrypoint (
main.rs)
The project aims for:
- Overall: >80% line coverage
- Critical modules: >90% (parser, linter, dependency resolution)
- Less critical: >70% (TUI, agent utilities)
Unit tests are colocated with the code they test:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_something() {
// ...
}
}Integration tests are in tests/ directories:
crates/lash-cli/tests/- CLI integration testscrates/lash-core/tests/- Core integration testscrates/lash-db/tests/- Database integration tests
Test fixtures are in crates/lash-cli/tests/fixtures/:
valid/- Valid task files for positive testsinvalid/- Invalid task files for error testingrepos/- Complete project fixtures
Common test utilities are in:
crates/lash-cli/tests/common/mod.rs- Shared helpers
- Test one thing - Each test should verify one specific behavior
- Use descriptive names -
test_parse_task_with_labels()nottest1() - Arrange-Act-Assert - Structure tests clearly:
// Arrange - set up test data let input = "test data"; // Act - execute the code under test let result = parse(input); // Assert - verify the outcome assert_eq!(result.unwrap(), expected);
- Test error cases - Don't just test happy paths
- Avoid flakiness - Tests must be deterministic
- Keep tests fast - Unit tests should run in milliseconds
✅ Do test:
- Public API behavior
- Edge cases and boundary conditions
- Error handling and validation
- Integration between components
❌ Don't test:
- Standard library functions
- Third-party library behavior
- Implementation details
- Trivial getters/setters
All public APIs should have executable doctests:
/// Parse a task file from a string
///
/// ```
/// use lash_core::parser::parse_file_from_string;
/// use lash_types::LashConfig;
///
/// let content = "# Test\n\n## Tasks\n\n- [ ] Task 1\n";
/// let config = LashConfig::default();
/// let result = parse_file_from_string(content, &config);
///
/// assert!(result.is_ok());
/// ```
pub fn parse_file_from_string(content: &str, config: &LashConfig) -> Result<TaskFile> {
// ...
}Doctest Best Practices:
- All doctests should be runnable by default (
cargo test --doc) - Use
no_runonly for examples that need I/O or external resources - Hide boilerplate setup with
#prefix - Keep examples minimal and focused
Tests run automatically on every PR via GitHub Actions. See .github/workflows/ci.yml.
The CI pipeline:
- Runs all tests on Linux, macOS, and Windows
- Checks formatting with
rustfmt - Runs linter with
clippy - Measures test coverage
- Runs benchmarks (report only, doesn't fail)
Install pre-commit hooks to run tests before committing:
./scripts/install-pre-commit-hooks.shThis ensures:
- Tests pass
- Code is formatted
- No lint errors
- Check you're on the same Rust version:
rustc --version - Clear cache:
cargo clean - Update dependencies:
cargo update
- Ensure tests actually execute the code
- Check that files aren't excluded in coverage config
- Verify you're using
--workspaceflag
- Benchmarks require a nightly compiler feature (criterion uses stable)
- Install with:
cargo bench
Based on benchmarks, Lash should achieve:
- Parsing: >1000 tasks/sec
- Linting: >500 tasks/sec
- Full Index: <5s for 1000 files
- Incremental Index: <1s for 100 changed files
- Query: <100ms for typical filters
- Search: <200ms for typical queries
Run cargo bench to verify performance meets targets.