# JS unit test support for py.test - (c) 2007 Guido Wesdorp. All rights # reserved # # This software is distributed under the terms of the JSBase # License. See LICENSE.txt for license text. import py here = py.magic.autopath().dirpath() class JSTest(py.test.collect.Item): def run(self): path = self.fspath test = self.name.split('/')[-1] paths = [path.strpath, (here / 'exception.js').strpath, (here / 'testing.js').strpath, (here / 'misclib.js').strpath, ] testjs = (here / 'testing/testbase.js').read() % ( paths, test, '__main__') curdir = str(py.path.local('.')) py.std.os.chdir(str(self.fspath.dirpath())) try: jspath = self.fspath.new(basename='__testbase_temp.js') try: jspath.write(testjs) pipe = py.std.os.popen('js "%s"' % (jspath,)) try: data = {} for line in pipe: done = self._handle_line(line, data) if done: errdata = data[data['current']] if errdata: self.fail(errdata) print errdata finally: pipe.close() finally: jspath.remove() finally: py.std.os.chdir(curdir) def fail(self, errdata): py.test.fail( '\nJS traceback (most recent last): \n%s\n%s\n' % ( (errdata[1:] and self._format_tb(errdata[1:-5]) or 'no traceback available' ), errdata[0], ) ) _handling_traceback = False _printing = False def _handle_line(self, line, data): line = line[:-1] printing = self._printing self._printing = False if line.startswith('end test'): return True if self._handling_traceback and line != 'end traceback': data[data['current']].append(line) if line.startswith('PRINTED: '): print line[9:] self._printing = True elif line.startswith('running test '): testname = line[13:] data['current'] = testname data[testname] = [] elif line.startswith('success'): pass elif line.startswith('failure: '): data[data['current']].append(line.split(':', 1)[1].strip()) elif line.startswith('traceback'): self._handling_traceback = True elif line.startswith('end traceback'): self._handling_traceback = False else: if printing: self._printing = True print line def _format_tb(self, tb): tb.reverse() ret = [] for line in tb: line = line.strip() if not line: continue funcsig, lineinfo = line.rsplit('@', 1) fpath, lineno = lineinfo.rsplit(':', 1) fname = py.path.local(fpath).basename # XXX might filter out too much... but it's better than leaving it # all in (since it adds a couple of lines to the end of the tb, # making it harder to find the problem line) if fname in ['__testbase_temp.js', '__testbase_find.js', 'exception.js']: continue lineno = int(lineno) if lineno == 0: fname = "" ret.append('File "%s", line %s, in %s' % ( fname, lineno, funcsig or '?')) if lineno > 0: line = py.path.local(fpath).readlines()[lineno - 1] ret.append(' %s' % (line.strip(),)) return '\n'.join([' %s' % (r,) for r in ret]) class JSChecker(py.test.collect.Module): def __repr__(self): return py.test.collect.Collector.__repr__(self) def setup(self): pass def teardown(self): pass def run(self): findjs = here.join('testing/findtests.js').read() % ( self.fspath.strpath, '__main__') curdir = str(py.path.local('.')) py.std.os.chdir(str(self.fspath.dirpath())) tests = [] try: jspath = self.fspath.new(basename='__findtests.js') try: jspath.write(findjs) stdin, pipe, stderr = py.std.os.popen3('js "%s"' % (jspath,)) try: error = stderr.next() print 'Error read:', error except StopIteration: pass else: if error.find('command not found') > -1: py.test.skip( 'error running "js" (SpiderMonkey), which is ' 'required to run JS tests') else: py.test.fail(error) return try: for line in pipe: tests.append(line.strip()) finally: py.std.sys.stdout = py.std.sys.__stdout__ pipe.close() finally: jspath.remove() finally: py.std.os.chdir(curdir) return ['%s/%s' % (self.fspath.basename, test) for test in tests] def join(self, name): if py.path.local(name).dirpath().strpath.endswith('.js'): return JSTest(name, self) return super(JSChecker, self).join(name) class Directory(py.test.collect.Directory): def run(self): if self.fspath == here: return [p.basename for p in self.fspath.listdir('test_*') if p.ext in ['.py', '.js']] return super(Directory, self).run() def join(self, name): if not name.endswith('.js'): return super(Directory, self).join(name) p = self.fspath.join(name) if p.check(file=1): return JSChecker(p, parent=self)