# Reaper MCP Unit Tests

This directory contains comprehensive unit tests for the underlying functionality of the Reaper MCP server functions.

## Overview

As requested, these tests focus on testing the **underlying functionality** of the MCP server functions, not the MCP wrapper layer itself. The tests use generated audio (e.g., tones with known frequencies) to verify that audio analysis functions work correctly.

## Test Files

### 1. `test_audio_analysis.py`
Tests for audio analysis functions that extract metadata from audio files.

**Test Classes:**
- `TestEstimateKey` (8 tests): Tests key estimation with generated tones
  - Tests known frequencies: A4 (440 Hz), C4 (261.63 Hz), E4, G4, D4, F4
  - Tests edge cases: silence, empty arrays
  - **Example:** Generates a 440 Hz sine wave and verifies it's detected as key "A"

- `TestEstimateTempo` (6 tests): Tests tempo/BPM estimation
  - Tests click tracks at known BPMs: 90, 120, 140
  - Tests tempo clamping (min 60, max 180 BPM)
  - Tests edge case: silence (returns default 120 BPM)

- `TestAnalyzeAudioData` (4 tests): Tests comprehensive audio data analysis
  - Mono and stereo audio handling
  - RMS energy calculation
  - Peak amplitude detection

- `TestAnalyzeAudioFile` (3 tests): Tests file-based analysis
  - File analysis with caching
  - Error handling for nonexistent files

- `TestBatchAnalyzeSamples` (5 tests): Tests batch directory analysis
  - Multiple file analysis
  - Extension filtering
  - Force re-analysis option

**Total:** 26 tests

### 2. `test_waveform_generation.py`
Tests for waveform and synthesis generation functions.

**Test Classes:**
- `TestGenerateSineWave` (6 tests): Sine wave generation
  - Basic generation with default parameters
  - Custom parameters (frequency, duration, amplitude, sample rate)
  - Input validation (invalid frequency, duration, amplitude)

- `TestGenerateSquareWave` (2 tests): Square wave generation
- `TestGenerateSawtoothWave` (2 tests): Sawtooth wave generation
- `TestGenerateTriangleWave` (2 tests): Triangle wave generation

- `TestGenerateNoise` (4 tests): Noise generation
  - White, pink, and brown noise
  - Invalid noise type handling

- `TestGenerateFMSynth` (2 tests): FM synthesis
- `TestGenerateAdditiveSynth` (3 tests): Additive synthesis
- `TestGenerateADSREnvelope` (3 tests): ADSR envelope generation
- `TestApplyEnvelopeToWaveform` (2 tests): Envelope application
- `TestGenerateSubtractiveSynth` (5 tests): Subtractive synthesis
  - Lowpass, highpass, bandpass filters
  - Invalid parameter handling

**Total:** 31 tests

### 3. `test_audio_processing.py`
Tests for audio processing and effects functions.

**Test Classes:**
- `TestApplyFade` (6 tests): Fade in/out effects
  - Fade in only
  - Fade out only
  - Both fades
  - No fade (identity)
  - Error handling

- `TestReverseAudio` (3 tests): Audio reversal
  - Verification that audio is correctly reversed
  - Length preservation

- `TestTimeStretchAudio` (5 tests): Time stretching
  - Slowing down (rate < 1.0)
  - Speeding up (rate > 1.0)
  - Pitch preservation option
  - Invalid rate handling

- `TestPitchShiftAudio` (5 tests): Pitch shifting
  - Shifting up/down in semitones
  - Zero semitones (identity)
  - Octave shift (12 semitones)

- `TestNormalizeAudio` (4 tests): Audio normalization
  - Normalization to target dB
  - Already normalized audio handling

- `TestApplyEQ` (6 tests): Equalization
  - Boost/cut low, mid, high frequencies
  - All bands simultaneously
  - No change (identity)

- `TestApplyCompression` (5 tests): Dynamic range compression
  - Various compression ratios
  - Fast/slow attack times
  - Limiting (high ratio)

**Total:** 34 tests

## Running the Tests

### Prerequisites
Ensure all dependencies are installed:
```bash
pip install numpy soundfile scipy
```

### Using unittest (Python's built-in test runner)
```bash
# Run all tests
python -m unittest discover tests -v

# Run specific test file
python -m unittest tests.test_audio_analysis -v
python -m unittest tests.test_waveform_generation -v
python -m unittest tests.test_audio_processing -v

# Run specific test class
python -m unittest tests.test_audio_analysis.TestEstimateKey -v

# Run specific test method
python -m unittest tests.test_audio_analysis.TestEstimateKey.test_estimate_key_a4 -v
```

### Using pytest (if installed)
```bash
# Install pytest
pip install pytest

# Run all tests
pytest tests/ -v

# Run specific test file
pytest tests/test_audio_analysis.py -v

# Run with coverage
pytest tests/ --cov=reaper_mcp.audio --cov-report=html
```

## Test Strategy

### Key Estimation Tests
The key estimation tests follow the approach suggested in the issue: **generate tones with known frequencies and verify the estimation is correct**.

Example from `test_audio_analysis.py`:
```python
def test_estimate_key_a4(self):
    """Test key estimation with A4 (440 Hz) - should detect A."""
    audio = self._generate_tone(440.0)  # Generate 440 Hz sine wave
    key = _estimate_key(audio, self.sample_rate)
    self.assertEqual(key, "A", f"Expected 'A' but got '{key}'")
```

### Tempo Estimation Tests
Tests generate click tracks at known BPMs to verify tempo detection:
```python
def test_estimate_tempo_120_bpm(self):
    """Test tempo estimation with 120 BPM click track."""
    audio = self._generate_click_track(120.0)
    tempo = _estimate_tempo(audio, self.sample_rate)
    # Allow some tolerance in tempo detection
    self.assertGreaterEqual(tempo, 115.0)
    self.assertLessEqual(tempo, 125.0)
```

### Synthetic Audio Generation
All tests use synthesized audio data (sine waves, click tracks, noise) rather than requiring external audio files. This makes the tests:
- **Self-contained**: No external dependencies
- **Fast**: Generated on-the-fly
- **Reproducible**: Same input always produces same output
- **Precise**: Known ground truth for validation

## Test Coverage

**Total Tests:** 91 comprehensive unit tests

These tests cover:
- ✅ Audio analysis (tempo, key, metadata extraction)
- ✅ Waveform generation (sine, square, sawtooth, triangle)
- ✅ Synthesis (FM, additive, subtractive)
- ✅ Envelope generation and application (ADSR)
- ✅ Audio processing (fade, reverse, time stretch, pitch shift)
- ✅ Audio effects (normalize, EQ, compression)
- ✅ Noise generation (white, pink, brown)
- ✅ Edge cases and error handling
- ✅ File I/O and caching

## Notes

- Tests create temporary files in system temp directories and clean them up automatically
- Some tests may generate audio files in the working directory (cleaned up in tearDown)
- Tests are designed to be independent and can run in any order
- All tests use in-memory audio generation to avoid external file dependencies

## Troubleshooting

### Import Issues
If you encounter timeout issues when importing test modules, it may be due to MCP server initialization blocking. The tests are designed to import only the underlying functions (e.g., `_estimate_tempo`, `_estimate_key`) which don't have MCP decorators, but Python still executes module-level code during import.

**Workaround:** Run tests individually or ensure the MCP server is not automatically started during module import.

### Missing Dependencies
If tests fail due to missing dependencies:
```bash
pip install numpy soundfile scipy
```

### Audio Backend Issues
If soundfile fails to load audio:
```bash
# Linux
sudo apt-get install libsndfile1

# macOS
brew install libsndfile
```

## Future Enhancements

Potential additions to the test suite:
- Integration tests that test MCP tool decorators
- Performance benchmarks for audio processing functions
- Tests for MIDI functions (if midi module is implemented)
- Tests for project management functions
- Mock tests for Reaper DAW interactions
