diff --git a/tests/auto/testlib/selftests/generate_expected_output.py b/tests/auto/testlib/selftests/generate_expected_output.py
index b917dacc782..1bf8cf6603c 100755
--- a/tests/auto/testlib/selftests/generate_expected_output.py
+++ b/tests/auto/testlib/selftests/generate_expected_output.py
@@ -32,89 +32,185 @@
##
#############################################################################
-#regenerate all test's output
+# Regenerate all tests' output.
+#
+# Usage: cd to the build directory corresponding to this script's
+# location; invoke this script; optionally pass the names of sub-dirs
+# to limit which tests to regenerate expected_* files for.
import os
-import sys
import subprocess
-import re
-formats = ['xml', 'txt', 'xunitxml', 'lightxml']
+class Fail (Exception): pass
-qtver = subprocess.check_output(['qmake', '-query', 'QT_VERSION']).strip().decode('utf-8')
-rootPath = os.getcwd()
+class Cleaner (object):
+ """Tool to clean up test output to make diff-ing runs useful.
-isWindows = sys.platform == 'win32'
+ We care about whether tests pass or fail - if that changes,
+ something that matters has happened - and we care about some
+ changes to what they say when they do fail; but we don't care
+ exactly what line of what file the failing line of code now
+ occupies, nor do we care how many milliseconds each test took to
+ run; and changes to the Qt version number mean nothing to us.
-replacements = [
- (qtver, r'@INSERT_QT_VERSION_HERE@'),
- (r'Config: Using QtTest library.*', r'Config: Using QtTest library'), # Build string in text logs
- (rootPath.encode('unicode-escape').decode('utf-8'), r''),
- (r'( *)', r'\1'),
- (r'( *)[^<]+', r'\1'), # Build element in xml, lightxml
- (r'', r'') # Build in xunitxml
-]
+ Create one singleton instance; it'll do mildly expensive things
+ once and you can use its .clean() method to tidy up your test
+ output."""
-extraArgs = {
- "commandlinedata": "fiveTablePasses fiveTablePasses:fiveTablePasses_data1 -v2",
- "benchlibcallgrind": "-callgrind",
- "benchlibeventcounter": "-eventcounter",
- "benchliboptions": "-eventcounter",
- "benchlibtickcounter": "-tickcounter",
- "badxml": "-eventcounter",
- "benchlibcounting": "-eventcounter",
- "printdatatags": "-datatags",
- "printdatatagswithglobaltags": "-datatags",
- "silent": "-silent",
- "verbose1": "-v1",
- "verbose2": "-v2",
-}
+ def __init__(self, here, command):
+ """Set up the details we need for later cleaning.
-# Replace all occurrences of searchExp in one file
-def replaceInFile(file):
- import sys
- import fileinput
- for line in fileinput.input(file, inplace=1):
- for searchExp, replaceExp in replacements:
- line = re.sub(searchExp, replaceExp, line)
- sys.stdout.write(line)
+ Takes two parameters: here is $PWD and command is how this
+ script was invoked, from which we'll work out where it is; in
+ a shadow build, the former is the build tree's location
+ corresponding to this last. Checks $PWD does look as expected
+ in a build tree - raising Fail() if not - then invokes qmake
+ to discover Qt version (saved as .version for the benefit of
+ clients) and prepares the sequence of (regex, replace) pairs
+ that .clean() needs to do its job."""
+ self.version, self.__replace = self.__getPatterns(here, command)
-def subdirs():
- result = []
- for path in os.listdir('.'):
- if os.path.isdir('./' + path):
- result.append(path)
- return result
+ import re
+ @staticmethod
+ def __getPatterns(here, command,
+ patterns = (
+ # Timings:
+ (r'( *', r'\1"0"/>'), # xml, lightxml
+ (r'(Totals:.*,) *[0-9.]+ms', r'\1 0ms'), # txt
+ # Benchmarks:
+ (r'[0-9,.]+( (?:CPU ticks|msecs) per iteration \(total:) [0-9,.]+ ', r'0\1 0, '), # txt
+ (r'(,"(?:CPUTicks|WalltimeMilliseconds)"),\d+,\d+,', r'\1,0,0,'), # csv
+ (r'([^<]+', r'\1/>'), # xml, lightxml
+ (r'()', r'\1\2'), # xunitxml
+ # Line numbers in source files:
+ (r'(Loc: \[[^[\]()]+)\(\d+\)', r'\1(0)'), # txt
+ # (r'(\[Loc: [^[\]()]+)\(\d+\)', r'\1(0)'), # teamcity
+ (r'(