forked from MicroPythonOS/MicroPythonOS
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_audiomanager.py
More file actions
225 lines (180 loc) · 8.14 KB
/
test_audiomanager.py
File metadata and controls
225 lines (180 loc) · 8.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# Unit tests for AudioManager service
import unittest
import sys
# Import centralized mocks
from mpos.testing import (
MockMachine,
MockPWM,
MockPin,
MockThread,
inject_mocks,
)
# Inject mocks before importing AudioManager
inject_mocks({
'machine': MockMachine(),
'_thread': MockThread,
})
# Now import the module to test
from mpos.audio.audiomanager import AudioManager
class TestAudioManager(unittest.TestCase):
"""Test cases for AudioManager service."""
def setUp(self):
"""Initialize AudioManager before each test."""
self.buzzer = MockPWM(MockPin(46))
self.i2s_pins = {'sck': 2, 'ws': 47, 'sd': 16}
# Reset singleton instance for each test
AudioManager._instance = None
AudioManager(
i2s_pins=self.i2s_pins,
buzzer_instance=self.buzzer
)
# Reset volume to default after creating instance
AudioManager.set_volume(70)
def tearDown(self):
"""Clean up after each test."""
AudioManager.stop()
def test_initialization(self):
"""Test that AudioManager initializes correctly."""
am = AudioManager.get()
self.assertEqual(am._i2s_pins, self.i2s_pins)
self.assertEqual(am._buzzer_instance, self.buzzer)
def test_has_i2s(self):
"""Test has_i2s() returns correct value."""
# With I2S configured
AudioManager._instance = None
AudioManager(i2s_pins=self.i2s_pins, buzzer_instance=None)
self.assertTrue(AudioManager.has_i2s())
# Without I2S configured
AudioManager._instance = None
AudioManager(i2s_pins=None, buzzer_instance=self.buzzer)
self.assertFalse(AudioManager.has_i2s())
def test_has_buzzer(self):
"""Test has_buzzer() returns correct value."""
# With buzzer configured
AudioManager._instance = None
AudioManager(i2s_pins=None, buzzer_instance=self.buzzer)
self.assertTrue(AudioManager.has_buzzer())
# Without buzzer configured
AudioManager._instance = None
AudioManager(i2s_pins=self.i2s_pins, buzzer_instance=None)
self.assertFalse(AudioManager.has_buzzer())
def test_stream_types(self):
"""Test stream type constants and priority order."""
self.assertEqual(AudioManager.STREAM_MUSIC, 0)
self.assertEqual(AudioManager.STREAM_NOTIFICATION, 1)
self.assertEqual(AudioManager.STREAM_ALARM, 2)
# Higher number = higher priority
self.assertTrue(AudioManager.STREAM_MUSIC < AudioManager.STREAM_NOTIFICATION)
self.assertTrue(AudioManager.STREAM_NOTIFICATION < AudioManager.STREAM_ALARM)
def test_volume_control(self):
"""Test volume get/set operations."""
# Set volume
AudioManager.set_volume(50)
self.assertEqual(AudioManager.get_volume(), 50)
# Test clamping to 0-100 range
AudioManager.set_volume(150)
self.assertEqual(AudioManager.get_volume(), 100)
AudioManager.set_volume(-10)
self.assertEqual(AudioManager.get_volume(), 0)
def test_no_hardware_rejects_playback(self):
"""Test that no hardware rejects all playback requests."""
# Re-initialize with no hardware
AudioManager._instance = None
AudioManager(i2s_pins=None, buzzer_instance=None)
# WAV should be rejected (no I2S)
result = AudioManager.play_wav("test.wav")
self.assertFalse(result)
# RTTTL should be rejected (no buzzer)
result = AudioManager.play_rtttl("Test:d=4,o=5,b=120:c")
self.assertFalse(result)
def test_i2s_only_rejects_rtttl(self):
"""Test that I2S-only config rejects buzzer playback."""
# Re-initialize with I2S only
AudioManager._instance = None
AudioManager(i2s_pins=self.i2s_pins, buzzer_instance=None)
# RTTTL should be rejected (no buzzer)
result = AudioManager.play_rtttl("Test:d=4,o=5,b=120:c")
self.assertFalse(result)
def test_buzzer_only_rejects_wav(self):
"""Test that buzzer-only config rejects I2S playback."""
# Re-initialize with buzzer only
AudioManager._instance = None
AudioManager(i2s_pins=None, buzzer_instance=self.buzzer)
# WAV should be rejected (no I2S)
result = AudioManager.play_wav("test.wav")
self.assertFalse(result)
def test_is_playing_initially_false(self):
"""Test that is_playing() returns False initially."""
# Reset to ensure clean state
AudioManager._instance = None
AudioManager(i2s_pins=self.i2s_pins, buzzer_instance=self.buzzer)
self.assertFalse(AudioManager.is_playing())
def test_stop_with_no_playback(self):
"""Test that stop() can be called when nothing is playing."""
# Should not raise exception
AudioManager.stop()
self.assertFalse(AudioManager.is_playing())
def test_audio_focus_check_no_current_stream(self):
"""Test audio focus allows playback when no stream is active."""
am = AudioManager.get()
result = am._check_audio_focus(AudioManager.STREAM_MUSIC)
self.assertTrue(result)
def test_volume_default_value(self):
"""Test that default volume is reasonable."""
# After init, volume should be at default (70)
AudioManager(i2s_pins=None, buzzer_instance=None)
self.assertEqual(AudioManager.get_volume(), 70)
class TestAudioManagerRecording(unittest.TestCase):
"""Test cases for AudioManager recording functionality."""
def setUp(self):
"""Initialize AudioManager with microphone before each test."""
self.buzzer = MockPWM(MockPin(46))
# I2S pins with microphone input
self.i2s_pins_with_mic = {'sck': 2, 'ws': 47, 'sd': 16, 'sd_in': 15}
# I2S pins without microphone input
self.i2s_pins_no_mic = {'sck': 2, 'ws': 47, 'sd': 16}
# Reset singleton instance for each test
AudioManager._instance = None
AudioManager(
i2s_pins=self.i2s_pins_with_mic,
buzzer_instance=self.buzzer
)
# Reset volume to default after creating instance
AudioManager.set_volume(70)
def tearDown(self):
"""Clean up after each test."""
AudioManager.stop()
def test_has_microphone_with_sd_in(self):
"""Test has_microphone() returns True when sd_in pin is configured."""
AudioManager._instance = None
AudioManager(i2s_pins=self.i2s_pins_with_mic, buzzer_instance=None)
self.assertTrue(AudioManager.has_microphone())
def test_has_microphone_without_sd_in(self):
"""Test has_microphone() returns False when sd_in pin is not configured."""
AudioManager._instance = None
AudioManager(i2s_pins=self.i2s_pins_no_mic, buzzer_instance=None)
self.assertFalse(AudioManager.has_microphone())
def test_has_microphone_no_i2s(self):
"""Test has_microphone() returns False when no I2S is configured."""
AudioManager._instance = None
AudioManager(i2s_pins=None, buzzer_instance=self.buzzer)
self.assertFalse(AudioManager.has_microphone())
def test_is_recording_initially_false(self):
"""Test that is_recording() returns False initially."""
self.assertFalse(AudioManager.is_recording())
def test_record_wav_no_microphone(self):
"""Test that record_wav() fails when no microphone is configured."""
AudioManager._instance = None
AudioManager(i2s_pins=self.i2s_pins_no_mic, buzzer_instance=None)
result = AudioManager.record_wav("test.wav")
self.assertFalse(result, "record_wav() fails when no microphone is configured")
def test_record_wav_no_i2s(self):
AudioManager._instance = None
AudioManager(i2s_pins=None, buzzer_instance=self.buzzer)
result = AudioManager.record_wav("test.wav")
self.assertFalse(result, "record_wav() should fail when no I2S is configured")
def test_stop_with_no_recording(self):
"""Test that stop() can be called when nothing is recording."""
# Should not raise exception
AudioManager.stop()
self.assertFalse(AudioManager.is_recording())