Skip to content

Commit 4e992cc

Browse files
committed
feat: implement integration tests for sources args
1 parent e06006c commit 4e992cc

File tree

16 files changed

+616
-105
lines changed

16 files changed

+616
-105
lines changed

.dev/27-integration-tests-revamp-plan.md

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -131,18 +131,25 @@ tests/integration_tests/version/
131131
- Directory structure created successfully
132132
- Ready for Phase 2 implementation
133133

134-
#### Phase 2: Implement Main Config Tests (`main/`)
135-
136-
- Create `tests/integration_tests/version/main/mod.rs`
137-
- Implement individual MainConfig tests:
138-
- `sources/`: git vs stdin (≤3 git tests)
139-
- `formats.rs`: --input-format, --output-format individually
140-
- `schemas.rs`: --schema, --schema-ron individually
141-
- `templates.rs`: --output-template individually
142-
- `directory.rs`: -C flag individually
143-
- `combinations.rs`: MainConfig option combinations
144-
- Use direct imports: `use zerv::test_utils::{ZervFixture, GitRepoFixture};`
145-
- Test and validate main config functionality
134+
#### Phase 2: Implement Main Config Tests (`main/`) 🔄 IN PROGRESS
135+
136+
- ✅ Created `tests/integration_tests/version/main/mod.rs`
137+
- ✅ Implemented `sources/` tests:
138+
- `sources/stdin.rs`: 6 stdin tests using `ZervFixture` with `TestCommand.stdin()` (✅ PASSED)
139+
- `sources/git.rs`: 1 comprehensive git integration test with Docker gating (✅ PASSED)
140+
- ✅ Enhanced `TestCommand` with `.stdin()` support for cleaner testing
141+
- ✅ Refactored tests to use `rstest` for cleaner parameterized testing
142+
- ✅ Enhanced `ZervFixture.with_vcs_data()` to accept `Option` types for better flexibility
143+
- **Result**: 7 tests passing (100% success rate)
144+
- **Performance**: Tests run in <0.3 seconds without Docker
145+
146+
**Remaining MainConfig Tests:**
147+
148+
- ❌ `formats.rs`: Test `--input-format` (semver/pep440/zerv) and `--output-format` (semver/pep440/zerv) combinations
149+
- ❌ `schemas.rs`: Test `--schema` (tier1/tier2/tier3) and `--schema-ron` (custom RON schema) options
150+
- ❌ `templates.rs`: Test `--output-template` with Handlebars template rendering
151+
- ❌ `directory.rs`: Test `-C` flag for changing working directory before execution
152+
- ❌ `combinations.rs`: Test MainConfig option combinations (format + schema, template + format, etc.)
146153
147154
#### Phase 3: Implement Override Tests (`overrides/`)
148155

CLAUDE.md

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
Zerv is a dynamic versioning CLI tool written in Rust that generates versions for any commit from git and other version control systems. It supports multiple version formats (SemVer, PEP440, CalVer) and is designed for CI/CD builds.
8+
9+
## Essential Commands
10+
11+
### Development Setup
12+
13+
```bash
14+
make setup_dev # Install pre-commit hooks and cargo-tarpaulin
15+
```
16+
17+
### Testing
18+
19+
```bash
20+
make test_easy # Quick tests: Docker Git + Docker tests skipped (fast, coverage gaps)
21+
make test # Full test suite: Docker Git + Docker tests enabled (full coverage)
22+
make test_flaky # Run 5 iterations to detect flaky tests
23+
```
24+
25+
### Building and Running
26+
27+
```bash
28+
make run # Run the CLI with cargo run
29+
cargo build # Build debug version
30+
cargo build --release # Build optimized release version
31+
```
32+
33+
### Code Quality
34+
35+
```bash
36+
make lint # Check code formatting and clippy warnings
37+
make update # Update Rust toolchain and dependencies
38+
```
39+
40+
### Coverage
41+
42+
```bash
43+
make test # Generates coverage reports
44+
make open_coverage # Open HTML coverage report
45+
```
46+
47+
### Documentation
48+
49+
```bash
50+
make docs # Generate documentation via cargo xtask
51+
```
52+
53+
## High-Level Architecture
54+
55+
### Pipeline Architecture
56+
57+
The core processing follows a clear pipeline pattern:
58+
59+
```
60+
Input → VCS Detection → Version Parsing → Transformation → Format Output
61+
```
62+
63+
**Key Modules:**
64+
65+
- **`src/vcs/`**: Version Control System abstraction (currently Git only)
66+
- Detects VCS repositories and extracts metadata
67+
- `VcsData` struct contains tag versions, distance, commits, branches, timestamps
68+
69+
- **`src/version/`**: Version format implementations
70+
- `VersionObject`: Universal internal representation
71+
- `PEP440`: Python versioning standard
72+
- `SemVer`: Semantic versioning
73+
- `Zerv`: Custom component-based format with variable references
74+
75+
- **`src/pipeline/`**: Data transformation layer
76+
- `parse_version_from_tag()`: Extracts version from git tags
77+
- `vcs_data_to_zerv_vars()`: Converts VCS metadata to Zerv variables
78+
79+
- **`src/schema/`**: Schema and preset management
80+
- Presets for common versioning schemes (standard, calver)
81+
- RON-based schema parsing for custom formats
82+
83+
- **`src/cli/`**: Command-line interface (in development)
84+
- Main commands: `version`, `check`
85+
- Output formatting and display logic
86+
87+
### State-Based Versioning Tiers
88+
89+
Zerv uses a three-tier system based on repository state:
90+
91+
- **Tier 1** (Tagged, clean): `major.minor.patch`
92+
- **Tier 2** (Distance, clean): `major.minor.patch.post<distance>+branch.<commit>`
93+
- **Tier 3** (Dirty): `major.minor.patch.dev<timestamp>+branch.<commit>`
94+
95+
### Test Infrastructure
96+
97+
The project has extensive test utilities in `src/test_utils/`:
98+
99+
- **Environment-aware Git testing**: Uses `DockerGit` locally, `NativeGit` in CI
100+
- **`GitOperations` trait**: Unified interface for both implementations
101+
- **`GitRepoFixture`**: Creates isolated test repositories with specific states
102+
- **`TestDir`**: Temporary directory management with automatic cleanup
103+
104+
## Testing Standards
105+
106+
### Environment Variables
107+
108+
- `ZERV_TEST_NATIVE_GIT=true`: Use native Git (set in CI for platform testing)
109+
- `ZERV_TEST_DOCKER=true`: Enable Docker-dependent tests (requires Docker)
110+
111+
### Git Testing Pattern
112+
113+
ALWAYS use the environment-aware pattern:
114+
115+
```rust
116+
use crate::test_utils::{GitOperations, get_git_impl};
117+
118+
let git_impl = get_git_impl(); // Returns DockerGit or NativeGit based on environment
119+
git_impl.init_repo(&test_dir)?;
120+
```
121+
122+
### Docker Test Gating
123+
124+
For Docker-dependent tests:
125+
126+
```rust
127+
use crate::test_utils::should_run_docker_tests;
128+
129+
#[test]
130+
fn test_docker_functionality() {
131+
if !should_run_docker_tests() {
132+
return; // Skip when Docker tests are disabled
133+
}
134+
// Test code here
135+
}
136+
```
137+
138+
### Flaky Test Prevention
139+
140+
- Use `GitOperations` trait methods for atomic operations
141+
- Create fresh Git implementations for each test directory
142+
- Include detailed error messages with context
143+
- Verify intermediate states (e.g., `.git` directory exists)
144+
- Never reuse Git implementations across different directories
145+
146+
## Coding Standards
147+
148+
### Error Handling
149+
150+
- **ALWAYS** use `zerv::error::ZervError` for custom errors
151+
- Use `io::Error::other()` instead of `io::Error::new(io::ErrorKind::Other, ...)`
152+
- Include context in error messages for debugging
153+
- Proper error propagation with `?` operator
154+
155+
### Constants Usage
156+
157+
**MANDATORY**: Always use constants instead of bare strings:
158+
159+
```rust
160+
// GOOD
161+
use crate::utils::constants::{fields, formats, sources, schema_names};
162+
match field_name.as_str() {
163+
fields::MAJOR => // ...
164+
fields::MINOR => // ...
165+
}
166+
167+
// BAD - Never use bare strings
168+
match field_name.as_str() {
169+
"major" => // ...
170+
}
171+
```
172+
173+
### Code Reuse
174+
175+
Before implementing new test utilities:
176+
177+
- Check `src/test_utils/` for existing infrastructure
178+
- Reuse `TestDir`, `GitOperations` trait, and other helpers
179+
- Use `get_git_impl()` for environment-aware Git operations
180+
- Avoid duplicating code across files
181+
182+
### Performance Standards
183+
184+
- Parse 1000+ versions in <100ms
185+
- Minimal VCS command calls (batch when possible)
186+
- Use compiled regex patterns for speed
187+
- Zero-copy string operations where possible
188+
189+
## CI/CD
190+
191+
### Multi-Platform Testing
192+
193+
- **Linux**: Native Git + Docker tests enabled
194+
- **macOS**: Native Git + Docker tests skipped
195+
- **Windows**: Native Git + Docker tests skipped
196+
197+
### Pre-commit Hooks
198+
199+
The project uses pre-commit hooks for:
200+
201+
- Code formatting (rustfmt)
202+
- Linting (clippy)
203+
- Running tests
204+
205+
### GitHub Actions
206+
207+
Main workflows:
208+
209+
- `ci-test.yml`: Runs tests across Linux, macOS, Windows
210+
- `ci-pre-commit.yml`: Validates formatting and linting
211+
- `cd.yml`: Release automation
212+
- `security.yml`: Security scanning with SonarCloud
213+
214+
## Important Files
215+
216+
### Development Documentation
217+
218+
Read `.dev/00-README.md` FIRST before any coding task. All `.dev/` documents use sequential numbering (00, 01, 02...) where higher numbers indicate more recent plans.
219+
220+
### Cursor Rules (Apply to Claude Code)
221+
222+
Key rules in `.cursor/rules/`:
223+
224+
- `dev-workflow.mdc`: Development workflow and git practices
225+
- `testing-standards.mdc`: Comprehensive testing requirements
226+
- `cli-implementation.mdc`: CLI standards and patterns
227+
- `docker-git-testing.mdc`: Docker testing architecture
228+
229+
## Running Tests for Specific Features
230+
231+
```bash
232+
# Run all tests
233+
cargo test
234+
235+
# Run git-related tests
236+
cargo test git
237+
238+
# Run specific test file
239+
cargo test --test integration_test_name
240+
241+
# Run with features
242+
cargo test --features test-utils
243+
244+
# Run a single test
245+
cargo test test_name -- --exact
246+
```
247+
248+
## Configuration
249+
250+
Centralized config in `src/config.rs`:
251+
252+
- Loads environment variables (`ZERV_TEST_NATIVE_GIT`, `ZERV_TEST_DOCKER`)
253+
- Validates boolean parsing
254+
- Single source of truth for environment configuration

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,6 @@ tempfile = { version = "^3.0", optional = true }
4646
[dev-dependencies]
4747
rstest = "^0.26.0"
4848
serial_test = "^3.0"
49+
shlex = "^1.3"
4950
tempfile = "^3.0"
5051
zerv = { path = ".", features = ["test-utils"] }

src/cli/utils/template/context.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,13 @@ mod tests {
9191

9292
fn vcs_zerv() -> ZervFixture {
9393
ZervFixture::new().with_version(1, 2, 3).with_vcs_data(
94-
0,
95-
true,
96-
"main".to_string(),
97-
"abcdef123456".to_string(),
98-
"xyz789".to_string(),
99-
1234567890,
100-
"main".to_string(),
94+
Some(0),
95+
Some(true),
96+
Some("main".to_string()),
97+
Some("abcdef123456".to_string()),
98+
Some("xyz789".to_string()),
99+
Some(1234567890),
100+
Some("main".to_string()),
101101
)
102102
}
103103

src/test_utils/zerv/vars.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -105,21 +105,21 @@ impl ZervVarsFixture {
105105
#[allow(clippy::too_many_arguments)]
106106
pub fn with_vcs_data(
107107
mut self,
108-
distance: u64,
109-
dirty: bool,
110-
bumped_branch: String,
111-
bumped_commit_hash: String,
112-
last_commit_hash: String,
113-
last_timestamp: u64,
114-
last_branch: String,
108+
distance: Option<u64>,
109+
dirty: Option<bool>,
110+
bumped_branch: Option<String>,
111+
bumped_commit_hash: Option<String>,
112+
last_commit_hash: Option<String>,
113+
last_timestamp: Option<u64>,
114+
last_branch: Option<String>,
115115
) -> Self {
116-
self.vars.distance = Some(distance);
117-
self.vars.dirty = Some(dirty);
118-
self.vars.bumped_branch = Some(bumped_branch);
119-
self.vars.bumped_commit_hash = Some(bumped_commit_hash);
120-
self.vars.last_commit_hash = Some(last_commit_hash);
121-
self.vars.last_timestamp = Some(last_timestamp);
122-
self.vars.last_branch = Some(last_branch);
116+
self.vars.distance = distance;
117+
self.vars.dirty = dirty;
118+
self.vars.bumped_branch = bumped_branch;
119+
self.vars.bumped_commit_hash = bumped_commit_hash;
120+
self.vars.last_commit_hash = last_commit_hash;
121+
self.vars.last_timestamp = last_timestamp;
122+
self.vars.last_branch = last_branch;
123123
self
124124
}
125125

0 commit comments

Comments
 (0)