1207 self.failures.append((test, reason)) |
1206 self.failures.append((test, reason)) |
1208 |
1207 |
1209 if self._options.first: |
1208 if self._options.first: |
1210 self.stop() |
1209 self.stop() |
1211 else: |
1210 else: |
1212 iolock.acquire() |
1211 with iolock: |
1213 if not self._options.nodiff: |
1212 if not self._options.nodiff: |
1214 self.stream.write('\nERROR: %s output changed\n' % test) |
1213 self.stream.write('\nERROR: %s output changed\n' % test) |
1215 |
1214 |
1216 self.stream.write('!') |
1215 self.stream.write('!') |
1217 self.stream.flush() |
1216 self.stream.flush() |
1218 iolock.release() |
|
1219 |
1217 |
1220 def addSuccess(self, test): |
1218 def addSuccess(self, test): |
1221 iolock.acquire() |
1219 with iolock: |
1222 super(TestResult, self).addSuccess(test) |
1220 super(TestResult, self).addSuccess(test) |
1223 iolock.release() |
|
1224 self.successes.append(test) |
1221 self.successes.append(test) |
1225 |
1222 |
1226 def addError(self, test, err): |
1223 def addError(self, test, err): |
1227 super(TestResult, self).addError(test, err) |
1224 super(TestResult, self).addError(test, err) |
1228 if self._options.first: |
1225 if self._options.first: |
1229 self.stop() |
1226 self.stop() |
1230 |
1227 |
1231 # Polyfill. |
1228 # Polyfill. |
1232 def addSkip(self, test, reason): |
1229 def addSkip(self, test, reason): |
1233 self.skipped.append((test, reason)) |
1230 self.skipped.append((test, reason)) |
1234 iolock.acquire() |
1231 with iolock: |
1235 if self.showAll: |
1232 if self.showAll: |
1236 self.stream.writeln('skipped %s' % reason) |
1233 self.stream.writeln('skipped %s' % reason) |
1237 else: |
1234 else: |
1238 self.stream.write('s') |
1235 self.stream.write('s') |
1239 self.stream.flush() |
1236 self.stream.flush() |
1240 iolock.release() |
|
1241 |
1237 |
1242 def addIgnore(self, test, reason): |
1238 def addIgnore(self, test, reason): |
1243 self.ignored.append((test, reason)) |
1239 self.ignored.append((test, reason)) |
1244 iolock.acquire() |
1240 with iolock: |
1245 if self.showAll: |
1241 if self.showAll: |
1246 self.stream.writeln('ignored %s' % reason) |
1242 self.stream.writeln('ignored %s' % reason) |
1247 else: |
|
1248 if reason != 'not retesting' and reason != "doesn't match keyword": |
|
1249 self.stream.write('i') |
|
1250 else: |
1243 else: |
1251 self.testsRun += 1 |
1244 if reason not in ('not retesting', "doesn't match keyword"): |
1252 self.stream.flush() |
1245 self.stream.write('i') |
1253 iolock.release() |
1246 else: |
|
1247 self.testsRun += 1 |
|
1248 self.stream.flush() |
1254 |
1249 |
1255 def addWarn(self, test, reason): |
1250 def addWarn(self, test, reason): |
1256 self.warned.append((test, reason)) |
1251 self.warned.append((test, reason)) |
1257 |
1252 |
1258 if self._options.first: |
1253 if self._options.first: |
1259 self.stop() |
1254 self.stop() |
1260 |
1255 |
1261 iolock.acquire() |
1256 with iolock: |
1262 if self.showAll: |
1257 if self.showAll: |
1263 self.stream.writeln('warned %s' % reason) |
1258 self.stream.writeln('warned %s' % reason) |
1264 else: |
1259 else: |
1265 self.stream.write('~') |
1260 self.stream.write('~') |
1266 self.stream.flush() |
1261 self.stream.flush() |
1267 iolock.release() |
|
1268 |
1262 |
1269 def addOutputMismatch(self, test, ret, got, expected): |
1263 def addOutputMismatch(self, test, ret, got, expected): |
1270 """Record a mismatch in test output for a particular test.""" |
1264 """Record a mismatch in test output for a particular test.""" |
1271 if self.shouldStop: |
1265 if self.shouldStop: |
1272 # don't print, some other test case already failed and |
1266 # don't print, some other test case already failed and |
1276 |
1270 |
1277 accepted = False |
1271 accepted = False |
1278 failed = False |
1272 failed = False |
1279 lines = [] |
1273 lines = [] |
1280 |
1274 |
1281 iolock.acquire() |
1275 with iolock: |
1282 if self._options.nodiff: |
1276 if self._options.nodiff: |
1283 pass |
1277 pass |
1284 elif self._options.view: |
1278 elif self._options.view: |
1285 os.system("%s %s %s" % |
1279 os.system("%s %s %s" % |
1286 (self._options.view, test.refpath, test.errpath)) |
1280 (self._options.view, test.refpath, test.errpath)) |
1287 else: |
|
1288 servefail, lines = getdiff(expected, got, |
|
1289 test.refpath, test.errpath) |
|
1290 if servefail: |
|
1291 self.addFailure( |
|
1292 test, |
|
1293 'server failed to start (HGPORT=%s)' % test._startport) |
|
1294 else: |
1281 else: |
1295 self.stream.write('\n') |
1282 servefail, lines = getdiff(expected, got, |
1296 for line in lines: |
1283 test.refpath, test.errpath) |
1297 self.stream.write(line) |
1284 if servefail: |
1298 self.stream.flush() |
1285 self.addFailure( |
1299 |
1286 test, |
1300 # handle interactive prompt without releasing iolock |
1287 'server failed to start (HGPORT=%s)' % test._startport) |
1301 if self._options.interactive: |
|
1302 self.stream.write('Accept this change? [n] ') |
|
1303 answer = sys.stdin.readline().strip() |
|
1304 if answer.lower() in ('y', 'yes'): |
|
1305 if test.name.endswith('.t'): |
|
1306 rename(test.errpath, test.path) |
|
1307 else: |
1288 else: |
1308 rename(test.errpath, '%s.out' % test.path) |
1289 self.stream.write('\n') |
1309 accepted = True |
1290 for line in lines: |
1310 if not accepted and not failed: |
1291 self.stream.write(line) |
1311 self.faildata[test.name] = ''.join(lines) |
1292 self.stream.flush() |
1312 iolock.release() |
1293 |
|
1294 # handle interactive prompt without releasing iolock |
|
1295 if self._options.interactive: |
|
1296 self.stream.write('Accept this change? [n] ') |
|
1297 answer = sys.stdin.readline().strip() |
|
1298 if answer.lower() in ('y', 'yes'): |
|
1299 if test.name.endswith('.t'): |
|
1300 rename(test.errpath, test.path) |
|
1301 else: |
|
1302 rename(test.errpath, '%s.out' % test.path) |
|
1303 accepted = True |
|
1304 if not accepted and not failed: |
|
1305 self.faildata[test.name] = ''.join(lines) |
1313 |
1306 |
1314 return accepted |
1307 return accepted |
1315 |
1308 |
1316 def startTest(self, test): |
1309 def startTest(self, test): |
1317 super(TestResult, self).startTest(test) |
1310 super(TestResult, self).startTest(test) |
1500 failed = len(result.failures) |
1492 failed = len(result.failures) |
1501 warned = len(result.warned) |
1493 warned = len(result.warned) |
1502 skipped = len(result.skipped) |
1494 skipped = len(result.skipped) |
1503 ignored = len(result.ignored) |
1495 ignored = len(result.ignored) |
1504 |
1496 |
1505 iolock.acquire() |
1497 with iolock: |
1506 self.stream.writeln('') |
1498 self.stream.writeln('') |
1507 |
1499 |
1508 if not self._runner.options.noskips: |
1500 if not self._runner.options.noskips: |
1509 for test, msg in result.skipped: |
1501 for test, msg in result.skipped: |
1510 self.stream.writeln('Skipped %s: %s' % (test.name, msg)) |
1502 self.stream.writeln('Skipped %s: %s' % (test.name, msg)) |
1511 for test, msg in result.warned: |
1503 for test, msg in result.warned: |
1512 self.stream.writeln('Warned %s: %s' % (test.name, msg)) |
1504 self.stream.writeln('Warned %s: %s' % (test.name, msg)) |
1513 for test, msg in result.failures: |
1505 for test, msg in result.failures: |
1514 self.stream.writeln('Failed %s: %s' % (test.name, msg)) |
1506 self.stream.writeln('Failed %s: %s' % (test.name, msg)) |
1515 for test, msg in result.errors: |
1507 for test, msg in result.errors: |
1516 self.stream.writeln('Errored %s: %s' % (test.name, msg)) |
1508 self.stream.writeln('Errored %s: %s' % (test.name, msg)) |
1517 |
1509 |
1518 if self._runner.options.xunit: |
1510 if self._runner.options.xunit: |
1519 xuf = open(self._runner.options.xunit, 'wb') |
1511 xuf = open(self._runner.options.xunit, 'wb') |
1520 try: |
1512 try: |
1521 timesd = dict((t[0], t[3]) for t in result.times) |
1513 timesd = dict((t[0], t[3]) for t in result.times) |
1522 doc = minidom.Document() |
1514 doc = minidom.Document() |
1523 s = doc.createElement('testsuite') |
1515 s = doc.createElement('testsuite') |
1524 s.setAttribute('name', 'run-tests') |
1516 s.setAttribute('name', 'run-tests') |
1525 s.setAttribute('tests', str(result.testsRun)) |
1517 s.setAttribute('tests', str(result.testsRun)) |
1526 s.setAttribute('errors', "0") # TODO |
1518 s.setAttribute('errors', "0") # TODO |
1527 s.setAttribute('failures', str(failed)) |
1519 s.setAttribute('failures', str(failed)) |
1528 s.setAttribute('skipped', str(skipped + ignored)) |
1520 s.setAttribute('skipped', str(skipped + ignored)) |
1529 doc.appendChild(s) |
1521 doc.appendChild(s) |
1530 for tc in result.successes: |
1522 for tc in result.successes: |
1531 t = doc.createElement('testcase') |
1523 t = doc.createElement('testcase') |
1532 t.setAttribute('name', tc.name) |
1524 t.setAttribute('name', tc.name) |
1533 t.setAttribute('time', '%.3f' % timesd[tc.name]) |
1525 t.setAttribute('time', '%.3f' % timesd[tc.name]) |
1534 s.appendChild(t) |
1526 s.appendChild(t) |
1535 for tc, err in sorted(result.faildata.iteritems()): |
1527 for tc, err in sorted(result.faildata.iteritems()): |
1536 t = doc.createElement('testcase') |
1528 t = doc.createElement('testcase') |
1537 t.setAttribute('name', tc) |
1529 t.setAttribute('name', tc) |
1538 t.setAttribute('time', '%.3f' % timesd[tc]) |
1530 t.setAttribute('time', '%.3f' % timesd[tc]) |
1539 # createCDATASection expects a unicode or it will convert |
1531 # createCDATASection expects a unicode or it will |
1540 # using default conversion rules, which will fail if |
1532 # convert using default conversion rules, which will |
1541 # string isn't ASCII. |
1533 # fail if string isn't ASCII. |
1542 err = cdatasafe(err).decode('utf-8', 'replace') |
1534 err = cdatasafe(err).decode('utf-8', 'replace') |
1543 cd = doc.createCDATASection(err) |
1535 cd = doc.createCDATASection(err) |
1544 t.appendChild(cd) |
1536 t.appendChild(cd) |
1545 s.appendChild(t) |
1537 s.appendChild(t) |
1546 xuf.write(doc.toprettyxml(indent=' ', encoding='utf-8')) |
1538 xuf.write(doc.toprettyxml(indent=' ', encoding='utf-8')) |
1547 finally: |
1539 finally: |
1548 xuf.close() |
1540 xuf.close() |
1549 |
1541 |
1550 if self._runner.options.json: |
1542 if self._runner.options.json: |
1551 if json is None: |
1543 if json is None: |
1552 raise ImportError("json module not installed") |
1544 raise ImportError("json module not installed") |
1553 jsonpath = os.path.join(self._runner._testdir, 'report.json') |
1545 jsonpath = os.path.join(self._runner._testdir, 'report.json') |
1554 fp = open(jsonpath, 'w') |
1546 fp = open(jsonpath, 'w') |
1555 try: |
1547 try: |
1556 timesd = {} |
1548 timesd = {} |
1557 for tdata in result.times: |
1549 for tdata in result.times: |
1558 test = tdata[0] |
1550 test = tdata[0] |
1559 timesd[test] = tdata[1:] |
1551 timesd[test] = tdata[1:] |
1560 |
1552 |
1561 outcome = {} |
1553 outcome = {} |
1562 groups = [('success', ((tc, None) for tc in result.successes)), |
1554 groups = [('success', ((tc, None) |
1563 ('failure', result.failures), |
1555 for tc in result.successes)), |
1564 ('skip', result.skipped)] |
1556 ('failure', result.failures), |
1565 for res, testcases in groups: |
1557 ('skip', result.skipped)] |
1566 for tc, __ in testcases: |
1558 for res, testcases in groups: |
1567 testresult = {'result': res, |
1559 for tc, __ in testcases: |
1568 'time': ('%0.3f' % timesd[tc.name][2]), |
1560 tres = {'result': res, |
1569 'cuser': ('%0.3f' % timesd[tc.name][0]), |
1561 'time': ('%0.3f' % timesd[tc.name][2]), |
1570 'csys': ('%0.3f' % timesd[tc.name][1])} |
1562 'cuser': ('%0.3f' % timesd[tc.name][0]), |
1571 outcome[tc.name] = testresult |
1563 'csys': ('%0.3f' % timesd[tc.name][1])} |
1572 |
1564 outcome[tc.name] = tres |
1573 jsonout = json.dumps(outcome, sort_keys=True, indent=4) |
1565 |
1574 fp.writelines(("testreport =", jsonout)) |
1566 jsonout = json.dumps(outcome, sort_keys=True, indent=4) |
1575 finally: |
1567 fp.writelines(("testreport =", jsonout)) |
1576 fp.close() |
1568 finally: |
1577 |
1569 fp.close() |
1578 self._runner._checkhglib('Tested') |
1570 |
1579 |
1571 self._runner._checkhglib('Tested') |
1580 self.stream.writeln('# Ran %d tests, %d skipped, %d warned, %d failed.' |
1572 |
1581 % (result.testsRun, |
1573 self.stream.writeln( |
1582 skipped + ignored, warned, failed)) |
1574 '# Ran %d tests, %d skipped, %d warned, %d failed.' |
1583 if failed: |
1575 % (result.testsRun, |
1584 self.stream.writeln('python hash seed: %s' % |
1576 skipped + ignored, warned, failed)) |
1585 os.environ['PYTHONHASHSEED']) |
1577 if failed: |
1586 if self._runner.options.time: |
1578 self.stream.writeln('python hash seed: %s' % |
1587 self.printtimes(result.times) |
1579 os.environ['PYTHONHASHSEED']) |
1588 |
1580 if self._runner.options.time: |
1589 iolock.release() |
1581 self.printtimes(result.times) |
1590 |
1582 |
1591 return result |
1583 return result |
1592 |
1584 |
1593 def printtimes(self, times): |
1585 def printtimes(self, times): |
1594 # iolock held by run |
1586 # iolock held by run |