improvisation-lab / tests /service /test_base_practice_service.py
atsushieee's picture
Upload folder using huggingface_hub
29e2c21 verified
"""Tests for BasePracticeService."""
import time
import numpy as np
import pytest
from improvisation_lab.config import Config
from improvisation_lab.service.base_practice_service import PitchResult
from improvisation_lab.service.piece_practice_service import \
BasePracticeService
class MockBasePracticeService(BasePracticeService):
def generate_melody(self):
pass
class TestBasePracticeService:
@pytest.fixture
def init_module(self):
"""Create BasePracticeService instance for testing."""
config = Config()
self.service = MockBasePracticeService(config)
@pytest.mark.usefixtures("init_module")
def test_process_audio_no_voice(self):
"""Test processing audio with no voice detected."""
audio_data = np.zeros(1024, dtype=np.float32)
result = self.service.process_audio(audio_data, target_note="A")
assert isinstance(result, PitchResult)
assert result.current_base_note is None
assert not result.is_correct
@pytest.mark.usefixtures("init_module")
def test_process_audio_with_voice(self):
"""Test processing audio with voice detected."""
sample_rate = 16000
duration = 0.1
t = np.linspace(0, duration, int(sample_rate * duration))
audio_data = np.sin(2 * np.pi * 440 * t)
result = self.service.process_audio(audio_data, target_note="A")
assert isinstance(result, PitchResult)
assert result.current_base_note == "A"
assert result.is_correct
@pytest.mark.usefixtures("init_module")
def test_process_audio_incorrect_pitch(self):
"""Test processing audio with incorrect pitch."""
sample_rate = 16000
duration = 0.1
t = np.linspace(0, duration, int(sample_rate * duration))
# Generate 440Hz (A4) when target is C4
audio_data = np.sin(2 * np.pi * 440 * t)
result = self.service.process_audio(audio_data, target_note="C")
assert isinstance(result, PitchResult)
assert result.current_base_note == "A"
assert not result.is_correct
assert result.remaining_time == self.service.config.audio.note_duration
@pytest.mark.usefixtures("init_module")
def test_correct_pitch_timing(self):
"""Test timing behavior with correct pitch."""
sample_rate = 16000
duration = 0.1
t = np.linspace(0, duration, int(sample_rate * duration))
audio_data = np.sin(2 * np.pi * 440 * t)
# First detection
result1 = self.service.process_audio(audio_data, target_note="A")
initial_time = self.service.correct_pitch_start_time
assert result1.is_correct
assert result1.remaining_time == self.service.config.audio.note_duration
# Wait a bit
time.sleep(0.5)
# Second detection
result2 = self.service.process_audio(audio_data, target_note="A")
assert result2.is_correct
assert result2.remaining_time < self.service.config.audio.note_duration
assert initial_time == self.service.correct_pitch_start_time
@pytest.mark.usefixtures("init_module")
def test_correct_pitch_completion(self):
"""Test completion of correct pitch duration."""
sample_rate = 16000
duration = 0.1
t = np.linspace(0, duration, int(sample_rate * duration))
audio_data = np.sin(2 * np.pi * 440 * t)
# First detection
result1 = self.service.process_audio(audio_data, target_note="A")
assert result1.remaining_time == self.service.config.audio.note_duration
# Wait for full duration
time.sleep(self.service.config.audio.note_duration + 0.1)
# Final detection
result2 = self.service.process_audio(audio_data, target_note="A")
assert result2.remaining_time == 0