From: Zachary Ware Date: Mon, 5 Sep 2016 20:09:41 +0000 (-0500) Subject: Issue #27748: Simplify test_winsound. X-Git-Tag: v2.7.13rc1~179 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=344582771c0f52cea5d1e074e3a96e75ed5b110c;p=python Issue #27748: Simplify test_winsound. The tests no longer attempt to figure out if a soundcard or particular system sounds are available. Instead, it just tries everything and accepts RuntimeError as a flavor of success. --- diff --git a/Lib/test/check_soundcard.vbs b/Lib/test/check_soundcard.vbs deleted file mode 100644 index 8c21852f81..0000000000 --- a/Lib/test/check_soundcard.vbs +++ /dev/null @@ -1,13 +0,0 @@ -rem Check for a working sound-card - exit with 0 if OK, 1 otherwise. -set wmi = GetObject("winmgmts:") -set scs = wmi.InstancesOf("win32_sounddevice") -for each sc in scs - set status = sc.Properties_("Status") - wscript.Echo(sc.Properties_("Name") + "/" + status) - if status = "OK" then - wscript.Quit 0 rem normal exit - end if -next -rem No sound card found - exit with status code of 1 -wscript.Quit 1 - diff --git a/Lib/test/test_winsound.py b/Lib/test/test_winsound.py index c94a4dc3d3..c3725ef3eb 100644 --- a/Lib/test/test_winsound.py +++ b/Lib/test/test_winsound.py @@ -1,42 +1,41 @@ # Ridiculously simple test of the winsound module for Windows. -import unittest -from test import test_support -test_support.requires('audio') -import time +from __future__ import print_function + +import functools import os import subprocess +import time +import unittest + +from test import test_support as support -winsound = test_support.import_module('winsound') -ctypes = test_support.import_module('ctypes') -import _winreg - -def has_sound(sound): - """Find out if a particular event is configured with a default sound""" - try: - # Ask the mixer API for the number of devices it knows about. - # When there are no devices, PlaySound will fail. - if ctypes.windll.winmm.mixerGetNumDevs() is 0: - return False - - key = _winreg.OpenKeyEx(_winreg.HKEY_CURRENT_USER, - "AppEvents\Schemes\Apps\.Default\{0}\.Default".format(sound)) - value = _winreg.EnumValue(key, 0)[1] - if value is not u"": - return True +support.requires('audio') +winsound = support.import_module('winsound') + +# Unless we actually have an ear in the room, we have no idea whether a sound +# actually plays, and it's incredibly flaky trying to figure out if a sound +# even *should* play. Instead of guessing, just call the function and assume +# it either passed or raised the RuntimeError we expect in case of failure. +def sound_func(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + try: + ret = func(*args, **kwargs) + except RuntimeError as e: + if support.verbose: + print(func.__name__, 'failed:', e) else: - return False - except WindowsError: - return False + if support.verbose: + print(func.__name__, 'returned') + return ret + return wrapper + +safe_Beep = sound_func(winsound.Beep) +safe_MessageBeep = sound_func(winsound.MessageBeep) +safe_PlaySound = sound_func(winsound.PlaySound) class BeepTest(unittest.TestCase): - # As with PlaySoundTest, incorporate the _have_soundcard() check - # into our test methods. If there's no audio device present, - # winsound.Beep returns 0 and GetLastError() returns 127, which - # is: ERROR_PROC_NOT_FOUND ("The specified procedure could not - # be found"). (FWIW, virtual/Hyper-V systems fall under this - # scenario as they have no sound devices whatsoever (not even - # a legacy Beep device).) def test_errors(self): self.assertRaises(TypeError, winsound.Beep) @@ -44,27 +43,13 @@ class BeepTest(unittest.TestCase): self.assertRaises(ValueError, winsound.Beep, 32768, 75) def test_extremes(self): - self._beep(37, 75) - self._beep(32767, 75) + safe_Beep(37, 75) + safe_Beep(32767, 75) def test_increasingfrequency(self): for i in xrange(100, 2000, 100): - self._beep(i, 75) - - def _beep(self, *args): - # these tests used to use _have_soundcard(), but it's quite - # possible to have a soundcard, and yet have the beep driver - # disabled. So basically, we have no way of knowing whether - # a beep should be produced or not, so currently if these - # tests fail we're ignoring them - # - # XXX the right fix for this is to define something like - # _have_enabled_beep_driver() and use that instead of the - # try/except below - try: - winsound.Beep(*args) - except RuntimeError: - pass + safe_Beep(i, 75) + class MessageBeepTest(unittest.TestCase): @@ -74,22 +59,22 @@ class MessageBeepTest(unittest.TestCase): def test_default(self): self.assertRaises(TypeError, winsound.MessageBeep, "bad") self.assertRaises(TypeError, winsound.MessageBeep, 42, 42) - winsound.MessageBeep() + safe_MessageBeep() def test_ok(self): - winsound.MessageBeep(winsound.MB_OK) + safe_MessageBeep(winsound.MB_OK) def test_asterisk(self): - winsound.MessageBeep(winsound.MB_ICONASTERISK) + safe_MessageBeep(winsound.MB_ICONASTERISK) def test_exclamation(self): - winsound.MessageBeep(winsound.MB_ICONEXCLAMATION) + safe_MessageBeep(winsound.MB_ICONEXCLAMATION) def test_hand(self): - winsound.MessageBeep(winsound.MB_ICONHAND) + safe_MessageBeep(winsound.MB_ICONHAND) def test_question(self): - winsound.MessageBeep(winsound.MB_ICONQUESTION) + safe_MessageBeep(winsound.MB_ICONQUESTION) class PlaySoundTest(unittest.TestCase): @@ -103,151 +88,38 @@ class PlaySoundTest(unittest.TestCase): "none", winsound.SND_ASYNC | winsound.SND_MEMORY ) - @unittest.skipUnless(has_sound("SystemAsterisk"), "No default SystemAsterisk") - def test_alias_asterisk(self): - if _have_soundcard(): - winsound.PlaySound('SystemAsterisk', winsound.SND_ALIAS) - else: - self.assertRaises( - RuntimeError, - winsound.PlaySound, - 'SystemAsterisk', winsound.SND_ALIAS - ) - - @unittest.skipUnless(has_sound("SystemExclamation"), "No default SystemExclamation") - def test_alias_exclamation(self): - if _have_soundcard(): - winsound.PlaySound('SystemExclamation', winsound.SND_ALIAS) - else: - self.assertRaises( - RuntimeError, - winsound.PlaySound, - 'SystemExclamation', winsound.SND_ALIAS - ) - - @unittest.skipUnless(has_sound("SystemExit"), "No default SystemExit") - def test_alias_exit(self): - if _have_soundcard(): - winsound.PlaySound('SystemExit', winsound.SND_ALIAS) - else: - self.assertRaises( - RuntimeError, - winsound.PlaySound, - 'SystemExit', winsound.SND_ALIAS - ) - - @unittest.skipUnless(has_sound("SystemHand"), "No default SystemHand") - def test_alias_hand(self): - if _have_soundcard(): - winsound.PlaySound('SystemHand', winsound.SND_ALIAS) - else: - self.assertRaises( - RuntimeError, - winsound.PlaySound, - 'SystemHand', winsound.SND_ALIAS - ) - - @unittest.skipUnless(has_sound("SystemQuestion"), "No default SystemQuestion") - def test_alias_question(self): - if _have_soundcard(): - winsound.PlaySound('SystemQuestion', winsound.SND_ALIAS) - else: - self.assertRaises( - RuntimeError, - winsound.PlaySound, - 'SystemQuestion', winsound.SND_ALIAS - ) + def test_aliases(self): + aliases = [ + "SystemAsterisk", + "SystemExclamation", + "SystemExit", + "SystemHand", + "SystemQuestion", + ] + for alias in aliases: + safe_PlaySound(alias, winsound.SND_ALIAS) def test_alias_fallback(self): - # In the absence of the ability to tell if a sound was actually - # played, this test has two acceptable outcomes: success (no error, - # sound was theoretically played; although as issue #19987 shows - # a box without a soundcard can "succeed") or RuntimeError. Any - # other error is a failure. - try: - winsound.PlaySound('!"$%&/(#+*', winsound.SND_ALIAS) - except RuntimeError: - pass + safe_PlaySound('!"$%&/(#+*', winsound.SND_ALIAS) def test_alias_nofallback(self): - if _have_soundcard(): - # Note that this is not the same as asserting RuntimeError - # will get raised: you cannot convert this to - # self.assertRaises(...) form. The attempt may or may not - # raise RuntimeError, but it shouldn't raise anything other - # than RuntimeError, and that's all we're trying to test - # here. The MS docs aren't clear about whether the SDK - # PlaySound() with SND_ALIAS and SND_NODEFAULT will return - # True or False when the alias is unknown. On Tim's WinXP - # box today, it returns True (no exception is raised). What - # we'd really like to test is that no sound is played, but - # that requires first wiring an eardrum class into unittest - # . - try: - winsound.PlaySound( - '!"$%&/(#+*', - winsound.SND_ALIAS | winsound.SND_NODEFAULT - ) - except RuntimeError: - pass - else: - self.assertRaises( - RuntimeError, - winsound.PlaySound, - '!"$%&/(#+*', winsound.SND_ALIAS | winsound.SND_NODEFAULT - ) + safe_PlaySound('!"$%&/(#+*', winsound.SND_ALIAS | winsound.SND_NODEFAULT) def test_stopasync(self): - if _have_soundcard(): - winsound.PlaySound( - 'SystemQuestion', - winsound.SND_ALIAS | winsound.SND_ASYNC | winsound.SND_LOOP - ) - time.sleep(0.5) - try: - winsound.PlaySound( - 'SystemQuestion', - winsound.SND_ALIAS | winsound.SND_NOSTOP - ) - except RuntimeError: - pass - else: # the first sound might already be finished - pass - winsound.PlaySound(None, winsound.SND_PURGE) - else: - # Issue 8367: PlaySound(None, winsound.SND_PURGE) - # does not raise on systems without a sound card. - pass - - -def _get_cscript_path(): - """Return the full path to cscript.exe or None.""" - for dir in os.environ.get("PATH", "").split(os.pathsep): - cscript_path = os.path.join(dir, "cscript.exe") - if os.path.exists(cscript_path): - return cscript_path - -__have_soundcard_cache = None -def _have_soundcard(): - """Return True iff this computer has a soundcard.""" - global __have_soundcard_cache - if __have_soundcard_cache is None: - cscript_path = _get_cscript_path() - if cscript_path is None: - # Could not find cscript.exe to run our VBScript helper. Default - # to True: most computers these days *do* have a soundcard. - return True - - check_script = os.path.join(os.path.dirname(__file__), - "check_soundcard.vbs") - p = subprocess.Popen([cscript_path, check_script], - stdout=subprocess.PIPE) - __have_soundcard_cache = not p.wait() - return __have_soundcard_cache + safe_PlaySound( + 'SystemQuestion', + winsound.SND_ALIAS | winsound.SND_ASYNC | winsound.SND_LOOP + ) + time.sleep(0.5) + safe_PlaySound('SystemQuestion', winsound.SND_ALIAS | winsound.SND_NOSTOP) + # Issue 8367: PlaySound(None, winsound.SND_PURGE) + # does not raise on systems without a sound card. + winsound.PlaySound(None, winsound.SND_PURGE) def test_main(): - test_support.run_unittest(BeepTest, MessageBeepTest, PlaySoundTest) + support.run_unittest(BeepTest, MessageBeepTest, PlaySoundTest) + if __name__=="__main__": test_main()