1# Ridiculously simple test of the winsound module for Windows. 2 3import unittest 4from test import test_support 5import time 6import os 7import subprocess 8 9winsound = test_support.import_module('winsound') 10ctypes = test_support.import_module('ctypes') 11import _winreg 12 13def has_sound(sound): 14 """Find out if a particular event is configured with a default sound""" 15 try: 16 # Ask the mixer API for the number of devices it knows about. 17 # When there are no devices, PlaySound will fail. 18 if ctypes.windll.winmm.mixerGetNumDevs() is 0: 19 return False 20 21 key = _winreg.OpenKeyEx(_winreg.HKEY_CURRENT_USER, 22 "AppEvents\Schemes\Apps\.Default\{0}\.Default".format(sound)) 23 value = _winreg.EnumValue(key, 0)[1] 24 if value is not u"": 25 return True 26 else: 27 return False 28 except WindowsError: 29 return False 30 31class BeepTest(unittest.TestCase): 32 # As with PlaySoundTest, incorporate the _have_soundcard() check 33 # into our test methods. If there's no audio device present, 34 # winsound.Beep returns 0 and GetLastError() returns 127, which 35 # is: ERROR_PROC_NOT_FOUND ("The specified procedure could not 36 # be found"). (FWIW, virtual/Hyper-V systems fall under this 37 # scenario as they have no sound devices whatsoever (not even 38 # a legacy Beep device).) 39 40 def test_errors(self): 41 self.assertRaises(TypeError, winsound.Beep) 42 self.assertRaises(ValueError, winsound.Beep, 36, 75) 43 self.assertRaises(ValueError, winsound.Beep, 32768, 75) 44 45 def test_extremes(self): 46 self._beep(37, 75) 47 self._beep(32767, 75) 48 49 def test_increasingfrequency(self): 50 for i in xrange(100, 2000, 100): 51 self._beep(i, 75) 52 53 def _beep(self, *args): 54 # these tests used to use _have_soundcard(), but it's quite 55 # possible to have a soundcard, and yet have the beep driver 56 # disabled. So basically, we have no way of knowing whether 57 # a beep should be produced or not, so currently if these 58 # tests fail we're ignoring them 59 # 60 # XXX the right fix for this is to define something like 61 # _have_enabled_beep_driver() and use that instead of the 62 # try/except below 63 try: 64 winsound.Beep(*args) 65 except RuntimeError: 66 pass 67 68class MessageBeepTest(unittest.TestCase): 69 70 def tearDown(self): 71 time.sleep(0.5) 72 73 def test_default(self): 74 self.assertRaises(TypeError, winsound.MessageBeep, "bad") 75 self.assertRaises(TypeError, winsound.MessageBeep, 42, 42) 76 winsound.MessageBeep() 77 78 def test_ok(self): 79 winsound.MessageBeep(winsound.MB_OK) 80 81 def test_asterisk(self): 82 winsound.MessageBeep(winsound.MB_ICONASTERISK) 83 84 def test_exclamation(self): 85 winsound.MessageBeep(winsound.MB_ICONEXCLAMATION) 86 87 def test_hand(self): 88 winsound.MessageBeep(winsound.MB_ICONHAND) 89 90 def test_question(self): 91 winsound.MessageBeep(winsound.MB_ICONQUESTION) 92 93 94class PlaySoundTest(unittest.TestCase): 95 96 def test_errors(self): 97 self.assertRaises(TypeError, winsound.PlaySound) 98 self.assertRaises(TypeError, winsound.PlaySound, "bad", "bad") 99 self.assertRaises( 100 RuntimeError, 101 winsound.PlaySound, 102 "none", winsound.SND_ASYNC | winsound.SND_MEMORY 103 ) 104 105 @unittest.skipUnless(has_sound("SystemAsterisk"), "No default SystemAsterisk") 106 def test_alias_asterisk(self): 107 if _have_soundcard(): 108 winsound.PlaySound('SystemAsterisk', winsound.SND_ALIAS) 109 else: 110 self.assertRaises( 111 RuntimeError, 112 winsound.PlaySound, 113 'SystemAsterisk', winsound.SND_ALIAS 114 ) 115 116 @unittest.skipUnless(has_sound("SystemExclamation"), "No default SystemExclamation") 117 def test_alias_exclamation(self): 118 if _have_soundcard(): 119 winsound.PlaySound('SystemExclamation', winsound.SND_ALIAS) 120 else: 121 self.assertRaises( 122 RuntimeError, 123 winsound.PlaySound, 124 'SystemExclamation', winsound.SND_ALIAS 125 ) 126 127 @unittest.skipUnless(has_sound("SystemExit"), "No default SystemExit") 128 def test_alias_exit(self): 129 if _have_soundcard(): 130 winsound.PlaySound('SystemExit', winsound.SND_ALIAS) 131 else: 132 self.assertRaises( 133 RuntimeError, 134 winsound.PlaySound, 135 'SystemExit', winsound.SND_ALIAS 136 ) 137 138 @unittest.skipUnless(has_sound("SystemHand"), "No default SystemHand") 139 def test_alias_hand(self): 140 if _have_soundcard(): 141 winsound.PlaySound('SystemHand', winsound.SND_ALIAS) 142 else: 143 self.assertRaises( 144 RuntimeError, 145 winsound.PlaySound, 146 'SystemHand', winsound.SND_ALIAS 147 ) 148 149 @unittest.skipUnless(has_sound("SystemQuestion"), "No default SystemQuestion") 150 def test_alias_question(self): 151 if _have_soundcard(): 152 winsound.PlaySound('SystemQuestion', winsound.SND_ALIAS) 153 else: 154 self.assertRaises( 155 RuntimeError, 156 winsound.PlaySound, 157 'SystemQuestion', winsound.SND_ALIAS 158 ) 159 160 def test_alias_fallback(self): 161 # This test can't be expected to work on all systems. The MS 162 # PlaySound() docs say: 163 # 164 # If it cannot find the specified sound, PlaySound uses the 165 # default system event sound entry instead. If the function 166 # can find neither the system default entry nor the default 167 # sound, it makes no sound and returns FALSE. 168 # 169 # It's known to return FALSE on some real systems. 170 171 # winsound.PlaySound('!"$%&/(#+*', winsound.SND_ALIAS) 172 return 173 174 def test_alias_nofallback(self): 175 if _have_soundcard(): 176 # Note that this is not the same as asserting RuntimeError 177 # will get raised: you cannot convert this to 178 # self.assertRaises(...) form. The attempt may or may not 179 # raise RuntimeError, but it shouldn't raise anything other 180 # than RuntimeError, and that's all we're trying to test 181 # here. The MS docs aren't clear about whether the SDK 182 # PlaySound() with SND_ALIAS and SND_NODEFAULT will return 183 # True or False when the alias is unknown. On Tim's WinXP 184 # box today, it returns True (no exception is raised). What 185 # we'd really like to test is that no sound is played, but 186 # that requires first wiring an eardrum class into unittest 187 # <wink>. 188 try: 189 winsound.PlaySound( 190 '!"$%&/(#+*', 191 winsound.SND_ALIAS | winsound.SND_NODEFAULT 192 ) 193 except RuntimeError: 194 pass 195 else: 196 self.assertRaises( 197 RuntimeError, 198 winsound.PlaySound, 199 '!"$%&/(#+*', winsound.SND_ALIAS | winsound.SND_NODEFAULT 200 ) 201 202 def test_stopasync(self): 203 if _have_soundcard(): 204 winsound.PlaySound( 205 'SystemQuestion', 206 winsound.SND_ALIAS | winsound.SND_ASYNC | winsound.SND_LOOP 207 ) 208 time.sleep(0.5) 209 try: 210 winsound.PlaySound( 211 'SystemQuestion', 212 winsound.SND_ALIAS | winsound.SND_NOSTOP 213 ) 214 except RuntimeError: 215 pass 216 else: # the first sound might already be finished 217 pass 218 winsound.PlaySound(None, winsound.SND_PURGE) 219 else: 220 # Issue 8367: PlaySound(None, winsound.SND_PURGE) 221 # does not raise on systems without a sound card. 222 pass 223 224 225def _get_cscript_path(): 226 """Return the full path to cscript.exe or None.""" 227 for dir in os.environ.get("PATH", "").split(os.pathsep): 228 cscript_path = os.path.join(dir, "cscript.exe") 229 if os.path.exists(cscript_path): 230 return cscript_path 231 232__have_soundcard_cache = None 233def _have_soundcard(): 234 """Return True iff this computer has a soundcard.""" 235 global __have_soundcard_cache 236 if __have_soundcard_cache is None: 237 cscript_path = _get_cscript_path() 238 if cscript_path is None: 239 # Could not find cscript.exe to run our VBScript helper. Default 240 # to True: most computers these days *do* have a soundcard. 241 return True 242 243 check_script = os.path.join(os.path.dirname(__file__), 244 "check_soundcard.vbs") 245 p = subprocess.Popen([cscript_path, check_script], 246 stdout=subprocess.PIPE) 247 __have_soundcard_cache = not p.wait() 248 return __have_soundcard_cache 249 250 251def test_main(): 252 test_support.run_unittest(BeepTest, MessageBeepTest, PlaySoundTest) 253 254if __name__=="__main__": 255 test_main() 256