# Python Tools for Visual Studio # Copyright(c) Microsoft Corporation # All rights reserved. # # Licensed under the Apache License, Version 2.0 (the License); you may not use # this file except in compliance with the License. You may obtain a copy of the # License at http://www.apache.org/licenses/LICENSE-2.0 # # THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS # OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY # IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, # MERCHANTABLITY OR NON-INFRINGEMENT. # # See the Apache Version 2.0 License for specific language governing # permissions and limitations under the License. __author__ = "Microsoft Corporation " __version__ = "3.0.0.0" import os import sys import json import unittest import socket import traceback from types import CodeType, FunctionType import signal try: import thread except: import _thread as thread class _TestOutput(object): """file like object which redirects output to the repl window.""" errors = 'strict' def __init__(self, old_out, is_stdout): self.is_stdout = is_stdout self.old_out = old_out if sys.version >= '3.' and hasattr(old_out, 'buffer'): self.buffer = _TestOutputBuffer(old_out.buffer, is_stdout) def flush(self): if self.old_out: self.old_out.flush() def writelines(self, lines): for line in lines: self.write(line) @property def encoding(self): return 'utf8' def write(self, value): _channel.send_event('stdout' if self.is_stdout else 'stderr', content=value) if self.old_out: self.old_out.write(value) # flush immediately, else things go wonky and out of order self.flush() def isatty(self): return True def next(self): pass @property def name(self): if self.is_stdout: return "" else: return "" def __getattr__(self, name): return getattr(self.old_out, name) class _TestOutputBuffer(object): def __init__(self, old_buffer, is_stdout): self.buffer = old_buffer self.is_stdout = is_stdout def write(self, data): _channel.send_event('stdout' if self.is_stdout else 'stderr', content=data) self.buffer.write(data) def flush(self): self.buffer.flush() def truncate(self, pos = None): return self.buffer.truncate(pos) def tell(self): return self.buffer.tell() def seek(self, pos, whence = 0): return self.buffer.seek(pos, whence) class _IpcChannel(object): def __init__(self, socket, callback): self.socket = socket self.seq = 0 self.callback = callback self.lock = thread.allocate_lock() self._closed = False # start the testing reader thread loop self.test_thread_id = thread.start_new_thread(self.readSocket, ()) def close(self): self._closed = True def readSocket(self): try: data = self.socket.recv(1024) self.callback() except OSError: if not self._closed: raise def receive(self): pass def send_event(self, name, **args): with self.lock: body = {'type': 'event', 'seq': self.seq, 'event':name, 'body':args} self.seq += 1 content = json.dumps(body).encode('utf8') headers = ('Content-Length: %d\n\n' % (len(content), )).encode('utf8') self.socket.send(headers) self.socket.send(content) _channel = None class VsTestResult(unittest.TextTestResult): def startTest(self, test): super(VsTestResult, self).startTest(test) if _channel is not None: _channel.send_event( name='start', test = test.id() ) def addError(self, test, err): super(VsTestResult, self).addError(test, err) self.sendResult(test, 'error', err) def addFailure(self, test, err): super(VsTestResult, self).addFailure(test, err) self.sendResult(test, 'failed', err) def addSuccess(self, test): super(VsTestResult, self).addSuccess(test) self.sendResult(test, 'passed') def addSkip(self, test, reason): super(VsTestResult, self).addSkip(test, reason) self.sendResult(test, 'skipped') def addExpectedFailure(self, test, err): super(VsTestResult, self).addExpectedFailure(test, err) self.sendResult(test, 'failed', err) def addUnexpectedSuccess(self, test): super(VsTestResult, self).addUnexpectedSuccess(test) self.sendResult(test, 'passed') def sendResult(self, test, outcome, trace = None): if _channel is not None: tb = None message = None if trace is not None: traceback.print_exc() formatted = traceback.format_exception(*trace) # Remove the 'Traceback (most recent call last)' formatted = formatted[1:] tb = ''.join(formatted) message = str(trace[1]) _channel.send_event( name='result', outcome=outcome, traceback = tb, message = message, test = test.id() ) def stopTests(): try: os.kill(os.getpid(), signal.SIGUSR1) except: try: os.kill(os.getpid(), signal.SIGTERM) except: pass class ExitCommand(Exception): pass def signal_handler(signal, frame): raise ExitCommand() def main(): import os import sys import unittest from optparse import OptionParser global _channel parser = OptionParser(prog = 'visualstudio_py_testlauncher', usage = 'Usage: %prog [