test_winsound.py 8.9 KB

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