changeset 61:24f144e11b5e

Accurate run-time reporting on Win32
author Oleg Oshmyan <chortos@inbox.lv>
date Tue, 21 Dec 2010 19:38:58 +0200
parents 7c6dba0b84f2
children 593ad09cd69b
files testcases.py
diffstat 1 files changed, 74 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/testcases.py	Tue Dec 21 03:08:04 2010 +0200
+++ b/testcases.py	Tue Dec 21 19:38:58 2010 +0200
@@ -94,14 +94,84 @@
 	from errno import EINTR
 except ImportError:
 	try:
+		from _subprocess import WAIT_OBJECT_0, STD_INPUT_HANDLE, INFINITE
+	except ImportError:
+		WAIT_OBJECT_0 = 0
+		STD_INPUT_HANDLE = -10
+		INFINITE = -1
+	try:
 		import ctypes
+		SetConsoleMode = ctypes.windll.kernel32.SetConsoleMode
+		FlushConsoleInputBuffer = ctypes.windll.kernel32.FlushConsoleInputBuffer
 		WaitForMultipleObjects = ctypes.windll.kernel32.WaitForMultipleObjects
+		ReadConsoleInputA = ctypes.windll.kernel32.ReadConsoleInputA
+		try:
+			from _subprocess import GetStdHandle
+		except ImportError:
+			GetStdHandle = ctypes.windll.kernel32.GetStdHandle
 	except (ImportError, AttributeError):
-		pass
+		console_input = False
 	else:
-		# TODO: implement Win32 call()
-		pass
-	call = None
+		hStdin = GetStdHandle(STD_INPUT_HANDLE)
+		console_input = bool(SetConsoleMode(hStdin, 1))
+		if console_input:
+			FlushConsoleInputBuffer(hStdin)
+			class KEY_EVENT_RECORD(ctypes.Structure):
+				_fields_ = (("bKeyDown", ctypes.c_int),
+					        ("wRepeatCount", ctypes.c_ushort),
+					        ("wVirtualKeyCode", ctypes.c_ushort),
+					        ("wVirtualScanCode", ctypes.c_ushort),
+					        ("UnicodeChar", ctypes.c_wchar),
+					        ("dwControlKeyState", ctypes.c_uint))
+			class INPUT_RECORD(ctypes.Structure):
+				_fields_ = (("EventType", ctypes.c_int),
+					        ("KeyEvent", KEY_EVENT_RECORD))
+	# Memory limits (currently) are not supported
+	def call(*args, **kwargs):
+		case = kwargs.pop('case')
+		try:
+			case.process = Popen(*args, **kwargs)
+		except OSError:
+			raise CannotStartTestee(sys.exc_info()[1])
+		case.time_started = clock()
+		if not console_input:
+			if case.maxtime:
+				if WaitForSingleObject(case.process._handle, int(case.maxtime * 1000)) != WAIT_OBJECT_0:
+					raise TimeLimitExceeded
+			else:
+				case.process.wait()
+		else:
+			ir = INPUT_RECORD()
+			n = ctypes.c_int()
+			lpHandles = (ctypes.c_int * 2)(hStdin, case.process._handle)
+			if case.maxtime:
+				time_end = clock() + case.maxtime
+				while case.process.poll() is None:
+					remaining = time_end - clock()
+					if remaining > 0:
+						if WaitForMultipleObjects(2, lpHandles, False, int(remaining * 1000)) == WAIT_OBJECT_0:
+							ReadConsoleInputA(hStdin, ctypes.byref(ir), 1, ctypes.byref(n))
+							if ir.EventType == 1 and ir.KeyEvent.bKeyDown and ir.KeyEvent.wVirtualKeyCode == 27:
+								raise CanceledByUser
+					else:
+						raise TimeLimitExceeded
+			else:
+				while case.process.poll() is None:
+					if WaitForMultipleObjects(2, lpHandles, False, INFINITE) == WAIT_OBJECT_0:
+						ReadConsoleInputA(hStdin, ctypes.byref(ir), 1, ctypes.byref(n))
+						if ir.EventType == 1 and ir.KeyEvent.bKeyDown and ir.KeyEvent.wVirtualKeyCode == 27:
+							raise CanceledByUser
+		case.time_stopped = clock()
+	if not console_input:
+		try:
+			try:
+				from _subprocess import WaitForSingleObject
+			except ImportError:
+				import ctypes
+				WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject
+		except (ImportError, AttributeError):
+			# TODO: move the default implementation here
+			call = None
 else:
 	# Make SIGCHLD interrupt sleep() and select()
 	def bury_child(signum, frame):
@@ -114,7 +184,6 @@
 	# If you want this to work, don't set any stdio argument to PIPE
 	def call_real(*args, **kwargs):
 		bury_child.case = case = kwargs.pop('case')
-		# FIXME: kill the process no matter what
 		try:
 			case.process = Popen(*args, **kwargs)
 		except OSError: