Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Run tests with coverage
run: yarn test:coverage
- name: Run tests with coverage and JUnit report
run: yarn vitest run --coverage --reporter=default --reporter=junit --outputFile=test-report.junit.xml

- name: Upload Frontend coverage to Codecov
uses: codecov/codecov-action@v5
Expand All @@ -95,6 +95,15 @@ jobs:
flags: frontend
fail_ci_if_error: true

- name: Upload test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: test-report.junit.xml
flags: frontend
report_type: test_results

- name: Upload HTML coverage report
uses: actions/upload-artifact@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .planning/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6

| Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------|
| 1. Test Coverage | 0/TBD | Not started | - |
| 1. Test Coverage | 1/3 | In progress | - |
| 2. VB-Cable Integration | 0/TBD | Not started | - |
| 3. Audio Core Polish | 0/TBD | Not started | - |
| 4. Auto-Updater | 0/TBD | Not started | - |
Expand Down
20 changes: 10 additions & 10 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,27 @@
## Current Position

Phase: 1 of 6 (Test Coverage)
Plan: Not started
Status: Ready to plan
Last activity: 2025-12-29 - Project initialized
Plan: 1 of 3 in current phase
Status: In progress
Last activity: 2025-12-29 - Completed 01-01-PLAN.md

Progress: ░░░░░░░░░░ 0%
Progress: ░░░░░░░░░ 10%

## Performance Metrics

**Velocity:**
- Total plans completed: 0
- Average duration: -
- Total execution time: 0 hours
- Total plans completed: 1
- Average duration: ~15 min
- Total execution time: 0.25 hours

**By Phase:**

| Phase | Plans | Total | Avg/Plan |
|-------|-------|-------|----------|
| - | - | - | - |
| 1. Test Coverage | 1/3 | 15 min | 15 min |

**Recent Trend:**
- Last 5 plans: -
- Last 5 plans: 01-01 (15 min)
- Trend: -

*Updated after each plan completion*
Expand Down Expand Up @@ -70,5 +70,5 @@ Drift notes: None
## Session Continuity

Last session: 2025-12-29
Stopped at: Project initialization complete
Stopped at: Completed 01-01-PLAN.md (Rust Unit Tests)
Resume file: None
172 changes: 172 additions & 0 deletions .planning/phases/01-test-coverage/01-01-PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
---
phase: 01-test-coverage
plan: 01
type: execute
---

<objective>
Expand Rust unit test coverage for untested modules.

Purpose: Provide test foundation for audio subsystem modules that currently lack tests, enabling confident refactoring in later phases.
Output: New test modules in device.rs, decode.rs, error.rs with passing tests and maintained 45%+ coverage threshold.
</objective>

<execution_context>
~/.claude/get-shit-done/workflows/execute-phase.md
~/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/codebase/TESTING.md

**Issue:** #77 Improve Rust unit test coverage

**Current State:**
- 117 existing Rust tests across 9 modules
- Coverage threshold: 45% (CI enforced)
- Test patterns established in cache.rs, manager.rs, playback.rs

**Modules WITHOUT tests:**
- `audio/error.rs` - Error enum with Display/From traits
- `audio/decode.rs` - Audio decoding (only integration tests exist)
- `audio/device.rs` - Device enumeration (requires mocking cpal)

**Modules WITH tests (reference patterns):**
@src-tauri/src/audio/cache.rs
@src-tauri/src/persistence.rs

**Constraints:**
- Follow existing test patterns (inline `#[cfg(test)]` modules)
- Use Arrange/Act/Assert structure
- Tests must pass: `cargo test`
- Coverage must stay >= 45%: `cargo llvm-cov --fail-under-lines 45`
</context>

<tasks>

<task type="auto">
<name>Task 1: Add AudioError tests</name>
<files>src-tauri/src/audio/error.rs</files>
<action>
Add `#[cfg(test)]` module to error.rs with tests for:
- Display trait output for each error variant (verify error messages are readable)
- From<io::Error> conversion works correctly
- Into<String> conversion for Tauri command error handling

Test pattern from existing code:
```rust
#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_audio_error_display_file_open() {
let err = AudioError::FileOpen(std::io::Error::new(
std::io::ErrorKind::NotFound,
"test error"
));
let msg = err.to_string();
assert!(msg.contains("Failed to open audio file"));
}
}
```

Cover all error variants: FileOpen, ProbeFormat, NoTracks, DecoderCreation, PacketRead, Decode, NoData, DeviceEnumeration, NoDevices, DeviceConfig, UnsupportedFormat, StreamBuild, StreamStart, InvalidDeviceId, DeviceNotFound.
</action>
<verify>cargo test audio::error::tests -- --nocapture</verify>
<done>All 15 error variants have Display tests, From/Into conversions tested</done>
</task>

<task type="auto">
<name>Task 2: Add decode.rs unit tests</name>
<files>src-tauri/src/audio/decode.rs</files>
<action>
Add `#[cfg(test)]` module to decode.rs with tests for:
- Error handling for non-existent files
- Error handling for invalid/corrupted audio files
- Successful decode using existing test fixtures (tests/fixtures/)

Use existing fixtures:
- test_mono.mp3 (1s, 44.1kHz, Mono)
- test_stereo.ogg (1s, 48kHz, Stereo)
- test_stereo.m4a (1s, 48kHz, Stereo)

Test pattern:
```rust
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;

fn get_fixture_path(filename: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("fixtures")
.join(filename)
}

#[test]
fn test_decode_nonexistent_file() {
let result = decode_audio_file("/nonexistent/path.mp3");
assert!(result.is_err());
}

#[test]
fn test_decode_mp3_fixture() {
let path = get_fixture_path("test_mono.mp3");
let result = decode_audio_file(path.to_str().unwrap());
assert!(result.is_ok());
let audio = result.unwrap();
assert!(audio.samples.len() > 0);
assert_eq!(audio.sample_rate, 44100);
assert_eq!(audio.channels, 1);
}
}
```

Test all three formats (MP3, OGG, M4A) and verify sample_rate, channels, and non-empty samples.
</action>
<verify>cargo test audio::decode::tests -- --nocapture</verify>
<done>Decode tests for all 3 formats pass, error cases covered</done>
</task>

<task type="auto">
<name>Task 3: Verify coverage threshold</name>
<files>src-tauri/</files>
<action>
Run full test suite and verify coverage threshold:

1. Run all tests: `cargo test`
2. Run coverage check: `cargo llvm-cov --fail-under-lines 45`
3. If coverage dropped, identify gaps and add targeted tests

Note: device.rs tests are challenging due to cpal hardware dependency - skip if mocking is complex. Focus on error.rs and decode.rs which provide more testable pure functions.
</action>
<verify>cargo llvm-cov --fail-under-lines 45 passes</verify>
<done>All tests pass, coverage >= 45%, no regressions</done>
</task>

</tasks>

<verification>
Before declaring plan complete:
- [ ] `cargo test` passes all tests (including new ones)
- [ ] `cargo llvm-cov --fail-under-lines 45` passes
- [ ] No compiler warnings in test code
- [ ] New tests follow existing patterns (Arrange/Act/Assert)
</verification>

<success_criteria>
- All tasks completed
- All verification checks pass
- AudioError has Display tests for all 15 variants
- decode.rs has unit tests for MP3, OGG, M4A fixtures
- Coverage threshold maintained at 45%+
</success_criteria>

<output>
After completion, create `.planning/phases/01-test-coverage/01-01-SUMMARY.md`
</output>
71 changes: 71 additions & 0 deletions .planning/phases/01-test-coverage/01-01-SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Phase 1 Plan 1: Rust Unit Tests Summary

**28 neue Unit-Tests für AudioError Display/Conversion und Audio-Dekodierung aller 3 Formate (MP3, OGG, M4A)**

## Performance

- **Duration:** ~15 min
- **Started:** 2025-12-29T14:30:00Z
- **Completed:** 2025-12-29T14:45:00Z
- **Tasks:** 3
- **Files modified:** 4

## Accomplishments

- 18 AudioError Display-Tests für alle 15 Fehler-Varianten + From/Into-Conversions
- 10 decode.rs Unit-Tests für MP3, OGG, M4A inkl. Error-Handling und Sample-Validierung
- Coverage von 52.94% (über 45% Schwellenwert)

## Files Created/Modified

- `src-tauri/src/audio/error.rs` - 18 neue Tests für Display trait und Conversions
- `src-tauri/src/audio/decode.rs` - 10 neue Tests für alle Audio-Formate
- `src-tauri/src/audio/mod.rs` - Debug derive für AudioData hinzugefügt
- `src-tauri/Cargo.toml` - AAC Feature für symphonia aktiviert

## Decisions Made

None - followed plan as specified.

## Deviations from Plan

### Auto-fixed Issues

**1. [Rule 3 - Blocking] Added Debug derive to AudioData struct**
- **Found during:** Task 2 (decode.rs tests)
- **Issue:** `unwrap_err()` in tests requires `Debug` trait on `AudioData`
- **Fix:** Added `#[derive(Debug, Clone)]` to AudioData in mod.rs
- **Files modified:** src-tauri/src/audio/mod.rs
- **Verification:** Tests compile and pass
- **Commit:** (this commit)

**2. [Rule 3 - Blocking] Enabled AAC codec feature for M4A decoding**
- **Found during:** Task 2 (M4A fixture tests failed)
- **Issue:** symphonia had `isomp4` (container) but not `aac` (codec) - M4A tests failed with "unsupported codec"
- **Fix:** Added `aac` feature to symphonia in Cargo.toml
- **Files modified:** src-tauri/Cargo.toml
- **Verification:** M4A tests pass, all 3 formats decode correctly
- **Commit:** (this commit)

### Deferred Enhancements

None - no enhancements logged to ISSUES.md.

---

**Total deviations:** 2 auto-fixed (both blocking issues preventing test compilation/execution)
**Impact on plan:** Both fixes necessary for test suite to work. No scope creep.

## Issues Encountered

None - all tasks completed successfully after addressing blocking issues.

## Next Phase Readiness

- Test foundation expanded with 28 new tests (117 -> 145 total)
- Coverage increased and threshold maintained at 52.94%
- Ready for 01-02-PLAN.md (Frontend component tests)

---
*Phase: 01-test-coverage*
*Completed: 2025-12-29*
4 changes: 2 additions & 2 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ thiserror = "1.0"
# Audio dependencies
cpal = "0.15"
lru = "0.12"
# Symphonia for audio decoding (MP3, WAV, OGG support)
symphonia = { version = "0.5", features = ["mp3", "isomp4", "vorbis"] }
# Symphonia for audio decoding (MP3, OGG/Vorbis, M4A/AAC support)
symphonia = { version = "0.5", features = ["mp3", "isomp4", "aac", "vorbis"] }
tauri-plugin-dialog = "2.0"

# Logging dependencies
Expand Down
Loading