1# Ridiculously simple test of the winsound module for Windows.
2
3import functools
4import time
5import unittest
6
7from test import support
8from test.support import import_helper
9
10
11support.requires('audio')
12winsound = import_helper.import_module('winsound')
13
14
15# Unless we actually have an ear in the room, we have no idea whether a sound
16# actually plays, and it's incredibly flaky trying to figure out if a sound
17# even *should* play.  Instead of guessing, just call the function and assume
18# it either passed or raised the RuntimeError we expect in case of failure.
19def sound_func(func):
20    @functools.wraps(func)
21    def wrapper(*args, **kwargs):
22        try:
23            ret = func(*args, **kwargs)
24        except RuntimeError as e:
25            if support.verbose:
26                print(func.__name__, 'failed:', e)
27        else:
28            if support.verbose:
29                print(func.__name__, 'returned')
30            return ret
31    return wrapper
32
33
34safe_Beep = sound_func(winsound.Beep)
35safe_MessageBeep = sound_func(winsound.MessageBeep)
36safe_PlaySound = sound_func(winsound.PlaySound)
37
38
39class BeepTest(unittest.TestCase):
40
41    def test_errors(self):
42        self.assertRaises(TypeError, winsound.Beep)
43        self.assertRaises(ValueError, winsound.Beep, 36, 75)
44        self.assertRaises(ValueError, winsound.Beep, 32768, 75)
45
46    def test_extremes(self):
47        safe_Beep(37, 75)
48        safe_Beep(32767, 75)
49
50    def test_increasingfrequency(self):
51        for i in range(100, 2000, 100):
52            safe_Beep(i, 75)
53
54    def test_keyword_args(self):
55        safe_Beep(duration=75, frequency=2000)
56
57
58class MessageBeepTest(unittest.TestCase):
59
60    def tearDown(self):
61        time.sleep(0.5)
62
63    def test_default(self):
64        self.assertRaises(TypeError, winsound.MessageBeep, "bad")
65        self.assertRaises(TypeError, winsound.MessageBeep, 42, 42)
66        safe_MessageBeep()
67
68    def test_ok(self):
69        safe_MessageBeep(winsound.MB_OK)
70
71    def test_asterisk(self):
72        safe_MessageBeep(winsound.MB_ICONASTERISK)
73
74    def test_exclamation(self):
75        safe_MessageBeep(winsound.MB_ICONEXCLAMATION)
76
77    def test_hand(self):
78        safe_MessageBeep(winsound.MB_ICONHAND)
79
80    def test_question(self):
81        safe_MessageBeep(winsound.MB_ICONQUESTION)
82
83    def test_keyword_args(self):
84        safe_MessageBeep(type=winsound.MB_OK)
85
86
87class PlaySoundTest(unittest.TestCase):
88
89    def test_errors(self):
90        self.assertRaises(TypeError, winsound.PlaySound)
91        self.assertRaises(TypeError, winsound.PlaySound, "bad", "bad")
92        self.assertRaises(
93            RuntimeError,
94            winsound.PlaySound,
95            "none", winsound.SND_ASYNC | winsound.SND_MEMORY
96        )
97        self.assertRaises(TypeError, winsound.PlaySound, b"bad", 0)
98        self.assertRaises(TypeError, winsound.PlaySound, "bad",
99                          winsound.SND_MEMORY)
100        self.assertRaises(TypeError, winsound.PlaySound, 1, 0)
101        # embedded null character
102        self.assertRaises(ValueError, winsound.PlaySound, 'bad\0', 0)
103
104    def test_keyword_args(self):
105        safe_PlaySound(flags=winsound.SND_ALIAS, sound="SystemExit")
106
107    def test_snd_memory(self):
108        with open(support.findfile('pluck-pcm8.wav',
109                                   subdir='audiodata'), 'rb') as f:
110            audio_data = f.read()
111        safe_PlaySound(audio_data, winsound.SND_MEMORY)
112        audio_data = bytearray(audio_data)
113        safe_PlaySound(audio_data, winsound.SND_MEMORY)
114
115    def test_snd_filename(self):
116        fn = support.findfile('pluck-pcm8.wav', subdir='audiodata')
117        safe_PlaySound(fn, winsound.SND_FILENAME | winsound.SND_NODEFAULT)
118
119    def test_aliases(self):
120        aliases = [
121            "SystemAsterisk",
122            "SystemExclamation",
123            "SystemExit",
124            "SystemHand",
125            "SystemQuestion",
126        ]
127        for alias in aliases:
128            with self.subTest(alias=alias):
129                safe_PlaySound(alias, winsound.SND_ALIAS)
130
131    def test_alias_fallback(self):
132        safe_PlaySound('!"$%&/(#+*', winsound.SND_ALIAS)
133
134    def test_alias_nofallback(self):
135        safe_PlaySound('!"$%&/(#+*', winsound.SND_ALIAS | winsound.SND_NODEFAULT)
136
137    def test_stopasync(self):
138        safe_PlaySound(
139            'SystemQuestion',
140            winsound.SND_ALIAS | winsound.SND_ASYNC | winsound.SND_LOOP
141        )
142        time.sleep(0.5)
143        safe_PlaySound('SystemQuestion', winsound.SND_ALIAS | winsound.SND_NOSTOP)
144        # Issue 8367: PlaySound(None, winsound.SND_PURGE)
145        # does not raise on systems without a sound card.
146        winsound.PlaySound(None, winsound.SND_PURGE)
147
148
149if __name__ == "__main__":
150    unittest.main()
151