From c8dc871dc377d452a100e875cf8dd04cc72d78e7 Mon Sep 17 00:00:00 2001 From: Pete Bell Date: Wed, 26 Nov 2025 12:24:43 +0000 Subject: [PATCH] Add comprehensive tests for Speaker and DistanceSensor classes - test_speaker_default_values: Tests basic Speaker initialization with default freq (440Hz) and volume (0) - test_speaker_alt_values: Tests custom initial_freq and initial_volume parameters with delta tolerance for PWM frequency variations - test_speaker_note_conversion: Tests _to_freq() method for string notes, MIDI notes, and direct frequency values - test_speaker_play_single_note: Tests playing a single note and verifies volume is 0 after playback - test_speaker_play_note_list: Tests playing a sequence of notes with durations - test_distance_sensor_basic: Tests DistanceSensor initialization with default max_distance (1.0m) - test_distance_sensor_custom_max_distance: Tests custom max_distance parameter Speaker tests use pins 15-19, DistanceSensor tests use pins 22-25 to avoid conflicts. Uses assertAlmostEqual with delta=10 for PWM frequency assertions to account for hardware limitations. --- tests/test_picozero.py | 113 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 103 insertions(+), 10 deletions(-) diff --git a/tests/test_picozero.py b/tests/test_picozero.py index e994cd2..e14bb67 100644 --- a/tests/test_picozero.py +++ b/tests/test_picozero.py @@ -146,7 +146,7 @@ def test_digital_LED(self): d.close() def test_pwm_output_device_default_values(self): - d = PWMOutputDevice(1) + d = PWMOutputDevice(14) self.assertTrue(d.active_high) self.assertEqual(d.value, 0) @@ -178,7 +178,7 @@ def test_pwm_output_device_default_values(self): def test_pwm_output_device_alt_values(self): d = PWMOutputDevice( - 1, freq=200, duty_factor=10000, active_high=False, initial_value=True + 5, freq=200, duty_factor=10000, active_high=False, initial_value=True ) self.assertFalse(d.active_high) @@ -188,8 +188,8 @@ def test_pwm_output_device_alt_values(self): d.off() # prior to micropython v1.20 PWM returned 1 less than the duty_factor # unless the duty was set to the maximum 65535 - # self.assertEqual(d._pwm.duty_u16(), 9999) - self.assertEqual(d._pwm.duty_u16(), 10000) + # Accept either 9999 (older MicroPython) or 10000 (v1.20+) + self.assertIn(d._pwm.duty_u16(), [9999, 10000]) self.assertAlmostEqual(d.value, 0, places=2) d.on() @@ -201,7 +201,7 @@ def test_pwm_output_device_alt_values(self): d.close() def test_pwm_output_device_blink(self): - d = PWMOutputDevice(1) + d = PWMOutputDevice(6) d.blink() values = log_device_values(d, 1.1) @@ -217,7 +217,7 @@ def test_pwm_output_device_blink(self): d.close() def test_pwm_output_device_pulse(self): - d = PWMOutputDevice(1) + d = PWMOutputDevice(7) d.pulse(n=1) values = log_device_values(d, 2.1) @@ -298,7 +298,7 @@ def test_pwm_output_device_pulse(self): d.close() def test_motor_default_values(self): - d = Motor(1, 2) + d = Motor(8, 9) self.assertEqual(d.value, 0) @@ -347,7 +347,7 @@ def test_motor_alt_values(self): d.close() def test_robot(self): - d = Robot(left=(1, 2), right=(3, 4)) + d = Robot(left=(10, 11), right=(12, 13)) d.forward() self.assertEqual(d.value, (1, 1)) @@ -368,11 +368,11 @@ def test_robot(self): d.close() def test_LED_factory(self): - d = LED(1) + d = LED(20) self.assertIsInstance(d, PWMLED) d.close() - d = LED(1, pwm=False) + d = LED(21, pwm=False) self.assertIsInstance(d, DigitalLED) d.close() @@ -503,6 +503,81 @@ def test_servo_alt_values(self): d.close() + def test_speaker_default_values(self): + s = Speaker(15) + + self.assertEqual(s.pin, 15) + self.assertEqual(s.volume, 0) + self.assertEqual(s.freq, 440) + + s.on() + self.assertEqual(s.volume, 1) + + s.off() + self.assertEqual(s.volume, 0) + + s.close() + + def test_speaker_alt_values(self): + s = Speaker(16, initial_freq=523, initial_volume=0.5) + + # PWM frequency may be slightly different due to hardware limitations + self.assertAlmostEqual(s.freq, 523, delta=10) + self.assertEqual(s.volume, 0.5) + + s.volume = 0.75 + self.assertEqual(s.volume, 0.75) + + s.freq = 440 + self.assertAlmostEqual(s.freq, 440, delta=10) + + s.close() + + def test_speaker_note_conversion(self): + s = Speaker(17) + + # Test string note conversion + freq = s._to_freq("a4") + self.assertEqual(freq, 440) + + freq = s._to_freq("c4") + self.assertEqual(freq, 262) + + # Test MIDI note conversion (A4 = MIDI note 69 = 440Hz) + freq = s._to_freq(69) + self.assertEqual(freq, 440) + + # Test direct frequency + freq = s._to_freq(500) + self.assertEqual(freq, 500) + + # Test None/empty + freq = s._to_freq(None) + self.assertIsNone(freq) + + freq = s._to_freq("") + self.assertIsNone(freq) + + s.close() + + def test_speaker_play_single_note(self): + s = Speaker(18) + + # Play single frequency + s.play(440, duration=0.1, n=1, wait=True) + self.assertEqual(s.volume, 0) # Should be off after playing + + s.close() + + def test_speaker_play_note_list(self): + s = Speaker(19) + + # Play list of notes with durations + s.play([(440, 0.1), (523, 0.1)], n=1, wait=True) + self.assertEqual(s.volume, 0) + + s.close() + ########################################################################### # INPUT DEVICES ########################################################################### @@ -675,5 +750,23 @@ def test_pico_temp_sensor(self): self.assertEqual(pico_temp_sensor.pin, 4) self.assertIsNotNone(pico_temp_sensor.temp) + def test_distance_sensor_basic(self): + # Create a mock distance sensor + d = DistanceSensor(echo=22, trigger=23) + + self.assertEqual(d.pins, (22, 23)) + self.assertEqual(d.max_distance, 1.0) + + # Note: Without actual hardware, we can't test the distance reading + # but we can verify the object is created correctly + + # Clean up - Note: DistanceSensor doesn't have a close() method + # so we just let it go out of scope + + def test_distance_sensor_custom_max_distance(self): + d = DistanceSensor(echo=24, trigger=25, max_distance=2.5) + + self.assertEqual(d.max_distance, 2.5) + unittest.main()