From f86151617920a4e3a348e24b999f9ab593fa2e3a Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 7 Aug 2013 21:43:12 +0000 Subject: [lit] Avoid deprecated dict.has_key() method. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187917 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/Util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/Util.py b/utils/lit/lit/Util.py index 6f09eed..3b28db4 100644 --- a/utils/lit/lit/Util.py +++ b/utils/lit/lit/Util.py @@ -6,7 +6,7 @@ def detectCPUs(): """ # Linux, Unix and MacOS: if hasattr(os, "sysconf"): - if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"): + if "SC_NPROCESSORS_ONLN" in os.sysconf_names: # Linux & Unix: ncpus = os.sysconf("SC_NPROCESSORS_ONLN") if isinstance(ncpus, int) and ncpus > 0: @@ -14,7 +14,7 @@ def detectCPUs(): else: # OSX: return int(capture(['sysctl', '-n', 'hw.ncpu'])) # Windows: - if os.environ.has_key("NUMBER_OF_PROCESSORS"): + if "NUMBER_OF_PROCESSORS" in os.environ: ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]) if ncpus > 0: return ncpus -- cgit v1.1 From a1ba7527ded837e4c98149f7b1fe848a93177e07 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 7 Aug 2013 21:43:17 +0000 Subject: [lit] Use list comprehensions instead of map(). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187918 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitConfig.py | 2 +- utils/lit/lit/TestRunner.py | 3 ++- utils/lit/lit/__init__.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index bd7a603..9a5ff99 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -32,7 +32,7 @@ class LitConfig: # The name of the test runner. self.progname = progname # The items to add to the PATH environment variable. - self.path = list(map(str, path)) + self.path = list([str(p) for p in path]) self.quiet = bool(quiet) self.useValgrind = bool(useValgrind) self.valgrindLeakCheck = bool(valgrindLeakCheck) diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 989a992..1beb92c 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -416,7 +416,8 @@ def parseIntegratedTestScript(test, normalize_slashes=False, # Strip the trailing newline and any extra whitespace. return ln.strip() - script = map(processLine, script) + script = [processLine(ln) + for ln in script] # Verify the script contains a run line. if not script: diff --git a/utils/lit/lit/__init__.py b/utils/lit/lit/__init__.py index b9f573d..3967fdd 100644 --- a/utils/lit/lit/__init__.py +++ b/utils/lit/lit/__init__.py @@ -6,6 +6,6 @@ from .main import main __author__ = 'Daniel Dunbar' __email__ = 'daniel@zuster.org' __versioninfo__ = (0, 3, 0) -__version__ = '.'.join(map(str, __versioninfo__)) + 'dev' +__version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev' __all__ = [] -- cgit v1.1 From bd9bb2c515173a2d9fa8f8472e06a753618c0c7a Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 7 Aug 2013 21:43:23 +0000 Subject: [lit] Avoid comparisons with None. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187919 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestRunner.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 1beb92c..9fe9eb9 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -224,7 +224,9 @@ def executeShCmd(cmd, cfg, cwd, results): results.append((cmd.commands[i], out, err, res)) if cmd.pipe_err: # Python treats the exit code as a signed char. - if res < 0: + if exitCode is None: + exitCode = res + elif res < 0: exitCode = min(exitCode, res) else: exitCode = max(exitCode, res) -- cgit v1.1 From 9c2c660e1228fe513b5940a7fb5d3a763728dcbc Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 7 Aug 2013 21:43:34 +0000 Subject: [lit] Report the traceback when config import fails. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187920 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestingConfig.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'utils') diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index f4ff89f..925099c 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -74,6 +74,11 @@ class TestingConfig: # return control without error. if e.args: raise + except: + import traceback + litConfig.fatal( + 'unable to parse config file %r, traceback: %s' % ( + path, traceback.format_exc())) f.close() else: if mustExist: -- cgit v1.1 From 05fb743a99ac6a1fc147682a2262a6190f193ab4 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 7 Aug 2013 23:09:55 +0000 Subject: [lit] Make string encoding issues explicit. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187931 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/ProgressBar.py | 6 +++++- utils/lit/lit/TestFormats.py | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/lit/lit/ProgressBar.py b/utils/lit/lit/ProgressBar.py index 0454ba2..2481bdf 100644 --- a/utils/lit/lit/ProgressBar.py +++ b/utils/lit/lit/ProgressBar.py @@ -135,7 +135,11 @@ class TerminalController: # For any modern terminal, we should be able to just ignore # these, so strip them out. import curses - cap = curses.tigetstr(cap_name) or '' + cap = curses.tigetstr(cap_name) + if cap is None: + cap = '' + else: + cap = cap.decode('ascii') return re.sub(r'\$<\d+>[/*]?', '', cap) def render(self, template): diff --git a/utils/lit/lit/TestFormats.py b/utils/lit/lit/TestFormats.py index 9e0c7a0..9c43a21 100644 --- a/utils/lit/lit/TestFormats.py +++ b/utils/lit/lit/TestFormats.py @@ -30,6 +30,7 @@ class GoogleTest(object): try: lines = lit.Util.capture([path, '--gtest_list_tests'], env=localConfig.environment) + lines = lines.decode('ascii') if kIsWindows: lines = lines.replace('\r', '') lines = lines.split('\n') -- cgit v1.1 From 32b7d4dfc1eefd1081c5bf9533c25616aee129bd Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 7 Aug 2013 23:10:01 +0000 Subject: [lit] Explicitly convert dict items() result to a list. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187932 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index acf6101..c11f020 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -297,7 +297,7 @@ def main(builtinParameters = {}): if t.suite not in suitesAndTests: suitesAndTests[t.suite] = [] suitesAndTests[t.suite].append(t) - suitesAndTests = suitesAndTests.items() + suitesAndTests = list(suitesAndTests.items()) suitesAndTests.sort(key = lambda item: item[0].name) # Show the suites, if requested. -- cgit v1.1 From 91a62c34d8e40f3f5b51b07b2edb156f7bcbbffc Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 7 Aug 2013 23:10:05 +0000 Subject: [lit] Always list individual UNRESOLVED tests. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187933 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index c11f020..41c2a2f 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -400,9 +400,10 @@ def main(builtinParameters = {}): if t.result.isFailure: hasFailures = True - # FIXME: Show unresolved and (optionally) unsupported tests. + # Print each test in any of the failing groups. for title,code in (('Unexpected Passing Tests', lit.Test.XPASS), - ('Failing Tests', lit.Test.FAIL)): + ('Failing Tests', lit.Test.FAIL), + ('Unresolved Tests', lit.Test.UNRESOLVED)): elts = byCode.get(code) if not elts: continue -- cgit v1.1 From 6104a4e4cc614f5ddbde0e79c156801e21b8d0df Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 7 Aug 2013 23:10:20 +0000 Subject: [lit] Remove unnecessary list copy. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187934 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitConfig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index 9a5ff99..fda1b7b 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -32,7 +32,7 @@ class LitConfig: # The name of the test runner. self.progname = progname # The items to add to the PATH environment variable. - self.path = list([str(p) for p in path]) + self.path = [str(p) for p in path] self.quiet = bool(quiet) self.useValgrind = bool(useValgrind) self.valgrindLeakCheck = bool(valgrindLeakCheck) -- cgit v1.1 From 9d11edb416d2a61ddaee15664acb52432094079f Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 8 Aug 2013 20:59:13 +0000 Subject: [lit] Remove on_clone member, which is no longer used. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188006 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestingConfig.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index 925099c..d4d218b 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -45,7 +45,6 @@ class TestingConfig: environment = environment, substitutions = [], unsupported = False, - on_clone = None, test_exec_root = None, test_source_root = None, excludes = [], @@ -90,7 +89,7 @@ class TestingConfig: return config def __init__(self, parent, name, suffixes, test_format, - environment, substitutions, unsupported, on_clone, + environment, substitutions, unsupported, test_exec_root, test_source_root, excludes, available_features, pipefail): self.parent = parent @@ -100,7 +99,6 @@ class TestingConfig: self.environment = dict(environment) self.substitutions = list(substitutions) self.unsupported = unsupported - self.on_clone = on_clone self.test_exec_root = test_exec_root self.test_source_root = test_source_root self.excludes = set(excludes) @@ -111,15 +109,12 @@ class TestingConfig: # FIXME: Chain implementations? # # FIXME: Allow extra parameters? - cfg = TestingConfig(self, self.name, self.suffixes, self.test_format, - self.environment, self.substitutions, - self.unsupported, self.on_clone, - self.test_exec_root, self.test_source_root, - self.excludes, self.available_features, - self.pipefail) - if cfg.on_clone: - cfg.on_clone(self, cfg, path) - return cfg + return TestingConfig(self, self.name, self.suffixes, self.test_format, + self.environment, self.substitutions, + self.unsupported, + self.test_exec_root, self.test_source_root, + self.excludes, self.available_features, + self.pipefail) def finish(self, litConfig): """finish() - Finish this config object, after loading is complete.""" -- cgit v1.1 From 0e5f7c5d2f81cadfd48a8e4c06578e774fab6006 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 8 Aug 2013 20:59:16 +0000 Subject: [lit] Eliminate some nested imports. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188007 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitConfig.py | 7 ++----- utils/lit/lit/ProgressBar.py | 1 - utils/lit/lit/Util.py | 12 ++++++------ utils/lit/lit/main.py | 1 - 4 files changed, 8 insertions(+), 13 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index fda1b7b..c183613 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -1,5 +1,7 @@ from __future__ import absolute_import +import inspect import os +import sys import lit.Test import lit.TestFormats @@ -75,8 +77,6 @@ class LitConfig: def getBashPath(self): """getBashPath - Get the path to 'bash'""" - import os - if self.bashPath is not None: return self.bashPath @@ -110,8 +110,6 @@ class LitConfig: return dir def _write_message(self, kind, message): - import inspect, os, sys - # Get the file/line where this message was generated. f = inspect.currentframe() # Step out of _write_message, and then out of wrapper. @@ -134,6 +132,5 @@ class LitConfig: self.numErrors += 1 def fatal(self, message): - import sys self._write_message('fatal', message) sys.exit(2) diff --git a/utils/lit/lit/ProgressBar.py b/utils/lit/lit/ProgressBar.py index 2481bdf..8b9b81e 100644 --- a/utils/lit/lit/ProgressBar.py +++ b/utils/lit/lit/ProgressBar.py @@ -273,7 +273,6 @@ class ProgressBar: self.cleared = 1 def test(): - import time tc = TerminalController() p = ProgressBar(tc, 'Tests') for i in range(101): diff --git a/utils/lit/lit/Util.py b/utils/lit/lit/Util.py index 3b28db4..d7d6d7f 100644 --- a/utils/lit/lit/Util.py +++ b/utils/lit/lit/Util.py @@ -1,4 +1,9 @@ -import os, sys +import errno +import itertools +import math +import os +import subprocess +import sys def detectCPUs(): """ @@ -23,8 +28,6 @@ def detectCPUs(): def mkdir_p(path): """mkdir_p(path) - Make the "path" directory, if it does not exist; this will also make directories for any missing parent directories.""" - import errno - if not path or os.path.exists(path): return @@ -41,7 +44,6 @@ def mkdir_p(path): raise def capture(args, env=None): - import subprocess """capture(command) - Run the given command (or argv list) in a shell and return the standard output.""" p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -93,8 +95,6 @@ def whichTools(tools, paths): return None def printHistogram(items, title = 'Items'): - import itertools, math - items.sort(key = lambda item: item[1]) maxValue = max([v for _,v in items]) diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 41c2a2f..9fff757 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -161,7 +161,6 @@ def main(builtinParameters = {}): # blocking operation (hopefully exec) than to try and unblock other threads. # # FIXME: This is a hack. - import sys sys.setcheckinterval(1000) global options -- cgit v1.1 From 59c6b1073c48befe021de024a693bed94147120c Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 8 Aug 2013 20:59:20 +0000 Subject: [lit] Remove --repeat option, which wasn't that useful. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188008 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/Test.py | 8 -------- utils/lit/lit/TestRunner.py | 2 -- utils/lit/lit/main.py | 8 -------- 3 files changed, 18 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py index 9471e3a..cf12425 100644 --- a/utils/lit/lit/Test.py +++ b/utils/lit/lit/Test.py @@ -58,14 +58,6 @@ class Test: self.output = None # The wall time to execute this test, if timing and once complete. self.elapsed = None - # The repeat index of this test, or None. - self.index = None - - def copyWithIndex(self, index): - import copy - res = copy.copy(self) - res.index = index - return res def setResult(self, result, output, elapsed): assert self.result is None, "Test result already set!" diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 9fe9eb9..27e29b7 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -344,8 +344,6 @@ def parseIntegratedTestScript(test, normalize_slashes=False, execdir,execbase = os.path.split(execpath) tmpDir = os.path.join(execdir, 'Output') tmpBase = os.path.join(tmpDir, execbase) - if test.index is not None: - tmpBase += '_%d' % test.index # Normalize slashes, if requested. if normalize_slashes: diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 9fff757..5eaf725 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -242,9 +242,6 @@ def main(builtinParameters = {}): group.add_option("", "--show-tests", dest="showTests", help="Show all discovered tests", action="store_true", default=False) - group.add_option("", "--repeat", dest="repeatTests", metavar="N", - help="Repeat tests N times (for timing)", - action="store", default=None, type=int) parser.add_option_group(group) (opts, args) = parser.parse_args() @@ -347,11 +344,6 @@ def main(builtinParameters = {}): header = '-- Testing: %d%s tests, %d threads --'%(len(tests),extra, opts.numThreads) - if opts.repeatTests: - tests = [t.copyWithIndex(i) - for t in tests - for i in range(opts.repeatTests)] - progressBar = None if not opts.quiet: if opts.succinct and opts.useProgressBar: -- cgit v1.1 From abb9de5257375dbf10c87bdbf40ecafa777a0881 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 8 Aug 2013 20:59:25 +0000 Subject: [lit] Change --show-{tests,suites} to exit after printing. - This is a more sensible behavior than printing and also running tests. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188009 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 5 ++++- utils/lit/tests/discovery.py | 15 +++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 5eaf725..767fe10 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -311,7 +311,10 @@ def main(builtinParameters = {}): ts_tests.sort(key = lambda test: test.path_in_suite) for test in ts_tests: print(' %s' % (test.getFullName(),)) - + + # Exit. + sys.exit(0) + # Select and order the tests. numTotalTests = len(tests) diff --git a/utils/lit/tests/discovery.py b/utils/lit/tests/discovery.py index be98c4b..2801089 100644 --- a/utils/lit/tests/discovery.py +++ b/utils/lit/tests/discovery.py @@ -1,7 +1,7 @@ # Check the basic discovery process, including a sub-suite. # # RUN: %{lit} %{inputs}/discovery \ -# RUN: -j 1 --debug --show-tests --show-suites --max-tests 0 \ +# RUN: -j 1 --debug --show-tests --show-suites \ # RUN: -v > %t.out 2> %t.err # RUN: FileCheck --check-prefix=CHECK-BASIC-OUT < %t.out %s # RUN: FileCheck --check-prefix=CHECK-BASIC-ERR < %t.err %s @@ -24,7 +24,6 @@ # CHECK-BASIC-OUT: top-level-suite :: subdir/test-three # CHECK-BASIC-OUT: top-level-suite :: test-one # CHECK-BASIC-OUT: top-level-suite :: test-two -# CHECK-BASIC-OUT: -- Testing: 0 # Check discovery when exact test names are given. @@ -32,19 +31,18 @@ # RUN: %{lit} \ # RUN: %{inputs}/discovery/subdir/test-three.py \ # RUN: %{inputs}/discovery/subsuite/test-one.txt \ -# RUN: -j 1 --show-tests --show-suites --max-tests 0 -v > %t.out +# RUN: -j 1 --show-tests --show-suites -v > %t.out # RUN: FileCheck --check-prefix=CHECK-EXACT-TEST < %t.out %s # # CHECK-EXACT-TEST: -- Available Tests -- # CHECK-EXACT-TEST: sub-suite :: test-one # CHECK-EXACT-TEST: top-level-suite :: subdir/test-three -# CHECK-EXACT-TEST: -- Testing: 0 # Check discovery when using an exec path. # # RUN: %{lit} %{inputs}/exec-discovery \ -# RUN: -j 1 --debug --show-tests --show-suites --max-tests 0 \ +# RUN: -j 1 --debug --show-tests --show-suites \ # RUN: -v > %t.out 2> %t.err # RUN: FileCheck --check-prefix=CHECK-ASEXEC-OUT < %t.out %s # RUN: FileCheck --check-prefix=CHECK-ASEXEC-ERR < %t.err %s @@ -70,7 +68,6 @@ # CHECK-ASEXEC-OUT: top-level-suite :: subdir/test-three # CHECK-ASEXEC-OUT: top-level-suite :: test-one # CHECK-ASEXEC-OUT: top-level-suite :: test-two -# CHECK-ASEXEC-OUT: -- Testing: 0 # Check discovery when exact test names are given. # @@ -78,12 +75,11 @@ # # RUN: %{lit} \ # RUN: %{inputs}/exec-discovery/subdir/test-three.py \ -# RUN: -j 1 --show-tests --show-suites --max-tests 0 -v > %t.out +# RUN: -j 1 --show-tests --show-suites -v > %t.out # RUN: FileCheck --check-prefix=CHECK-ASEXEC-EXACT-TEST < %t.out %s # # CHECK-ASEXEC-EXACT-TEST: -- Available Tests -- # CHECK-ASEXEC-EXACT-TEST: top-level-suite :: subdir/test-three -# CHECK-ASEXEC-EXACT-TEST: -- Testing: 0 # Check that we don't recurse infinitely when loading an site specific test @@ -91,7 +87,7 @@ # # RUN: %{lit} \ # RUN: %{inputs}/exec-discovery-in-tree/obj/ \ -# RUN: -j 1 --show-tests --show-suites --max-tests 0 -v > %t.out +# RUN: -j 1 --show-tests --show-suites -v > %t.out # RUN: FileCheck --check-prefix=CHECK-ASEXEC-INTREE < %t.out %s # # CHECK-ASEXEC-INTREE: exec-discovery-in-tree-suite - 1 tests @@ -99,4 +95,3 @@ # CHECK-ASEXEC-INTREE-NEXT: Exec Root : {{.*/exec-discovery-in-tree/obj$}} # CHECK-ASEXEC-INTREE-NEXT: -- Available Tests -- # CHECK-ASEXEC-INTREE-NEXT: exec-discovery-in-tree-suite :: test-one -# CHECK-ASEXEC-INTREE: -- Testing: 0 -- cgit v1.1 From b3c0c58ca4ecd21566899b369eb70742e44cc8ea Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 9 Aug 2013 00:08:46 +0000 Subject: [lit] Eliminate parent argument from TestingConfig.frompath(), which is effectively unused. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188032 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitConfig.py | 2 +- utils/lit/lit/TestingConfig.py | 11 +++++++++-- utils/lit/lit/discovery.py | 5 ++--- 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index c183613..d493b33 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -73,7 +73,7 @@ class LitConfig: if self.debug: self.note('load_config from %r' % path) return lit.TestingConfig.TestingConfig.frompath( - path, config.parent, self, mustExist = True, config = config) + path, config, self, mustExist = True) def getBashPath(self): """getBashPath - Get the path to 'bash'""" diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index d4d218b..6df84b6 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -9,7 +9,14 @@ class TestingConfig: """ @staticmethod - def frompath(path, parent, litConfig, mustExist, config = None): + def frompath(path, config, litConfig, mustExist): + """ + frompath(path, config, litConfig, mustExist) -> TestingConfig + + Load the configuration module at the provided path into the given config + object (or create a new one if None is provided) and return the config. + """ + if config is None: # Set the environment based on the command line arguments. environment = { @@ -38,7 +45,7 @@ class TestingConfig: if litConfig.valgrindLeakCheck: available_features.append('vg_leak') - config = TestingConfig(parent, + config = TestingConfig(None, name = '', suffixes = set(), test_format = None, diff --git a/utils/lit/lit/discovery.py b/utils/lit/lit/discovery.py index f76bd22..35b29c6 100644 --- a/utils/lit/lit/discovery.py +++ b/utils/lit/lit/discovery.py @@ -83,9 +83,8 @@ def getLocalConfig(ts, path_in_suite, litConfig, cache): cfgpath = os.path.join(source_path, litConfig.local_config_name) if litConfig.debug: litConfig.note('loading local config %r' % cfgpath) - return TestingConfig.frompath(cfgpath, parent, litConfig, - mustExist = False, - config = parent.clone(cfgpath)) + return TestingConfig.frompath(cfgpath, parent.clone(cfgpath), litConfig, + mustExist = False) def search(path_in_suite): key = (ts, path_in_suite) -- cgit v1.1 From 3279653eb85d2f09175f6a2deb0a12b93fed9ecf Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 9 Aug 2013 00:08:56 +0000 Subject: [lit] Only create config copies when a local config file is present. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188033 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestingConfig.py | 4 ++-- utils/lit/lit/discovery.py | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index 6df84b6..ec15f38 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -9,7 +9,7 @@ class TestingConfig: """ @staticmethod - def frompath(path, config, litConfig, mustExist): + def frompath(path, config, litConfig, mustExist=True): """ frompath(path, config, litConfig, mustExist) -> TestingConfig @@ -112,7 +112,7 @@ class TestingConfig: self.available_features = set(available_features) self.pipefail = pipefail - def clone(self, path): + def clone(self): # FIXME: Chain implementations? # # FIXME: Allow extra parameters? diff --git a/utils/lit/lit/discovery.py b/utils/lit/lit/discovery.py index 35b29c6..afcee58 100644 --- a/utils/lit/lit/discovery.py +++ b/utils/lit/lit/discovery.py @@ -78,13 +78,20 @@ def getLocalConfig(ts, path_in_suite, litConfig, cache): else: parent = search(path_in_suite[:-1]) - # Load the local configuration. + # Check if there is a local configuration file. source_path = ts.getSourcePath(path_in_suite) cfgpath = os.path.join(source_path, litConfig.local_config_name) + + # If not, just reuse the parent config. + if not os.path.exists(cfgpath): + return parent + + # Otherwise, copy the current config and load the local configuration + # file into it. + config = parent.clone() if litConfig.debug: litConfig.note('loading local config %r' % cfgpath) - return TestingConfig.frompath(cfgpath, parent.clone(cfgpath), litConfig, - mustExist = False) + return TestingConfig.frompath(cfgpath, config, litConfig) def search(path_in_suite): key = (ts, path_in_suite) -- cgit v1.1 From 49e51429c1e1cf37b2cc23fdf208d9f470acf430 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 9 Aug 2013 00:09:02 +0000 Subject: [lit] Eliminate mustExist parameter from TestingConfig.frompath(). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188034 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitConfig.py | 3 +- utils/lit/lit/TestingConfig.py | 66 ++++++++++++++++++++---------------------- utils/lit/lit/discovery.py | 2 +- 3 files changed, 34 insertions(+), 37 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index d493b33..6e669d5 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -72,8 +72,7 @@ class LitConfig: path.""" if self.debug: self.note('load_config from %r' % path) - return lit.TestingConfig.TestingConfig.frompath( - path, config, self, mustExist = True) + return lit.TestingConfig.TestingConfig.frompath(path, config, self) def getBashPath(self): """getBashPath - Get the path to 'bash'""" diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index ec15f38..8c619e1 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -9,7 +9,7 @@ class TestingConfig: """ @staticmethod - def frompath(path, config, litConfig, mustExist=True): + def frompath(path, config, litConfig): """ frompath(path, config, litConfig, mustExist) -> TestingConfig @@ -58,39 +58,37 @@ class TestingConfig: available_features = available_features, pipefail = True) - if os.path.exists(path): - # FIXME: Improve detection and error reporting of errors in the - # config file. - f = open(path) - cfg_globals = dict(globals()) - cfg_globals['config'] = config - cfg_globals['lit'] = litConfig - cfg_globals['__file__'] = path - try: - data = f.read() - if PY2: - exec("exec data in cfg_globals") - else: - exec(data, cfg_globals) - if litConfig.debug: - litConfig.note('... loaded config %r' % path) - except SystemExit: - e = sys.exc_info()[1] - # We allow normal system exit inside a config file to just - # return control without error. - if e.args: - raise - except: - import traceback - litConfig.fatal( - 'unable to parse config file %r, traceback: %s' % ( - path, traceback.format_exc())) - f.close() - else: - if mustExist: - litConfig.fatal('unable to load config from %r ' % path) - elif litConfig.debug: - litConfig.note('... config not found - %r' %path) + # Load the config script data. + f = open(path) + try: + data = f.read() + except: + litConfig.fatal('unable to load config file: %r' % (path,)) + f.close() + + # Execute the config script to initialize the object. + cfg_globals = dict(globals()) + cfg_globals['config'] = config + cfg_globals['lit'] = litConfig + cfg_globals['__file__'] = path + try: + if PY2: + exec("exec data in cfg_globals") + else: + exec(data, cfg_globals) + if litConfig.debug: + litConfig.note('... loaded config %r' % path) + except SystemExit: + e = sys.exc_info()[1] + # We allow normal system exit inside a config file to just + # return control without error. + if e.args: + raise + except: + import traceback + litConfig.fatal( + 'unable to parse config file %r, traceback: %s' % ( + path, traceback.format_exc())) config.finish(litConfig) return config diff --git a/utils/lit/lit/discovery.py b/utils/lit/lit/discovery.py index afcee58..c5f48a6 100644 --- a/utils/lit/lit/discovery.py +++ b/utils/lit/lit/discovery.py @@ -42,7 +42,7 @@ def getTestSuite(item, litConfig, cache): if litConfig.debug: litConfig.note('loading suite config %r' % cfgpath) - cfg = TestingConfig.frompath(cfgpath, None, litConfig, mustExist = True) + cfg = TestingConfig.frompath(cfgpath, None, litConfig) source_root = os.path.realpath(cfg.test_source_root or path) exec_root = os.path.realpath(cfg.test_exec_root or path) return Test.TestSuite(cfg.name, source_root, exec_root, cfg), () -- cgit v1.1 From 6c749c5fbc94a9f133ed05e389aab4309f187684 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 9 Aug 2013 00:36:58 +0000 Subject: [lit] Split TestingConfig.frompath() into separate ctor and load methods. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188038 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitConfig.py | 3 +- utils/lit/lit/TestingConfig.py | 98 ++++++++++++++++++++++-------------------- utils/lit/lit/discovery.py | 8 ++-- 3 files changed, 58 insertions(+), 51 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index 6e669d5..bcaea13 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -72,7 +72,8 @@ class LitConfig: path.""" if self.debug: self.note('load_config from %r' % path) - return lit.TestingConfig.TestingConfig.frompath(path, config, self) + config.load_from_path(path, self) + return config def getBashPath(self): """getBashPath - Get the path to 'bash'""" diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index 8c619e1..a122b78 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -9,54 +9,59 @@ class TestingConfig: """ @staticmethod - def frompath(path, config, litConfig): + def fromdefaults(litConfig): """ - frompath(path, config, litConfig, mustExist) -> TestingConfig + fromdefaults(litConfig -> TestingConfig - Load the configuration module at the provided path into the given config - object (or create a new one if None is provided) and return the config. + Create a TestingConfig object with default values. + """ + # Set the environment based on the command line arguments. + environment = { + 'LIBRARY_PATH' : os.environ.get('LIBRARY_PATH',''), + 'LD_LIBRARY_PATH' : os.environ.get('LD_LIBRARY_PATH',''), + 'PATH' : os.pathsep.join(litConfig.path + + [os.environ.get('PATH','')]), + 'SYSTEMROOT' : os.environ.get('SYSTEMROOT',''), + 'TERM' : os.environ.get('TERM',''), + 'LLVM_DISABLE_CRASH_REPORT' : '1', + } + + if sys.platform == 'win32': + environment.update({ + 'INCLUDE' : os.environ.get('INCLUDE',''), + 'PATHEXT' : os.environ.get('PATHEXT',''), + 'PYTHONUNBUFFERED' : '1', + 'TEMP' : os.environ.get('TEMP',''), + 'TMP' : os.environ.get('TMP',''), + }) + + # Set the default available features based on the LitConfig. + available_features = [] + if litConfig.useValgrind: + available_features.append('valgrind') + if litConfig.valgrindLeakCheck: + available_features.append('vg_leak') + + return TestingConfig(None, + name = '', + suffixes = set(), + test_format = None, + environment = environment, + substitutions = [], + unsupported = False, + test_exec_root = None, + test_source_root = None, + excludes = [], + available_features = available_features, + pipefail = True) + + def load_from_path(self, path, litConfig): """ + load_from_path(path, litConfig) - if config is None: - # Set the environment based on the command line arguments. - environment = { - 'LIBRARY_PATH' : os.environ.get('LIBRARY_PATH',''), - 'LD_LIBRARY_PATH' : os.environ.get('LD_LIBRARY_PATH',''), - 'PATH' : os.pathsep.join(litConfig.path + - [os.environ.get('PATH','')]), - 'SYSTEMROOT' : os.environ.get('SYSTEMROOT',''), - 'TERM' : os.environ.get('TERM',''), - 'LLVM_DISABLE_CRASH_REPORT' : '1', - } - - if sys.platform == 'win32': - environment.update({ - 'INCLUDE' : os.environ.get('INCLUDE',''), - 'PATHEXT' : os.environ.get('PATHEXT',''), - 'PYTHONUNBUFFERED' : '1', - 'TEMP' : os.environ.get('TEMP',''), - 'TMP' : os.environ.get('TMP',''), - }) - - # Set the default available features based on the LitConfig. - available_features = [] - if litConfig.useValgrind: - available_features.append('valgrind') - if litConfig.valgrindLeakCheck: - available_features.append('vg_leak') - - config = TestingConfig(None, - name = '', - suffixes = set(), - test_format = None, - environment = environment, - substitutions = [], - unsupported = False, - test_exec_root = None, - test_source_root = None, - excludes = [], - available_features = available_features, - pipefail = True) + Load the configuration module at the provided path into the given config + object. + """ # Load the config script data. f = open(path) @@ -68,7 +73,7 @@ class TestingConfig: # Execute the config script to initialize the object. cfg_globals = dict(globals()) - cfg_globals['config'] = config + cfg_globals['config'] = self cfg_globals['lit'] = litConfig cfg_globals['__file__'] = path try: @@ -90,8 +95,7 @@ class TestingConfig: 'unable to parse config file %r, traceback: %s' % ( path, traceback.format_exc())) - config.finish(litConfig) - return config + self.finish(litConfig) def __init__(self, parent, name, suffixes, test_format, environment, substitutions, unsupported, diff --git a/utils/lit/lit/discovery.py b/utils/lit/lit/discovery.py index c5f48a6..26882fe 100644 --- a/utils/lit/lit/discovery.py +++ b/utils/lit/lit/discovery.py @@ -38,11 +38,12 @@ def getTestSuite(item, litConfig, cache): ts, relative = search(parent) return (ts, relative + (base,)) - # We found a config file, load it. + # We found a test suite, create a new config for it and load it. if litConfig.debug: litConfig.note('loading suite config %r' % cfgpath) - cfg = TestingConfig.frompath(cfgpath, None, litConfig) + cfg = TestingConfig.fromdefaults(litConfig) + cfg.load_from_path(cfgpath, litConfig) source_root = os.path.realpath(cfg.test_source_root or path) exec_root = os.path.realpath(cfg.test_exec_root or path) return Test.TestSuite(cfg.name, source_root, exec_root, cfg), () @@ -91,7 +92,8 @@ def getLocalConfig(ts, path_in_suite, litConfig, cache): config = parent.clone() if litConfig.debug: litConfig.note('loading local config %r' % cfgpath) - return TestingConfig.frompath(cfgpath, config, litConfig) + config.load_from_path(cfgpath, litConfig) + return config def search(path_in_suite): key = (ts, path_in_suite) -- cgit v1.1 From 38649827c38a4fcb93219eb29e104c91b0228e56 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 9 Aug 2013 00:37:05 +0000 Subject: [lit] Inject the lit specific config object as 'lit_config' when loading config files. - Injecting it as 'lit' is gross, since that name should be used to refer to the actual package. For now both are available so it is possibly to cleanup test config files incrementally. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188039 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestingConfig.py | 1 + 1 file changed, 1 insertion(+) (limited to 'utils') diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index a122b78..d1492af 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -75,6 +75,7 @@ class TestingConfig: cfg_globals = dict(globals()) cfg_globals['config'] = self cfg_globals['lit'] = litConfig + cfg_globals['lit_config'] = litConfig cfg_globals['__file__'] = path try: if PY2: -- cgit v1.1 From 128ce319ec47c46dc7da16aa3a75185899878745 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 9 Aug 2013 00:37:15 +0000 Subject: [lit] Rename lit.{TestFormats,Util} to their aliased names {formats,util}. - With compatibility hack in lit.__init__, so this hopefully shouldn't break anything. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188040 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitConfig.py | 16 +-- utils/lit/lit/ShUtil.py | 8 +- utils/lit/lit/TestFormats.py | 230 ------------------------------------------- utils/lit/lit/TestRunner.py | 6 +- utils/lit/lit/Util.py | 140 -------------------------- utils/lit/lit/__init__.py | 4 + utils/lit/lit/formats.py | 230 +++++++++++++++++++++++++++++++++++++++++++ utils/lit/lit/main.py | 6 +- utils/lit/lit/util.py | 140 ++++++++++++++++++++++++++ 9 files changed, 392 insertions(+), 388 deletions(-) delete mode 100644 utils/lit/lit/TestFormats.py delete mode 100644 utils/lit/lit/Util.py create mode 100644 utils/lit/lit/formats.py create mode 100644 utils/lit/lit/util.py (limited to 'utils') diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index bcaea13..4b312e2 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -4,9 +4,9 @@ import os import sys import lit.Test -import lit.TestFormats +import lit.formats import lit.TestingConfig -import lit.Util +import lit.util class LitConfig: """LitConfig - Configuration data for a 'lit' test runner instance, shared @@ -22,10 +22,10 @@ class LitConfig: Test = lit.Test # Provide access to built-in formats. - formats = lit.TestFormats + formats = lit.formats # Provide access to built-in utility functions. - util = lit.Util + util = lit.util def __init__(self, progname, path, quiet, useValgrind, valgrindLeakCheck, valgrindArgs, @@ -80,7 +80,7 @@ class LitConfig: if self.bashPath is not None: return self.bashPath - self.bashPath = lit.Util.which('bash', os.pathsep.join(self.path)) + self.bashPath = lit.util.which('bash', os.pathsep.join(self.path)) if self.bashPath is None: # Check some known paths. for path in ('/bin/bash', '/usr/bin/bash', '/usr/local/bin/bash'): @@ -96,13 +96,13 @@ class LitConfig: def getToolsPath(self, dir, paths, tools): if dir is not None and os.path.isabs(dir) and os.path.isdir(dir): - if not lit.Util.checkToolsPath(dir, tools): + if not lit.util.checkToolsPath(dir, tools): return None else: - dir = lit.Util.whichTools(tools, paths) + dir = lit.util.whichTools(tools, paths) # bash - self.bashPath = lit.Util.which('bash', dir) + self.bashPath = lit.util.which('bash', dir) if self.bashPath is None: self.note("Unable to find 'bash.exe'.") self.bashPath = '' diff --git a/utils/lit/lit/ShUtil.py b/utils/lit/lit/ShUtil.py index fb0689b..1945ba7 100644 --- a/utils/lit/lit/ShUtil.py +++ b/utils/lit/lit/ShUtil.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import itertools -import lit.Util +import lit.util from lit.ShCommands import Command, Pipeline, Seq class ShLexer: @@ -75,7 +75,7 @@ class ShLexer: # Outside of a string, '\\' escapes everything. self.eat() if self.pos == self.end: - lit.Util.warning( + lit.util.warning( "escape at end of quoted argument in: %r" % self.data) return str str += self.eat() @@ -93,7 +93,7 @@ class ShLexer: # Inside a '"' quoted string, '\\' only escapes the quote # character and backslash, otherwise it is preserved. if self.pos == self.end: - lit.Util.warning( + lit.util.warning( "escape at end of quoted argument in: %r" % self.data) return str c = self.eat() @@ -105,7 +105,7 @@ class ShLexer: str += '\\' + c else: str += c - lit.Util.warning("missing quote character in %r" % self.data) + lit.util.warning("missing quote character in %r" % self.data) return str def lex_arg_checked(self, c): diff --git a/utils/lit/lit/TestFormats.py b/utils/lit/lit/TestFormats.py deleted file mode 100644 index 9c43a21..0000000 --- a/utils/lit/lit/TestFormats.py +++ /dev/null @@ -1,230 +0,0 @@ -from __future__ import absolute_import -import os -import sys - -import lit.Test -import lit.TestRunner -import lit.Util - -kIsWindows = sys.platform in ['win32', 'cygwin'] - -class GoogleTest(object): - def __init__(self, test_sub_dir, test_suffix): - self.test_sub_dir = os.path.normcase(str(test_sub_dir)).split(';') - self.test_suffix = str(test_suffix) - - # On Windows, assume tests will also end in '.exe'. - if kIsWindows: - self.test_suffix += '.exe' - - def getGTestTests(self, path, litConfig, localConfig): - """getGTestTests(path) - [name] - - Return the tests available in gtest executable. - - Args: - path: String path to a gtest executable - litConfig: LitConfig instance - localConfig: TestingConfig instance""" - - try: - lines = lit.Util.capture([path, '--gtest_list_tests'], - env=localConfig.environment) - lines = lines.decode('ascii') - if kIsWindows: - lines = lines.replace('\r', '') - lines = lines.split('\n') - except: - litConfig.error("unable to discover google-tests in %r" % path) - raise StopIteration - - nested_tests = [] - for ln in lines: - if not ln.strip(): - continue - - prefix = '' - index = 0 - while ln[index*2:index*2+2] == ' ': - index += 1 - while len(nested_tests) > index: - nested_tests.pop() - - ln = ln[index*2:] - if ln.endswith('.'): - nested_tests.append(ln) - else: - yield ''.join(nested_tests) + ln - - # Note: path_in_suite should not include the executable name. - def getTestsInExecutable(self, testSuite, path_in_suite, execpath, - litConfig, localConfig): - if not execpath.endswith(self.test_suffix): - return - (dirname, basename) = os.path.split(execpath) - # Discover the tests in this executable. - for testname in self.getGTestTests(execpath, litConfig, localConfig): - testPath = path_in_suite + (basename, testname) - yield lit.Test.Test(testSuite, testPath, localConfig) - - def getTestsInDirectory(self, testSuite, path_in_suite, - litConfig, localConfig): - source_path = testSuite.getSourcePath(path_in_suite) - for filename in os.listdir(source_path): - filepath = os.path.join(source_path, filename) - if os.path.isdir(filepath): - # Iterate over executables in a directory. - if not os.path.normcase(filename) in self.test_sub_dir: - continue - dirpath_in_suite = path_in_suite + (filename, ) - for subfilename in os.listdir(filepath): - execpath = os.path.join(filepath, subfilename) - for test in self.getTestsInExecutable( - testSuite, dirpath_in_suite, execpath, - litConfig, localConfig): - yield test - elif ('.' in self.test_sub_dir): - for test in self.getTestsInExecutable( - testSuite, path_in_suite, filepath, - litConfig, localConfig): - yield test - - def execute(self, test, litConfig): - testPath,testName = os.path.split(test.getSourcePath()) - while not os.path.exists(testPath): - # Handle GTest parametrized and typed tests, whose name includes - # some '/'s. - testPath, namePrefix = os.path.split(testPath) - testName = os.path.join(namePrefix, testName) - - cmd = [testPath, '--gtest_filter=' + testName] - if litConfig.useValgrind: - cmd = litConfig.valgrindArgs + cmd - - if litConfig.noExecute: - return lit.Test.PASS, '' - - out, err, exitCode = lit.TestRunner.executeCommand( - cmd, env=test.config.environment) - - if not exitCode: - return lit.Test.PASS,'' - - return lit.Test.FAIL, out + err - -### - -class FileBasedTest(object): - def getTestsInDirectory(self, testSuite, path_in_suite, - litConfig, localConfig): - source_path = testSuite.getSourcePath(path_in_suite) - for filename in os.listdir(source_path): - # Ignore dot files and excluded tests. - if (filename.startswith('.') or - filename in localConfig.excludes): - continue - - filepath = os.path.join(source_path, filename) - if not os.path.isdir(filepath): - base,ext = os.path.splitext(filename) - if ext in localConfig.suffixes: - yield lit.Test.Test(testSuite, path_in_suite + (filename,), - localConfig) - -class ShTest(FileBasedTest): - def __init__(self, execute_external = False): - self.execute_external = execute_external - - def execute(self, test, litConfig): - return lit.TestRunner.executeShTest(test, litConfig, - self.execute_external) - -### - -import re -import tempfile - -class OneCommandPerFileTest: - # FIXME: Refactor into generic test for running some command on a directory - # of inputs. - - def __init__(self, command, dir, recursive=False, - pattern=".*", useTempInput=False): - if isinstance(command, str): - self.command = [command] - else: - self.command = list(command) - if dir is not None: - dir = str(dir) - self.dir = dir - self.recursive = bool(recursive) - self.pattern = re.compile(pattern) - self.useTempInput = useTempInput - - def getTestsInDirectory(self, testSuite, path_in_suite, - litConfig, localConfig): - dir = self.dir - if dir is None: - dir = testSuite.getSourcePath(path_in_suite) - - for dirname,subdirs,filenames in os.walk(dir): - if not self.recursive: - subdirs[:] = [] - - subdirs[:] = [d for d in subdirs - if (d != '.svn' and - d not in localConfig.excludes)] - - for filename in filenames: - if (filename.startswith('.') or - not self.pattern.match(filename) or - filename in localConfig.excludes): - continue - - path = os.path.join(dirname,filename) - suffix = path[len(dir):] - if suffix.startswith(os.sep): - suffix = suffix[1:] - test = lit.Test.Test( - testSuite, path_in_suite + tuple(suffix.split(os.sep)), - localConfig) - # FIXME: Hack? - test.source_path = path - yield test - - def createTempInput(self, tmp, test): - abstract - - def execute(self, test, litConfig): - if test.config.unsupported: - return (lit.Test.UNSUPPORTED, 'Test is unsupported') - - cmd = list(self.command) - - # If using temp input, create a temporary file and hand it to the - # subclass. - if self.useTempInput: - tmp = tempfile.NamedTemporaryFile(suffix='.cpp') - self.createTempInput(tmp, test) - tmp.flush() - cmd.append(tmp.name) - elif hasattr(test, 'source_path'): - cmd.append(test.source_path) - else: - cmd.append(test.getSourcePath()) - - out, err, exitCode = lit.TestRunner.executeCommand(cmd) - - diags = out + err - if not exitCode and not diags.strip(): - return lit.Test.PASS,'' - - # Try to include some useful information. - report = """Command: %s\n""" % ' '.join(["'%s'" % a - for a in cmd]) - if self.useTempInput: - report += """Temporary File: %s\n""" % tmp.name - report += "--\n%s--\n""" % open(tmp.name).read() - report += """Output:\n--\n%s--""" % diags - - return lit.Test.FAIL, report diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 27e29b7..8929c0b 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -10,7 +10,7 @@ except ImportError: import lit.ShUtil as ShUtil import lit.Test as Test -import lit.Util as Util +import lit.util class InternalShellError(Exception): def __init__(self, command, message): @@ -154,7 +154,7 @@ def executeShCmd(cmd, cfg, cwd, results): # Resolve the executable path ourselves. args = list(j.args) - args[0] = Util.which(args[0], cfg.environment['PATH']) + args[0] = lit.util.which(args[0], cfg.environment['PATH']) if not args[0]: raise InternalShellError(j, '%r: command not found' % j.args[0]) @@ -472,7 +472,7 @@ def executeShTest(test, litConfig, useExternalSh, return (Test.PASS, '') # Create the output directory if it does not already exist. - Util.mkdir_p(os.path.dirname(tmpBase)) + lit.util.mkdir_p(os.path.dirname(tmpBase)) if useExternalSh: res = executeScript(test, litConfig, tmpBase, script, execdir) diff --git a/utils/lit/lit/Util.py b/utils/lit/lit/Util.py deleted file mode 100644 index d7d6d7f..0000000 --- a/utils/lit/lit/Util.py +++ /dev/null @@ -1,140 +0,0 @@ -import errno -import itertools -import math -import os -import subprocess -import sys - -def detectCPUs(): - """ - Detects the number of CPUs on a system. Cribbed from pp. - """ - # Linux, Unix and MacOS: - if hasattr(os, "sysconf"): - if "SC_NPROCESSORS_ONLN" in os.sysconf_names: - # Linux & Unix: - ncpus = os.sysconf("SC_NPROCESSORS_ONLN") - if isinstance(ncpus, int) and ncpus > 0: - return ncpus - else: # OSX: - return int(capture(['sysctl', '-n', 'hw.ncpu'])) - # Windows: - if "NUMBER_OF_PROCESSORS" in os.environ: - ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]) - if ncpus > 0: - return ncpus - return 1 # Default - -def mkdir_p(path): - """mkdir_p(path) - Make the "path" directory, if it does not exist; this - will also make directories for any missing parent directories.""" - if not path or os.path.exists(path): - return - - parent = os.path.dirname(path) - if parent != path: - mkdir_p(parent) - - try: - os.mkdir(path) - except OSError: - e = sys.exc_info()[1] - # Ignore EEXIST, which may occur during a race condition. - if e.errno != errno.EEXIST: - raise - -def capture(args, env=None): - """capture(command) - Run the given command (or argv list) in a shell and - return the standard output.""" - p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=env) - out,_ = p.communicate() - return out - -def which(command, paths = None): - """which(command, [paths]) - Look up the given command in the paths string - (or the PATH environment variable, if unspecified).""" - - if paths is None: - paths = os.environ.get('PATH','') - - # Check for absolute match first. - if os.path.isfile(command): - return command - - # Would be nice if Python had a lib function for this. - if not paths: - paths = os.defpath - - # Get suffixes to search. - # On Cygwin, 'PATHEXT' may exist but it should not be used. - if os.pathsep == ';': - pathext = os.environ.get('PATHEXT', '').split(';') - else: - pathext = [''] - - # Search the paths... - for path in paths.split(os.pathsep): - for ext in pathext: - p = os.path.join(path, command + ext) - if os.path.exists(p): - return p - - return None - -def checkToolsPath(dir, tools): - for tool in tools: - if not os.path.exists(os.path.join(dir, tool)): - return False; - return True; - -def whichTools(tools, paths): - for path in paths.split(os.pathsep): - if checkToolsPath(path, tools): - return path - return None - -def printHistogram(items, title = 'Items'): - items.sort(key = lambda item: item[1]) - - maxValue = max([v for _,v in items]) - - # Select first "nice" bar height that produces more than 10 bars. - power = int(math.ceil(math.log(maxValue, 10))) - for inc in itertools.cycle((5, 2, 2.5, 1)): - barH = inc * 10**power - N = int(math.ceil(maxValue / barH)) - if N > 10: - break - elif inc == 1: - power -= 1 - - histo = [set() for i in range(N)] - for name,v in items: - bin = min(int(N * v/maxValue), N-1) - histo[bin].add(name) - - barW = 40 - hr = '-' * (barW + 34) - print('\nSlowest %s:' % title) - print(hr) - for name,value in items[-20:]: - print('%.2fs: %s' % (value, name)) - print('\n%s Times:' % title) - print(hr) - pDigits = int(math.ceil(math.log(maxValue, 10))) - pfDigits = max(0, 3-pDigits) - if pfDigits: - pDigits += pfDigits + 1 - cDigits = int(math.ceil(math.log(len(items), 10))) - print("[%s] :: [%s] :: [%s]" % ('Range'.center((pDigits+1)*2 + 3), - 'Percentage'.center(barW), - 'Count'.center(cDigits*2 + 1))) - print(hr) - for i,row in enumerate(histo): - pct = float(len(row)) / len(items) - w = int(barW * pct) - print("[%*.*fs,%*.*fs) :: [%s%s] :: [%*d/%*d]" % ( - pDigits, pfDigits, i*barH, pDigits, pfDigits, (i+1)*barH, - '*'*w, ' '*(barW-w), cDigits, len(row), cDigits, len(items))) - diff --git a/utils/lit/lit/__init__.py b/utils/lit/lit/__init__.py index 3967fdd..7b39cc5 100644 --- a/utils/lit/lit/__init__.py +++ b/utils/lit/lit/__init__.py @@ -9,3 +9,7 @@ __versioninfo__ = (0, 3, 0) __version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev' __all__ = [] + +# Compatibility hacks for old names. +from . import util as Util +from . import formats as TestFormats diff --git a/utils/lit/lit/formats.py b/utils/lit/lit/formats.py new file mode 100644 index 0000000..7a93adf --- /dev/null +++ b/utils/lit/lit/formats.py @@ -0,0 +1,230 @@ +from __future__ import absolute_import +import os +import sys + +import lit.Test +import lit.TestRunner +import lit.util + +kIsWindows = sys.platform in ['win32', 'cygwin'] + +class GoogleTest(object): + def __init__(self, test_sub_dir, test_suffix): + self.test_sub_dir = os.path.normcase(str(test_sub_dir)).split(';') + self.test_suffix = str(test_suffix) + + # On Windows, assume tests will also end in '.exe'. + if kIsWindows: + self.test_suffix += '.exe' + + def getGTestTests(self, path, litConfig, localConfig): + """getGTestTests(path) - [name] + + Return the tests available in gtest executable. + + Args: + path: String path to a gtest executable + litConfig: LitConfig instance + localConfig: TestingConfig instance""" + + try: + lines = lit.util.capture([path, '--gtest_list_tests'], + env=localConfig.environment) + lines = lines.decode('ascii') + if kIsWindows: + lines = lines.replace('\r', '') + lines = lines.split('\n') + except: + litConfig.error("unable to discover google-tests in %r" % path) + raise StopIteration + + nested_tests = [] + for ln in lines: + if not ln.strip(): + continue + + prefix = '' + index = 0 + while ln[index*2:index*2+2] == ' ': + index += 1 + while len(nested_tests) > index: + nested_tests.pop() + + ln = ln[index*2:] + if ln.endswith('.'): + nested_tests.append(ln) + else: + yield ''.join(nested_tests) + ln + + # Note: path_in_suite should not include the executable name. + def getTestsInExecutable(self, testSuite, path_in_suite, execpath, + litConfig, localConfig): + if not execpath.endswith(self.test_suffix): + return + (dirname, basename) = os.path.split(execpath) + # Discover the tests in this executable. + for testname in self.getGTestTests(execpath, litConfig, localConfig): + testPath = path_in_suite + (basename, testname) + yield lit.Test.Test(testSuite, testPath, localConfig) + + def getTestsInDirectory(self, testSuite, path_in_suite, + litConfig, localConfig): + source_path = testSuite.getSourcePath(path_in_suite) + for filename in os.listdir(source_path): + filepath = os.path.join(source_path, filename) + if os.path.isdir(filepath): + # Iterate over executables in a directory. + if not os.path.normcase(filename) in self.test_sub_dir: + continue + dirpath_in_suite = path_in_suite + (filename, ) + for subfilename in os.listdir(filepath): + execpath = os.path.join(filepath, subfilename) + for test in self.getTestsInExecutable( + testSuite, dirpath_in_suite, execpath, + litConfig, localConfig): + yield test + elif ('.' in self.test_sub_dir): + for test in self.getTestsInExecutable( + testSuite, path_in_suite, filepath, + litConfig, localConfig): + yield test + + def execute(self, test, litConfig): + testPath,testName = os.path.split(test.getSourcePath()) + while not os.path.exists(testPath): + # Handle GTest parametrized and typed tests, whose name includes + # some '/'s. + testPath, namePrefix = os.path.split(testPath) + testName = os.path.join(namePrefix, testName) + + cmd = [testPath, '--gtest_filter=' + testName] + if litConfig.useValgrind: + cmd = litConfig.valgrindArgs + cmd + + if litConfig.noExecute: + return lit.Test.PASS, '' + + out, err, exitCode = lit.TestRunner.executeCommand( + cmd, env=test.config.environment) + + if not exitCode: + return lit.Test.PASS,'' + + return lit.Test.FAIL, out + err + +### + +class FileBasedTest(object): + def getTestsInDirectory(self, testSuite, path_in_suite, + litConfig, localConfig): + source_path = testSuite.getSourcePath(path_in_suite) + for filename in os.listdir(source_path): + # Ignore dot files and excluded tests. + if (filename.startswith('.') or + filename in localConfig.excludes): + continue + + filepath = os.path.join(source_path, filename) + if not os.path.isdir(filepath): + base,ext = os.path.splitext(filename) + if ext in localConfig.suffixes: + yield lit.Test.Test(testSuite, path_in_suite + (filename,), + localConfig) + +class ShTest(FileBasedTest): + def __init__(self, execute_external = False): + self.execute_external = execute_external + + def execute(self, test, litConfig): + return lit.TestRunner.executeShTest(test, litConfig, + self.execute_external) + +### + +import re +import tempfile + +class OneCommandPerFileTest: + # FIXME: Refactor into generic test for running some command on a directory + # of inputs. + + def __init__(self, command, dir, recursive=False, + pattern=".*", useTempInput=False): + if isinstance(command, str): + self.command = [command] + else: + self.command = list(command) + if dir is not None: + dir = str(dir) + self.dir = dir + self.recursive = bool(recursive) + self.pattern = re.compile(pattern) + self.useTempInput = useTempInput + + def getTestsInDirectory(self, testSuite, path_in_suite, + litConfig, localConfig): + dir = self.dir + if dir is None: + dir = testSuite.getSourcePath(path_in_suite) + + for dirname,subdirs,filenames in os.walk(dir): + if not self.recursive: + subdirs[:] = [] + + subdirs[:] = [d for d in subdirs + if (d != '.svn' and + d not in localConfig.excludes)] + + for filename in filenames: + if (filename.startswith('.') or + not self.pattern.match(filename) or + filename in localConfig.excludes): + continue + + path = os.path.join(dirname,filename) + suffix = path[len(dir):] + if suffix.startswith(os.sep): + suffix = suffix[1:] + test = lit.Test.Test( + testSuite, path_in_suite + tuple(suffix.split(os.sep)), + localConfig) + # FIXME: Hack? + test.source_path = path + yield test + + def createTempInput(self, tmp, test): + abstract + + def execute(self, test, litConfig): + if test.config.unsupported: + return (lit.Test.UNSUPPORTED, 'Test is unsupported') + + cmd = list(self.command) + + # If using temp input, create a temporary file and hand it to the + # subclass. + if self.useTempInput: + tmp = tempfile.NamedTemporaryFile(suffix='.cpp') + self.createTempInput(tmp, test) + tmp.flush() + cmd.append(tmp.name) + elif hasattr(test, 'source_path'): + cmd.append(test.source_path) + else: + cmd.append(test.getSourcePath()) + + out, err, exitCode = lit.TestRunner.executeCommand(cmd) + + diags = out + err + if not exitCode and not diags.strip(): + return lit.Test.PASS,'' + + # Try to include some useful information. + report = """Command: %s\n""" % ' '.join(["'%s'" % a + for a in cmd]) + if self.useTempInput: + report += """Temporary File: %s\n""" % tmp.name + report += "--\n%s--\n""" % open(tmp.name).read() + report += """Output:\n--\n%s--""" % diags + + return lit.Test.FAIL, report diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 767fe10..fb3614a 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -12,7 +12,7 @@ import math, os, platform, random, re, sys, time, threading, traceback import lit.ProgressBar import lit.LitConfig import lit.Test -import lit.Util +import lit.util import lit.discovery @@ -255,7 +255,7 @@ def main(builtinParameters = {}): # I haven't seen this bug occur with 2.5.2 and later, so only enable multiple # threads by default there. if sys.hexversion >= 0x2050200: - opts.numThreads = lit.Util.detectCPUs() + opts.numThreads = lit.util.detectCPUs() else: opts.numThreads = 1 @@ -417,7 +417,7 @@ def main(builtinParameters = {}): byTime = list(times.items()) byTime.sort(key = lambda item: item[1]) if byTime: - lit.Util.printHistogram(byTime, title='Tests') + lit.util.printHistogram(byTime, title='Tests') for name,code in (('Expected Passes ', lit.Test.PASS), ('Expected Failures ', lit.Test.XFAIL), diff --git a/utils/lit/lit/util.py b/utils/lit/lit/util.py new file mode 100644 index 0000000..d7d6d7f --- /dev/null +++ b/utils/lit/lit/util.py @@ -0,0 +1,140 @@ +import errno +import itertools +import math +import os +import subprocess +import sys + +def detectCPUs(): + """ + Detects the number of CPUs on a system. Cribbed from pp. + """ + # Linux, Unix and MacOS: + if hasattr(os, "sysconf"): + if "SC_NPROCESSORS_ONLN" in os.sysconf_names: + # Linux & Unix: + ncpus = os.sysconf("SC_NPROCESSORS_ONLN") + if isinstance(ncpus, int) and ncpus > 0: + return ncpus + else: # OSX: + return int(capture(['sysctl', '-n', 'hw.ncpu'])) + # Windows: + if "NUMBER_OF_PROCESSORS" in os.environ: + ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]) + if ncpus > 0: + return ncpus + return 1 # Default + +def mkdir_p(path): + """mkdir_p(path) - Make the "path" directory, if it does not exist; this + will also make directories for any missing parent directories.""" + if not path or os.path.exists(path): + return + + parent = os.path.dirname(path) + if parent != path: + mkdir_p(parent) + + try: + os.mkdir(path) + except OSError: + e = sys.exc_info()[1] + # Ignore EEXIST, which may occur during a race condition. + if e.errno != errno.EEXIST: + raise + +def capture(args, env=None): + """capture(command) - Run the given command (or argv list) in a shell and + return the standard output.""" + p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + env=env) + out,_ = p.communicate() + return out + +def which(command, paths = None): + """which(command, [paths]) - Look up the given command in the paths string + (or the PATH environment variable, if unspecified).""" + + if paths is None: + paths = os.environ.get('PATH','') + + # Check for absolute match first. + if os.path.isfile(command): + return command + + # Would be nice if Python had a lib function for this. + if not paths: + paths = os.defpath + + # Get suffixes to search. + # On Cygwin, 'PATHEXT' may exist but it should not be used. + if os.pathsep == ';': + pathext = os.environ.get('PATHEXT', '').split(';') + else: + pathext = [''] + + # Search the paths... + for path in paths.split(os.pathsep): + for ext in pathext: + p = os.path.join(path, command + ext) + if os.path.exists(p): + return p + + return None + +def checkToolsPath(dir, tools): + for tool in tools: + if not os.path.exists(os.path.join(dir, tool)): + return False; + return True; + +def whichTools(tools, paths): + for path in paths.split(os.pathsep): + if checkToolsPath(path, tools): + return path + return None + +def printHistogram(items, title = 'Items'): + items.sort(key = lambda item: item[1]) + + maxValue = max([v for _,v in items]) + + # Select first "nice" bar height that produces more than 10 bars. + power = int(math.ceil(math.log(maxValue, 10))) + for inc in itertools.cycle((5, 2, 2.5, 1)): + barH = inc * 10**power + N = int(math.ceil(maxValue / barH)) + if N > 10: + break + elif inc == 1: + power -= 1 + + histo = [set() for i in range(N)] + for name,v in items: + bin = min(int(N * v/maxValue), N-1) + histo[bin].add(name) + + barW = 40 + hr = '-' * (barW + 34) + print('\nSlowest %s:' % title) + print(hr) + for name,value in items[-20:]: + print('%.2fs: %s' % (value, name)) + print('\n%s Times:' % title) + print(hr) + pDigits = int(math.ceil(math.log(maxValue, 10))) + pfDigits = max(0, 3-pDigits) + if pfDigits: + pDigits += pfDigits + 1 + cDigits = int(math.ceil(math.log(len(items), 10))) + print("[%s] :: [%s] :: [%s]" % ('Range'.center((pDigits+1)*2 + 3), + 'Percentage'.center(barW), + 'Count'.center(cDigits*2 + 1))) + print(hr) + for i,row in enumerate(histo): + pct = float(len(row)) / len(items) + w = int(barW * pct) + print("[%*.*fs,%*.*fs) :: [%s%s] :: [%*d/%*d]" % ( + pDigits, pfDigits, i*barH, pDigits, pfDigits, (i+1)*barH, + '*'*w, ' '*(barW-w), cDigits, len(row), cDigits, len(items))) + -- cgit v1.1 From efdcf800fe45e9e9eefaf05fc075c68e1ee50fd3 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 9 Aug 2013 19:39:42 +0000 Subject: [lit] Fix typo. - Noticed by edward-san (IRC). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188096 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestingConfig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index d1492af..1fd94b8 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -11,7 +11,7 @@ class TestingConfig: @staticmethod def fromdefaults(litConfig): """ - fromdefaults(litConfig -> TestingConfig + fromdefaults(litConfig) -> TestingConfig Create a TestingConfig object with default values. """ -- cgit v1.1 From 4981a6ca97aac2b5a491895cdfd87c44f98bd7a0 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 9 Aug 2013 21:39:17 +0000 Subject: [lit] Update lit's own tests to use lit_config and lit package, as appropriate. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188107 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/tests/Inputs/discovery/lit.cfg | 1 + utils/lit/tests/Inputs/discovery/subsuite/lit.cfg | 1 + utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg | 4 +++- utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg | 2 +- utils/lit/tests/Inputs/exec-discovery/lit.site.cfg | 2 +- utils/lit/tests/Inputs/progress-bar/lit.cfg | 1 + utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg | 1 + utils/lit/tests/Inputs/shtest-format/lit.cfg | 1 + utils/lit/tests/Inputs/shtest-shell/lit.cfg | 1 + utils/lit/tests/Inputs/unittest-adaptor/lit.cfg | 1 + utils/lit/tests/lit.cfg | 4 +++- 11 files changed, 15 insertions(+), 4 deletions(-) (limited to 'utils') diff --git a/utils/lit/tests/Inputs/discovery/lit.cfg b/utils/lit/tests/Inputs/discovery/lit.cfg index 4049ab1..1c5436b 100644 --- a/utils/lit/tests/Inputs/discovery/lit.cfg +++ b/utils/lit/tests/Inputs/discovery/lit.cfg @@ -1,3 +1,4 @@ +import lit.formats config.name = 'top-level-suite' config.suffixes = ['.txt'] config.test_format = lit.formats.ShTest() diff --git a/utils/lit/tests/Inputs/discovery/subsuite/lit.cfg b/utils/lit/tests/Inputs/discovery/subsuite/lit.cfg index 0c2979d..b49329a 100644 --- a/utils/lit/tests/Inputs/discovery/subsuite/lit.cfg +++ b/utils/lit/tests/Inputs/discovery/subsuite/lit.cfg @@ -1,3 +1,4 @@ +import lit.formats config.name = 'sub-suite' config.suffixes = ['.txt'] config.test_format = lit.formats.ShTest() diff --git a/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg b/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg index 342b2fd..ae25b4f 100644 --- a/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg +++ b/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg @@ -1,6 +1,8 @@ +import lit.formats + # Verify that the site configuration was loaded. if config.test_source_root is None or config.test_exec_root is None: - lit.fatal("No site specific configuration") + lit_config.fatal("No site specific configuration") config.name = 'exec-discovery-in-tree-suite' config.suffixes = ['.txt'] diff --git a/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg b/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg index de9a3d0..4061c89 100644 --- a/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg +++ b/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg @@ -1,4 +1,4 @@ import os config.test_exec_root = os.path.dirname(__file__) config.test_source_root = os.path.dirname(config.test_exec_root) -lit.load_config(config, os.path.join(config.test_source_root, "lit.cfg")) \ No newline at end of file +lit_config.load_config(config, os.path.join(config.test_source_root, "lit.cfg")) \ No newline at end of file diff --git a/utils/lit/tests/Inputs/exec-discovery/lit.site.cfg b/utils/lit/tests/Inputs/exec-discovery/lit.site.cfg index 796569a..ac273c7 100644 --- a/utils/lit/tests/Inputs/exec-discovery/lit.site.cfg +++ b/utils/lit/tests/Inputs/exec-discovery/lit.site.cfg @@ -2,4 +2,4 @@ import os config.test_exec_root = os.path.dirname(__file__) config.test_source_root = os.path.join(os.path.dirname(config.test_exec_root), "discovery") -lit.load_config(config, os.path.join(config.test_source_root, "lit.cfg")) +lit_config.load_config(config, os.path.join(config.test_source_root, "lit.cfg")) diff --git a/utils/lit/tests/Inputs/progress-bar/lit.cfg b/utils/lit/tests/Inputs/progress-bar/lit.cfg index 4878b65..7f31129 100644 --- a/utils/lit/tests/Inputs/progress-bar/lit.cfg +++ b/utils/lit/tests/Inputs/progress-bar/lit.cfg @@ -1,3 +1,4 @@ +import lit.formats config.name = 'shtest-shell' config.suffixes = ['.txt'] config.test_format = lit.formats.ShTest() diff --git a/utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg b/utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg index d14d147..5e87c72 100644 --- a/utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg +++ b/utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg @@ -1 +1,2 @@ +import lit.formats config.test_format = lit.formats.ShTest(execute_external=True) diff --git a/utils/lit/tests/Inputs/shtest-format/lit.cfg b/utils/lit/tests/Inputs/shtest-format/lit.cfg index 78dd1bf..9b47985 100644 --- a/utils/lit/tests/Inputs/shtest-format/lit.cfg +++ b/utils/lit/tests/Inputs/shtest-format/lit.cfg @@ -1,3 +1,4 @@ +import lit.formats config.name = 'shtest-format' config.suffixes = ['.txt'] config.test_format = lit.formats.ShTest() diff --git a/utils/lit/tests/Inputs/shtest-shell/lit.cfg b/utils/lit/tests/Inputs/shtest-shell/lit.cfg index 4878b65..7f31129 100644 --- a/utils/lit/tests/Inputs/shtest-shell/lit.cfg +++ b/utils/lit/tests/Inputs/shtest-shell/lit.cfg @@ -1,3 +1,4 @@ +import lit.formats config.name = 'shtest-shell' config.suffixes = ['.txt'] config.test_format = lit.formats.ShTest() diff --git a/utils/lit/tests/Inputs/unittest-adaptor/lit.cfg b/utils/lit/tests/Inputs/unittest-adaptor/lit.cfg index 52de709..9e08a86 100644 --- a/utils/lit/tests/Inputs/unittest-adaptor/lit.cfg +++ b/utils/lit/tests/Inputs/unittest-adaptor/lit.cfg @@ -1,3 +1,4 @@ +import lit.formats config.name = 'unittest-adaptor' config.suffixes = ['.txt'] config.test_format = lit.formats.ShTest() diff --git a/utils/lit/tests/lit.cfg b/utils/lit/tests/lit.cfg index 32760ce..f148c91 100644 --- a/utils/lit/tests/lit.cfg +++ b/utils/lit/tests/lit.cfg @@ -2,6 +2,8 @@ import os +import lit.formats + # Configuration file for the 'lit' test runner. # name: The name of this test suite. @@ -31,6 +33,6 @@ config.substitutions.append(('%{lit}', os.path.join(src_root, 'lit.py'))) # Enable coverage.py reporting, assuming the coverage module has been installed # and sitecustomize.py in the virtualenv has been modified appropriately. -if lit.params.get('check-coverage', None): +if lit_config.params.get('check-coverage', None): config.environment['COVERAGE_PROCESS_START'] = os.path.join( os.path.dirname(__file__), ".coveragerc") -- cgit v1.1 From a5e463ea5fa7f671cf029b420bc2f375b8e71fba Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 9 Aug 2013 21:39:24 +0000 Subject: [lit] Drop deprecated aliases for lit and old module names. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188108 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitConfig.py | 9 --------- utils/lit/lit/TestingConfig.py | 1 - utils/lit/lit/__init__.py | 4 ---- 3 files changed, 14 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index 4b312e2..ed75e34 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -18,15 +18,6 @@ class LitConfig: easily. """ - # Provide access to Test module. - Test = lit.Test - - # Provide access to built-in formats. - formats = lit.formats - - # Provide access to built-in utility functions. - util = lit.util - def __init__(self, progname, path, quiet, useValgrind, valgrindLeakCheck, valgrindArgs, noExecute, debug, isWindows, diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index 1fd94b8..3f198c6 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -74,7 +74,6 @@ class TestingConfig: # Execute the config script to initialize the object. cfg_globals = dict(globals()) cfg_globals['config'] = self - cfg_globals['lit'] = litConfig cfg_globals['lit_config'] = litConfig cfg_globals['__file__'] = path try: diff --git a/utils/lit/lit/__init__.py b/utils/lit/lit/__init__.py index 7b39cc5..3967fdd 100644 --- a/utils/lit/lit/__init__.py +++ b/utils/lit/lit/__init__.py @@ -9,7 +9,3 @@ __versioninfo__ = (0, 3, 0) __version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev' __all__ = [] - -# Compatibility hacks for old names. -from . import util as Util -from . import formats as TestFormats -- cgit v1.1 From de404a2809c8cd5a017ddd7084aa28e2f36fac2d Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 9 Aug 2013 21:39:28 +0000 Subject: [lit] Move ManyTests examples to lit/examples/many-tests. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188109 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/examples/README.txt | 7 +++++++ utils/lit/examples/many-tests/README.txt | 10 ++++++++++ utils/lit/examples/many-tests/lit.cfg | 23 ++++++++++++++++++++++ utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg | 23 ---------------------- 4 files changed, 40 insertions(+), 23 deletions(-) create mode 100644 utils/lit/examples/README.txt create mode 100644 utils/lit/examples/many-tests/README.txt create mode 100644 utils/lit/examples/many-tests/lit.cfg delete mode 100644 utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg (limited to 'utils') diff --git a/utils/lit/examples/README.txt b/utils/lit/examples/README.txt new file mode 100644 index 0000000..a59daa8 --- /dev/null +++ b/utils/lit/examples/README.txt @@ -0,0 +1,7 @@ +============== + lit Examples +============== + +This directory contains examples of 'lit' test suite configurations. The test +suites they define can be run with 'lit examples/example-name', for more details +see the README in each example. diff --git a/utils/lit/examples/many-tests/README.txt b/utils/lit/examples/many-tests/README.txt new file mode 100644 index 0000000..6bffff1 --- /dev/null +++ b/utils/lit/examples/many-tests/README.txt @@ -0,0 +1,10 @@ +======================== + Many Tests lit Example +======================== + +This directory contains a trivial lit test suite configuration that defines a +custom test format which just generates a large (N=10000) number of tests that +do a small amount of work in the Python test execution code. + +This test suite is useful for testing the performance of lit on large numbers of +tests. diff --git a/utils/lit/examples/many-tests/lit.cfg b/utils/lit/examples/many-tests/lit.cfg new file mode 100644 index 0000000..8f7b940 --- /dev/null +++ b/utils/lit/examples/many-tests/lit.cfg @@ -0,0 +1,23 @@ +# -*- Python -*- + +from lit import Test + +class ManyTests(object): + def __init__(self, N=10000): + self.N = N + + def getTestsInDirectory(self, testSuite, path_in_suite, + litConfig, localConfig): + for i in range(self.N): + test_name = 'test-%04d' % (i,) + yield Test.Test(testSuite, path_in_suite + (test_name,), + localConfig) + + def execute(self, test, litConfig): + # Do a "non-trivial" amount of Python work. + sum = 0 + for i in range(10000): + sum += i + return Test.PASS,'' + +config.test_format = ManyTests() diff --git a/utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg b/utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg deleted file mode 100644 index 6cc4752..0000000 --- a/utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg +++ /dev/null @@ -1,23 +0,0 @@ -# -*- Python -*- - -Test = lit.Test - -class ManyTests(object): - def __init__(self, N=10000): - self.N = N - - def getTestsInDirectory(self, testSuite, path_in_suite, - litConfig, localConfig): - for i in range(self.N): - test_name = 'test-%04d' % (i,) - yield Test.Test(testSuite, path_in_suite + (test_name,), - localConfig) - - def execute(self, test, litConfig): - # Do a "non-trivial" amount of Python work. - sum = 0 - for i in range(10000): - sum += i - return Test.PASS,'' - -config.test_format = ManyTests() -- cgit v1.1 From ea549f0e12f367f5d0996a4bca441e64801b1e6e Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 9 Aug 2013 21:39:36 +0000 Subject: [lit] Remove old ExamplesTests directory. - The actual tests have better coverage than those, and they weren't useful anymore. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188110 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/ExampleTests/Clang/fsyntax-only.c | 4 -- utils/lit/lit/ExampleTests/Clang/lit.cfg | 47 --------------- .../lit/ExampleTests/LLVM.InTree/test/Bar/data.txt | 1 - .../lit/ExampleTests/LLVM.InTree/test/Bar/pct-S.ll | 1 - .../lit/lit/ExampleTests/LLVM.InTree/test/lit.cfg | 66 ---------------------- .../lit/ExampleTests/LLVM.InTree/test/lit.site.cfg | 7 --- .../lit/ExampleTests/LLVM.OutOfTree/lit.local.cfg | 1 - .../LLVM.OutOfTree/obj/test/Foo/lit.local.cfg | 0 .../LLVM.OutOfTree/obj/test/lit.site.cfg | 8 --- .../LLVM.OutOfTree/src/test/Foo/data.txt | 1 - .../LLVM.OutOfTree/src/test/Foo/pct-S.ll | 1 - .../ExampleTests/LLVM.OutOfTree/src/test/lit.cfg | 66 ---------------------- .../lit/lit/ExampleTests/ShExternal/lit.local.cfg | 6 -- .../lit/lit/ExampleTests/ShInternal/lit.local.cfg | 6 -- utils/lit/lit/ExampleTests/fail.c | 2 - utils/lit/lit/ExampleTests/lit.cfg | 26 --------- utils/lit/lit/ExampleTests/pass.c | 1 - utils/lit/lit/ExampleTests/required-and-missing.c | 4 -- utils/lit/lit/ExampleTests/required-and-present.c | 2 - utils/lit/lit/ExampleTests/vg-fail.c | 4 -- utils/lit/lit/ExampleTests/xfail-feature.c | 4 -- utils/lit/lit/ExampleTests/xfail.c | 2 - utils/lit/lit/ExampleTests/xpass.c | 2 - 23 files changed, 262 deletions(-) delete mode 100644 utils/lit/lit/ExampleTests/Clang/fsyntax-only.c delete mode 100644 utils/lit/lit/ExampleTests/Clang/lit.cfg delete mode 100644 utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt delete mode 100644 utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/pct-S.ll delete mode 100644 utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.cfg delete mode 100644 utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg delete mode 100644 utils/lit/lit/ExampleTests/LLVM.OutOfTree/lit.local.cfg delete mode 100644 utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/Foo/lit.local.cfg delete mode 100644 utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/lit.site.cfg delete mode 100644 utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/data.txt delete mode 100644 utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll delete mode 100644 utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg delete mode 100644 utils/lit/lit/ExampleTests/ShExternal/lit.local.cfg delete mode 100644 utils/lit/lit/ExampleTests/ShInternal/lit.local.cfg delete mode 100644 utils/lit/lit/ExampleTests/fail.c delete mode 100644 utils/lit/lit/ExampleTests/lit.cfg delete mode 100644 utils/lit/lit/ExampleTests/pass.c delete mode 100644 utils/lit/lit/ExampleTests/required-and-missing.c delete mode 100644 utils/lit/lit/ExampleTests/required-and-present.c delete mode 100644 utils/lit/lit/ExampleTests/vg-fail.c delete mode 100644 utils/lit/lit/ExampleTests/xfail-feature.c delete mode 100644 utils/lit/lit/ExampleTests/xfail.c delete mode 100644 utils/lit/lit/ExampleTests/xpass.c (limited to 'utils') diff --git a/utils/lit/lit/ExampleTests/Clang/fsyntax-only.c b/utils/lit/lit/ExampleTests/Clang/fsyntax-only.c deleted file mode 100644 index a4a064b..0000000 --- a/utils/lit/lit/ExampleTests/Clang/fsyntax-only.c +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: clang -fsyntax-only -Xclang -verify %s - -int f0(void) {} // expected-warning {{control reaches end of non-void function}} - diff --git a/utils/lit/lit/ExampleTests/Clang/lit.cfg b/utils/lit/lit/ExampleTests/Clang/lit.cfg deleted file mode 100644 index 9295bd9..0000000 --- a/utils/lit/lit/ExampleTests/Clang/lit.cfg +++ /dev/null @@ -1,47 +0,0 @@ -# -*- Python -*- - -# Configuration file for the 'lit' test runner. - -# name: The name of this test suite. -config.name = 'Clang' - -# testFormat: The test format to use to interpret tests. -# -# For now we require '&&' between commands, until they get globally killed and -# the test runner updated. -config.test_format = lit.formats.ShTest(execute_external = True) - -# suffixes: A list of file extensions to treat as test files. -config.suffixes = ['.c', '.cpp', '.m', '.mm'] - -# target_triple: Used by ShTest format for XFAIL checks. -config.target_triple = 'foo' - -### - -# Discover the 'clang' and 'clangcc' to use. - -import os - -def inferClang(PATH): - # Determine which clang to use. - clang = os.getenv('CLANG') - - # If the user set clang in the environment, definitely use that and don't - # try to validate. - if clang: - return clang - - # Otherwise look in the path. - clang = lit.util.which('clang', PATH) - - if not clang: - lit.fatal("couldn't find 'clang' program, try setting " - "CLANG in your environment") - - return clang - -clang = inferClang(config.environment['PATH']) -if not lit.quiet: - lit.note('using clang: %r' % clang) -config.substitutions.append( (' clang ', ' ' + clang + ' ') ) diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt b/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt deleted file mode 100644 index 45b983b..0000000 --- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt +++ /dev/null @@ -1 +0,0 @@ -hi diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/pct-S.ll b/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/pct-S.ll deleted file mode 100644 index 3ff3633..0000000 --- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/pct-S.ll +++ /dev/null @@ -1 +0,0 @@ -; RUN: grep "hi" %S/data.txt diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.cfg b/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.cfg deleted file mode 100644 index 533c445..0000000 --- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.cfg +++ /dev/null @@ -1,66 +0,0 @@ -# -*- Python -*- - -# Configuration file for the 'lit' test runner. - -import os - -# name: The name of this test suite. -config.name = 'LLVM' - -# testFormat: The test format to use to interpret tests. -config.test_format = lit.formats.ShTest() - -# suffixes: A list of file extensions to treat as test files, this is actually -# set by on_clone(). -config.suffixes = [ '.ll' ] - -# test_source_root: The root path where tests are located. -config.test_source_root = os.path.dirname(__file__) - -# test_exec_root: The root path where tests should be run. -llvm_obj_root = getattr(config, 'llvm_obj_root', None) -if llvm_obj_root is not None: - config.test_exec_root = os.path.join(llvm_obj_root, 'test') - -### - -import os - -# Check that the object root is known. -if config.test_exec_root is None: - # Otherwise, we haven't loaded the site specific configuration (the user is - # probably trying to run on a test file directly, and either the site - # configuration hasn't been created by the build system, or we are in an - # out-of-tree build situation). - - # Try to detect the situation where we are using an out-of-tree build by - # looking for 'llvm-config'. - # - # FIXME: I debated (i.e., wrote and threw away) adding logic to - # automagically generate the lit.site.cfg if we are in some kind of fresh - # build situation. This means knowing how to invoke the build system - # though, and I decided it was too much magic. - - llvm_config = lit.util.which('llvm-config', config.environment['PATH']) - if not llvm_config: - lit.fatal('No site specific configuration available!') - - # Get the source and object roots. - llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip() - llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip() - - # Validate that we got a tree which points to here. - this_src_root = os.path.dirname(config.test_source_root) - if os.path.realpath(llvm_src_root) != os.path.realpath(this_src_root): - lit.fatal('No site specific configuration available!') - - # Check that the site specific configuration exists. - site_cfg = os.path.join(llvm_obj_root, 'test', 'lit.site.cfg') - if not os.path.exists(site_cfg): - lit.fatal('No site specific configuration available!') - - # Okay, that worked. Notify the user of the automagic, and reconfigure. - lit.note('using out-of-tree build at %r' % llvm_obj_root) - lit.load_config(config, site_cfg) - raise SystemExit - diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg b/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg deleted file mode 100644 index d45f3ac..0000000 --- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Python -*- - -# Preserve some key paths for use by main LLVM test suite config. -config.llvm_obj_root = os.path.dirname(os.path.dirname(__file__)) - -# Let the main config do the real work. -lit.load_config(config, os.path.join(config.llvm_obj_root, 'test/lit.cfg')) diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/lit.local.cfg b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/lit.local.cfg deleted file mode 100644 index 80d0c7e..0000000 --- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/lit.local.cfg +++ /dev/null @@ -1 +0,0 @@ -config.excludes = ['src'] diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/Foo/lit.local.cfg b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/Foo/lit.local.cfg deleted file mode 100644 index e69de29..0000000 diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/lit.site.cfg b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/lit.site.cfg deleted file mode 100644 index 94a02d8..0000000 --- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/lit.site.cfg +++ /dev/null @@ -1,8 +0,0 @@ -# -*- Python -*- - -# Preserve some key paths for use by main LLVM test suite config. -config.llvm_obj_root = os.path.dirname(os.path.dirname(__file__)) - -# Let the main config do the real work. -lit.load_config(config, os.path.join(config.llvm_obj_root, - '../src/test/lit.cfg')) diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/data.txt b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/data.txt deleted file mode 100644 index 45b983b..0000000 --- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/data.txt +++ /dev/null @@ -1 +0,0 @@ -hi diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll deleted file mode 100644 index 3ff3633..0000000 --- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll +++ /dev/null @@ -1 +0,0 @@ -; RUN: grep "hi" %S/data.txt diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg deleted file mode 100644 index 533c445..0000000 --- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg +++ /dev/null @@ -1,66 +0,0 @@ -# -*- Python -*- - -# Configuration file for the 'lit' test runner. - -import os - -# name: The name of this test suite. -config.name = 'LLVM' - -# testFormat: The test format to use to interpret tests. -config.test_format = lit.formats.ShTest() - -# suffixes: A list of file extensions to treat as test files, this is actually -# set by on_clone(). -config.suffixes = [ '.ll' ] - -# test_source_root: The root path where tests are located. -config.test_source_root = os.path.dirname(__file__) - -# test_exec_root: The root path where tests should be run. -llvm_obj_root = getattr(config, 'llvm_obj_root', None) -if llvm_obj_root is not None: - config.test_exec_root = os.path.join(llvm_obj_root, 'test') - -### - -import os - -# Check that the object root is known. -if config.test_exec_root is None: - # Otherwise, we haven't loaded the site specific configuration (the user is - # probably trying to run on a test file directly, and either the site - # configuration hasn't been created by the build system, or we are in an - # out-of-tree build situation). - - # Try to detect the situation where we are using an out-of-tree build by - # looking for 'llvm-config'. - # - # FIXME: I debated (i.e., wrote and threw away) adding logic to - # automagically generate the lit.site.cfg if we are in some kind of fresh - # build situation. This means knowing how to invoke the build system - # though, and I decided it was too much magic. - - llvm_config = lit.util.which('llvm-config', config.environment['PATH']) - if not llvm_config: - lit.fatal('No site specific configuration available!') - - # Get the source and object roots. - llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip() - llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip() - - # Validate that we got a tree which points to here. - this_src_root = os.path.dirname(config.test_source_root) - if os.path.realpath(llvm_src_root) != os.path.realpath(this_src_root): - lit.fatal('No site specific configuration available!') - - # Check that the site specific configuration exists. - site_cfg = os.path.join(llvm_obj_root, 'test', 'lit.site.cfg') - if not os.path.exists(site_cfg): - lit.fatal('No site specific configuration available!') - - # Okay, that worked. Notify the user of the automagic, and reconfigure. - lit.note('using out-of-tree build at %r' % llvm_obj_root) - lit.load_config(config, site_cfg) - raise SystemExit - diff --git a/utils/lit/lit/ExampleTests/ShExternal/lit.local.cfg b/utils/lit/lit/ExampleTests/ShExternal/lit.local.cfg deleted file mode 100644 index 1061da6..0000000 --- a/utils/lit/lit/ExampleTests/ShExternal/lit.local.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# -*- Python -*- - -config.test_format = lit.formats.ShTest(execute_external = True) - -config.suffixes = ['.c'] - diff --git a/utils/lit/lit/ExampleTests/ShInternal/lit.local.cfg b/utils/lit/lit/ExampleTests/ShInternal/lit.local.cfg deleted file mode 100644 index 448eaa4..0000000 --- a/utils/lit/lit/ExampleTests/ShInternal/lit.local.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# -*- Python -*- - -config.test_format = lit.formats.ShTest(execute_external = False) - -config.suffixes = ['.c'] - diff --git a/utils/lit/lit/ExampleTests/fail.c b/utils/lit/lit/ExampleTests/fail.c deleted file mode 100644 index 84db41a..0000000 --- a/utils/lit/lit/ExampleTests/fail.c +++ /dev/null @@ -1,2 +0,0 @@ -// RUN: echo 'I am some stdout' -// RUN: false diff --git a/utils/lit/lit/ExampleTests/lit.cfg b/utils/lit/lit/ExampleTests/lit.cfg deleted file mode 100644 index 164daba..0000000 --- a/utils/lit/lit/ExampleTests/lit.cfg +++ /dev/null @@ -1,26 +0,0 @@ -# -*- Python -*- - -# Configuration file for the 'lit' test runner. - -# name: The name of this test suite. -config.name = 'Examples' - -# suffixes: A list of file extensions to treat as test files. -config.suffixes = ['.c', '.cpp', '.m', '.mm', '.ll'] - -# testFormat: The test format to use to interpret tests. -config.test_format = lit.formats.ShTest() - -# test_source_root: The path where tests are located (default is the test suite -# root). -config.test_source_root = None - -# test_exec_root: The path where tests are located (default is the test suite -# root). -config.test_exec_root = None - -# target_triple: Used by ShTest format for XFAIL checks. -config.target_triple = 'foo' - -# available_features: Used by ShTest format for REQUIRES checks. -config.available_features.add('some-feature-name') diff --git a/utils/lit/lit/ExampleTests/pass.c b/utils/lit/lit/ExampleTests/pass.c deleted file mode 100644 index 5c1031c..0000000 --- a/utils/lit/lit/ExampleTests/pass.c +++ /dev/null @@ -1 +0,0 @@ -// RUN: true diff --git a/utils/lit/lit/ExampleTests/required-and-missing.c b/utils/lit/lit/ExampleTests/required-and-missing.c deleted file mode 100644 index 47ba72e..0000000 --- a/utils/lit/lit/ExampleTests/required-and-missing.c +++ /dev/null @@ -1,4 +0,0 @@ -// This test shouldn't be run, the required feature is missing. -// -// RUN: false -// REQUIRES: some-missing-feature-name diff --git a/utils/lit/lit/ExampleTests/required-and-present.c b/utils/lit/lit/ExampleTests/required-and-present.c deleted file mode 100644 index 2a09e08..0000000 --- a/utils/lit/lit/ExampleTests/required-and-present.c +++ /dev/null @@ -1,2 +0,0 @@ -// RUN: true -// REQUIRES: some-feature-name diff --git a/utils/lit/lit/ExampleTests/vg-fail.c b/utils/lit/lit/ExampleTests/vg-fail.c deleted file mode 100644 index e3339ff..0000000 --- a/utils/lit/lit/ExampleTests/vg-fail.c +++ /dev/null @@ -1,4 +0,0 @@ -// This test should XPASS, when run without valgrind. - -// RUN: true -// XFAIL: valgrind diff --git a/utils/lit/lit/ExampleTests/xfail-feature.c b/utils/lit/lit/ExampleTests/xfail-feature.c deleted file mode 100644 index 3444bf8..0000000 --- a/utils/lit/lit/ExampleTests/xfail-feature.c +++ /dev/null @@ -1,4 +0,0 @@ -// This test should XPASS. - -// RUN: true -// XFAIL: some-feature-name diff --git a/utils/lit/lit/ExampleTests/xfail.c b/utils/lit/lit/ExampleTests/xfail.c deleted file mode 100644 index b36cd99..0000000 --- a/utils/lit/lit/ExampleTests/xfail.c +++ /dev/null @@ -1,2 +0,0 @@ -// RUN: false -// XFAIL: * diff --git a/utils/lit/lit/ExampleTests/xpass.c b/utils/lit/lit/ExampleTests/xpass.c deleted file mode 100644 index ad84990..0000000 --- a/utils/lit/lit/ExampleTests/xpass.c +++ /dev/null @@ -1,2 +0,0 @@ -// RUN: true -// XFAIL -- cgit v1.1 From dfb5ceae90c016ba4ca8a7f1a3b79c360d888f30 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 12 Aug 2013 10:39:45 +0000 Subject: Stablize MCK_Reg ordering in AsmMatcherEmitter clang bootstraps intermittently failed for me due a difference in the MCK_Reg ordering in ARMGenAsmMatcher.inc. E.g. in my latest run the stage 1 and stage 3 versions were the same but the stage 2 one was different (though still functionally correct). This meant that the .o comparison failed. MCK_Regs were assigned by iterating over a std::set< std::set >, and since std::set is sorted lexicographically, the order depended on the order of the pointer values. This patch replaces the pointer ordering with LessRecordByID. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188164 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/AsmMatcherEmitter.cpp | 40 +++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 19 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 468ce1c..52a33ab 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -125,6 +125,8 @@ namespace { class AsmMatcherInfo; struct SubtargetFeatureInfo; +typedef std::set RegisterSet; + class AsmMatcherEmitter { RecordKeeper &Records; public: @@ -185,7 +187,7 @@ struct ClassInfo { std::string ParserMethod; /// For register classes, the records for all the registers in this class. - std::set Registers; + RegisterSet Registers; /// For custom match classes, he diagnostic kind for when the predicate fails. std::string DiagnosticType; @@ -213,8 +215,8 @@ public: if (!isRegisterClass() || !RHS.isRegisterClass()) return false; - std::set Tmp; - std::insert_iterator< std::set > II(Tmp, Tmp.begin()); + RegisterSet Tmp; + std::insert_iterator II(Tmp, Tmp.begin()); std::set_intersection(Registers.begin(), Registers.end(), RHS.Registers.begin(), RHS.Registers.end(), II); @@ -1055,32 +1057,32 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { Target.getRegBank().getRegClasses(); // The register sets used for matching. - std::set< std::set > RegisterSets; + std::set RegisterSets; // Gather the defined sets. for (ArrayRef::const_iterator it = RegClassList.begin(), ie = RegClassList.end(); it != ie; ++it) - RegisterSets.insert(std::set( + RegisterSets.insert(RegisterSet( (*it)->getOrder().begin(), (*it)->getOrder().end())); // Add any required singleton sets. for (SmallPtrSet::iterator it = SingletonRegisters.begin(), ie = SingletonRegisters.end(); it != ie; ++it) { Record *Rec = *it; - RegisterSets.insert(std::set(&Rec, &Rec + 1)); + RegisterSets.insert(RegisterSet(&Rec, &Rec + 1)); } // Introduce derived sets where necessary (when a register does not determine // a unique register set class), and build the mapping of registers to the set // they should classify to. - std::map > RegisterMap; + std::map RegisterMap; for (std::vector::const_iterator it = Registers.begin(), ie = Registers.end(); it != ie; ++it) { const CodeGenRegister &CGR = **it; // Compute the intersection of all sets containing this register. - std::set ContainingSet; + RegisterSet ContainingSet; - for (std::set< std::set >::iterator it = RegisterSets.begin(), + for (std::set::iterator it = RegisterSets.begin(), ie = RegisterSets.end(); it != ie; ++it) { if (!it->count(CGR.TheDef)) continue; @@ -1090,10 +1092,10 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { continue; } - std::set Tmp; + RegisterSet Tmp; std::swap(Tmp, ContainingSet); - std::insert_iterator< std::set > II(ContainingSet, - ContainingSet.begin()); + std::insert_iterator II(ContainingSet, + ContainingSet.begin()); std::set_intersection(Tmp.begin(), Tmp.end(), it->begin(), it->end(), II); } @@ -1104,9 +1106,9 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { } // Construct the register classes. - std::map, ClassInfo*> RegisterSetClasses; + std::map RegisterSetClasses; unsigned Index = 0; - for (std::set< std::set >::iterator it = RegisterSets.begin(), + for (std::set::iterator it = RegisterSets.begin(), ie = RegisterSets.end(); it != ie; ++it, ++Index) { ClassInfo *CI = new ClassInfo(); CI->Kind = ClassInfo::RegisterClass0 + Index; @@ -1124,10 +1126,10 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { // Find the superclasses; we could compute only the subgroup lattice edges, // but there isn't really a point. - for (std::set< std::set >::iterator it = RegisterSets.begin(), + for (std::set::iterator it = RegisterSets.begin(), ie = RegisterSets.end(); it != ie; ++it) { ClassInfo *CI = RegisterSetClasses[*it]; - for (std::set< std::set >::iterator it2 = RegisterSets.begin(), + for (std::set::iterator it2 = RegisterSets.begin(), ie2 = RegisterSets.end(); it2 != ie2; ++it2) if (*it != *it2 && std::includes(it2->begin(), it2->end(), it->begin(), it->end())) @@ -1142,8 +1144,8 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { Record *Def = RC.getDef(); if (!Def) continue; - ClassInfo *CI = RegisterSetClasses[std::set(RC.getOrder().begin(), - RC.getOrder().end())]; + ClassInfo *CI = RegisterSetClasses[RegisterSet(RC.getOrder().begin(), + RC.getOrder().end())]; if (CI->ValueName.empty()) { CI->ClassName = RC.getName(); CI->Name = "MCK_" + RC.getName(); @@ -1155,7 +1157,7 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { } // Populate the map for individual registers. - for (std::map >::iterator it = RegisterMap.begin(), + for (std::map::iterator it = RegisterMap.begin(), ie = RegisterMap.end(); it != ie; ++it) RegisterClasses[it->first] = RegisterSetClasses[it->second]; -- cgit v1.1 From 1f85736c97980507833f1933796bf600f7efde67 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 12 Aug 2013 10:57:51 +0000 Subject: Revert r188164: Stablize MCK_Reg ordering in AsmMatcherEmitter Apparently caused a failure on Darwin git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188166 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/AsmMatcherEmitter.cpp | 40 +++++++++++++++++------------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 52a33ab..468ce1c 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -125,8 +125,6 @@ namespace { class AsmMatcherInfo; struct SubtargetFeatureInfo; -typedef std::set RegisterSet; - class AsmMatcherEmitter { RecordKeeper &Records; public: @@ -187,7 +185,7 @@ struct ClassInfo { std::string ParserMethod; /// For register classes, the records for all the registers in this class. - RegisterSet Registers; + std::set Registers; /// For custom match classes, he diagnostic kind for when the predicate fails. std::string DiagnosticType; @@ -215,8 +213,8 @@ public: if (!isRegisterClass() || !RHS.isRegisterClass()) return false; - RegisterSet Tmp; - std::insert_iterator II(Tmp, Tmp.begin()); + std::set Tmp; + std::insert_iterator< std::set > II(Tmp, Tmp.begin()); std::set_intersection(Registers.begin(), Registers.end(), RHS.Registers.begin(), RHS.Registers.end(), II); @@ -1057,32 +1055,32 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { Target.getRegBank().getRegClasses(); // The register sets used for matching. - std::set RegisterSets; + std::set< std::set > RegisterSets; // Gather the defined sets. for (ArrayRef::const_iterator it = RegClassList.begin(), ie = RegClassList.end(); it != ie; ++it) - RegisterSets.insert(RegisterSet( + RegisterSets.insert(std::set( (*it)->getOrder().begin(), (*it)->getOrder().end())); // Add any required singleton sets. for (SmallPtrSet::iterator it = SingletonRegisters.begin(), ie = SingletonRegisters.end(); it != ie; ++it) { Record *Rec = *it; - RegisterSets.insert(RegisterSet(&Rec, &Rec + 1)); + RegisterSets.insert(std::set(&Rec, &Rec + 1)); } // Introduce derived sets where necessary (when a register does not determine // a unique register set class), and build the mapping of registers to the set // they should classify to. - std::map RegisterMap; + std::map > RegisterMap; for (std::vector::const_iterator it = Registers.begin(), ie = Registers.end(); it != ie; ++it) { const CodeGenRegister &CGR = **it; // Compute the intersection of all sets containing this register. - RegisterSet ContainingSet; + std::set ContainingSet; - for (std::set::iterator it = RegisterSets.begin(), + for (std::set< std::set >::iterator it = RegisterSets.begin(), ie = RegisterSets.end(); it != ie; ++it) { if (!it->count(CGR.TheDef)) continue; @@ -1092,10 +1090,10 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { continue; } - RegisterSet Tmp; + std::set Tmp; std::swap(Tmp, ContainingSet); - std::insert_iterator II(ContainingSet, - ContainingSet.begin()); + std::insert_iterator< std::set > II(ContainingSet, + ContainingSet.begin()); std::set_intersection(Tmp.begin(), Tmp.end(), it->begin(), it->end(), II); } @@ -1106,9 +1104,9 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { } // Construct the register classes. - std::map RegisterSetClasses; + std::map, ClassInfo*> RegisterSetClasses; unsigned Index = 0; - for (std::set::iterator it = RegisterSets.begin(), + for (std::set< std::set >::iterator it = RegisterSets.begin(), ie = RegisterSets.end(); it != ie; ++it, ++Index) { ClassInfo *CI = new ClassInfo(); CI->Kind = ClassInfo::RegisterClass0 + Index; @@ -1126,10 +1124,10 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { // Find the superclasses; we could compute only the subgroup lattice edges, // but there isn't really a point. - for (std::set::iterator it = RegisterSets.begin(), + for (std::set< std::set >::iterator it = RegisterSets.begin(), ie = RegisterSets.end(); it != ie; ++it) { ClassInfo *CI = RegisterSetClasses[*it]; - for (std::set::iterator it2 = RegisterSets.begin(), + for (std::set< std::set >::iterator it2 = RegisterSets.begin(), ie2 = RegisterSets.end(); it2 != ie2; ++it2) if (*it != *it2 && std::includes(it2->begin(), it2->end(), it->begin(), it->end())) @@ -1144,8 +1142,8 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { Record *Def = RC.getDef(); if (!Def) continue; - ClassInfo *CI = RegisterSetClasses[RegisterSet(RC.getOrder().begin(), - RC.getOrder().end())]; + ClassInfo *CI = RegisterSetClasses[std::set(RC.getOrder().begin(), + RC.getOrder().end())]; if (CI->ValueName.empty()) { CI->ClassName = RC.getName(); CI->Name = "MCK_" + RC.getName(); @@ -1157,7 +1155,7 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { } // Populate the map for individual registers. - for (std::map::iterator it = RegisterMap.begin(), + for (std::map >::iterator it = RegisterMap.begin(), ie = RegisterMap.end(); it != ie; ++it) RegisterClasses[it->first] = RegisterSetClasses[it->second]; -- cgit v1.1 From d9a84efe44db2f4d983e49bc7370fc8cef449214 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Mon, 12 Aug 2013 23:05:59 +0000 Subject: [FileCheck] Fix a bug that cause FileCheck to misidentify check-prefix FileCheck should check to make sure the prefix was found, and not a word containing it (e.g -check-prefix=BASEREL shouldn't match NOBASEREL). Patch by Ron Ofir. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188221 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/FileCheck.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 8d5af58..82e8057 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -704,15 +704,26 @@ static bool ReadCheckFile(SourceMgr &SM, LineNumber += Buffer.substr(0, PrefixLoc).count('\n'); - Buffer = Buffer.substr(PrefixLoc); + // Keep the charcter before our prefix so we can validate that we have + // found our prefix, and account for cases when PrefixLoc is 0. + Buffer = Buffer.substr(std::min(PrefixLoc-1, PrefixLoc)); - const char *CheckPrefixStart = Buffer.data(); + const char *CheckPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); // When we find a check prefix, keep track of whether we find CHECK: or // CHECK-NEXT: bool IsCheckNext = false, IsCheckNot = false, IsCheckDag = false, IsCheckLabel = false; + // Make sure we have actually found our prefix, and not a word containing + // our prefix. + if (PrefixLoc != 0 && (isalnum(Buffer[0]) || + Buffer[0] == '-' || + Buffer[0] == '_')) { + Buffer = Buffer.substr(CheckPrefix.size()); + continue; + } + // Verify that the : is present after the prefix. if (Buffer[CheckPrefix.size()] == ':') { Buffer = Buffer.substr(CheckPrefix.size()+1); @@ -1026,11 +1037,24 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, return LastPos; } +bool ValidateCheckPrefix() { + // The check prefix must contain only alphanumeric, hyphens and underscores. + Regex prefixValidator("^[a-zA-Z0-9_-]*$"); + return prefixValidator.match(CheckPrefix); +} + int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); + if (!ValidateCheckPrefix()) { + errs() << "Supplied check-prefix is invalid! Prefixes must start with a " + "letter and contain only alphanumeric characters, hyphens and " + "underscores\n"; + return 2; + } + SourceMgr SM; // Read the expected strings from the check file. -- cgit v1.1 From 13e26da155d245e0d1e55fb8dc9f586426112fc2 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Tue, 13 Aug 2013 19:08:48 +0000 Subject: [lit] Support use of setup.py from other directories. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188309 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/setup.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/lit/setup.py b/utils/lit/setup.py index a94e6ea..10de6bb 100644 --- a/utils/lit/setup.py +++ b/utils/lit/setup.py @@ -1,7 +1,14 @@ import lit +import os -# FIXME: Support distutils? from setuptools import setup, find_packages + +# setuptools expects to be invoked from within the directory of setup.py, but it +# is nice to allow: +# python path/to/setup.py install +# to work (for scripts, etc.) +os.chdir(os.path.dirname(os.path.abspath(__file__))) + setup( name = "lit", version = lit.__version__, -- cgit v1.1 From 0fe3792a2fd6ed9c20d8bf8eb3689672cb30c1c7 Mon Sep 17 00:00:00 2001 From: Jack Carter Date: Tue, 13 Aug 2013 22:34:26 +0000 Subject: [Mips][msa] Value types for MSA support. Added v8f16 to ValueTypes.h, ValueTypes.cpp, ValueTypes.td, and CodeGenTarget.cpp Patch by Daniel Sanders git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188326 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenTarget.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'utils') diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index b2c883d..72fa9ec 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -98,6 +98,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v8i64: return "MVT::v8i64"; case MVT::v16i64: return "MVT::v16i64"; case MVT::v2f16: return "MVT::v2f16"; + case MVT::v8f16: return "MVT::v8f16"; case MVT::v2f32: return "MVT::v2f32"; case MVT::v4f32: return "MVT::v4f32"; case MVT::v8f32: return "MVT::v8f32"; -- cgit v1.1 From e908486f5badf116c8711da76729ea2b3aa933b4 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Wed, 14 Aug 2013 02:26:31 +0000 Subject: Lit: Introduce "%/[STpst] into parseIntegratedTestScript(), to normalize substitutions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188348 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestRunner.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'utils') diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 8929c0b..a8150e6 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -364,6 +364,15 @@ def parseIntegratedTestScript(test, normalize_slashes=False, ('%T', tmpDir), ('#_MARKER_#', '%')]) + # "%/[STpst]" should be normalized. + substitutions.extend([ + ('%/s', sourcepath.replace('\\', '/')), + ('%/S', sourcedir.replace('\\', '/')), + ('%/p', sourcedir.replace('\\', '/')), + ('%/t', tmpBase.replace('\\', '/') + '.tmp'), + ('%/T', tmpDir.replace('\\', '/')), + ]) + # Collect the test lines from the script. script = [] xfails = [] -- cgit v1.1 From f76c664f6bfe8a2184f500afbb9ae851e2e34987 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 05:06:55 +0000 Subject: [lit] Move formats into their own subpackage. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188355 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/formats.py | 230 ------------------------------------ utils/lit/lit/formats/__init__.py | 4 + utils/lit/lit/formats/base.py | 114 ++++++++++++++++++ utils/lit/lit/formats/googletest.py | 113 ++++++++++++++++++ utils/lit/lit/formats/shtest.py | 12 ++ 5 files changed, 243 insertions(+), 230 deletions(-) delete mode 100644 utils/lit/lit/formats.py create mode 100644 utils/lit/lit/formats/__init__.py create mode 100644 utils/lit/lit/formats/base.py create mode 100644 utils/lit/lit/formats/googletest.py create mode 100644 utils/lit/lit/formats/shtest.py (limited to 'utils') diff --git a/utils/lit/lit/formats.py b/utils/lit/lit/formats.py deleted file mode 100644 index 7a93adf..0000000 --- a/utils/lit/lit/formats.py +++ /dev/null @@ -1,230 +0,0 @@ -from __future__ import absolute_import -import os -import sys - -import lit.Test -import lit.TestRunner -import lit.util - -kIsWindows = sys.platform in ['win32', 'cygwin'] - -class GoogleTest(object): - def __init__(self, test_sub_dir, test_suffix): - self.test_sub_dir = os.path.normcase(str(test_sub_dir)).split(';') - self.test_suffix = str(test_suffix) - - # On Windows, assume tests will also end in '.exe'. - if kIsWindows: - self.test_suffix += '.exe' - - def getGTestTests(self, path, litConfig, localConfig): - """getGTestTests(path) - [name] - - Return the tests available in gtest executable. - - Args: - path: String path to a gtest executable - litConfig: LitConfig instance - localConfig: TestingConfig instance""" - - try: - lines = lit.util.capture([path, '--gtest_list_tests'], - env=localConfig.environment) - lines = lines.decode('ascii') - if kIsWindows: - lines = lines.replace('\r', '') - lines = lines.split('\n') - except: - litConfig.error("unable to discover google-tests in %r" % path) - raise StopIteration - - nested_tests = [] - for ln in lines: - if not ln.strip(): - continue - - prefix = '' - index = 0 - while ln[index*2:index*2+2] == ' ': - index += 1 - while len(nested_tests) > index: - nested_tests.pop() - - ln = ln[index*2:] - if ln.endswith('.'): - nested_tests.append(ln) - else: - yield ''.join(nested_tests) + ln - - # Note: path_in_suite should not include the executable name. - def getTestsInExecutable(self, testSuite, path_in_suite, execpath, - litConfig, localConfig): - if not execpath.endswith(self.test_suffix): - return - (dirname, basename) = os.path.split(execpath) - # Discover the tests in this executable. - for testname in self.getGTestTests(execpath, litConfig, localConfig): - testPath = path_in_suite + (basename, testname) - yield lit.Test.Test(testSuite, testPath, localConfig) - - def getTestsInDirectory(self, testSuite, path_in_suite, - litConfig, localConfig): - source_path = testSuite.getSourcePath(path_in_suite) - for filename in os.listdir(source_path): - filepath = os.path.join(source_path, filename) - if os.path.isdir(filepath): - # Iterate over executables in a directory. - if not os.path.normcase(filename) in self.test_sub_dir: - continue - dirpath_in_suite = path_in_suite + (filename, ) - for subfilename in os.listdir(filepath): - execpath = os.path.join(filepath, subfilename) - for test in self.getTestsInExecutable( - testSuite, dirpath_in_suite, execpath, - litConfig, localConfig): - yield test - elif ('.' in self.test_sub_dir): - for test in self.getTestsInExecutable( - testSuite, path_in_suite, filepath, - litConfig, localConfig): - yield test - - def execute(self, test, litConfig): - testPath,testName = os.path.split(test.getSourcePath()) - while not os.path.exists(testPath): - # Handle GTest parametrized and typed tests, whose name includes - # some '/'s. - testPath, namePrefix = os.path.split(testPath) - testName = os.path.join(namePrefix, testName) - - cmd = [testPath, '--gtest_filter=' + testName] - if litConfig.useValgrind: - cmd = litConfig.valgrindArgs + cmd - - if litConfig.noExecute: - return lit.Test.PASS, '' - - out, err, exitCode = lit.TestRunner.executeCommand( - cmd, env=test.config.environment) - - if not exitCode: - return lit.Test.PASS,'' - - return lit.Test.FAIL, out + err - -### - -class FileBasedTest(object): - def getTestsInDirectory(self, testSuite, path_in_suite, - litConfig, localConfig): - source_path = testSuite.getSourcePath(path_in_suite) - for filename in os.listdir(source_path): - # Ignore dot files and excluded tests. - if (filename.startswith('.') or - filename in localConfig.excludes): - continue - - filepath = os.path.join(source_path, filename) - if not os.path.isdir(filepath): - base,ext = os.path.splitext(filename) - if ext in localConfig.suffixes: - yield lit.Test.Test(testSuite, path_in_suite + (filename,), - localConfig) - -class ShTest(FileBasedTest): - def __init__(self, execute_external = False): - self.execute_external = execute_external - - def execute(self, test, litConfig): - return lit.TestRunner.executeShTest(test, litConfig, - self.execute_external) - -### - -import re -import tempfile - -class OneCommandPerFileTest: - # FIXME: Refactor into generic test for running some command on a directory - # of inputs. - - def __init__(self, command, dir, recursive=False, - pattern=".*", useTempInput=False): - if isinstance(command, str): - self.command = [command] - else: - self.command = list(command) - if dir is not None: - dir = str(dir) - self.dir = dir - self.recursive = bool(recursive) - self.pattern = re.compile(pattern) - self.useTempInput = useTempInput - - def getTestsInDirectory(self, testSuite, path_in_suite, - litConfig, localConfig): - dir = self.dir - if dir is None: - dir = testSuite.getSourcePath(path_in_suite) - - for dirname,subdirs,filenames in os.walk(dir): - if not self.recursive: - subdirs[:] = [] - - subdirs[:] = [d for d in subdirs - if (d != '.svn' and - d not in localConfig.excludes)] - - for filename in filenames: - if (filename.startswith('.') or - not self.pattern.match(filename) or - filename in localConfig.excludes): - continue - - path = os.path.join(dirname,filename) - suffix = path[len(dir):] - if suffix.startswith(os.sep): - suffix = suffix[1:] - test = lit.Test.Test( - testSuite, path_in_suite + tuple(suffix.split(os.sep)), - localConfig) - # FIXME: Hack? - test.source_path = path - yield test - - def createTempInput(self, tmp, test): - abstract - - def execute(self, test, litConfig): - if test.config.unsupported: - return (lit.Test.UNSUPPORTED, 'Test is unsupported') - - cmd = list(self.command) - - # If using temp input, create a temporary file and hand it to the - # subclass. - if self.useTempInput: - tmp = tempfile.NamedTemporaryFile(suffix='.cpp') - self.createTempInput(tmp, test) - tmp.flush() - cmd.append(tmp.name) - elif hasattr(test, 'source_path'): - cmd.append(test.source_path) - else: - cmd.append(test.getSourcePath()) - - out, err, exitCode = lit.TestRunner.executeCommand(cmd) - - diags = out + err - if not exitCode and not diags.strip(): - return lit.Test.PASS,'' - - # Try to include some useful information. - report = """Command: %s\n""" % ' '.join(["'%s'" % a - for a in cmd]) - if self.useTempInput: - report += """Temporary File: %s\n""" % tmp.name - report += "--\n%s--\n""" % open(tmp.name).read() - report += """Output:\n--\n%s--""" % diags - - return lit.Test.FAIL, report diff --git a/utils/lit/lit/formats/__init__.py b/utils/lit/lit/formats/__init__.py new file mode 100644 index 0000000..f4a303c --- /dev/null +++ b/utils/lit/lit/formats/__init__.py @@ -0,0 +1,4 @@ +from __future__ import absolute_import +from lit.formats.base import FileBasedTest, OneCommandPerFileTest +from lit.formats.googletest import GoogleTest +from lit.formats.shtest import ShTest diff --git a/utils/lit/lit/formats/base.py b/utils/lit/lit/formats/base.py new file mode 100644 index 0000000..3c38041 --- /dev/null +++ b/utils/lit/lit/formats/base.py @@ -0,0 +1,114 @@ +from __future__ import absolute_import +import os +import sys + +import lit.Test +import lit.TestRunner +import lit.util + +class FileBasedTest(object): + def getTestsInDirectory(self, testSuite, path_in_suite, + litConfig, localConfig): + source_path = testSuite.getSourcePath(path_in_suite) + for filename in os.listdir(source_path): + # Ignore dot files and excluded tests. + if (filename.startswith('.') or + filename in localConfig.excludes): + continue + + filepath = os.path.join(source_path, filename) + if not os.path.isdir(filepath): + base,ext = os.path.splitext(filename) + if ext in localConfig.suffixes: + yield lit.Test.Test(testSuite, path_in_suite + (filename,), + localConfig) + +### + +import re +import tempfile + +class OneCommandPerFileTest: + # FIXME: Refactor into generic test for running some command on a directory + # of inputs. + + def __init__(self, command, dir, recursive=False, + pattern=".*", useTempInput=False): + if isinstance(command, str): + self.command = [command] + else: + self.command = list(command) + if dir is not None: + dir = str(dir) + self.dir = dir + self.recursive = bool(recursive) + self.pattern = re.compile(pattern) + self.useTempInput = useTempInput + + def getTestsInDirectory(self, testSuite, path_in_suite, + litConfig, localConfig): + dir = self.dir + if dir is None: + dir = testSuite.getSourcePath(path_in_suite) + + for dirname,subdirs,filenames in os.walk(dir): + if not self.recursive: + subdirs[:] = [] + + subdirs[:] = [d for d in subdirs + if (d != '.svn' and + d not in localConfig.excludes)] + + for filename in filenames: + if (filename.startswith('.') or + not self.pattern.match(filename) or + filename in localConfig.excludes): + continue + + path = os.path.join(dirname,filename) + suffix = path[len(dir):] + if suffix.startswith(os.sep): + suffix = suffix[1:] + test = lit.Test.Test( + testSuite, path_in_suite + tuple(suffix.split(os.sep)), + localConfig) + # FIXME: Hack? + test.source_path = path + yield test + + def createTempInput(self, tmp, test): + abstract + + def execute(self, test, litConfig): + if test.config.unsupported: + return (lit.Test.UNSUPPORTED, 'Test is unsupported') + + cmd = list(self.command) + + # If using temp input, create a temporary file and hand it to the + # subclass. + if self.useTempInput: + tmp = tempfile.NamedTemporaryFile(suffix='.cpp') + self.createTempInput(tmp, test) + tmp.flush() + cmd.append(tmp.name) + elif hasattr(test, 'source_path'): + cmd.append(test.source_path) + else: + cmd.append(test.getSourcePath()) + + out, err, exitCode = lit.TestRunner.executeCommand(cmd) + + diags = out + err + if not exitCode and not diags.strip(): + return lit.Test.PASS,'' + + # Try to include some useful information. + report = """Command: %s\n""" % ' '.join(["'%s'" % a + for a in cmd]) + if self.useTempInput: + report += """Temporary File: %s\n""" % tmp.name + report += "--\n%s--\n""" % open(tmp.name).read() + report += """Output:\n--\n%s--""" % diags + + return lit.Test.FAIL, report diff --git a/utils/lit/lit/formats/googletest.py b/utils/lit/lit/formats/googletest.py new file mode 100644 index 0000000..06b6a29 --- /dev/null +++ b/utils/lit/lit/formats/googletest.py @@ -0,0 +1,113 @@ +from __future__ import absolute_import +import os +import sys + +import lit.Test +import lit.TestRunner +import lit.util + +kIsWindows = sys.platform in ['win32', 'cygwin'] + +class GoogleTest(object): + def __init__(self, test_sub_dir, test_suffix): + self.test_sub_dir = os.path.normcase(str(test_sub_dir)).split(';') + self.test_suffix = str(test_suffix) + + # On Windows, assume tests will also end in '.exe'. + if kIsWindows: + self.test_suffix += '.exe' + + def getGTestTests(self, path, litConfig, localConfig): + """getGTestTests(path) - [name] + + Return the tests available in gtest executable. + + Args: + path: String path to a gtest executable + litConfig: LitConfig instance + localConfig: TestingConfig instance""" + + try: + lines = lit.util.capture([path, '--gtest_list_tests'], + env=localConfig.environment) + lines = lines.decode('ascii') + if kIsWindows: + lines = lines.replace('\r', '') + lines = lines.split('\n') + except: + litConfig.error("unable to discover google-tests in %r" % path) + raise StopIteration + + nested_tests = [] + for ln in lines: + if not ln.strip(): + continue + + prefix = '' + index = 0 + while ln[index*2:index*2+2] == ' ': + index += 1 + while len(nested_tests) > index: + nested_tests.pop() + + ln = ln[index*2:] + if ln.endswith('.'): + nested_tests.append(ln) + else: + yield ''.join(nested_tests) + ln + + # Note: path_in_suite should not include the executable name. + def getTestsInExecutable(self, testSuite, path_in_suite, execpath, + litConfig, localConfig): + if not execpath.endswith(self.test_suffix): + return + (dirname, basename) = os.path.split(execpath) + # Discover the tests in this executable. + for testname in self.getGTestTests(execpath, litConfig, localConfig): + testPath = path_in_suite + (basename, testname) + yield lit.Test.Test(testSuite, testPath, localConfig) + + def getTestsInDirectory(self, testSuite, path_in_suite, + litConfig, localConfig): + source_path = testSuite.getSourcePath(path_in_suite) + for filename in os.listdir(source_path): + filepath = os.path.join(source_path, filename) + if os.path.isdir(filepath): + # Iterate over executables in a directory. + if not os.path.normcase(filename) in self.test_sub_dir: + continue + dirpath_in_suite = path_in_suite + (filename, ) + for subfilename in os.listdir(filepath): + execpath = os.path.join(filepath, subfilename) + for test in self.getTestsInExecutable( + testSuite, dirpath_in_suite, execpath, + litConfig, localConfig): + yield test + elif ('.' in self.test_sub_dir): + for test in self.getTestsInExecutable( + testSuite, path_in_suite, filepath, + litConfig, localConfig): + yield test + + def execute(self, test, litConfig): + testPath,testName = os.path.split(test.getSourcePath()) + while not os.path.exists(testPath): + # Handle GTest parametrized and typed tests, whose name includes + # some '/'s. + testPath, namePrefix = os.path.split(testPath) + testName = os.path.join(namePrefix, testName) + + cmd = [testPath, '--gtest_filter=' + testName] + if litConfig.useValgrind: + cmd = litConfig.valgrindArgs + cmd + + if litConfig.noExecute: + return lit.Test.PASS, '' + + out, err, exitCode = lit.TestRunner.executeCommand( + cmd, env=test.config.environment) + + if not exitCode: + return lit.Test.PASS,'' + + return lit.Test.FAIL, out + err diff --git a/utils/lit/lit/formats/shtest.py b/utils/lit/lit/formats/shtest.py new file mode 100644 index 0000000..30a6a33 --- /dev/null +++ b/utils/lit/lit/formats/shtest.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import + +import lit.TestRunner +from .base import FileBasedTest + +class ShTest(FileBasedTest): + def __init__(self, execute_external = False): + self.execute_external = execute_external + + def execute(self, test, litConfig): + return lit.TestRunner.executeShTest(test, litConfig, + self.execute_external) -- cgit v1.1 From 493e8d4bf503c8f573e0dce95ea146d181c623c6 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 05:07:01 +0000 Subject: [lit] Move executeCommand() into lit.util. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188356 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestRunner.py | 22 ++-------------------- utils/lit/lit/formats/base.py | 3 +-- utils/lit/lit/formats/googletest.py | 2 +- utils/lit/lit/util.py | 19 +++++++++++++++++++ 4 files changed, 23 insertions(+), 23 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index a8150e6..54bbd68 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -25,25 +25,6 @@ kUseCloseFDs = not kIsWindows # Use temporary files to replace /dev/null on Windows. kAvoidDevNull = kIsWindows -def executeCommand(command, cwd=None, env=None): - # Close extra file handles on UNIX (on Windows this cannot be done while - # also redirecting input). - close_fds = not kIsWindows - - p = subprocess.Popen(command, cwd=cwd, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=env, close_fds=close_fds) - out,err = p.communicate() - exitCode = p.wait() - - # Detect Ctrl-C in subprocess. - if exitCode == -signal.SIGINT: - raise KeyboardInterrupt - - return out, err, exitCode - def executeShCmd(cmd, cfg, cwd, results): if isinstance(cmd, ShUtil.Seq): if cmd.op == ';': @@ -308,7 +289,8 @@ def executeScript(test, litConfig, tmpBase, commands, cwd): # run on clang with no real loss. command = litConfig.valgrindArgs + command - return executeCommand(command, cwd=cwd, env=test.config.environment) + return lit.util.executeCommand(command, cwd=cwd, + env=test.config.environment) def isExpectedFail(test, xfails): # Check if any of the xfails match an available feature or the target. diff --git a/utils/lit/lit/formats/base.py b/utils/lit/lit/formats/base.py index 3c38041..b384ec2 100644 --- a/utils/lit/lit/formats/base.py +++ b/utils/lit/lit/formats/base.py @@ -3,7 +3,6 @@ import os import sys import lit.Test -import lit.TestRunner import lit.util class FileBasedTest(object): @@ -97,7 +96,7 @@ class OneCommandPerFileTest: else: cmd.append(test.getSourcePath()) - out, err, exitCode = lit.TestRunner.executeCommand(cmd) + out, err, exitCode = lit.util.executeCommand(cmd) diags = out + err if not exitCode and not diags.strip(): diff --git a/utils/lit/lit/formats/googletest.py b/utils/lit/lit/formats/googletest.py index 06b6a29..8465a0b 100644 --- a/utils/lit/lit/formats/googletest.py +++ b/utils/lit/lit/formats/googletest.py @@ -104,7 +104,7 @@ class GoogleTest(object): if litConfig.noExecute: return lit.Test.PASS, '' - out, err, exitCode = lit.TestRunner.executeCommand( + out, err, exitCode = lit.util.executeCommand( cmd, env=test.config.environment) if not exitCode: diff --git a/utils/lit/lit/util.py b/utils/lit/lit/util.py index d7d6d7f..ce26f06 100644 --- a/utils/lit/lit/util.py +++ b/utils/lit/lit/util.py @@ -2,6 +2,8 @@ import errno import itertools import math import os +import platform +import signal import subprocess import sys @@ -138,3 +140,20 @@ def printHistogram(items, title = 'Items'): pDigits, pfDigits, i*barH, pDigits, pfDigits, (i+1)*barH, '*'*w, ' '*(barW-w), cDigits, len(row), cDigits, len(items))) +# Close extra file handles on UNIX (on Windows this cannot be done while +# also redirecting input). +kUseCloseFDs = not (platform.system() == 'Windows') +def executeCommand(command, cwd=None, env=None): + p = subprocess.Popen(command, cwd=cwd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=env, close_fds=kUseCloseFDs) + out,err = p.communicate() + exitCode = p.wait() + + # Detect Ctrl-C in subprocess. + if exitCode == -signal.SIGINT: + raise KeyboardInterrupt + + return out, err, exitCode -- cgit v1.1 From 5403214852da123d09b91377ad0fa4543afc816c Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 05:07:04 +0000 Subject: [lit] Factor ShTest format script command parsing from other processing. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188357 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestRunner.py | 49 +++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 17 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 54bbd68..fb724c9 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -309,6 +309,25 @@ def isExpectedFail(test, xfails): return False +def parseIntegratedTestScriptCommands(sourcepath): + """ + parseIntegratedTestScriptCommands(source_path) -> commands + + Parse the commands in an integrated test script file into a list of + (line_number, command_type, line). + """ + line_number = 0 + for ln in open(sourcepath): + line_number += 1 + if 'RUN:' in ln: + yield (line_number, 'RUN', ln[ln.index('RUN:')+4:]) + elif 'XFAIL:' in ln: + yield (line_number, 'XFAIL', ln[ln.index('XFAIL:') + 6:]) + elif 'REQUIRES:' in ln: + yield (line_number, 'REQUIRES', ln[ln.index('REQUIRES:') + 9:]) + elif 'END.' in ln: + yield (line_number, 'END', ln[ln.index('END.') + 4:]) + def parseIntegratedTestScript(test, normalize_slashes=False, extra_substitutions=[]): """parseIntegratedTestScript - Scan an LLVM/Clang style integrated test @@ -359,14 +378,9 @@ def parseIntegratedTestScript(test, normalize_slashes=False, script = [] xfails = [] requires = [] - line_number = 0 - for ln in open(sourcepath): - line_number += 1 - if 'RUN:' in ln: - # Isolate the command to run. - index = ln.index('RUN:') - ln = ln[index+4:] - + for line_number, command_type, ln in \ + parseIntegratedTestScriptCommands(sourcepath): + if command_type == 'RUN': # Trim trailing whitespace. ln = ln.rstrip() @@ -384,16 +398,17 @@ def parseIntegratedTestScript(test, normalize_slashes=False, script[-1] = script[-1][:-1] + ln else: script.append(ln) - elif 'XFAIL:' in ln: - items = ln[ln.index('XFAIL:') + 6:].split(',') - xfails.extend([s.strip() for s in items]) - elif 'REQUIRES:' in ln: - items = ln[ln.index('REQUIRES:') + 9:].split(',') - requires.extend([s.strip() for s in items]) - elif 'END.' in ln: - # Check for END. lines. - if ln[ln.index('END.'):].strip() == 'END.': + elif command_type == 'XFAIL': + xfails.extend([s.strip() for s in ln.split(',')]) + elif command_type == 'REQUIRES': + requires.extend([s.strip() for s in ln.split(',')]) + elif command_type == 'END': + # END commands are only honored if the rest of the line is empty. + if not ln.strip(): break + else: + raise ValueError("unknown script command type: %r" % ( + command_type,)) # Apply substitutions to the script. Allow full regular # expression syntax. Replace each matching occurrence of regular -- cgit v1.1 From 6b78ef3762d0b48ac4493e81599be7af1491f8a6 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 05:07:09 +0000 Subject: [lit] Fix tests to execute lit with same python as invoked with. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188358 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/tests/lit.cfg | 5 ++++- utils/lit/tests/shell-parsing.py | 2 +- utils/lit/tests/unittest-adaptor.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/lit/tests/lit.cfg b/utils/lit/tests/lit.cfg index f148c91..a8d2591 100644 --- a/utils/lit/tests/lit.cfg +++ b/utils/lit/tests/lit.cfg @@ -1,6 +1,7 @@ # -*- Python -*- import os +import sys import lit.formats @@ -29,7 +30,9 @@ config.environment['PYTHONPATH'] = src_root config.substitutions.append(('%{src_root}', src_root)) config.substitutions.append(('%{inputs}', os.path.join( src_root, 'tests', 'Inputs'))) -config.substitutions.append(('%{lit}', os.path.join(src_root, 'lit.py'))) +config.substitutions.append(('%{lit}', "%%{python} %s" % ( + os.path.join(src_root, 'lit.py'),))) +config.substitutions.append(('%{python}', sys.executable)) # Enable coverage.py reporting, assuming the coverage module has been installed # and sitecustomize.py in the virtualenv has been modified appropriately. diff --git a/utils/lit/tests/shell-parsing.py b/utils/lit/tests/shell-parsing.py index f644132..a07e988 100644 --- a/utils/lit/tests/shell-parsing.py +++ b/utils/lit/tests/shell-parsing.py @@ -1,3 +1,3 @@ # Just run the ShUtil unit tests. # -# RUN: python -m lit.ShUtil +# RUN: %{python} -m lit.ShUtil diff --git a/utils/lit/tests/unittest-adaptor.py b/utils/lit/tests/unittest-adaptor.py index 243dd41..7435dda 100644 --- a/utils/lit/tests/unittest-adaptor.py +++ b/utils/lit/tests/unittest-adaptor.py @@ -1,6 +1,6 @@ # Check the lit adaption to run under unittest. # -# RUN: python %s %{inputs}/unittest-adaptor 2> %t.err +# RUN: %{python} %s %{inputs}/unittest-adaptor 2> %t.err # RUN: FileCheck < %t.err %s # # CHECK: unittest-adaptor :: test-one.txt ... ok -- cgit v1.1 From 213ab86ee6d51a27ec87ed8320c6b8407dd25595 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 05:07:13 +0000 Subject: [lit] Avoid StringIO. - We barely used it, and it is very hard to use in a 2.5-3 compatible way because of changing expectations for its input types. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188359 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestRunner.py | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index fb724c9..068e499 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -3,10 +3,6 @@ import os, signal, subprocess, sys import re import platform import tempfile -try: - from io import StringIO -except ImportError: - from StringIO import StringIO import lit.ShUtil as ShUtil import lit.Test as Test @@ -445,23 +441,33 @@ def parseIntegratedTestScript(test, normalize_slashes=False, return script,isXFail,tmpBase,execdir def formatTestOutput(status, out, err, exitCode, script): - output = StringIO() - output.write(u"Script:\n") - output.write(u"--\n") - output.write(u'\n'.join(script)) - output.write(u"\n--\n") - output.write(u"Exit Code: %r\n\n" % exitCode) + output = """\ +Script: +-- +%s +-- +Exit Code: %d + +""" % ('\n'.join(script), exitCode) + + # Append the stdout, if present. if out: - output.write(u"Command Output (stdout):\n") - output.write(u"--\n") - output.write(unicode(out)) - output.write(u"--\n") + output += """\ +Command Output (stdout): +-- +%s +-- +""" % (out,) + + # Append the stderr, if present. if err: - output.write(u"Command Output (stderr):\n") - output.write(u"--\n") - output.write(unicode(err)) - output.write(u"--\n") - return (status, output.getvalue()) + output += """\ +Command Output (stderr): +-- +%s +-- +""" % (err,) + return (status, output) def executeShTest(test, litConfig, useExternalSh, extra_substitutions=[]): -- cgit v1.1 From af5a9e3f1e5f89836c8af6aab274d726170deb8b Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 05:07:16 +0000 Subject: [lit] Fix a relative import issue I missed earlier. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188360 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitTestCase.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/LitTestCase.py b/utils/lit/lit/LitTestCase.py index 8951185..478dbae 100644 --- a/utils/lit/lit/LitTestCase.py +++ b/utils/lit/lit/LitTestCase.py @@ -1,5 +1,7 @@ +from __future__ import absolute_import import unittest -import Test + +import lit.Test """ TestCase adaptor for providing a 'unittest' compatible interface to 'lit' tests. @@ -24,7 +26,7 @@ class LitTestCase(unittest.TestCase): tr, output = self._test.config.test_format.execute( self._test, self._lit_config) - if tr is Test.UNRESOLVED: + if tr is lit.Test.UNRESOLVED: raise UnresolvedError(output) elif tr.isFailure: self.fail(output) -- cgit v1.1 From 47e7c040f4e03a5fd162ee7c8ea061cfe873eb23 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 15:24:58 +0000 Subject: [lit] Support parsing scripts with inconsistent or invalid encodings. - For whatever reason, we have a lot of test files with bogus unicode characters. This patch allows those scripts to still be parsed on Python3 by changing the parsing logic to work on binary files, and only require the actual script commands to be convertible to ascii. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188376 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestRunner.py | 54 +++++++++++++++++++++++++++++--------- utils/lit/tests/shtest-encoding.py | 3 +++ 2 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 utils/lit/tests/shtest-encoding.py (limited to 'utils') diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 068e499..8a9bddd 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -305,24 +305,54 @@ def isExpectedFail(test, xfails): return False -def parseIntegratedTestScriptCommands(sourcepath): +def parseIntegratedTestScriptCommands(source_path): """ parseIntegratedTestScriptCommands(source_path) -> commands Parse the commands in an integrated test script file into a list of (line_number, command_type, line). """ - line_number = 0 - for ln in open(sourcepath): - line_number += 1 - if 'RUN:' in ln: - yield (line_number, 'RUN', ln[ln.index('RUN:')+4:]) - elif 'XFAIL:' in ln: - yield (line_number, 'XFAIL', ln[ln.index('XFAIL:') + 6:]) - elif 'REQUIRES:' in ln: - yield (line_number, 'REQUIRES', ln[ln.index('REQUIRES:') + 9:]) - elif 'END.' in ln: - yield (line_number, 'END', ln[ln.index('END.') + 4:]) + + # This code is carefully written to be dual compatible with Python 2.5+ and + # Python 3 without requiring input files to always have valid codings. The + # trick we use is to open the file in binary mode and use the regular + # expression library to find the commands, with it scanning strings in + # Python2 and bytes in Python3. + # + # Once we find a match, we do require each script line to be decodable to + # ascii, so we convert the outputs to ascii before returning. This way the + # remaining code can work with "strings" agnostic of the executing Python + # version. + + def to_bytes(str): + # Encode to Latin1 to get binary data. + return str.encode('ISO-8859-1') + keywords = ('RUN:', 'XFAIL:', 'REQUIRES:', 'END.') + keywords_re = re.compile( + to_bytes("(%s)(.*)\n" % ("|".join(k for k in keywords),))) + + f = open(source_path, 'rb') + try: + # Read the entire file contents. + data = f.read() + + # Iterate over the matches. + line_number = 1 + last_match_position = 0 + for match in keywords_re.finditer(data): + # Compute the updated line number by counting the intervening + # newlines. + match_position = match.start() + line_number += data.count(to_bytes('\n'), last_match_position, + match_position) + last_match_position = match_position + + # Convert the keyword and line to ascii and yield the command. + keyword,ln = match.groups() + yield (line_number, keyword[:-1].decode('ascii'), + ln.decode('ascii')) + finally: + f.close() def parseIntegratedTestScript(test, normalize_slashes=False, extra_substitutions=[]): diff --git a/utils/lit/tests/shtest-encoding.py b/utils/lit/tests/shtest-encoding.py new file mode 100644 index 0000000..dfc987f --- /dev/null +++ b/utils/lit/tests/shtest-encoding.py @@ -0,0 +1,3 @@ +# RUN: true + +# Here is a string that cannot be decoded in line mode: Â. -- cgit v1.1 From 14a5c695a9a4dc773cfc37c0c4a847e0160e5396 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 15:55:25 +0000 Subject: Revert r188376, "[lit] Support parsing scripts with inconsistent or invalid encodings.", this doesn't work yet for bots using the internal shell. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188379 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestRunner.py | 54 +++++++++----------------------------- utils/lit/tests/shtest-encoding.py | 3 --- 2 files changed, 12 insertions(+), 45 deletions(-) delete mode 100644 utils/lit/tests/shtest-encoding.py (limited to 'utils') diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 8a9bddd..068e499 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -305,54 +305,24 @@ def isExpectedFail(test, xfails): return False -def parseIntegratedTestScriptCommands(source_path): +def parseIntegratedTestScriptCommands(sourcepath): """ parseIntegratedTestScriptCommands(source_path) -> commands Parse the commands in an integrated test script file into a list of (line_number, command_type, line). """ - - # This code is carefully written to be dual compatible with Python 2.5+ and - # Python 3 without requiring input files to always have valid codings. The - # trick we use is to open the file in binary mode and use the regular - # expression library to find the commands, with it scanning strings in - # Python2 and bytes in Python3. - # - # Once we find a match, we do require each script line to be decodable to - # ascii, so we convert the outputs to ascii before returning. This way the - # remaining code can work with "strings" agnostic of the executing Python - # version. - - def to_bytes(str): - # Encode to Latin1 to get binary data. - return str.encode('ISO-8859-1') - keywords = ('RUN:', 'XFAIL:', 'REQUIRES:', 'END.') - keywords_re = re.compile( - to_bytes("(%s)(.*)\n" % ("|".join(k for k in keywords),))) - - f = open(source_path, 'rb') - try: - # Read the entire file contents. - data = f.read() - - # Iterate over the matches. - line_number = 1 - last_match_position = 0 - for match in keywords_re.finditer(data): - # Compute the updated line number by counting the intervening - # newlines. - match_position = match.start() - line_number += data.count(to_bytes('\n'), last_match_position, - match_position) - last_match_position = match_position - - # Convert the keyword and line to ascii and yield the command. - keyword,ln = match.groups() - yield (line_number, keyword[:-1].decode('ascii'), - ln.decode('ascii')) - finally: - f.close() + line_number = 0 + for ln in open(sourcepath): + line_number += 1 + if 'RUN:' in ln: + yield (line_number, 'RUN', ln[ln.index('RUN:')+4:]) + elif 'XFAIL:' in ln: + yield (line_number, 'XFAIL', ln[ln.index('XFAIL:') + 6:]) + elif 'REQUIRES:' in ln: + yield (line_number, 'REQUIRES', ln[ln.index('REQUIRES:') + 9:]) + elif 'END.' in ln: + yield (line_number, 'END', ln[ln.index('END.') + 4:]) def parseIntegratedTestScript(test, normalize_slashes=False, extra_substitutions=[]): diff --git a/utils/lit/tests/shtest-encoding.py b/utils/lit/tests/shtest-encoding.py deleted file mode 100644 index dfc987f..0000000 --- a/utils/lit/tests/shtest-encoding.py +++ /dev/null @@ -1,3 +0,0 @@ -# RUN: true - -# Here is a string that cannot be decoded in line mode: Â. -- cgit v1.1 From 35d5e9044c580c843eb6e825d87816619e6d7f8f Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 18:22:41 +0000 Subject: [lit] Support parsing scripts with inconsistent or invalid encodings. - For whatever reason, we have a lot of test files with bogus unicode characters. This patch allows those scripts to still be parsed on Python3 by changing the parsing logic to work on binary files, and only require the actual script commands to be convertible to ascii. - This patch has been tweaked to now ensure that the command strings are not of unicode type on Python 2.6-7. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188398 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestRunner.py | 57 ++++++++++++++++++++++++++++++-------- utils/lit/tests/shtest-encoding.py | 3 ++ 2 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 utils/lit/tests/shtest-encoding.py (limited to 'utils') diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 068e499..3c658ea 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -305,24 +305,57 @@ def isExpectedFail(test, xfails): return False -def parseIntegratedTestScriptCommands(sourcepath): +def parseIntegratedTestScriptCommands(source_path): """ parseIntegratedTestScriptCommands(source_path) -> commands Parse the commands in an integrated test script file into a list of (line_number, command_type, line). """ - line_number = 0 - for ln in open(sourcepath): - line_number += 1 - if 'RUN:' in ln: - yield (line_number, 'RUN', ln[ln.index('RUN:')+4:]) - elif 'XFAIL:' in ln: - yield (line_number, 'XFAIL', ln[ln.index('XFAIL:') + 6:]) - elif 'REQUIRES:' in ln: - yield (line_number, 'REQUIRES', ln[ln.index('REQUIRES:') + 9:]) - elif 'END.' in ln: - yield (line_number, 'END', ln[ln.index('END.') + 4:]) + + # This code is carefully written to be dual compatible with Python 2.5+ and + # Python 3 without requiring input files to always have valid codings. The + # trick we use is to open the file in binary mode and use the regular + # expression library to find the commands, with it scanning strings in + # Python2 and bytes in Python3. + # + # Once we find a match, we do require each script line to be decodable to + # ascii, so we convert the outputs to ascii before returning. This way the + # remaining code can work with "strings" agnostic of the executing Python + # version. + + def to_bytes(str): + # Encode to Latin1 to get binary data. + return str.encode('ISO-8859-1') + keywords = ('RUN:', 'XFAIL:', 'REQUIRES:', 'END.') + keywords_re = re.compile( + to_bytes("(%s)(.*)\n" % ("|".join(k for k in keywords),))) + + f = open(source_path, 'rb') + try: + # Read the entire file contents. + data = f.read() + + # Iterate over the matches. + line_number = 1 + last_match_position = 0 + for match in keywords_re.finditer(data): + # Compute the updated line number by counting the intervening + # newlines. + match_position = match.start() + line_number += data.count(to_bytes('\n'), last_match_position, + match_position) + last_match_position = match_position + + # Convert the keyword and line to ascii strings and yield the + # command. Note that we take care to return regular strings in + # Python 2, to avoid other code having to differentiate between the + # str and unicode types. + keyword,ln = match.groups() + yield (line_number, str(keyword[:-1].decode('ascii')), + str(ln.decode('ascii'))) + finally: + f.close() def parseIntegratedTestScript(test, normalize_slashes=False, extra_substitutions=[]): diff --git a/utils/lit/tests/shtest-encoding.py b/utils/lit/tests/shtest-encoding.py new file mode 100644 index 0000000..dfc987f --- /dev/null +++ b/utils/lit/tests/shtest-encoding.py @@ -0,0 +1,3 @@ +# RUN: true + +# Here is a string that cannot be decoded in line mode: Â. -- cgit v1.1 From 80a06baec266e901f58797c39ac78c9552036b9d Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 22:21:01 +0000 Subject: [lit] Ensure test output is converted to strings where possible. - This cleans up the text output of failing tests when run under PY3. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188416 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestRunner.py | 10 ++++++ utils/lit/lit/util.py | 10 ++++++ .../Inputs/shtest-format/external_shell/fail.txt | 2 ++ .../external_shell/fail_with_bad_encoding.txt | 5 +++ .../external_shell/write-bad-encoding.sh | 3 ++ utils/lit/tests/Inputs/shtest-format/fail.txt | 1 + utils/lit/tests/shtest-format.py | 36 +++++++++++++++++++--- 7 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 utils/lit/tests/Inputs/shtest-format/external_shell/fail_with_bad_encoding.txt create mode 100755 utils/lit/tests/Inputs/shtest-format/external_shell/write-bad-encoding.sh (limited to 'utils') diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 3c658ea..6e03eb9 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -198,6 +198,16 @@ def executeShCmd(cmd, cfg, cwd, results): if res == -signal.SIGINT: raise KeyboardInterrupt + # Ensure the resulting output is always of string type. + try: + out = str(out.decode('ascii')) + except: + out = str(out) + try: + err = str(err.decode('ascii')) + except: + err = str(err) + results.append((cmd.commands[i], out, err, res)) if cmd.pipe_err: # Python treats the exit code as a signed char. diff --git a/utils/lit/lit/util.py b/utils/lit/lit/util.py index ce26f06..2b1010c 100644 --- a/utils/lit/lit/util.py +++ b/utils/lit/lit/util.py @@ -156,4 +156,14 @@ def executeCommand(command, cwd=None, env=None): if exitCode == -signal.SIGINT: raise KeyboardInterrupt + # Ensure the resulting output is always of string type. + try: + out = str(out.decode('ascii')) + except: + out = str(out) + try: + err = str(err.decode('ascii')) + except: + err = str(err) + return out, err, exitCode diff --git a/utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt b/utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt index 1e74be5..069e376 100644 --- a/utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt +++ b/utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt @@ -1,3 +1,5 @@ # Run a command that fails with error on stdout. # +# RUN: echo "line 1: failed test output on stdout" +# RUN: echo "line 2: failed test output on stdout" # RUN: cat "does-not-exist" diff --git a/utils/lit/tests/Inputs/shtest-format/external_shell/fail_with_bad_encoding.txt b/utils/lit/tests/Inputs/shtest-format/external_shell/fail_with_bad_encoding.txt new file mode 100644 index 0000000..f6157e6 --- /dev/null +++ b/utils/lit/tests/Inputs/shtest-format/external_shell/fail_with_bad_encoding.txt @@ -0,0 +1,5 @@ +# Run a command that fails with error on stdout. +# +# RUN: %S/write-bad-encoding.sh +# RUN: false + diff --git a/utils/lit/tests/Inputs/shtest-format/external_shell/write-bad-encoding.sh b/utils/lit/tests/Inputs/shtest-format/external_shell/write-bad-encoding.sh new file mode 100755 index 0000000..6b622cb --- /dev/null +++ b/utils/lit/tests/Inputs/shtest-format/external_shell/write-bad-encoding.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "a line with bad encoding: Â." diff --git a/utils/lit/tests/Inputs/shtest-format/fail.txt b/utils/lit/tests/Inputs/shtest-format/fail.txt index 49932c3..8c305eb 100644 --- a/utils/lit/tests/Inputs/shtest-format/fail.txt +++ b/utils/lit/tests/Inputs/shtest-format/fail.txt @@ -1 +1,2 @@ +# RUN: printf "line 1: failed test output on stdout\nline 2: failed test output on stdout" # RUN: false diff --git a/utils/lit/tests/shtest-format.py b/utils/lit/tests/shtest-format.py index 4b36873..a5ce2ff 100644 --- a/utils/lit/tests/shtest-format.py +++ b/utils/lit/tests/shtest-format.py @@ -8,14 +8,41 @@ # CHECK: -- Testing: # CHECK: FAIL: shtest-format :: external_shell/fail.txt -# CHECK: *** TEST 'shtest-format :: external_shell/fail.txt' FAILED *** +# CHECK-NEXT: *** TEST 'shtest-format :: external_shell/fail.txt' FAILED *** +# CHECK: Command Output (stdout): +# CHECK-NEXT: -- +# CHECK-NEXT: line 1: failed test output on stdout +# CHECK-NEXT: line 2: failed test output on stdout # CHECK: Command Output (stderr): -# CHECK: cat: does-not-exist: No such file or directory +# CHECK-NEXT: -- +# CHECK-NEXT: cat: does-not-exist: No such file or directory +# CHECK: -- + +# CHECK: FAIL: shtest-format :: external_shell/fail_with_bad_encoding.txt +# CHECK-NEXT: *** TEST 'shtest-format :: external_shell/fail_with_bad_encoding.txt' FAILED *** +# CHECK: Command Output (stdout): +# CHECK-NEXT: -- +# CHECK-NEXT: a line with bad encoding: # CHECK: -- # CHECK: PASS: shtest-format :: external_shell/pass.txt # CHECK: FAIL: shtest-format :: fail.txt +# CHECK-NEXT: *** TEST 'shtest-format :: fail.txt' FAILED *** +# CHECK-NEXT: Script: +# CHECK-NEXT: -- +# CHECK-NEXT: printf "line 1 +# CHECK-NEXT: false +# CHECK-NEXT: -- +# CHECK-NEXT: Exit Code: 1 +# +# CHECK: Command Output (stdout): +# CHECK-NEXT: -- +# CHECK-NEXT: Command 0: "printf" +# CHECK-NEXT: Command 0 Result: 0 +# CHECK-NEXT: Command 0 Output: +# CHECK-NEXT: line 1: failed test output on stdout +# CHECK-NEXT: line 2: failed test output on stdout # CHECK: UNRESOLVED: shtest-format :: no-test-line.txt # CHECK: PASS: shtest-format :: pass.txt @@ -31,8 +58,9 @@ # CHECK: Unexpected Passing Tests (1) # CHECK: shtest-format :: xpass.txt -# CHECK: Failing Tests (2) +# CHECK: Failing Tests (3) # CHECK: shtest-format :: external_shell/fail.txt +# CHECK: shtest-format :: external_shell/fail_with_bad_encoding.txt # CHECK: shtest-format :: fail.txt # CHECK: Expected Passes : 3 @@ -40,4 +68,4 @@ # CHECK: Unsupported Tests : 2 # CHECK: Unresolved Tests : 1 # CHECK: Unexpected Passes : 1 -# CHECK: Unexpected Failures: 2 +# CHECK: Unexpected Failures: 3 -- cgit v1.1 From 4fa59392684435c2196baf43c35c07fe8b348cae Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 22:21:11 +0000 Subject: [lit] Add test coverage of gtest format. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188417 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Inputs/googletest-format/DummySubDir/OneTest | 34 ++++++++++++++++++++++ utils/lit/tests/Inputs/googletest-format/lit.cfg | 3 ++ utils/lit/tests/googletest-format.py | 20 +++++++++++++ 3 files changed, 57 insertions(+) create mode 100755 utils/lit/tests/Inputs/googletest-format/DummySubDir/OneTest create mode 100644 utils/lit/tests/Inputs/googletest-format/lit.cfg create mode 100644 utils/lit/tests/googletest-format.py (limited to 'utils') diff --git a/utils/lit/tests/Inputs/googletest-format/DummySubDir/OneTest b/utils/lit/tests/Inputs/googletest-format/DummySubDir/OneTest new file mode 100755 index 0000000..9dff137 --- /dev/null +++ b/utils/lit/tests/Inputs/googletest-format/DummySubDir/OneTest @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +import sys + +if len(sys.argv) != 2: + raise ValueError("unexpected number of args") + +if sys.argv[1] == "--gtest_list_tests": + print("""\ +FirstTest. + subTestA + subTestB +ParameterizedTest/0. + subTest +ParameterizedTest/1. + subTest""") + sys.exit(0) +elif not sys.argv[1].startswith("--gtest_filter="): + raise ValueError("unexpected argument: %r" % (sys.argv[1])) + +test_name = sys.argv[1].split('=',1)[1] +if test_name == 'FirstTest.subTestA': + print('I am subTest A, I PASS') + sys.exit(0) +elif test_name == 'FirstTest.subTestB': + print('I am subTest B, I FAIL') + print('And I have two lines of output') + sys.exit(1) +elif test_name in ('ParameterizedTest/0.subTest', + 'ParameterizedTest/1.subTest'): + print('I am a parameterized test, I also PASS') + sys.exit(0) +else: + raise SystemExit("error: invalid test name: %r" % (test_name,)) diff --git a/utils/lit/tests/Inputs/googletest-format/lit.cfg b/utils/lit/tests/Inputs/googletest-format/lit.cfg new file mode 100644 index 0000000..f2f6cda --- /dev/null +++ b/utils/lit/tests/Inputs/googletest-format/lit.cfg @@ -0,0 +1,3 @@ +import lit.formats +config.name = 'googletest-format' +config.test_format = lit.formats.GoogleTest('DummySubDir', 'Test') diff --git a/utils/lit/tests/googletest-format.py b/utils/lit/tests/googletest-format.py new file mode 100644 index 0000000..a62fd1b --- /dev/null +++ b/utils/lit/tests/googletest-format.py @@ -0,0 +1,20 @@ +# Check the various features of the GoogleTest format. +# +# RUN: not %{lit} -j 1 -v %{inputs}/googletest-format > %t.out +# RUN: FileCheck < %t.out %s +# +# END. + +# CHECK: -- Testing: +# CHECK: PASS: googletest-format :: DummySubDir/OneTest/FirstTest.subTestA +# CHECK: FAIL: googletest-format :: DummySubDir/OneTest/FirstTest.subTestB +# CHECK-NEXT: *** TEST 'googletest-format :: DummySubDir/OneTest/FirstTest.subTestB' FAILED *** +# CHECK-NEXT: I am subTest B, I FAIL +# CHECK-NEXT: And I have two lines of output +# CHECK: *** +# CHECK: PASS: googletest-format :: DummySubDir/OneTest/ParameterizedTest/0.subTest +# CHECK: PASS: googletest-format :: DummySubDir/OneTest/ParameterizedTest/1.subTest +# CHECK: Failing Tests (1) +# CHECK: Expected Passes : 3 +# CHECK: Unexpected Failures: 1 + -- cgit v1.1 From b49fb7bcd5001567d2da06f6a6e1c7ba79649e1b Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 14 Aug 2013 23:15:39 +0000 Subject: [llvm-build] Make Py3 compatible. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188424 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/llvm-build/llvmbuild/__init__.py | 2 +- utils/llvm-build/llvmbuild/componentinfo.py | 93 +++++++++++---------- utils/llvm-build/llvmbuild/main.py | 122 +++++++++++++++------------- utils/llvm-build/llvmbuild/util.py | 2 +- 4 files changed, 117 insertions(+), 102 deletions(-) (limited to 'utils') diff --git a/utils/llvm-build/llvmbuild/__init__.py b/utils/llvm-build/llvmbuild/__init__.py index 7760218..eb20d09 100644 --- a/utils/llvm-build/llvmbuild/__init__.py +++ b/utils/llvm-build/llvmbuild/__init__.py @@ -1 +1 @@ -from main import main +from llvmbuild.main import main diff --git a/utils/llvm-build/llvmbuild/componentinfo.py b/utils/llvm-build/llvmbuild/componentinfo.py index e684ac2..eda3a48 100644 --- a/utils/llvm-build/llvmbuild/componentinfo.py +++ b/utils/llvm-build/llvmbuild/componentinfo.py @@ -2,11 +2,14 @@ Descriptor objects for entities that are part of the LLVM project. """ -import ConfigParser -import StringIO +from __future__ import absolute_import +try: + import configparser +except: + import ConfigParser as configparser import sys -from util import * +from llvmbuild.util import * class ParseError(Exception): pass @@ -29,7 +32,7 @@ class ComponentInfo(object): def __init__(self, subpath, name, dependencies, parent): if not subpath.startswith('/'): - raise ValueError,"invalid subpath: %r" % subpath + raise ValueError("invalid subpath: %r" % subpath) self.subpath = subpath self.name = name self.dependencies = list(dependencies) @@ -100,11 +103,11 @@ class GroupComponentInfo(ComponentInfo): ComponentInfo.__init__(self, subpath, name, [], parent) def get_llvmbuild_fragment(self): - result = StringIO.StringIO() - print >>result, 'type = %s' % self.type_name - print >>result, 'name = %s' % self.name - print >>result, 'parent = %s' % self.parent - return result.getvalue() + return """\ +type = %s +name = %s +parent = %s +""" % (self.type_name, self.name, self.parent) class LibraryComponentInfo(ComponentInfo): type_name = 'Library' @@ -152,21 +155,22 @@ class LibraryComponentInfo(ComponentInfo): yield ('library group', r) def get_llvmbuild_fragment(self): - result = StringIO.StringIO() - print >>result, 'type = %s' % self.type_name - print >>result, 'name = %s' % self.name - print >>result, 'parent = %s' % self.parent + result = """\ +type = %s +name = %s +parent = %s +""" % (self.type_name, self.name, self.parent) if self.library_name is not None: - print >>result, 'library_name = %s' % self.library_name + result += 'library_name = %s\n' % self.library_name if self.required_libraries: - print >>result, 'required_libraries = %s' % ' '.join( + result += 'required_libraries = %s\n' % ' '.join( self.required_libraries) if self.add_to_library_groups: - print >>result, 'add_to_library_groups = %s' % ' '.join( + result += 'add_to_library_groups = %s\n' % ' '.join( self.add_to_library_groups) if not self.installed: - print >>result, 'installed = 0' - return result.getvalue() + result += 'installed = 0\n' + return result def get_library_name(self): return self.library_name or self.name @@ -237,17 +241,18 @@ class LibraryGroupComponentInfo(ComponentInfo): yield ('library group', r) def get_llvmbuild_fragment(self): - result = StringIO.StringIO() - print >>result, 'type = %s' % self.type_name - print >>result, 'name = %s' % self.name - print >>result, 'parent = %s' % self.parent + result = """\ +type = %s +name = %s +parent = %s +""" % (self.type_name, self.name, self.parent) if self.required_libraries and not self._is_special_group: - print >>result, 'required_libraries = %s' % ' '.join( + result += 'required_libraries = %s\n' % ' '.join( self.required_libraries) if self.add_to_library_groups: - print >>result, 'add_to_library_groups = %s' % ' '.join( + result += 'add_to_library_groups = %s\n' % ' '.join( self.add_to_library_groups) - return result.getvalue() + return result def get_llvmconfig_component_name(self): return self.name.lower() @@ -309,21 +314,22 @@ class TargetGroupComponentInfo(ComponentInfo): yield ('library group', r) def get_llvmbuild_fragment(self): - result = StringIO.StringIO() - print >>result, 'type = %s' % self.type_name - print >>result, 'name = %s' % self.name - print >>result, 'parent = %s' % self.parent + result = """\ +type = %s +name = %s +parent = %s +""" % (self.type_name, self.name, self.parent) if self.required_libraries: - print >>result, 'required_libraries = %s' % ' '.join( + result += 'required_libraries = %s\n' % ' '.join( self.required_libraries) if self.add_to_library_groups: - print >>result, 'add_to_library_groups = %s' % ' '.join( + result += 'add_to_library_groups = %s\n' % ' '.join( self.add_to_library_groups) for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler', 'has_jit'): if getattr(self, bool_key): - print >>result, '%s = 1' % (bool_key,) - return result.getvalue() + result += '%s = 1\n' % (bool_key,) + return result def get_llvmconfig_component_name(self): return self.name.lower() @@ -352,13 +358,13 @@ class ToolComponentInfo(ComponentInfo): yield ('required library', r) def get_llvmbuild_fragment(self): - result = StringIO.StringIO() - print >>result, 'type = %s' % self.type_name - print >>result, 'name = %s' % self.name - print >>result, 'parent = %s' % self.parent - print >>result, 'required_libraries = %s' % ' '.join( - self.required_libraries) - return result.getvalue() + return """\ +type = %s +name = %s +parent = %s +required_libraries = %s +""" % (self.type_name, self.name, self.parent, + ' '.join(self.required_libraries)) class BuildToolComponentInfo(ToolComponentInfo): type_name = 'BuildTool' @@ -418,7 +424,7 @@ _component_type_map = dict( TargetGroupComponentInfo, OptionalLibraryComponentInfo)) def load_from_path(path, subpath): # Load the LLVMBuild.txt file as an .ini format file. - parser = ConfigParser.RawConfigParser() + parser = configparser.RawConfigParser() parser.read(path) # Extract the common section. @@ -459,8 +465,9 @@ def _read_components_from_parser(parser, path, subpath): section, path, "unable to instantiate: %r" % type_name) import traceback traceback.print_exc() - raise SystemExit, 1 - except ParseError,e: + raise SystemExit(1) + except ParseError: + e = sys.exc_info()[1] fatal("unable to load component %r in %r: %s" % ( section, path, e.message)) diff --git a/utils/llvm-build/llvmbuild/main.py b/utils/llvm-build/llvmbuild/main.py index 87e8819..eacefdf 100644 --- a/utils/llvm-build/llvmbuild/main.py +++ b/utils/llvm-build/llvmbuild/main.py @@ -1,11 +1,11 @@ -import StringIO +from __future__ import absolute_import import os import sys -import componentinfo -import configutil +import llvmbuild.componentinfo as componentinfo +import llvmbuild.configutil as configutil -from util import * +from llvmbuild.util import * ### @@ -186,7 +186,7 @@ class LLVMProjectInfo(object): set(self.component_infos), key = lambda c: c.name) while components_to_visit: - visit_component_info(iter(components_to_visit).next(), [], set()) + visit_component_info(components_to_visit[0], [], set()) # Canonicalize children lists. for c in self.ordered_component_infos: @@ -194,7 +194,7 @@ class LLVMProjectInfo(object): def print_tree(self): def visit(node, depth = 0): - print '%s%-40s (%s)' % (' '*depth, node.name, node.type_name) + print('%s%-40s (%s)' % (' '*depth, node.name, node.type_name)) for c in node.children: visit(c, depth + 1) visit(self.component_info_map['$ROOT']) @@ -283,7 +283,7 @@ subdirectories = %s header_name = '.' + os.path.join(subpath, 'LLVMBuild.txt') header_pad = '-' * (80 - len(header_fmt % (header_name, ''))) header_string = header_fmt % (header_name, header_pad) - print >>f, """\ + f.write("""\ %s ; ; The LLVM Compiler Infrastructure @@ -300,17 +300,18 @@ subdirectories = %s ; http://llvm.org/docs/LLVMBuild.html ; ;===------------------------------------------------------------------------===; -""" % header_string + +""" % header_string) # Write out each fragment.each component fragment. for name,fragment in fragments: comment = comments_map.get(name) if comment is not None: f.write(comment) - print >>f, "[%s]" % name + f.write("[%s]\n" % name) f.write(fragment) if fragment is not fragments[-1][1]: - print >>f + f.write('\n') f.close() @@ -363,7 +364,7 @@ subdirectories = %s is_installed) # Convert to a list of entries and sort by name. - entries = entries.values() + entries = list(entries.values()) # Create an 'all' pseudo component. We keep the dependency list small by # only listing entries that have no other dependents. @@ -382,7 +383,7 @@ subdirectories = %s # Write out the library table. make_install_dir(os.path.dirname(output_path)) f = open(output_path, 'w') - print >>f, """\ + f.write("""\ //===- llvm-build generated file --------------------------------*- C++ -*-===// // // Component Library Depenedency Table @@ -390,32 +391,33 @@ subdirectories = %s // Automatically generated file, do not edit! // //===----------------------------------------------------------------------===// -""" - print >>f, 'struct AvailableComponent {' - print >>f, ' /// The name of the component.' - print >>f, ' const char *Name;' - print >>f, '' - print >>f, ' /// The name of the library for this component (or NULL).' - print >>f, ' const char *Library;' - print >>f, '' - print >>f, ' /// Whether the component is installed.' - print >>f, ' bool IsInstalled;' - print >>f, '' - print >>f, '\ - /// The list of libraries required when linking this component.' - print >>f, ' const char *RequiredLibraries[%d];' % ( - max_required_libraries) - print >>f, '} AvailableComponents[%d] = {' % len(entries) + +""") + f.write('struct AvailableComponent {\n') + f.write(' /// The name of the component.\n') + f.write(' const char *Name;\n') + f.write('\n') + f.write(' /// The name of the library for this component (or NULL).\n') + f.write(' const char *Library;\n') + f.write('\n') + f.write(' /// Whether the component is installed.\n') + f.write(' bool IsInstalled;\n') + f.write('\n') + f.write('\ + /// The list of libraries required when linking this component.\n') + f.write(' const char *RequiredLibraries[%d];\n' % ( + max_required_libraries)) + f.write('} AvailableComponents[%d] = {\n' % len(entries)) for name,library_name,required_names,is_installed in entries: if library_name is None: library_name_as_cstr = '0' else: library_name_as_cstr = '"lib%s.a"' % library_name - print >>f, ' { "%s", %s, %d, { %s } },' % ( + f.write(' { "%s", %s, %d, { %s } },\n' % ( name, library_name_as_cstr, is_installed, ', '.join('"%s"' % dep - for dep in required_names)) - print >>f, '};' + for dep in required_names))) + f.write('};\n') f.close() def get_required_libraries_for_component(self, ci, traverse_groups = False): @@ -512,7 +514,7 @@ subdirectories = %s header_name = os.path.basename(output_path) header_pad = '-' * (80 - len(header_fmt % (header_name, ''))) header_string = header_fmt % (header_name, header_pad) - print >>f, """\ + f.write("""\ %s # # The LLVM Compiler Infrastructure @@ -528,10 +530,11 @@ subdirectories = %s # This file is autogenerated by llvm-build, do not edit! # #===------------------------------------------------------------------------===# -""" % header_string + +""" % header_string) # Write the dependency information in the best way we can. - print >>f, """ + f.write(""" # LLVMBuild CMake fragment dependencies. # # CMake has no builtin way to declare that the configuration depends on @@ -541,30 +544,32 @@ subdirectories = %s # CMake. # # FIXME: File a CMake RFE to get a properly supported version of this -# feature.""" +# feature. +""") for dep in dependencies: - print >>f, """\ + f.write("""\ configure_file(\"%s\" - ${CMAKE_CURRENT_BINARY_DIR}/DummyConfigureOutput)""" % ( - cmake_quote_path(dep),) + ${CMAKE_CURRENT_BINARY_DIR}/DummyConfigureOutput)\n""" % ( + cmake_quote_path(dep),)) # Write the properties we use to encode the required library dependency # information in a form CMake can easily use directly. - print >>f, """ + f.write(""" # Explicit library dependency information. # # The following property assignments effectively create a map from component -# names to required libraries, in a way that is easily accessed from CMake.""" +# names to required libraries, in a way that is easily accessed from CMake. +""") for ci in self.ordered_component_infos: # We only write the information for libraries currently. if ci.type_name != 'Library': continue - print >>f, """\ -set_property(GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_%s %s)""" % ( + f.write("""\ +set_property(GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_%s %s)\n""" % ( ci.get_prefixed_library_name(), " ".join(sorted( dep.get_prefixed_library_name() - for dep in self.get_required_libraries_for_component(ci)))) + for dep in self.get_required_libraries_for_component(ci))))) f.close() @@ -590,7 +595,7 @@ set_property(GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_%s %s)""" % ( header_name = os.path.basename(output_path) header_pad = '-' * (80 - len(header_fmt % (header_name, ''))) header_string = header_fmt % (header_name, header_pad) - print >>f, """\ + f.write("""\ %s # # The LLVM Compiler Infrastructure @@ -606,30 +611,33 @@ set_property(GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_%s %s)""" % ( # This file is autogenerated by llvm-build, do not edit! # #===------------------------------------------------------------------------===# -""" % header_string + +""" % header_string) # Write the dependencies for the fragment. # # FIXME: Technically, we need to properly quote for Make here. - print >>f, """\ + f.write("""\ # Clients must explicitly enable LLVMBUILD_INCLUDE_DEPENDENCIES to get # these dependencies. This is a compromise to help improve the -# performance of recursive Make systems.""" - print >>f, 'ifeq ($(LLVMBUILD_INCLUDE_DEPENDENCIES),1)' - print >>f, "# The dependencies for this Makefile fragment itself." - print >>f, "%s: \\" % (mk_quote_string_for_target(output_path),) +# performance of recursive Make systems. +""") + f.write('ifeq ($(LLVMBUILD_INCLUDE_DEPENDENCIES),1)\n') + f.write("# The dependencies for this Makefile fragment itself.\n") + f.write("%s: \\\n" % (mk_quote_string_for_target(output_path),)) for dep in dependencies: - print >>f, "\t%s \\" % (dep,) - print >>f + f.write("\t%s \\\n" % (dep,)) + f.write('\n') # Generate dummy rules for each of the dependencies, so that things # continue to work correctly if any of those files are moved or removed. - print >>f, """\ + f.write("""\ # The dummy targets to allow proper regeneration even when files are moved or -# removed.""" +# removed. +""") for dep in dependencies: - print >>f, "%s:" % (mk_quote_string_for_target(dep),) - print >>f, 'endif' + f.write("%s:\n" % (mk_quote_string_for_target(dep),)) + f.write('endif\n') f.close() @@ -801,7 +809,7 @@ given by --build-root) at the same SUBPATH""", dest="optional_components", metavar="NAMES", help=("Enable the given space or semi-colon separated " "list of optional components"), - action="store", default=None) + action="store", default="") parser.add_option_group(group) (opts, args) = parser.parse_args() diff --git a/utils/llvm-build/llvmbuild/util.py b/utils/llvm-build/llvmbuild/util.py index e581af2..ca021c4 100644 --- a/utils/llvm-build/llvmbuild/util.py +++ b/utils/llvm-build/llvmbuild/util.py @@ -3,7 +3,7 @@ import sys def _write_message(kind, message): program = os.path.basename(sys.argv[0]) - print >>sys.stderr, '%s: %s: %s' % (program, kind, message) + sys.stderr.write('%s: %s: %s\n' % (program, kind, message)) note = lambda message: _write_message('note', message) warning = lambda message: _write_message('warning', message) -- cgit v1.1 From 23114d0da70559e88d506d88b6863e89ad98a66f Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 15 Aug 2013 22:52:20 +0000 Subject: [lit] Remove some done TODOs. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188502 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/TODO | 4 ---- 1 file changed, 4 deletions(-) (limited to 'utils') diff --git a/utils/lit/TODO b/utils/lit/TODO index d2ff842..e209fad 100644 --- a/utils/lit/TODO +++ b/utils/lit/TODO @@ -8,10 +8,6 @@ - Support a timeout / ulimit. - - Rename 'lit' injected variable for config to be lit_config. - - - Allow import of 'lit' in test suite definitions. - - Create an explicit test suite object (instead of using the top-level TestingConfig object). -- cgit v1.1 From 3369599db29739cd94087c34d0f7df8d00c00eb1 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Fri, 16 Aug 2013 01:43:31 +0000 Subject: Fixing a warning about control reaching the end of a non-void function. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188524 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenInstruction.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'utils') diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp index 3673204..8ec7682 100644 --- a/utils/TableGen/CodeGenInstruction.cpp +++ b/utils/TableGen/CodeGenInstruction.cpp @@ -192,6 +192,7 @@ CGIOperandList::ParseOperandName(const std::string &Op, bool AllowWholeOp) { // Otherwise, didn't find it! PrintFatalError(TheDef->getName() + ": unknown suboperand name in '" + Op + "'"); + return std::make_pair(0U, 0U); } static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops) { -- cgit v1.1 From 6d3aa547a522ae53c3aff6b40f0a23f9a22dcd87 Mon Sep 17 00:00:00 2001 From: Stephen Lin Date: Fri, 16 Aug 2013 17:29:01 +0000 Subject: FileCheck: Fix stray quote in CHECK-LABEL error message. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188564 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/FileCheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 82e8057..37c7874 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -768,7 +768,7 @@ static bool ReadCheckFile(SourceMgr &SM, SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), SourceMgr::DK_Error, "found '"+CheckPrefix+"-LABEL:' with variable definition" - " or use'"); + " or use"); return true; } -- cgit v1.1 From 70360e67624b5897490de29b51b1b616afcb8f5e Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 16 Aug 2013 23:30:23 +0000 Subject: [lit] Rewrite TODO list, and elaborate on some things. - If anyone is interested in lit's feature set, I'd appreciate any comments on the elaborated items. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188590 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/TODO | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 129 insertions(+), 12 deletions(-) (limited to 'utils') diff --git a/utils/lit/TODO b/utils/lit/TODO index e209fad..419056a 100644 --- a/utils/lit/TODO +++ b/utils/lit/TODO @@ -1,22 +1,139 @@ - - Move temp directory name into local test config. +================ + lit TODO Items +================ - - Add --show-unsupported, don't show by default? +Infrastructure +============== - - Optionally use multiprocessing. +1. Change to always load suites, then resolve command line arguments? - - Support valgrind in all configs, and LLVM style valgrind. + Currently we expect each input argument to be a path on disk; we do a + recursive search to find the test suite for each item, but then we only do a + local search based at the input path to find tests. Additionally, for any path + that matches a file on disk we explicitly construct a test instance (bypassing + the formats on discovery implementation). - - Support a timeout / ulimit. + This has a couple problems: - - Create an explicit test suite object (instead of using the top-level - TestingConfig object). + * The test format doesn't have control over the test instances that result + from file paths. - - Allow 'lit' driver to cooperate with test suites to add options (or at least - sanitize accepted params). + * It isn't possible to specify virtual tests as inputs. For example, it is not + possible to specify an individual subtest to run with the googletest format. - - Consider move to identifying all tests by path-to-test-suite and then path to + * The test format doesn't have full control over the discovery of tests in + subdirectories. + + Instead, we should move to a model whereby first all of the input specifiers + are resolved to test suites, and then the resolution of the input specifier is + delegated to each test suite. This could take a couple forms: + + * We could resolve to test suites, then fully load each test suite, then have + a fixed process to map input specifiers to tests in the test suite + (presumably based on path-in-suite derivations). This has the benefit of + being consistent across all test formats, but the downside of requiring + loading the entire test suite. + + * We could delegate all of the resolution of specifiers to the test + suite. This would allow formats that anticipate large test suites to manage + their own resolution for better performance. We could provide a default + resolution strategy that was similar to what we do now (start at subpaths + for directories, but allow the test format control over what happens for + individual tests). + +2. Consider move to identifying all tests by path-to-test-suite and then path to subtest, and don't use test suite names. - - Consider move to change workflow to always load suites, then resolve command - line arguments. + Currently the test suite name is presented as part of test names, but it has + no other useful function, and it is something that has to be skipped over to + cut-and-paste a name to subsequently use to rerun a test. If we just + represented each test suite by the path to its suite, then it would allow more + easy cut-and-paste of the test output lines. This has the downside that the + lines might get rather long. + +3. Allow 'lit' driver to cooperate with test formats and suites to add options + (or at least sanitize accepted params). + + We have started to use the --params method more and more extensively, and it is + cumbersome and error prone. Additionally, there are currently various options + ``lit`` honors that should more correctly be specified as belonging to the + ShTest test format. + + It would be really nice if we could allow test formats and test suites to add + their own options to be parsed. The difficulty here, of course, is that we + don't know what test formats or test suites are in use until we have parsed the + input specifiers. For test formats we could ostensibly require all the possible + formats to be registered in order to have options, but for test suites we would + certainly have to load the suite before we can query it for what options it + understands. + + That leaves us with the following options: + + * Currently we could almost get away with parsing the input specifiers without + having done option parsing first (the exception is ``--config-prefix``) but + that isn't a very extensible design. + + * We could make a distinction in the command line syntax for test format and + test suite options. For example, we could require something like:: + + lit -j 1 -sv input-specifier -- --some-format-option + + which would be relatively easy to implement with optparser (I think). + + * We could allow fully interspersed arguments by first extracting the options + lit knows about and parsing them, then dispatching the remainder to the + formats. This seems the most convenient for users, who are unlikely to care + about (or even be aware of) the distinction between the generic lit + infrastructure and format or suite specific options. + +4. Eliminate duplicate execution models for ShTest tests. + + Currently, the ShTest format uses tests written with shell-script like syntax, + and executes them in one of two ways. The first way is by converting them into + a bash script and literally executing externally them using bash. The second + way is through the use of an internal shell parser and shell execution code + (built on the subprocess module). The external execution mode is used on most + Unix systems that have bash, the internal execution mode is used on Windows. + + Having two ways to do the same thing is error prone and leads to unnecessary + complexity in the testing environment. Additionally, because the mode that + converts scripts to bash doesn't try and validate the syntax, it is possible + to write tests that use bash shell features unsupported by the internal + shell. Such tests won't work on Windows but this may not be obvious to the + developer writing the test. + + Another limitation is that when executing the scripts externally, the ShTest + format has no idea which commands fail, or what output comes from which + commands, so this limits how convenient the output of ShTest failures can be + and limits other features (for example, knowing what temporary files were + written). + + We should eliminate having two ways of executing the same tests to reduce + platform differences and make it easier to develop new features in the ShTest + module. This is currently blocked on: + + * The external execution mode is faster in some situations, because it avoids + being bottlenecked on the GIL. We could fix this by moving to a good + multiprocessing model. + + * Some tests in LLVM/Clang are explicitly disabled with the internal shell + (because they use features specific to bash). We would need to rewrite these + tests, or add additional features to the internal shell handling to allow + them to pass. + + +Miscellaneous +============= + +* Move temp directory name into local test config. + +* Add --show-unsupported, don't show by default? + +* Optionally use multiprocessing. + +* Support valgrind in all configs, and LLVM style valgrind. + +* Support a timeout / ulimit. +* Create an explicit test suite object (instead of using the top-level + TestingConfig object). -- cgit v1.1 From 7b0cdf7bf44e626977d607279a933e45346aeac8 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 21 Aug 2013 22:26:26 +0000 Subject: [lit] Extract TestFormat base class, for future use. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188945 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/Test.py | 6 ------ utils/lit/lit/formats/__init__.py | 2 +- utils/lit/lit/formats/base.py | 9 +++++++-- utils/lit/lit/formats/googletest.py | 3 ++- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py index cf12425..dc2a435 100644 --- a/utils/lit/lit/Test.py +++ b/utils/lit/lit/Test.py @@ -20,12 +20,6 @@ UNSUPPORTED = TestResult('UNSUPPORTED', False) # Test classes. -class TestFormat: - """TestFormat - Test information provider.""" - - def __init__(self, name): - self.name = name - class TestSuite: """TestSuite - Information on a group of tests. diff --git a/utils/lit/lit/formats/__init__.py b/utils/lit/lit/formats/__init__.py index f4a303c..6862708 100644 --- a/utils/lit/lit/formats/__init__.py +++ b/utils/lit/lit/formats/__init__.py @@ -1,4 +1,4 @@ from __future__ import absolute_import -from lit.formats.base import FileBasedTest, OneCommandPerFileTest +from lit.formats.base import TestFormat, FileBasedTest, OneCommandPerFileTest from lit.formats.googletest import GoogleTest from lit.formats.shtest import ShTest diff --git a/utils/lit/lit/formats/base.py b/utils/lit/lit/formats/base.py index b384ec2..9e5420b 100644 --- a/utils/lit/lit/formats/base.py +++ b/utils/lit/lit/formats/base.py @@ -5,7 +5,12 @@ import sys import lit.Test import lit.util -class FileBasedTest(object): +class TestFormat(object): + pass + +### + +class FileBasedTest(TestFormat): def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, localConfig): source_path = testSuite.getSourcePath(path_in_suite) @@ -27,7 +32,7 @@ class FileBasedTest(object): import re import tempfile -class OneCommandPerFileTest: +class OneCommandPerFileTest(TestFormat): # FIXME: Refactor into generic test for running some command on a directory # of inputs. diff --git a/utils/lit/lit/formats/googletest.py b/utils/lit/lit/formats/googletest.py index 8465a0b..b77e184 100644 --- a/utils/lit/lit/formats/googletest.py +++ b/utils/lit/lit/formats/googletest.py @@ -5,10 +5,11 @@ import sys import lit.Test import lit.TestRunner import lit.util +from .base import TestFormat kIsWindows = sys.platform in ['win32', 'cygwin'] -class GoogleTest(object): +class GoogleTest(TestFormat): def __init__(self, test_sub_dir, test_suffix): self.test_sub_dir = os.path.normcase(str(test_sub_dir)).split(';') self.test_suffix = str(test_suffix) -- cgit v1.1 From 0dd41a99e31d098165571911fbb7d9d9a453595f Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 21 Aug 2013 22:26:34 +0000 Subject: [lit] Simplify --time-tests code. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188946 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index fb3614a..8f71685 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -407,17 +407,11 @@ def main(builtinParameters = {}): print(' %s' % t.getFullName()) sys.stdout.write('\n') - if opts.timeTests: - # Collate, in case we repeated tests. - times = {} - for t in tests: - key = t.getFullName() - times[key] = times.get(key, 0.) + t.elapsed - - byTime = list(times.items()) - byTime.sort(key = lambda item: item[1]) - if byTime: - lit.util.printHistogram(byTime, title='Tests') + if opts.timeTests and tests: + # Order by time. + test_times = [(t.getFullName(), t.elapsed) + for t in tests] + lit.util.printHistogram(test_times, title='Tests') for name,code in (('Expected Passes ', lit.Test.PASS), ('Expected Failures ', lit.Test.XFAIL), -- cgit v1.1 From ccd21b26dd16c6dff207b3ded3df2bb90f1b9e6e Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 21 Aug 2013 22:26:37 +0000 Subject: [lit] Factor out a separate Test.Result() object. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188947 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/Test.py | 37 ++++++++++++++++++++++--------------- utils/lit/lit/main.py | 36 ++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 33 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py index dc2a435..d37854e 100644 --- a/utils/lit/lit/Test.py +++ b/utils/lit/lit/Test.py @@ -2,7 +2,9 @@ import os # Test results. -class TestResult: +class ResultCode(object): + """Test result codes.""" + def __init__(self, name, isFailure): self.name = name self.isFailure = isFailure @@ -11,12 +13,23 @@ class TestResult: return '%s%r' % (self.__class__.__name__, (self.name, self.isFailure)) -PASS = TestResult('PASS', False) -XFAIL = TestResult('XFAIL', False) -FAIL = TestResult('FAIL', True) -XPASS = TestResult('XPASS', True) -UNRESOLVED = TestResult('UNRESOLVED', True) -UNSUPPORTED = TestResult('UNSUPPORTED', False) +PASS = ResultCode('PASS', False) +XFAIL = ResultCode('XFAIL', False) +FAIL = ResultCode('FAIL', True) +XPASS = ResultCode('XPASS', True) +UNRESOLVED = ResultCode('UNRESOLVED', True) +UNSUPPORTED = ResultCode('UNSUPPORTED', False) + +class Result(object): + """Wrapper for the results of executing an individual test.""" + + def __init__(self, code, output, elapsed): + # The result code. + self.code = code + # The test output. + self.output = output + # The wall timing to execute the test, if timing. + self.elapsed = elapsed # Test classes. @@ -46,18 +59,12 @@ class Test: self.suite = suite self.path_in_suite = path_in_suite self.config = config - # The test result code, once complete. + # The test result, once complete. self.result = None - # Any additional output from the test, once complete. - self.output = None - # The wall time to execute this test, if timing and once complete. - self.elapsed = None def setResult(self, result, output, elapsed): assert self.result is None, "Test result already set!" - self.result = result - self.output = output - self.elapsed = elapsed + self.result = Result(result, output, elapsed) def getFullName(self): return self.suite.config.name + ' :: ' + '/'.join(self.path_in_suite) diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 8f71685..9608803 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -27,7 +27,7 @@ class TestingProgressDisplay: def update(self, test): # Avoid locking overhead in quiet mode - if self.opts.quiet and not test.result.isFailure: + if self.opts.quiet and not test.result.code.isFailure: self.completed += 1 return @@ -52,19 +52,19 @@ class TestingProgressDisplay: self.progressBar.update(float(self.completed)/self.numTests, test.getFullName()) - if self.opts.succinct and not test.result.isFailure: + if self.opts.succinct and not test.result.code.isFailure: return if self.progressBar: self.progressBar.clear() - print('%s: %s (%d of %d)' % (test.result.name, test.getFullName(), + print('%s: %s (%d of %d)' % (test.result.code.name, test.getFullName(), self.completed, self.numTests)) - if test.result.isFailure and self.opts.showOutput: + if test.result.code.isFailure and self.opts.showOutput: print("%s TEST '%s' FAILED %s" % ('*'*20, test.getFullName(), '*'*20)) - print(test.output) + print(test.result.output) print("*" * 20) sys.stdout.flush() @@ -380,18 +380,18 @@ def main(builtinParameters = {}): print('Testing Time: %.2fs'%(time.time() - startTime)) # Update results for any tests which weren't run. - for t in tests: - if t.result is None: - t.setResult(lit.Test.UNRESOLVED, '', 0.0) + for test in tests: + if test.result is None: + test.setResult(lit.Test.UNRESOLVED, '', 0.0) # List test results organized by kind. hasFailures = False byCode = {} - for t in tests: - if t.result not in byCode: - byCode[t.result] = [] - byCode[t.result].append(t) - if t.result.isFailure: + for test in tests: + if test.result.code not in byCode: + byCode[test.result.code] = [] + byCode[test.result.code].append(test) + if test.result.code.isFailure: hasFailures = True # Print each test in any of the failing groups. @@ -403,16 +403,16 @@ def main(builtinParameters = {}): continue print('*'*20) print('%s (%d):' % (title, len(elts))) - for t in elts: - print(' %s' % t.getFullName()) + for test in elts: + print(' %s' % test.getFullName()) sys.stdout.write('\n') if opts.timeTests and tests: # Order by time. - test_times = [(t.getFullName(), t.elapsed) - for t in tests] + test_times = [(test.getFullName(), test.result.elapsed) + for test in tests] lit.util.printHistogram(test_times, title='Tests') - + for name,code in (('Expected Passes ', lit.Test.PASS), ('Expected Failures ', lit.Test.XFAIL), ('Unsupported Tests ', lit.Test.UNSUPPORTED), -- cgit v1.1 From d3bf8a2c0aefe36cb4bfc6f41983aa09caae2acb Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 21 Aug 2013 22:26:40 +0000 Subject: [lit] Allow formats to return lit.Test.Result instances directly. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188948 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/Test.py | 12 ++++++++---- utils/lit/lit/main.py | 19 +++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py index d37854e..c1bacb3 100644 --- a/utils/lit/lit/Test.py +++ b/utils/lit/lit/Test.py @@ -23,7 +23,7 @@ UNSUPPORTED = ResultCode('UNSUPPORTED', False) class Result(object): """Wrapper for the results of executing an individual test.""" - def __init__(self, code, output, elapsed): + def __init__(self, code, output='', elapsed=None): # The result code. self.code = code # The test output. @@ -62,9 +62,13 @@ class Test: # The test result, once complete. self.result = None - def setResult(self, result, output, elapsed): - assert self.result is None, "Test result already set!" - self.result = Result(result, output, elapsed) + def setResult(self, result): + if self.result is not None: + raise ArgumentError("test result already set") + if not isinstance(result, Result): + raise ArgumentError("unexpected result type") + + self.result = result def getFullName(self): return self.suite.config.name + ' :: ' + '/'.join(self.path_in_suite) diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 9608803..b84140f 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -118,8 +118,15 @@ class Tester(threading.Thread): result = None startTime = time.time() try: - result, output = test.config.test_format.execute(test, - self.litConfig) + result = test.config.test_format.execute(test, self.litConfig) + + # Support deprecated result from execute() which returned the result + # code and additional output as a tuple. + if isinstance(result, tuple): + code, output = result + result = lit.Test.Result(code, output) + elif not isinstance(result, lit.Test.Result): + raise ValueError("unexpected result from test execution") except KeyboardInterrupt: # This is a sad hack. Unfortunately subprocess goes # bonkers with ctrl-c and we start forking merrily. @@ -128,13 +135,13 @@ class Tester(threading.Thread): except: if self.litConfig.debug: raise - result = lit.Test.UNRESOLVED output = 'Exception during script execution:\n' output += traceback.format_exc() output += '\n' - elapsed = time.time() - startTime + result = lit.Test.Result(lit.Test.UNRESOLVED, output) + result.elapsed = time.time() - startTime - test.setResult(result, output, elapsed) + test.setResult(result) self.display.update(test) def runTests(numThreads, litConfig, provider, display): @@ -382,7 +389,7 @@ def main(builtinParameters = {}): # Update results for any tests which weren't run. for test in tests: if test.result is None: - test.setResult(lit.Test.UNRESOLVED, '', 0.0) + test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0)) # List test results organized by kind. hasFailures = False -- cgit v1.1 From f72bc792264941d1cdffe99775ce5e28bcdc51a4 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 21 Aug 2013 22:26:42 +0000 Subject: [lit] Lift XFAIL handling to core infrastructure. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188949 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/Test.py | 37 +++++++++++++++++++++++++++++++++++ utils/lit/lit/TestRunner.py | 42 ++++++---------------------------------- utils/lit/tests/shtest-format.py | 5 +++++ 3 files changed, 48 insertions(+), 36 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py index c1bacb3..59ca694 100644 --- a/utils/lit/lit/Test.py +++ b/utils/lit/lit/Test.py @@ -59,6 +59,10 @@ class Test: self.suite = suite self.path_in_suite = path_in_suite self.config = config + # A list of conditions under which this test is expected to fail. These + # can optionally be provided by test format handlers, and will be + # honored when the test result is supplied. + self.xfails = [] # The test result, once complete. self.result = None @@ -70,6 +74,13 @@ class Test: self.result = result + # Apply the XFAIL handling to resolve the result exit code. + if self.isExpectedToFail(): + if self.result.code == PASS: + self.result.code = XPASS + elif self.result.code == FAIL: + self.result.code = XFAIL + def getFullName(self): return self.suite.config.name + ' :: ' + '/'.join(self.path_in_suite) @@ -78,3 +89,29 @@ class Test: def getExecPath(self): return self.suite.getExecPath(self.path_in_suite) + + def isExpectedToFail(self): + """ + isExpectedToFail() -> bool + + Check whether this test is expected to fail in the current + configuration. This check relies on the test xfails property which by + some test formats may not be computed until the test has first been + executed. + """ + + # Check if any of the xfails match an available feature or the target. + for item in self.xfails: + # If this is the wildcard, it always fails. + if item == '*': + return True + + # If this is an exact match for one of the features, it fails. + if item in self.config.available_features: + return True + + # If this is a part of the target triple, it fails. + if item in self.suite.config.target_triple: + return True + + return False diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 6e03eb9..cf98b7a 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -298,23 +298,6 @@ def executeScript(test, litConfig, tmpBase, commands, cwd): return lit.util.executeCommand(command, cwd=cwd, env=test.config.environment) -def isExpectedFail(test, xfails): - # Check if any of the xfails match an available feature or the target. - for item in xfails: - # If this is the wildcard, it always fails. - if item == '*': - return True - - # If this is an exact match for one of the features, it fails. - if item in test.config.available_features: - return True - - # If this is a part of the target triple, it fails. - if item in test.suite.config.target_triple: - return True - - return False - def parseIntegratedTestScriptCommands(source_path): """ parseIntegratedTestScriptCommands(source_path) -> commands @@ -415,7 +398,6 @@ def parseIntegratedTestScript(test, normalize_slashes=False, # Collect the test lines from the script. script = [] - xfails = [] requires = [] for line_number, command_type, ln in \ parseIntegratedTestScriptCommands(sourcepath): @@ -438,7 +420,7 @@ def parseIntegratedTestScript(test, normalize_slashes=False, else: script.append(ln) elif command_type == 'XFAIL': - xfails.extend([s.strip() for s in ln.split(',')]) + test.xfails.extend([s.strip() for s in ln.split(',')]) elif command_type == 'REQUIRES': requires.extend([s.strip() for s in ln.split(',')]) elif command_type == 'END': @@ -480,8 +462,7 @@ def parseIntegratedTestScript(test, normalize_slashes=False, return (Test.UNSUPPORTED, "Test requires the following features: %s" % msg) - isXFail = isExpectedFail(test, xfails) - return script,isXFail,tmpBase,execdir + return script,tmpBase,execdir def formatTestOutput(status, out, err, exitCode, script): output = """\ @@ -521,7 +502,7 @@ def executeShTest(test, litConfig, useExternalSh, if len(res) == 2: return res - script, isXFail, tmpBase, execdir = res + script, tmpBase, execdir = res if litConfig.noExecute: return (Test.PASS, '') @@ -537,20 +518,9 @@ def executeShTest(test, litConfig, useExternalSh, return res out,err,exitCode = res - if isXFail: - ok = exitCode != 0 - if ok: - status = Test.XFAIL - else: - status = Test.XPASS + if exitCode == 0: + status = Test.PASS else: - ok = exitCode == 0 - if ok: - status = Test.PASS - else: - status = Test.FAIL - - if ok: - return (status,'') + status = Test.FAIL return formatTestOutput(status, out, err, exitCode, script) diff --git a/utils/lit/tests/shtest-format.py b/utils/lit/tests/shtest-format.py index a5ce2ff..1c23119 100644 --- a/utils/lit/tests/shtest-format.py +++ b/utils/lit/tests/shtest-format.py @@ -53,6 +53,11 @@ # CHECK: XFAIL: shtest-format :: xfail-target.txt # CHECK: XFAIL: shtest-format :: xfail.txt # CHECK: XPASS: shtest-format :: xpass.txt +# CHECK-NEXT: *** TEST 'shtest-format :: xpass.txt' FAILED *** +# CHECK-NEXT: Script +# CHECK-NEXT: -- +# CHECK-NEXT: true +# CHECK-NEXT: -- # CHECK: Testing Time # CHECK: Unexpected Passing Tests (1) -- cgit v1.1 From 4db169d31e34df89d10660960070de073f0f28af Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 21 Aug 2013 22:26:47 +0000 Subject: [lit] Fix a couple lingering Py3 compat issues in ProgressBar. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188951 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/ProgressBar.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/ProgressBar.py b/utils/lit/lit/ProgressBar.py index 8b9b81e..e3644f1 100644 --- a/utils/lit/lit/ProgressBar.py +++ b/utils/lit/lit/ProgressBar.py @@ -5,6 +5,10 @@ import sys, re, time +def to_bytes(str): + # Encode to Latin1 to get binary data. + return str.encode('ISO-8859-1') + class TerminalController: """ A class that can be used to portably generate formatted output to @@ -116,19 +120,23 @@ class TerminalController: set_fg = self._tigetstr('setf') if set_fg: for i,color in zip(range(len(self._COLORS)), self._COLORS): - setattr(self, color, curses.tparm(set_fg, i) or '') + setattr(self, color, self._tparm(set_fg, i)) set_fg_ansi = self._tigetstr('setaf') if set_fg_ansi: for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): - setattr(self, color, curses.tparm(set_fg_ansi, i) or '') + setattr(self, color, self._tparm(set_fg_ansi, i)) set_bg = self._tigetstr('setb') if set_bg: for i,color in zip(range(len(self._COLORS)), self._COLORS): - setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '') + setattr(self, 'BG_'+color, self._tparm(set_bg, i)) set_bg_ansi = self._tigetstr('setab') if set_bg_ansi: for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): - setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '') + setattr(self, 'BG_'+color, self._tparm(set_bg_ansi, i)) + + def _tparm(self, arg, index): + import curses + return curses.tparm(to_bytes(arg), index).decode('ascii') or '' def _tigetstr(self, cap_name): # String capabilities can include "delays" of the form "$<2>". -- cgit v1.1 From 9d3c398d61c749a0d8ab7c5c127d661cd5ac1db2 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Thu, 22 Aug 2013 01:34:09 +0000 Subject: Remove llvm-lit from the cmake install target. Since it's an llvm-internal tool, we shouldn't install it. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188976 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/llvm-lit/CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) (limited to 'utils') diff --git a/utils/llvm-lit/CMakeLists.txt b/utils/llvm-lit/CMakeLists.txt index 602cc88..b535eae 100644 --- a/utils/llvm-lit/CMakeLists.txt +++ b/utils/llvm-lit/CMakeLists.txt @@ -2,11 +2,3 @@ configure_file( llvm-lit.in ${LLVM_TOOLS_BINARY_DIR}/llvm-lit ) - -install(FILES - ${LLVM_TOOLS_BINARY_DIR}/llvm-lit - DESTINATION bin - PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE - GROUP_READ GROUP_EXECUTE - WORLD_READ WORLD_EXECUTE - ) -- cgit v1.1 From f7ab3a84b3e1b5a647ae9456a5edb99d86b35329 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Thu, 22 Aug 2013 09:57:11 +0000 Subject: ARM: use TableGen patterns to select CMOV operations. Back in the mists of time (2008), it seems TableGen couldn't handle the patterns necessary to match ARM's CMOV node that we convert select operations to, so we wrote a lot of fairly hairy C++ to do it for us. TableGen can deal with it now: there were a few minor differences to CodeGen (see tests), but nothing obviously worse that I could see, so we should probably address anything that *does* come up in a localised manner. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188995 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenInstruction.cpp | 2 +- utils/TableGen/InstrInfoEmitter.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp index 8ec7682..bf59d3a 100644 --- a/utils/TableGen/CodeGenInstruction.cpp +++ b/utils/TableGen/CodeGenInstruction.cpp @@ -90,7 +90,7 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { if (unsigned NumArgs = MIOpInfo->getNumArgs()) NumOps = NumArgs; - if (Rec->isSubClassOf("PredicateOperand")) + if (Rec->isSubClassOf("PredicateOp")) isPredicable = true; else if (Rec->isSubClassOf("OptionalDefOperand")) hasOptionalDef = true; diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index c8304de..cfbf915 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -132,8 +132,8 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { Res += "|(1<isSubClassOf("PredicateOperand")) + // was of type PredicateOp. + if (Inst.Operands[i].Rec->isSubClassOf("PredicateOp")) Res += "|(1< Date: Thu, 22 Aug 2013 12:18:28 +0000 Subject: AVX-512: Added masked SHIFT commands, more encoding tests git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189005 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 40 +++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 7962f9b..d2675d7 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -818,17 +818,20 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { case X86Local::MRM5r: case X86Local::MRM6r: case X86Local::MRM7r: - // Operand 1 is a register operand in the R/M field. - // Operand 2 (optional) is an immediate or relocation. - // Operand 3 (optional) is an immediate. - if (HasVEX_4VPrefix) - assert(numPhysicalOperands <= 3 && - "Unexpected number of operands for MRMnRFrm with VEX_4V"); - else - assert(numPhysicalOperands <= 3 && - "Unexpected number of operands for MRMnRFrm"); + { + // Operand 1 is a register operand in the R/M field. + // Operand 2 (optional) is an immediate or relocation. + // Operand 3 (optional) is an immediate. + unsigned kOp = (HasEVEX_K) ? 1:0; + unsigned Op4v = (HasVEX_4VPrefix) ? 1:0; + if (numPhysicalOperands > 3 + kOp + Op4v) + llvm_unreachable("Unexpected number of operands for MRMnr"); + } if (HasVEX_4VPrefix) HANDLE_OPERAND(vvvvRegister) + + if (HasEVEX_K) + HANDLE_OPERAND(writemaskRegister) HANDLE_OPTIONAL(rmRegister) HANDLE_OPTIONAL(relocation) HANDLE_OPTIONAL(immediate) @@ -841,16 +844,19 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { case X86Local::MRM5m: case X86Local::MRM6m: case X86Local::MRM7m: - // Operand 1 is a memory operand (possibly SIB-extended) - // Operand 2 (optional) is an immediate or relocation. - if (HasVEX_4VPrefix) - assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 && - "Unexpected number of operands for MRMnMFrm"); - else - assert(numPhysicalOperands >= 1 && numPhysicalOperands <= 2 && - "Unexpected number of operands for MRMnMFrm"); + { + // Operand 1 is a memory operand (possibly SIB-extended) + // Operand 2 (optional) is an immediate or relocation. + unsigned kOp = (HasEVEX_K) ? 1:0; + unsigned Op4v = (HasVEX_4VPrefix) ? 1:0; + if (numPhysicalOperands < 1 + kOp + Op4v || + numPhysicalOperands > 2 + kOp + Op4v) + llvm_unreachable("Unexpected number of operands for MRMnm"); + } if (HasVEX_4VPrefix) HANDLE_OPERAND(vvvvRegister) + if (HasEVEX_K) + HANDLE_OPERAND(writemaskRegister) HANDLE_OPERAND(memory) HANDLE_OPTIONAL(relocation) break; -- cgit v1.1 From d93969c32a6bbae3326a1f485c4c85be1cb39406 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 23 Aug 2013 02:25:47 +0000 Subject: Add an OtherPreserved field to the CalleeSaved TableGen class. This field specifies registers that are preserved across function calls, but that should not be included in the generates SaveList array. This can be used ot generate regmasks for architectures that save registers through other means, like SPARC's register windows. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189084 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/RegisterInfoEmitter.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index 731dccf..9a30e15 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -1314,9 +1314,21 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, OS << "0 };\n"; // Emit the *_RegMask bit mask of call-preserved registers. + BitVector Covered = RegBank.computeCoveredRegisters(*Regs); + + // Check for an optional OtherPreserved set. + // Add those registers to RegMask, but not to SaveList. + if (DagInit *OPDag = + dyn_cast(CSRSet->getValueInit("OtherPreserved"))) { + SetTheory::RecSet OPSet; + RegBank.getSets().evaluate(OPDag, OPSet, CSRSet->getLoc()); + Covered |= RegBank.computeCoveredRegisters( + ArrayRef(OPSet.begin(), OPSet.end())); + } + OS << "static const uint32_t " << CSRSet->getName() << "_RegMask[] = { "; - printBitVectorAsHex(OS, RegBank.computeCoveredRegisters(*Regs), 32); + printBitVectorAsHex(OS, Covered, 32); OS << "};\n"; } OS << "\n\n"; -- cgit v1.1 From 5768bb8d77892926dff0d078b1fb08c14ea791f3 Mon Sep 17 00:00:00 2001 From: Andrea Di Biagio Date: Fri, 23 Aug 2013 11:53:55 +0000 Subject: Add function attribute 'optnone'. This function attribute indicates that the function is not optimized by any optimization or code generator passes with the exception of interprocedural optimization passes. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189101 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/kate/llvm.xml | 1 + utils/vim/llvm.vim | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/kate/llvm.xml b/utils/kate/llvm.xml index 1778cfc..3e32b50 100644 --- a/utils/kate/llvm.xml +++ b/utils/kate/llvm.xml @@ -85,6 +85,7 @@ noredzone noreturn nounwind + optnone optsize readnone readonly diff --git a/utils/vim/llvm.vim b/utils/vim/llvm.vim index 6c87cff..b28c07f 100644 --- a/utils/vim/llvm.vim +++ b/utils/vim/llvm.vim @@ -48,7 +48,7 @@ syn keyword llvmKeyword linkonce linkonce_odr linkonce_odr_auto_hide syn keyword llvmKeyword localdynamic localexec minsize module monotonic syn keyword llvmKeyword msp430_intrcc naked nest noalias nocapture syn keyword llvmKeyword noimplicitfloat noinline nonlazybind noredzone noreturn -syn keyword llvmKeyword nounwind optsize personality private protected +syn keyword llvmKeyword nounwind optnone optsize personality private protected syn keyword llvmKeyword ptx_device ptx_kernel readnone readonly release syn keyword llvmKeyword returns_twice sanitize_thread sanitize_memory syn keyword llvmKeyword section seq_cst sideeffect signext singlethread -- cgit v1.1 From 055f4e99ffb32462db6fc62f9a306f2865acacb0 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Tue, 27 Aug 2013 23:47:01 +0000 Subject: Option parsing: support case-insensitive option matching. Link.exe's command line options are case-insensitive. This patch adds a new attribute to OptTable to let the option parser to compare options, ignoring case. Command lines are generally case-insensitive on Windows. CL.exe is an exception. So this new attribute should be useful for other commands running on Windows. Differential Revision: http://llvm-reviews.chandlerc.com/D1485 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189416 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/OptParserEmitter.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp index 86328bf..f269436 100644 --- a/utils/TableGen/OptParserEmitter.cpp +++ b/utils/TableGen/OptParserEmitter.cpp @@ -13,27 +13,25 @@ #include "llvm/ADT/Twine.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" +#include #include +#include using namespace llvm; +// Ordering on Info. The logic should match with the consumer-side function in +// llvm/Option/OptTable.h. static int StrCmpOptionName(const char *A, const char *B) { - char a = *A, b = *B; - while (a == b) { - if (a == '\0') - return 0; - - a = *++A; - b = *++B; + size_t I = strlen(A); + size_t J = strlen(B); + if (I == J) { + if (int N = strcasecmp(A, B)) + return N; + return strcmp(A, B); } - - if (a == '\0') // A is a prefix of B. - return 1; - if (b == '\0') // B is a prefix of A. - return -1; - - // Otherwise lexicographic. - return (a < b) ? -1 : 1; + if (I < J) + return strncasecmp(A, B, I) < 0 ? -1 : 1; + return strncasecmp(A, B, J) <= 0 ? -1 : 1; } static int CompareOptionRecords(const void *Av, const void *Bv) { @@ -50,7 +48,7 @@ static int CompareOptionRecords(const void *Av, const void *Bv) { if (!ASent) if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(), B->getValueAsString("Name").c_str())) - return Cmp; + return Cmp; if (!ASent) { std::vector APrefixes = A->getValueAsListOfStrings("Prefixes"); -- cgit v1.1 From 1997734e37775a68182b3fd508a52e0c28ff36f8 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Wed, 28 Aug 2013 00:02:06 +0000 Subject: Revert "Option parsing: support case-insensitive option matching." as it broke Windows buildbot. This reverts r189416. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189424 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/OptParserEmitter.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp index f269436..86328bf 100644 --- a/utils/TableGen/OptParserEmitter.cpp +++ b/utils/TableGen/OptParserEmitter.cpp @@ -13,25 +13,27 @@ #include "llvm/ADT/Twine.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" -#include #include -#include using namespace llvm; -// Ordering on Info. The logic should match with the consumer-side function in -// llvm/Option/OptTable.h. static int StrCmpOptionName(const char *A, const char *B) { - size_t I = strlen(A); - size_t J = strlen(B); - if (I == J) { - if (int N = strcasecmp(A, B)) - return N; - return strcmp(A, B); + char a = *A, b = *B; + while (a == b) { + if (a == '\0') + return 0; + + a = *++A; + b = *++B; } - if (I < J) - return strncasecmp(A, B, I) < 0 ? -1 : 1; - return strncasecmp(A, B, J) <= 0 ? -1 : 1; + + if (a == '\0') // A is a prefix of B. + return 1; + if (b == '\0') // B is a prefix of A. + return -1; + + // Otherwise lexicographic. + return (a < b) ? -1 : 1; } static int CompareOptionRecords(const void *Av, const void *Bv) { @@ -48,7 +50,7 @@ static int CompareOptionRecords(const void *Av, const void *Bv) { if (!ASent) if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(), B->getValueAsString("Name").c_str())) - return Cmp; + return Cmp; if (!ASent) { std::vector APrefixes = A->getValueAsListOfStrings("Prefixes"); -- cgit v1.1 From 862b50420122e8be173ae534fcd1668c8c4be916 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Wed, 28 Aug 2013 07:03:02 +0000 Subject: Add missing include git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189448 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/SequenceToOffsetTable.h | 1 + 1 file changed, 1 insertion(+) (limited to 'utils') diff --git a/utils/TableGen/SequenceToOffsetTable.h b/utils/TableGen/SequenceToOffsetTable.h index fcda233..e6ab664 100644 --- a/utils/TableGen/SequenceToOffsetTable.h +++ b/utils/TableGen/SequenceToOffsetTable.h @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace llvm { -- cgit v1.1 From 2957273b888dabe8be8e2fa5ac691e39879685c4 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Wed, 28 Aug 2013 20:04:31 +0000 Subject: Option parsing: support case-insensitive option matching. Re-submitting r189416 with fix for Windows build on where strcasecmp is not defined. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189501 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/OptParserEmitter.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp index 86328bf..7fb7d65 100644 --- a/utils/TableGen/OptParserEmitter.cpp +++ b/utils/TableGen/OptParserEmitter.cpp @@ -13,18 +13,23 @@ #include "llvm/ADT/Twine.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" +#include +#include #include using namespace llvm; +// Ordering on Info. The logic should match with the consumer-side function in +// llvm/Option/OptTable.h. static int StrCmpOptionName(const char *A, const char *B) { - char a = *A, b = *B; + const char *X = A, *Y = B; + char a = tolower(*A), b = tolower(*B); while (a == b) { if (a == '\0') - return 0; + return strcmp(A, B); - a = *++A; - b = *++B; + a = tolower(*++X); + b = tolower(*++Y); } if (a == '\0') // A is a prefix of B. @@ -50,7 +55,7 @@ static int CompareOptionRecords(const void *Av, const void *Bv) { if (!ASent) if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(), B->getValueAsString("Name").c_str())) - return Cmp; + return Cmp; if (!ASent) { std::vector APrefixes = A->getValueAsListOfStrings("Prefixes"); -- cgit v1.1 From 8a1d9b207a2bec95dfdc72700f8edafd44c98c17 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 00:40:59 +0000 Subject: [lit] Update LitTestCase to support lit.Test.Result. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189544 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitTestCase.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/LitTestCase.py b/utils/lit/lit/LitTestCase.py index 478dbae..ba91fa0 100644 --- a/utils/lit/lit/LitTestCase.py +++ b/utils/lit/lit/LitTestCase.py @@ -23,10 +23,18 @@ class LitTestCase(unittest.TestCase): return self._test.getFullName() def runTest(self): - tr, output = self._test.config.test_format.execute( + result = self._test.config.test_format.execute( self._test, self._lit_config) - if tr is lit.Test.UNRESOLVED: - raise UnresolvedError(output) - elif tr.isFailure: - self.fail(output) + # Support deprecated result from execute() which returned the result + # code and additional output as a tuple. + if isinstance(result, tuple): + code, output = result + result = lit.Test.Result(code, output) + elif not isinstance(result, lit.Test.Result): + raise ValueError("unexpected result from test execution") + + if result.code is lit.Test.UNRESOLVED: + raise UnresolvedError(result.output) + elif result.code.isFailure: + self.fail(result.output) -- cgit v1.1 From 501cba385cf2ae5db1d646ec75e1d4d57e015d80 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 00:41:09 +0000 Subject: [lit] Update shtest format to return lit.Test.Result objects. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189545 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestRunner.py | 61 ++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 40 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index cf98b7a..120f89a 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -239,7 +239,7 @@ def executeScriptInternal(test, litConfig, tmpBase, commands, cwd): cmds.append(ShUtil.ShParser(ln, litConfig.isWindows, test.config.pipefail).parse()) except: - return (Test.FAIL, "shell parser error on: %r" % ln) + return lit.Test.Result(Test.FAIL, "shell parser error on: %r" % ln) cmd = cmds[0] for c in cmds[1:]: @@ -448,65 +448,36 @@ def parseIntegratedTestScript(test, normalize_slashes=False, # Verify the script contains a run line. if not script: - return (Test.UNRESOLVED, "Test has no run line!") + return lit.Test.Result(Test.UNRESOLVED, "Test has no run line!") # Check for unterminated run lines. if script[-1][-1] == '\\': - return (Test.UNRESOLVED, "Test has unterminated run lines (with '\\')") + return lit.Test.Result(Test.UNRESOLVED, + "Test has unterminated run lines (with '\\')") # Check that we have the required features: missing_required_features = [f for f in requires if f not in test.config.available_features] if missing_required_features: msg = ', '.join(missing_required_features) - return (Test.UNSUPPORTED, - "Test requires the following features: %s" % msg) + return lit.Test.Result(Test.UNSUPPORTED, + "Test requires the following features: %s" % msg) return script,tmpBase,execdir -def formatTestOutput(status, out, err, exitCode, script): - output = """\ -Script: --- -%s --- -Exit Code: %d - -""" % ('\n'.join(script), exitCode) - - # Append the stdout, if present. - if out: - output += """\ -Command Output (stdout): --- -%s --- -""" % (out,) - - # Append the stderr, if present. - if err: - output += """\ -Command Output (stderr): --- -%s --- -""" % (err,) - return (status, output) - def executeShTest(test, litConfig, useExternalSh, extra_substitutions=[]): if test.config.unsupported: return (Test.UNSUPPORTED, 'Test is unsupported') res = parseIntegratedTestScript(test, useExternalSh, extra_substitutions) - if len(res) == 2: + if isinstance(res, lit.Test.Result): return res + if litConfig.noExecute: + return lit.Test.Result(Test.PASS) script, tmpBase, execdir = res - if litConfig.noExecute: - return (Test.PASS, '') - # Create the output directory if it does not already exist. lit.util.mkdir_p(os.path.dirname(tmpBase)) @@ -514,7 +485,7 @@ def executeShTest(test, litConfig, useExternalSh, res = executeScript(test, litConfig, tmpBase, script, execdir) else: res = executeScriptInternal(test, litConfig, tmpBase, script, execdir) - if len(res) == 2: + if isinstance(res, lit.Test.Result): return res out,err,exitCode = res @@ -523,4 +494,14 @@ def executeShTest(test, litConfig, useExternalSh, else: status = Test.FAIL - return formatTestOutput(status, out, err, exitCode, script) + # Form the output log. + output = """Script:\n--\n%s\n--\nExit Code: %d\n\n""" % ( + '\n'.join(script), exitCode) + + # Append the outputs, if present. + if out: + output += """Command Output (stdout):\n--\n%s\n--\n""" % (out,) + if err: + output += """Command Output (stderr):\n--\n%s\n--\n""" % (err,) + + return lit.Test.Result(status, output) -- cgit v1.1 From 6f25e872e46ca9ae8b84c0ad411f98e4868b1c87 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 00:41:15 +0000 Subject: [lit] Add a TODO. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189546 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/TODO | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'utils') diff --git a/utils/lit/TODO b/utils/lit/TODO index 419056a..e6aeb3d 100644 --- a/utils/lit/TODO +++ b/utils/lit/TODO @@ -121,6 +121,35 @@ Infrastructure tests, or add additional features to the internal shell handling to allow them to pass. +5. Consider changing core to support setup vs. execute distinction. + + Many of the existing test formats are cleanly divided into two phases, once + parses the test format and extracts XFAIL and REQUIRES information, etc., and + the other code actually executes the test. + + We could make this distinction part of the core infrastructure and that would + enable a couple things: + + * The REQUIREs handling could be lifted to the core, which is nice. + + * This would provide a clear place to insert subtest support, because the + setup phase could be responsible for providing subtests back to the + core. That would provide part of the infrastructure to parallelize them, for + example, and would probably interact well with other possible features like + parameterized tests. + + * This affords a clean implementation of --no-execute. + + * One possible downside could be for test formats that cannot determine their + subtests without having executed the test. Supporting such formats would + either force the test to actually be executed in the setup stage (which + might be ok, as long as the API was explicitly phrased to support that), or + would mean we are forced into supporting subtests as return values from the + execute phase. + + Any format can just keep all of its code in execute, presumably, so the only + cost of implementing this is its impact on the API and futures changes. + Miscellaneous ============= -- cgit v1.1 From 8253cc047de523fd2097e4d85417316ff9a37ad5 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 00:48:39 +0000 Subject: [lit] Change lit.Test.ResultCode to be unique across pickling. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189549 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/Test.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'utils') diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py index 59ca694..05cae99 100644 --- a/utils/lit/lit/Test.py +++ b/utils/lit/lit/Test.py @@ -5,6 +5,17 @@ import os class ResultCode(object): """Test result codes.""" + # We override __new__ and __getnewargs__ to ensure that pickling still + # provides unique ResultCode objects in any particular instance. + _instances = {} + def __new__(cls, name, isFailure): + res = cls._instances.get(name) + if res is None: + cls._instances[name] = res = super(ResultCode, cls).__new__(cls) + return res + def __getnewargs__(self): + return (self.name, self.isFailure) + def __init__(self, name, isFailure): self.name = name self.isFailure = isFailure -- cgit v1.1 From 5b2efc28fd193701d2d05780c7b8d8ee5bf75c31 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 00:48:45 +0000 Subject: [lit] Factor out Run class to capture configuration + discovered tests. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189550 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 39 +++++++++++++++++++++------------------ utils/lit/lit/run.py | 8 ++++++++ 2 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 utils/lit/lit/run.py (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index b84140f..7625959 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -12,6 +12,7 @@ import math, os, platform, random, re, sys, time, threading, traceback import lit.ProgressBar import lit.LitConfig import lit.Test +import lit.run import lit.util import lit.discovery @@ -291,12 +292,14 @@ def main(builtinParameters = {}): params = userParams, config_prefix = opts.configPrefix) - tests = lit.discovery.find_tests_for_inputs(litConfig, inputs) + # Perform test discovery. + run = lit.run.Run(litConfig, + lit.discovery.find_tests_for_inputs(litConfig, inputs)) if opts.showSuites or opts.showTests: # Aggregate the tests by suite. suitesAndTests = {} - for t in tests: + for t in run.tests: if t.suite not in suitesAndTests: suitesAndTests[t.suite] = [] suitesAndTests[t.suite].append(t) @@ -323,7 +326,7 @@ def main(builtinParameters = {}): sys.exit(0) # Select and order the tests. - numTotalTests = len(tests) + numTotalTests = len(run.tests) # First, select based on the filter expression if given. if opts.filter: @@ -332,26 +335,26 @@ def main(builtinParameters = {}): except: parser.error("invalid regular expression for --filter: %r" % ( opts.filter)) - tests = [t for t in tests - if rex.search(t.getFullName())] + run.tests = [t for t in run.tests + if rex.search(t.getFullName())] # Then select the order. if opts.shuffle: - random.shuffle(tests) + random.shuffle(run.tests) else: - tests.sort(key = lambda t: t.getFullName()) + run.tests.sort(key = lambda t: t.getFullName()) # Finally limit the number of tests, if desired. if opts.maxTests is not None: - tests = tests[:opts.maxTests] + run.tests = run.tests[:opts.maxTests] # Don't create more threads than tests. - opts.numThreads = min(len(tests), opts.numThreads) + opts.numThreads = min(len(run.tests), opts.numThreads) extra = '' - if len(tests) != numTotalTests: + if len(run.tests) != numTotalTests: extra = ' of %d' % numTotalTests - header = '-- Testing: %d%s tests, %d threads --'%(len(tests),extra, + header = '-- Testing: %d%s tests, %d threads --'%(len(run.tests), extra, opts.numThreads) progressBar = None @@ -367,8 +370,8 @@ def main(builtinParameters = {}): print(header) startTime = time.time() - display = TestingProgressDisplay(opts, len(tests), progressBar) - provider = TestProvider(tests, opts.maxTime) + display = TestingProgressDisplay(opts, len(run.tests), progressBar) + provider = TestProvider(run.tests, opts.maxTime) try: import win32api @@ -387,14 +390,14 @@ def main(builtinParameters = {}): print('Testing Time: %.2fs'%(time.time() - startTime)) # Update results for any tests which weren't run. - for test in tests: + for test in run.tests: if test.result is None: test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0)) # List test results organized by kind. hasFailures = False byCode = {} - for test in tests: + for test in run.tests: if test.result.code not in byCode: byCode[test.result.code] = [] byCode[test.result.code].append(test) @@ -414,12 +417,12 @@ def main(builtinParameters = {}): print(' %s' % test.getFullName()) sys.stdout.write('\n') - if opts.timeTests and tests: + if opts.timeTests and run.tests: # Order by time. test_times = [(test.getFullName(), test.result.elapsed) - for test in tests] + for test in run.tests] lit.util.printHistogram(test_times, title='Tests') - + for name,code in (('Expected Passes ', lit.Test.PASS), ('Expected Failures ', lit.Test.XFAIL), ('Unsupported Tests ', lit.Test.UNSUPPORTED), diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py new file mode 100644 index 0000000..8a9f87b --- /dev/null +++ b/utils/lit/lit/run.py @@ -0,0 +1,8 @@ +class Run(object): + """ + This class represents a concrete, configured testing run. + """ + + def __init__(self, lit_config, tests): + self.lit_config = lit_config + self.tests = tests -- cgit v1.1 From 8c59003cc382e4b2fb15b267aa2d356e869a89cc Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 00:48:55 +0000 Subject: [lit] Move top-level execute code into Run object. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189551 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitTestCase.py | 18 ++++++------------ utils/lit/lit/discovery.py | 7 +++++-- utils/lit/lit/main.py | 34 +++++++--------------------------- utils/lit/lit/run.py | 31 +++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 41 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/LitTestCase.py b/utils/lit/lit/LitTestCase.py index ba91fa0..e04846c 100644 --- a/utils/lit/lit/LitTestCase.py +++ b/utils/lit/lit/LitTestCase.py @@ -11,10 +11,10 @@ class UnresolvedError(RuntimeError): pass class LitTestCase(unittest.TestCase): - def __init__(self, test, lit_config): + def __init__(self, test, run): unittest.TestCase.__init__(self) self._test = test - self._lit_config = lit_config + self._run = run def id(self): return self._test.getFullName() @@ -23,17 +23,11 @@ class LitTestCase(unittest.TestCase): return self._test.getFullName() def runTest(self): - result = self._test.config.test_format.execute( - self._test, self._lit_config) - - # Support deprecated result from execute() which returned the result - # code and additional output as a tuple. - if isinstance(result, tuple): - code, output = result - result = lit.Test.Result(code, output) - elif not isinstance(result, lit.Test.Result): - raise ValueError("unexpected result from test execution") + # Run the test. + self._run.execute_test(self._test) + # Adapt the result to unittest. + result = self._test.result if result.code is lit.Test.UNRESOLVED: raise UnresolvedError(result.output) elif result.code.isFailure: diff --git a/utils/lit/lit/discovery.py b/utils/lit/lit/discovery.py index 26882fe..263e546 100644 --- a/utils/lit/lit/discovery.py +++ b/utils/lit/lit/discovery.py @@ -5,6 +5,7 @@ Test discovery functions. import os import sys +import lit.run from lit.TestingConfig import TestingConfig from lit import LitConfig, Test @@ -245,7 +246,9 @@ def load_test_suite(inputs): isWindows = (platform.system()=='Windows'), params = {}) - tests = find_tests_for_inputs(litConfig, inputs) + # Perform test discovery. + run = lit.run.Run(litConfig, find_tests_for_inputs(litConfig, inputs)) # Return a unittest test suite which just runs the tests in order. - return unittest.TestSuite([LitTestCase(test, litConfig) for test in tests]) + return unittest.TestSuite([LitTestCase(test, run) + for test in run.tests]) diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 7625959..1480a7a 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -102,9 +102,9 @@ class TestProvider: return item class Tester(threading.Thread): - def __init__(self, litConfig, provider, display): + def __init__(self, run_instance, provider, display): threading.Thread.__init__(self) - self.litConfig = litConfig + self.run_instance = run_instance self.provider = provider self.display = display @@ -116,45 +116,25 @@ class Tester(threading.Thread): self.runTest(item) def runTest(self, test): - result = None - startTime = time.time() try: - result = test.config.test_format.execute(test, self.litConfig) - - # Support deprecated result from execute() which returned the result - # code and additional output as a tuple. - if isinstance(result, tuple): - code, output = result - result = lit.Test.Result(code, output) - elif not isinstance(result, lit.Test.Result): - raise ValueError("unexpected result from test execution") + self.run_instance.execute_test(test) except KeyboardInterrupt: # This is a sad hack. Unfortunately subprocess goes # bonkers with ctrl-c and we start forking merrily. print('\nCtrl-C detected, goodbye.') os.kill(0,9) - except: - if self.litConfig.debug: - raise - output = 'Exception during script execution:\n' - output += traceback.format_exc() - output += '\n' - result = lit.Test.Result(lit.Test.UNRESOLVED, output) - result.elapsed = time.time() - startTime - - test.setResult(result) self.display.update(test) -def runTests(numThreads, litConfig, provider, display): +def runTests(numThreads, run, provider, display): # If only using one testing thread, don't use threads at all; this lets us # profile, among other things. if numThreads == 1: - t = Tester(litConfig, provider, display) + t = Tester(run, provider, display) t.run() return # Otherwise spin up the testing threads and wait for them to finish. - testers = [Tester(litConfig, provider, display) + testers = [Tester(run, provider, display) for i in range(numThreads)] for t in testers: t.start() @@ -383,7 +363,7 @@ def main(builtinParameters = {}): return True win32api.SetConsoleCtrlHandler(console_ctrl_handler, True) - runTests(opts.numThreads, litConfig, provider, display) + runTests(opts.numThreads, run, provider, display) display.finish() if not opts.quiet: diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py index 8a9f87b..4466667 100644 --- a/utils/lit/lit/run.py +++ b/utils/lit/lit/run.py @@ -1,3 +1,8 @@ +import time +import traceback + +import lit.Test + class Run(object): """ This class represents a concrete, configured testing run. @@ -6,3 +11,29 @@ class Run(object): def __init__(self, lit_config, tests): self.lit_config = lit_config self.tests = tests + + def execute_test(self, test): + result = None + startTime = time.time() + try: + result = test.config.test_format.execute(test, self.lit_config) + + # Support deprecated result from execute() which returned the result + # code and additional output as a tuple. + if isinstance(result, tuple): + code, output = result + result = lit.Test.Result(code, output) + elif not isinstance(result, lit.Test.Result): + raise ValueError("unexpected result from test execution") + except KeyboardInterrupt: + raise + except: + if self.lit_config.debug: + raise + output = 'Exception during script execution:\n' + output += traceback.format_exc() + output += '\n' + result = lit.Test.Result(lit.Test.UNRESOLVED, output) + result.elapsed = time.time() - startTime + + test.setResult(result) -- cgit v1.1 From ec8e0592544de7b99b87535352a26b0420c51820 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 00:54:02 +0000 Subject: [lit] Factor out a results consumer interface for test execution. - Also, change TestProvider interface to operate on test indices. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189552 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 64 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 20 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 1480a7a..0a7347b 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -73,7 +73,7 @@ class TestingProgressDisplay: class TestProvider: def __init__(self, tests, maxTime): self.maxTime = maxTime - self.iter = iter(tests) + self.iter = iter(range(len(tests))) self.lock = threading.Lock() self.startTime = time.time() self.canceled = False @@ -101,12 +101,11 @@ class TestProvider: self.lock.release() return item -class Tester(threading.Thread): - def __init__(self, run_instance, provider, display): - threading.Thread.__init__(self) +class Tester(object): + def __init__(self, run_instance, provider, consumer): self.run_instance = run_instance self.provider = provider - self.display = display + self.consumer = consumer def run(self): while 1: @@ -114,8 +113,10 @@ class Tester(threading.Thread): if item is None: break self.runTest(item) + self.consumer.taskFinished() - def runTest(self, test): + def runTest(self, test_index): + test = self.run_instance.tests[test_index] try: self.run_instance.execute_test(test) except KeyboardInterrupt: @@ -123,26 +124,47 @@ class Tester(threading.Thread): # bonkers with ctrl-c and we start forking merrily. print('\nCtrl-C detected, goodbye.') os.kill(0,9) + self.consumer.update(test_index, test) + +class ThreadResultsConsumer(object): + def __init__(self, display): + self.display = display + + def update(self, test_index, test): self.display.update(test) + def taskFinished(self): + pass + + def handleResults(self): + pass + +def run_one_tester(run, provider, display): + tester = Tester(run, provider, display) + tester.run() + def runTests(numThreads, run, provider, display): - # If only using one testing thread, don't use threads at all; this lets us + consumer = ThreadResultsConsumer(display) + + # If only using one testing thread, don't use tasks at all; this lets us # profile, among other things. if numThreads == 1: - t = Tester(run, provider, display) - t.run() + run_one_tester(run, provider, consumer) return - # Otherwise spin up the testing threads and wait for them to finish. - testers = [Tester(run, provider, display) - for i in range(numThreads)] - for t in testers: + # Start all of the tasks. + tasks = [threading.Thread(target=run_one_tester, + args=(run, provider, consumer)) + for i in range(numThreads)] + for t in tasks: t.start() - try: - for t in testers: - t.join() - except KeyboardInterrupt: - sys.exit(2) + + # Allow the consumer to handle results, if necessary. + consumer.handleResults() + + # Wait for all the tasks to complete. + for t in tasks: + t.join() def main(builtinParameters = {}): # Bump the GIL check interval, its more important to get any one thread to a @@ -362,8 +384,10 @@ def main(builtinParameters = {}): provider.cancel() return True win32api.SetConsoleCtrlHandler(console_ctrl_handler, True) - - runTests(opts.numThreads, run, provider, display) + try: + runTests(opts.numThreads, run, provider, display) + except KeyboardInterrupt: + sys.exit(2) display.finish() if not opts.quiet: -- cgit v1.1 From b11b690d3f36d552091423293489f845090efb4f Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 00:54:09 +0000 Subject: [lit] Put display lock inside the ThreadResultsConsumer. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189553 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 0a7347b..29275ac 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -22,23 +22,9 @@ class TestingProgressDisplay: self.opts = opts self.numTests = numTests self.current = None - self.lock = threading.Lock() self.progressBar = progressBar self.completed = 0 - def update(self, test): - # Avoid locking overhead in quiet mode - if self.opts.quiet and not test.result.code.isFailure: - self.completed += 1 - return - - # Output lock. - self.lock.acquire() - try: - self.handleUpdate(test) - finally: - self.lock.release() - def finish(self): if self.progressBar: self.progressBar.clear() @@ -47,13 +33,14 @@ class TestingProgressDisplay: elif self.opts.succinct: sys.stdout.write('\n') - def handleUpdate(self, test): + def update(self, test): self.completed += 1 if self.progressBar: self.progressBar.update(float(self.completed)/self.numTests, test.getFullName()) - if self.opts.succinct and not test.result.code.isFailure: + if not test.result.code.isFailure and \ + (self.opts.quiet or self.opts.succinct): return if self.progressBar: @@ -129,9 +116,14 @@ class Tester(object): class ThreadResultsConsumer(object): def __init__(self, display): self.display = display + self.lock = threading.Lock() def update(self, test_index, test): - self.display.update(test) + self.lock.acquire() + try: + self.display.update(test) + finally: + self.lock.release() def taskFinished(self): pass -- cgit v1.1 From 07f0f16bfd58c3e44babae65ccd88b9621d15f48 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 00:54:15 +0000 Subject: [lit] Refactor test execution logic into lit.run.Run. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189554 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 124 +-------------------------------------- utils/lit/lit/run.py | 157 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 158 insertions(+), 123 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 29275ac..5c40f1c 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -7,17 +7,16 @@ See lit.pod for more information. """ from __future__ import absolute_import -import math, os, platform, random, re, sys, time, threading, traceback +import math, os, platform, random, re, sys, time import lit.ProgressBar import lit.LitConfig import lit.Test import lit.run import lit.util - import lit.discovery -class TestingProgressDisplay: +class TestingProgressDisplay(object): def __init__(self, opts, numTests, progressBar=None): self.opts = opts self.numTests = numTests @@ -57,107 +56,6 @@ class TestingProgressDisplay: sys.stdout.flush() -class TestProvider: - def __init__(self, tests, maxTime): - self.maxTime = maxTime - self.iter = iter(range(len(tests))) - self.lock = threading.Lock() - self.startTime = time.time() - self.canceled = False - - def cancel(self): - self.lock.acquire() - self.canceled = True - self.lock.release() - - def get(self): - # Check if we have run out of time. - if self.maxTime is not None: - if time.time() - self.startTime > self.maxTime: - return None - - # Otherwise take the next test. - self.lock.acquire() - if self.canceled: - self.lock.release() - return None - for item in self.iter: - break - else: - item = None - self.lock.release() - return item - -class Tester(object): - def __init__(self, run_instance, provider, consumer): - self.run_instance = run_instance - self.provider = provider - self.consumer = consumer - - def run(self): - while 1: - item = self.provider.get() - if item is None: - break - self.runTest(item) - self.consumer.taskFinished() - - def runTest(self, test_index): - test = self.run_instance.tests[test_index] - try: - self.run_instance.execute_test(test) - except KeyboardInterrupt: - # This is a sad hack. Unfortunately subprocess goes - # bonkers with ctrl-c and we start forking merrily. - print('\nCtrl-C detected, goodbye.') - os.kill(0,9) - self.consumer.update(test_index, test) - -class ThreadResultsConsumer(object): - def __init__(self, display): - self.display = display - self.lock = threading.Lock() - - def update(self, test_index, test): - self.lock.acquire() - try: - self.display.update(test) - finally: - self.lock.release() - - def taskFinished(self): - pass - - def handleResults(self): - pass - -def run_one_tester(run, provider, display): - tester = Tester(run, provider, display) - tester.run() - -def runTests(numThreads, run, provider, display): - consumer = ThreadResultsConsumer(display) - - # If only using one testing thread, don't use tasks at all; this lets us - # profile, among other things. - if numThreads == 1: - run_one_tester(run, provider, consumer) - return - - # Start all of the tasks. - tasks = [threading.Thread(target=run_one_tester, - args=(run, provider, consumer)) - for i in range(numThreads)] - for t in tasks: - t.start() - - # Allow the consumer to handle results, if necessary. - consumer.handleResults() - - # Wait for all the tasks to complete. - for t in tasks: - t.join() - def main(builtinParameters = {}): # Bump the GIL check interval, its more important to get any one thread to a # blocking operation (hopefully exec) than to try and unblock other threads. @@ -365,19 +263,8 @@ def main(builtinParameters = {}): startTime = time.time() display = TestingProgressDisplay(opts, len(run.tests), progressBar) - provider = TestProvider(run.tests, opts.maxTime) - try: - import win32api - except ImportError: - pass - else: - def console_ctrl_handler(type): - provider.cancel() - return True - win32api.SetConsoleCtrlHandler(console_ctrl_handler, True) - try: - runTests(opts.numThreads, run, provider, display) + run.execute_tests(display, opts.numThreads, opts.maxTime) except KeyboardInterrupt: sys.exit(2) display.finish() @@ -385,11 +272,6 @@ def main(builtinParameters = {}): if not opts.quiet: print('Testing Time: %.2fs'%(time.time() - startTime)) - # Update results for any tests which weren't run. - for test in run.tests: - if test.result is None: - test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0)) - # List test results organized by kind. hasFailures = False byCode = {} diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py index 4466667..2ebce85 100644 --- a/utils/lit/lit/run.py +++ b/utils/lit/lit/run.py @@ -1,8 +1,98 @@ +import os +import threading import time import traceback +try: + import win32api +except ImportError: + win32api = None + import lit.Test +### +# Test Execution Implementation + +class TestProvider(object): + def __init__(self, tests, max_time): + self.max_time = max_time + self.iter = iter(range(len(tests))) + self.lock = threading.Lock() + self.start_time = time.time() + self.canceled = False + + def cancel(self): + self.lock.acquire() + self.canceled = True + self.lock.release() + + def get(self): + # Check if we have run out of time. + if self.max_time is not None: + if time.time() - self.start_time > self.max_time: + return None + + # Otherwise take the next test. + self.lock.acquire() + if self.canceled: + self.lock.release() + return None + for item in self.iter: + break + else: + item = None + self.lock.release() + return item + +class Tester(object): + def __init__(self, run_instance, provider, consumer): + self.run_instance = run_instance + self.provider = provider + self.consumer = consumer + + def run(self): + while 1: + item = self.provider.get() + if item is None: + break + self.run_test(item) + self.consumer.task_finished() + + def run_test(self, test_index): + test = self.run_instance.tests[test_index] + try: + self.run_instance.execute_test(test) + except KeyboardInterrupt: + # This is a sad hack. Unfortunately subprocess goes + # bonkers with ctrl-c and we start forking merrily. + print('\nCtrl-C detected, goodbye.') + os.kill(0,9) + self.consumer.update(test_index, test) + +class ThreadResultsConsumer(object): + def __init__(self, display): + self.display = display + self.lock = threading.Lock() + + def update(self, test_index, test): + self.lock.acquire() + try: + self.display.update(test) + finally: + self.lock.release() + + def task_finished(self): + pass + + def handle_results(self): + pass + +def run_one_tester(run, provider, display): + tester = Tester(run, provider, display) + tester.run() + +### + class Run(object): """ This class represents a concrete, configured testing run. @@ -14,7 +104,7 @@ class Run(object): def execute_test(self, test): result = None - startTime = time.time() + start_time = time.time() try: result = test.config.test_format.execute(test, self.lit_config) @@ -34,6 +124,69 @@ class Run(object): output += traceback.format_exc() output += '\n' result = lit.Test.Result(lit.Test.UNRESOLVED, output) - result.elapsed = time.time() - startTime + result.elapsed = time.time() - start_time test.setResult(result) + + def execute_tests(self, display, jobs, max_time=None): + """ + execute_tests(display, jobs, [max_time]) + + Execute each of the tests in the run, using up to jobs number of + parallel tasks, and inform the display of each individual result. The + provided tests should be a subset of the tests available in this run + object. + + If max_time is non-None, it should be a time in seconds after which to + stop executing tests. + + The display object will have its update method called with each test as + it is completed. The calls are guaranteed to be locked with respect to + one another, but are *not* guaranteed to be called on the same thread as + this method was invoked on. + + Upon completion, each test in the run will have its result + computed. Tests which were not actually executed (for any reason) will + be given an UNRESOLVED result. + """ + + # Create the test provider object. + provider = TestProvider(self.tests, max_time) + + # Install a console-control signal handler on Windows. + if win32api is not None: + def console_ctrl_handler(type): + provider.cancel() + return True + win32api.SetConsoleCtrlHandler(console_ctrl_handler, True) + + # Actually execute the tests. + self._execute_tests_with_provider(provider, display, jobs) + + # Update results for any tests which weren't run. + for test in self.tests: + if test.result is None: + test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0)) + + def _execute_tests_with_provider(self, provider, display, jobs): + consumer = ThreadResultsConsumer(display) + + # If only using one testing thread, don't use tasks at all; this lets us + # profile, among other things. + if jobs == 1: + run_one_tester(self, provider, consumer) + return + + # Start all of the tasks. + tasks = [threading.Thread(target=run_one_tester, + args=(self, provider, consumer)) + for i in range(jobs)] + for t in tasks: + t.start() + + # Allow the consumer to handle results, if necessary. + consumer.handle_results() + + # Wait for all the tasks to complete. + for t in tasks: + t.join() -- cgit v1.1 From df44de6d918255eb51f3d042681e006f33948f80 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 00:54:19 +0000 Subject: [lit] Implement --max-time support by using provider cancel method. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189555 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/run.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py index 2ebce85..617c3b9 100644 --- a/utils/lit/lit/run.py +++ b/utils/lit/lit/run.py @@ -14,11 +14,9 @@ import lit.Test # Test Execution Implementation class TestProvider(object): - def __init__(self, tests, max_time): - self.max_time = max_time + def __init__(self, tests): self.iter = iter(range(len(tests))) self.lock = threading.Lock() - self.start_time = time.time() self.canceled = False def cancel(self): @@ -27,16 +25,13 @@ class TestProvider(object): self.lock.release() def get(self): - # Check if we have run out of time. - if self.max_time is not None: - if time.time() - self.start_time > self.max_time: - return None - - # Otherwise take the next test. + # Check if we are cancelled. self.lock.acquire() if self.canceled: self.lock.release() return None + + # Otherwise take the next test. for item in self.iter: break else: @@ -151,7 +146,7 @@ class Run(object): """ # Create the test provider object. - provider = TestProvider(self.tests, max_time) + provider = TestProvider(self.tests) # Install a console-control signal handler on Windows. if win32api is not None: @@ -160,9 +155,20 @@ class Run(object): return True win32api.SetConsoleCtrlHandler(console_ctrl_handler, True) + # Install a timeout handler, if requested. + if max_time is not None: + def timeout_handler(): + provider.cancel() + timeout_timer = threading.Timer(max_time, timeout_handler) + timeout_timer.start() + # Actually execute the tests. self._execute_tests_with_provider(provider, display, jobs) + # Cancel the timeout handler. + if max_time is not None: + timeout_timer.cancel() + # Update results for any tests which weren't run. for test in self.tests: if test.result is None: -- cgit v1.1 From 4ac723b53f2eb69e604891853ca87d1e2b3ee788 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 00:54:23 +0000 Subject: [lit] Add support for multiprocessing, under --use-processes for now. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189556 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/TODO | 6 +-- utils/lit/lit/main.py | 9 +++- utils/lit/lit/run.py | 139 ++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 115 insertions(+), 39 deletions(-) (limited to 'utils') diff --git a/utils/lit/TODO b/utils/lit/TODO index e6aeb3d..c1a60c6 100644 --- a/utils/lit/TODO +++ b/utils/lit/TODO @@ -113,8 +113,8 @@ Infrastructure module. This is currently blocked on: * The external execution mode is faster in some situations, because it avoids - being bottlenecked on the GIL. We could fix this by moving to a good - multiprocessing model. + being bottlenecked on the GIL. This can hopefully be obviated simply by + using --use-processes. * Some tests in LLVM/Clang are explicitly disabled with the internal shell (because they use features specific to bash). We would need to rewrite these @@ -158,8 +158,6 @@ Miscellaneous * Add --show-unsupported, don't show by default? -* Optionally use multiprocessing. - * Support valgrind in all configs, and LLVM style valgrind. * Support a timeout / ulimit. diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 5c40f1c..50c9a66 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -142,6 +142,12 @@ def main(builtinParameters = {}): group.add_option("", "--show-tests", dest="showTests", help="Show all discovered tests", action="store_true", default=False) + group.add_option("", "--use-processes", dest="useProcesses", + help="Run tests in parallel with processes (not threads)", + action="store_true", default=False) + group.add_option("", "--use-threads", dest="useProcesses", + help="Run tests in parallel with threads (not processes)", + action="store_false", default=False) parser.add_option_group(group) (opts, args) = parser.parse_args() @@ -264,7 +270,8 @@ def main(builtinParameters = {}): startTime = time.time() display = TestingProgressDisplay(opts, len(run.tests), progressBar) try: - run.execute_tests(display, opts.numThreads, opts.maxTime) + run.execute_tests(display, opts.numThreads, opts.maxTime, + opts.useProcesses) except KeyboardInterrupt: sys.exit(2) display.finish() diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py index 617c3b9..8642ff1 100644 --- a/utils/lit/lit/run.py +++ b/utils/lit/lit/run.py @@ -2,42 +2,68 @@ import os import threading import time import traceback +try: + import Queue as queue +except ImportError: + import queue try: import win32api except ImportError: win32api = None +try: + import multiprocessing +except ImportError: + multiprocessing = None + import lit.Test ### # Test Execution Implementation -class TestProvider(object): - def __init__(self, tests): - self.iter = iter(range(len(tests))) +class LockedValue(object): + def __init__(self, value): self.lock = threading.Lock() - self.canceled = False + self._value = value - def cancel(self): + def _get_value(self): self.lock.acquire() - self.canceled = True - self.lock.release() + try: + return self._value + finally: + self.lock.release() - def get(self): - # Check if we are cancelled. + def _set_value(self, value): self.lock.acquire() - if self.canceled: - self.lock.release() + try: + self._value = value + finally: + self.lock.release() + + value = property(_get_value, _set_value) + +class TestProvider(object): + def __init__(self, tests, num_jobs, queue_impl, canceled_flag): + self.canceled_flag = canceled_flag + + # Create a shared queue to provide the test indices. + self.queue = queue_impl() + for i in range(len(tests)): + self.queue.put(i) + for i in range(num_jobs): + self.queue.put(None) + + def cancel(self): + self.canceled_flag.value = 1 + + def get(self): + # Check if we are canceled. + if self.canceled_flag.value: return None # Otherwise take the next test. - for item in self.iter: - break - else: - item = None - self.lock.release() - return item + return self.queue.get() class Tester(object): def __init__(self, run_instance, provider, consumer): @@ -46,7 +72,7 @@ class Tester(object): self.consumer = consumer def run(self): - while 1: + while True: item = self.provider.get() if item is None: break @@ -82,6 +108,42 @@ class ThreadResultsConsumer(object): def handle_results(self): pass +class MultiprocessResultsConsumer(object): + def __init__(self, run, display, num_jobs): + self.run = run + self.display = display + self.num_jobs = num_jobs + self.queue = multiprocessing.Queue() + + def update(self, test_index, test): + # This method is called in the child processes, and communicates the + # results to the actual display implementation via an output queue. + self.queue.put((test_index, test.result)) + + def task_finished(self): + # This method is called in the child processes, and communicates that + # individual tasks are complete. + self.queue.put(None) + + def handle_results(self): + # This method is called in the parent, and consumes the results from the + # output queue and dispatches to the actual display. The method will + # complete after each of num_jobs tasks has signalled completion. + completed = 0 + while completed != self.num_jobs: + # Wait for a result item. + item = self.queue.get() + if item is None: + completed += 1 + continue + + # Update the test result in the parent process. + index,result = item + test = self.run.tests[index] + test.result = result + + self.display.update(test) + def run_one_tester(run, provider, display): tester = Tester(run, provider, display) tester.run() @@ -123,7 +185,8 @@ class Run(object): test.setResult(result) - def execute_tests(self, display, jobs, max_time=None): + def execute_tests(self, display, jobs, max_time=None, + use_processes=False): """ execute_tests(display, jobs, [max_time]) @@ -145,8 +208,20 @@ class Run(object): be given an UNRESOLVED result. """ - # Create the test provider object. - provider = TestProvider(self.tests) + # Choose the appropriate parallel execution implementation. + if jobs == 1 or not use_processes or multiprocessing is None: + task_impl = threading.Thread + queue_impl = queue.Queue + canceled_flag = LockedValue(0) + consumer = ThreadResultsConsumer(display) + else: + task_impl = multiprocessing.Process + queue_impl = multiprocessing.Queue + canceled_flag = multiprocessing.Value('i', 0) + consumer = MultiprocessResultsConsumer(self, display, jobs) + + # Create the test provider. + provider = TestProvider(self.tests, jobs, queue_impl, canceled_flag) # Install a console-control signal handler on Windows. if win32api is not None: @@ -162,8 +237,12 @@ class Run(object): timeout_timer = threading.Timer(max_time, timeout_handler) timeout_timer.start() - # Actually execute the tests. - self._execute_tests_with_provider(provider, display, jobs) + # If not using multiple tasks, just run the tests directly. + if jobs == 1: + run_one_tester(self, provider, consumer) + else: + # Otherwise, execute the tests in parallel + self._execute_tests_in_parallel(task_impl, provider, consumer, jobs) # Cancel the timeout handler. if max_time is not None: @@ -174,18 +253,10 @@ class Run(object): if test.result is None: test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0)) - def _execute_tests_with_provider(self, provider, display, jobs): - consumer = ThreadResultsConsumer(display) - - # If only using one testing thread, don't use tasks at all; this lets us - # profile, among other things. - if jobs == 1: - run_one_tester(self, provider, consumer) - return - + def _execute_tests_in_parallel(self, task_impl, provider, consumer, jobs): # Start all of the tasks. - tasks = [threading.Thread(target=run_one_tester, - args=(self, provider, consumer)) + tasks = [task_impl(target=run_one_tester, + args=(self, provider, consumer)) for i in range(jobs)] for t in tasks: t.start() -- cgit v1.1 From cb4bfb340941186a0e326e4b00a88a50a86b7ff0 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 02:52:10 +0000 Subject: [lit] Fix internal shell's argv[0] handling. - At least on OS X, it is important for correct behavior of /bin/[ that argv[0] is passed as written, and not as the full executable path. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189559 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestRunner.py | 5 +++-- utils/lit/tests/shtest-format.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 120f89a..9752417 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -131,8 +131,8 @@ def executeShCmd(cmd, cfg, cwd, results): # Resolve the executable path ourselves. args = list(j.args) - args[0] = lit.util.which(args[0], cfg.environment['PATH']) - if not args[0]: + executable = lit.util.which(args[0], cfg.environment['PATH']) + if not executable: raise InternalShellError(j, '%r: command not found' % j.args[0]) # Replace uses of /dev/null with temporary files. @@ -145,6 +145,7 @@ def executeShCmd(cmd, cfg, cwd, results): args[i] = f.name procs.append(subprocess.Popen(args, cwd=cwd, + executable = executable, stdin = stdin, stdout = stdout, stderr = stderr, diff --git a/utils/lit/tests/shtest-format.py b/utils/lit/tests/shtest-format.py index 1c23119..751f0d7 100644 --- a/utils/lit/tests/shtest-format.py +++ b/utils/lit/tests/shtest-format.py @@ -7,6 +7,7 @@ # CHECK: -- Testing: +# CHECK: PASS: shtest-format :: argv0.txt # CHECK: FAIL: shtest-format :: external_shell/fail.txt # CHECK-NEXT: *** TEST 'shtest-format :: external_shell/fail.txt' FAILED *** # CHECK: Command Output (stdout): @@ -68,7 +69,7 @@ # CHECK: shtest-format :: external_shell/fail_with_bad_encoding.txt # CHECK: shtest-format :: fail.txt -# CHECK: Expected Passes : 3 +# CHECK: Expected Passes : 4 # CHECK: Expected Failures : 3 # CHECK: Unsupported Tests : 2 # CHECK: Unresolved Tests : 1 -- cgit v1.1 From e0ff96c11240d3f9463234f3278eb86f14be775c Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 29 Aug 2013 03:02:34 +0000 Subject: [lit] [tests] Add missing test input file. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189561 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/tests/Inputs/shtest-format/argv0.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 utils/lit/tests/Inputs/shtest-format/argv0.txt (limited to 'utils') diff --git a/utils/lit/tests/Inputs/shtest-format/argv0.txt b/utils/lit/tests/Inputs/shtest-format/argv0.txt new file mode 100644 index 0000000..2ff2890 --- /dev/null +++ b/utils/lit/tests/Inputs/shtest-format/argv0.txt @@ -0,0 +1,6 @@ +# Check that we route argv[0] as it was written, instead of the resolved +# path. This is important for some tools, in particular '[' which at least on OS +# X only recognizes that it is in '['-mode when its argv[0] is exactly +# '['. Otherwise it will refuse to accept the trailing closing bracket. +# +# RUN: [ "A" = "A" ] -- cgit v1.1 From aae60d1dc417dffb1b2486c8e7ca546cf3777901 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Thu, 29 Aug 2013 05:09:55 +0000 Subject: Move StringToOffsetTable into the TableGen include directory so I can use it in clang. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189567 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/AsmMatcherEmitter.cpp | 2 +- utils/TableGen/StringToOffsetTable.h | 83 ------------------------------------ 2 files changed, 1 insertion(+), 84 deletions(-) delete mode 100644 utils/TableGen/StringToOffsetTable.h (limited to 'utils') diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 468ce1c..31c17fb 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -97,7 +97,6 @@ //===----------------------------------------------------------------------===// #include "CodeGenTarget.h" -#include "StringToOffsetTable.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/STLExtras.h" @@ -110,6 +109,7 @@ #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/StringMatcher.h" +#include "llvm/TableGen/StringToOffsetTable.h" #include "llvm/TableGen/TableGenBackend.h" #include #include diff --git a/utils/TableGen/StringToOffsetTable.h b/utils/TableGen/StringToOffsetTable.h deleted file mode 100644 index d94d3a2..0000000 --- a/utils/TableGen/StringToOffsetTable.h +++ /dev/null @@ -1,83 +0,0 @@ -//===- StringToOffsetTable.h - Emit a big concatenated string ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef TBLGEN_STRING_TO_OFFSET_TABLE_H -#define TBLGEN_STRING_TO_OFFSET_TABLE_H - -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/Support/raw_ostream.h" -#include - -namespace llvm { - -/// StringToOffsetTable - This class uniques a bunch of nul-terminated strings -/// and keeps track of their offset in a massive contiguous string allocation. -/// It can then output this string blob and use indexes into the string to -/// reference each piece. -class StringToOffsetTable { - StringMap StringOffset; - std::string AggregateString; -public: - - unsigned GetOrAddStringOffset(StringRef Str, bool appendZero = true) { - StringMapEntry &Entry = StringOffset.GetOrCreateValue(Str, -1U); - if (Entry.getValue() == -1U) { - // Add the string to the aggregate if this is the first time found. - Entry.setValue(AggregateString.size()); - AggregateString.append(Str.begin(), Str.end()); - if (appendZero) - AggregateString += '\0'; - } - - return Entry.getValue(); - } - - void EmitString(raw_ostream &O) { - // Escape the string. - SmallString<256> Str; - raw_svector_ostream(Str).write_escaped(AggregateString); - AggregateString = Str.str(); - - O << " \""; - unsigned CharsPrinted = 0; - for (unsigned i = 0, e = AggregateString.size(); i != e; ++i) { - if (CharsPrinted > 70) { - O << "\"\n \""; - CharsPrinted = 0; - } - O << AggregateString[i]; - ++CharsPrinted; - - // Print escape sequences all together. - if (AggregateString[i] != '\\') - continue; - - assert(i+1 < AggregateString.size() && "Incomplete escape sequence!"); - if (isdigit(AggregateString[i+1])) { - assert(isdigit(AggregateString[i+2]) && - isdigit(AggregateString[i+3]) && - "Expected 3 digit octal escape!"); - O << AggregateString[++i]; - O << AggregateString[++i]; - O << AggregateString[++i]; - CharsPrinted += 3; - } else { - O << AggregateString[++i]; - ++CharsPrinted; - } - } - O << "\""; - } -}; - -} // end namespace llvm - -#endif -- cgit v1.1 From dd46230062c1e83db927737fd2b63237c4285019 Mon Sep 17 00:00:00 2001 From: Jim Grosbach Date: Thu, 29 Aug 2013 22:41:39 +0000 Subject: Tidy up. Trailing whitespace. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189617 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/FastISelEmitter.cpp | 78 +++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 39 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp index ce7f8c8..65d4253 100644 --- a/utils/TableGen/FastISelEmitter.cpp +++ b/utils/TableGen/FastISelEmitter.cpp @@ -46,7 +46,7 @@ class ImmPredicateSet { DenseMap ImmIDs; std::vector PredsByName; public: - + unsigned getIDFor(TreePredicateFn Pred) { unsigned &Entry = ImmIDs[Pred.getOrigPatFragRecord()]; if (Entry == 0) { @@ -55,16 +55,16 @@ public: } return Entry-1; } - + const TreePredicateFn &getPredicate(unsigned i) { assert(i < PredsByName.size()); return PredsByName[i]; } - + typedef std::vector::const_iterator iterator; iterator begin() const { return PredsByName.begin(); } iterator end() const { return PredsByName.end(); } - + }; } // End anonymous namespace @@ -77,9 +77,9 @@ struct OperandsSignature { enum { OK_Reg, OK_FP, OK_Imm, OK_Invalid = -1 }; char Repr; public: - + OpKind() : Repr(OK_Invalid) {} - + bool operator<(OpKind RHS) const { return Repr < RHS.Repr; } bool operator==(OpKind RHS) const { return Repr == RHS.Repr; } @@ -90,13 +90,13 @@ struct OperandsSignature { "Too many integer predicates for the 'Repr' char"); OpKind K; K.Repr = OK_Imm+V; return K; } - + bool isReg() const { return Repr == OK_Reg; } bool isFP() const { return Repr == OK_FP; } bool isImm() const { return Repr >= OK_Imm; } - + unsigned getImmCode() const { assert(isImm()); return Repr-OK_Imm; } - + void printManglingSuffix(raw_ostream &OS, ImmPredicateSet &ImmPredicates, bool StripImmCodes) const { if (isReg()) @@ -111,8 +111,8 @@ struct OperandsSignature { } } }; - - + + SmallVector Operands; bool operator<(const OperandsSignature &O) const { @@ -130,7 +130,7 @@ struct OperandsSignature { return true; return false; } - + /// getWithoutImmCodes - Return a copy of this with any immediate codes forced /// to zero. OperandsSignature getWithoutImmCodes() const { @@ -142,31 +142,31 @@ struct OperandsSignature { Result.Operands.push_back(OpKind::getImm(0)); return Result; } - + void emitImmediatePredicate(raw_ostream &OS, ImmPredicateSet &ImmPredicates) { bool EmittedAnything = false; for (unsigned i = 0, e = Operands.size(); i != e; ++i) { if (!Operands[i].isImm()) continue; - + unsigned Code = Operands[i].getImmCode(); if (Code == 0) continue; - + if (EmittedAnything) OS << " &&\n "; - + TreePredicateFn PredFn = ImmPredicates.getPredicate(Code-1); - + // Emit the type check. OS << "VT == " << getEnumName(PredFn.getOrigPatFragRecord()->getTree(0)->getType(0)) << " && "; - - + + OS << PredFn.getFnName() << "(imm" << i <<')'; EmittedAnything = true; } } - + /// initialize - Examine the given pattern and initialize the contents /// of the Operands array accordingly. Return true if all the operands /// are supported, false otherwise. @@ -177,12 +177,12 @@ struct OperandsSignature { const CodeGenRegisterClass *OrigDstRC) { if (InstPatNode->isLeaf()) return false; - + if (InstPatNode->getOperator()->getName() == "imm") { Operands.push_back(OpKind::getImm(0)); return true; } - + if (InstPatNode->getOperator()->getName() == "fpimm") { Operands.push_back(OpKind::getFP()); return true; @@ -211,19 +211,19 @@ struct OperandsSignature { Record *Rec = PredFn.getOrigPatFragRecord()->getRecord(); if (Rec->getValueAsBit("FastIselShouldIgnore")) return false; - + PredNo = ImmediatePredicates.getIDFor(PredFn)+1; } - + // Handle unmatched immediate sizes here. //if (Op->getType(0) != VT) // return false; - + Operands.push_back(OpKind::getImm(PredNo)); continue; } - + // For now, filter out any operand with a predicate. // For now, filter out any operand with multiple values. if (!Op->getPredicateFns().empty() || Op->getNumTypes() != 1) @@ -237,7 +237,7 @@ struct OperandsSignature { // For now, ignore other non-leaf nodes. return false; } - + assert(Op->hasTypeSet(0) && "Type infererence not done?"); // For now, all the operands must have the same type (if they aren't @@ -250,7 +250,7 @@ struct OperandsSignature { if (!OpDI) return false; Record *OpLeafRec = OpDI->getDef(); - + // For now, the only other thing we accept is register operands. const CodeGenRegisterClass *RC = 0; if (OpLeafRec->isSubClassOf("RegisterOperand")) @@ -375,7 +375,7 @@ class FastISelMap { std::map > SignaturesWithConstantForms; - + std::string InstNS; ImmPredicateSet ImmediatePredicates; public: @@ -551,13 +551,13 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) { SubRegNo, PhysRegInputs }; - + if (SimplePatterns[Operands][OpcodeName][VT][RetVT].count(PredicateCheck)) PrintFatalError(Pattern.getSrcRecord()->getLoc(), "Duplicate record in FastISel table!"); SimplePatterns[Operands][OpcodeName][VT][RetVT][PredicateCheck] = Memo; - + // If any of the operands were immediates with predicates on them, strip // them down to a signature that doesn't have predicates so that we can // associate them with the stripped predicate version. @@ -571,14 +571,14 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) { void FastISelMap::printImmediatePredicates(raw_ostream &OS) { if (ImmediatePredicates.begin() == ImmediatePredicates.end()) return; - + OS << "\n// FastEmit Immediate Predicate functions.\n"; for (ImmPredicateSet::iterator I = ImmediatePredicates.begin(), E = ImmediatePredicates.end(); I != E; ++I) { OS << "static bool " << I->getFnName() << "(int64_t Imm) {\n"; OS << I->getImmediatePredicateCode() << "\n}\n"; } - + OS << "\n\n"; } @@ -804,11 +804,11 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) { OS << ", "; Operands.PrintParameters(OS); OS << ") {\n"; - + // If there are any forms of this signature available that operand on // constrained forms of the immediate (e.g. 32-bit sext immediate in a // 64-bit operand), check them first. - + std::map >::iterator MI = SignaturesWithConstantForms.find(Operands); if (MI != SignaturesWithConstantForms.end()) { @@ -816,7 +816,7 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) { std::sort(MI->second.begin(), MI->second.end()); MI->second.erase(std::unique(MI->second.begin(), MI->second.end()), MI->second.end()); - + // Check each in order it was seen. It would be nice to have a good // relative ordering between them, but we're not going for optimality // here. @@ -831,11 +831,11 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) { MI->second[i].PrintArguments(OS); OS << "))\n return Reg;\n\n"; } - + // Done with this, remove it. SignaturesWithConstantForms.erase(MI); } - + OS << " switch (Opcode) {\n"; for (OpcodeTypeRetPredMap::const_iterator I = OTM.begin(), E = OTM.end(); I != E; ++I) { @@ -855,7 +855,7 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) { OS << "}\n"; OS << "\n"; } - + // TODO: SignaturesWithConstantForms should be empty here. } -- cgit v1.1 From ff372dc18d0d569cbcfb7346eb891d6a96219043 Mon Sep 17 00:00:00 2001 From: Jim Grosbach Date: Thu, 29 Aug 2013 22:41:43 +0000 Subject: Tidy up. Comment grammar. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189618 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/FastISelEmitter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp index 65d4253..e35cf0f 100644 --- a/utils/TableGen/FastISelEmitter.cpp +++ b/utils/TableGen/FastISelEmitter.cpp @@ -805,8 +805,8 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) { Operands.PrintParameters(OS); OS << ") {\n"; - // If there are any forms of this signature available that operand on - // constrained forms of the immediate (e.g. 32-bit sext immediate in a + // If there are any forms of this signature available that operate on + // constrained forms of the immediate (e.g., 32-bit sext immediate in a // 64-bit operand), check them first. std::map >::iterator MI -- cgit v1.1 From d8f2eb301c05b2d664a284df7604b82dad7ecab8 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Tue, 3 Sep 2013 19:43:28 +0000 Subject: TableGen: Enumerate Schedule Model too. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189839 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/InstrInfoEmitter.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index cfbf915..84bd4de 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -545,7 +545,15 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) { << "\t= " << i << ",\n"; } OS << " INSTRUCTION_LIST_END = " << NumberedInstructions.size() << "\n"; - OS << " };\n}\n"; + OS << " };\n"; + OS << "namespace Sched {\n"; + OS << " enum {\n"; + for (unsigned i = 0, e = SchedModels.numInstrSchedClasses(); i != e; ++i) { + OS << " " << SchedModels.getSchedClass(i).Name + << "\t= " << i << ",\n"; + } + OS << " SCHED_LIST_END = " << SchedModels.numInstrSchedClasses() << "\n"; + OS << " };\n}\n}\n"; OS << "} // End llvm namespace \n"; OS << "#endif // GET_INSTRINFO_ENUM\n\n"; -- cgit v1.1 From 4b3e5f24ecedc075a3d9f1a5bdb77190a3a01f22 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Tue, 3 Sep 2013 23:32:55 +0000 Subject: [lit] Allow config files to pass arbitrary values to child configs. - This aligns with how existing test suites end up wanting to use the local config files, conceptually it makes sense to consider them to be inherited. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189885 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestingConfig.py | 11 ----------- utils/lit/lit/discovery.py | 3 ++- utils/lit/tests/Inputs/discovery/lit.cfg | 3 +++ utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg | 3 +++ 4 files changed, 8 insertions(+), 12 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index 3f198c6..d541539 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -114,17 +114,6 @@ class TestingConfig: self.available_features = set(available_features) self.pipefail = pipefail - def clone(self): - # FIXME: Chain implementations? - # - # FIXME: Allow extra parameters? - return TestingConfig(self, self.name, self.suffixes, self.test_format, - self.environment, self.substitutions, - self.unsupported, - self.test_exec_root, self.test_source_root, - self.excludes, self.available_features, - self.pipefail) - def finish(self, litConfig): """finish() - Finish this config object, after loading is complete.""" diff --git a/utils/lit/lit/discovery.py b/utils/lit/lit/discovery.py index 263e546..c3c0f28 100644 --- a/utils/lit/lit/discovery.py +++ b/utils/lit/lit/discovery.py @@ -2,6 +2,7 @@ Test discovery functions. """ +import copy import os import sys @@ -90,7 +91,7 @@ def getLocalConfig(ts, path_in_suite, litConfig, cache): # Otherwise, copy the current config and load the local configuration # file into it. - config = parent.clone() + config = copy.copy(parent) if litConfig.debug: litConfig.note('loading local config %r' % cfgpath) config.load_from_path(cfgpath, litConfig) diff --git a/utils/lit/tests/Inputs/discovery/lit.cfg b/utils/lit/tests/Inputs/discovery/lit.cfg index 1c5436b..c48ca0b 100644 --- a/utils/lit/tests/Inputs/discovery/lit.cfg +++ b/utils/lit/tests/Inputs/discovery/lit.cfg @@ -9,3 +9,6 @@ config.test_format = lit.formats.ShTest() # #config.test_source_root = None #config.test_exec_root = None + +# Check that arbitrary config values are copied (tested by subdir/lit.local.cfg). +config.an_extra_variable = False diff --git a/utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg b/utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg index 5ae6b3c..631cb60 100644 --- a/utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg +++ b/utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg @@ -1 +1,4 @@ config.suffixes = ['.py'] + +# Check that the arbitrary config values in our parent was inherited. +assert hasattr(config, 'an_extra_variable') -- cgit v1.1 From 4f1e5fba415d422543ee820ac68c1020b0c11187 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 6 Sep 2013 18:12:01 +0000 Subject: debuginfo-tests: Add support for an lldb wrapper script to be used on darwin in lieu of gdb. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190186 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/test_debuginfo.pl | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/test_debuginfo.pl b/utils/test_debuginfo.pl index 0832a33..a6b6137 100755 --- a/utils/test_debuginfo.pl +++ b/utils/test_debuginfo.pl @@ -11,8 +11,13 @@ # and run the script generated from source program comments. Finally, # the debugger output is checked, using FileCheck, to validate # debugging information. +# +# On Darwin the default is to use the llgdb.py wrapper script which +# translates gdb commands into their lldb equivalents. use File::Basename; +use Config; +use Cwd; my $testcase_file = $ARGV[0]; my $executable_file = $ARGV[1]; @@ -23,6 +28,11 @@ my $output_dir = dirname $executable_file; my $debugger_script_file = "$output_dir/$input_filename.debugger.script"; my $output_file = "$output_dir/$input_filename.gdb.output"; +my %cmd_map = (); +# Assume lldb to be the debugger on Darwin. +my $use_lldb = 0; +$use_lldb = 1 if ($Config{osname} eq "darwin"); + # Extract debugger commands from testcase. They are marked with DEBUGGER: # at the beginning of a comment line. open(INPUT, $testcase_file); @@ -44,8 +54,15 @@ close(OUTPUT); # setup debugger and debugger options to run a script. my $my_debugger = $ENV{'DEBUGGER'}; if (!$my_debugger) { - $my_debugger = "gdb"; + if ($use_lldb) { + my $path = dirname(Cwd::abs_path($0)); + $my_debugger = "/usr/bin/env python $path/../tools/clang/test/debuginfo-tests/llgdb.py"; + } else { + $my_debugger = "gdb"; + } } + +# quiet / exit after cmdline / no init file / execute script my $debugger_options = "-q -batch -n -x"; # run debugger and capture output. -- cgit v1.1 From 71faecf16fd19eadaa42e2cb6c3b5165a9217f21 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Wed, 11 Sep 2013 11:22:26 +0000 Subject: llvm-tblgen: Stabilize subreg index tables. Otherwise SequenceToOffsetTable will sort by pointer and becomes non-deterministic. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190514 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/RegisterInfoEmitter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index 9a30e15..ee417bc 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -722,7 +722,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, // Keep track of sub-register names as well. These are not differentially // encoded. typedef SmallVector SubRegIdxVec; - SequenceToOffsetTable SubRegIdxSeqs; + SequenceToOffsetTable SubRegIdxSeqs; SmallVector SubRegIdxLists(Regs.size()); SequenceToOffsetTable RegStrings; @@ -1090,7 +1090,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, // Compress the sub-reg index lists. typedef std::vector IdxList; SmallVector SuperRegIdxLists(RegisterClasses.size()); - SequenceToOffsetTable SuperRegIdxSeqs; + SequenceToOffsetTable SuperRegIdxSeqs; BitVector MaskBV(RegisterClasses.size()); for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) { -- cgit v1.1 From 209a8c8e35cd770d483d597c4eb703a4ee8b0003 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Wed, 11 Sep 2013 15:42:16 +0000 Subject: llvm-tblgen: Mangle operand replacements into the strings in printAliasInstr. Cuts down the bloat in the AArch64 asm writer a bit. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190527 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/AsmWriterEmitter.cpp | 85 ++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 40 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index ac8d896..13b28df 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" @@ -657,7 +658,10 @@ public: void addCond(const std::string &C) { Conds.push_back(C); } - void addOperand(StringRef Op, unsigned Idx) { OpMap[Op] = Idx; } + void addOperand(StringRef Op, unsigned Idx) { + assert(Idx < 0xFF && "Index too large!"); + OpMap[Op] = Idx; + } unsigned getOpIndex(StringRef Op) { return OpMap[Op]; } bool isOpMapped(StringRef Op) { return OpMap.find(Op) != OpMap.end(); } @@ -681,12 +685,35 @@ public: O << ") {\n"; O.indent(6) << "// " << Result << "\n"; - O.indent(6) << "AsmString = \"" << AsmString << "\";\n"; - for (std::map::iterator - I = OpMap.begin(), E = OpMap.end(); I != E; ++I) - O.indent(6) << "OpMap.push_back(std::make_pair(\"" << I->first << "\", " - << I->second << "));\n"; + // Directly mangle mapped operands into the string. Each operand is + // identified by a '$' sign followed by a byte identifying the number of the + // operand. We add one to the index to avoid zero bytes. + std::pair ASM = StringRef(AsmString).split(' '); + SmallString<128> OutString = ASM.first; + if (!ASM.second.empty()) { + raw_svector_ostream OS(OutString); + OS << ' '; + for (StringRef::iterator I = ASM.second.begin(), E = ASM.second.end(); + I != E;) { + OS << *I; + if (*I == '$') { + StringRef::iterator Start = ++I; + while (I != E && + ((*I >= 'a' && *I <= 'z') || (*I >= 'A' && *I <= 'Z') || + (*I >= '0' && *I <= '9') || *I == '_')) + ++I; + StringRef Name(Start, I - Start); + assert(isOpMapped(Name) && "Unmapped operand!"); + OS << format("\\x%02X", (unsigned char)getOpIndex(Name) + 1); + } else { + ++I; + } + } + } + + // Emit the string. + O.indent(6) << "AsmString = \"" << OutString.str() << "\";\n"; O.indent(6) << "break;\n"; O.indent(4) << '}'; @@ -721,19 +748,6 @@ public: } // end anonymous namespace -static void EmitGetMapOperandNumber(raw_ostream &O) { - O << "static unsigned getMapOperandNumber(" - << "const SmallVectorImpl > &OpMap,\n"; - O << " StringRef Name) {\n"; - O << " for (SmallVectorImpl >::" - << "const_iterator\n"; - O << " I = OpMap.begin(), E = OpMap.end(); I != E; ++I)\n"; - O << " if (I->first == Name)\n"; - O << " return I->second;\n"; - O << " llvm_unreachable(\"Operand not in map!\");\n"; - O << "}\n\n"; -} - static unsigned CountNumOperands(StringRef AsmString) { unsigned NumOps = 0; std::pair ASM = AsmString.split(' '); @@ -955,11 +969,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { return; } - EmitGetMapOperandNumber(O); - O << HeaderO.str(); - O.indent(2) << "StringRef AsmString;\n"; - O.indent(2) << "SmallVector, 4> OpMap;\n"; + O.indent(2) << "const char *AsmString;\n"; O.indent(2) << "switch (MI->getOpcode()) {\n"; O.indent(2) << "default: return false;\n"; O << CasesO.str(); @@ -967,27 +978,21 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { // Code that prints the alias, replacing the operands with the ones from the // MCInst. - O << " std::pair ASM = AsmString.split(' ');\n"; - O << " OS << '\\t' << ASM.first;\n"; + O << " unsigned I = 0;\n"; + O << " while (AsmString[I] != ' ' && AsmString[I] != '\\0')\n"; + O << " ++I;\n"; + O << " OS << '\\t' << StringRef(AsmString, I);\n"; - O << " if (!ASM.second.empty()) {\n"; + O << " if (AsmString[I] != '\\0') {\n"; O << " OS << '\\t';\n"; - O << " for (StringRef::iterator\n"; - O << " I = ASM.second.begin(), E = ASM.second.end(); I != E; ) {\n"; - O << " if (*I == '$') {\n"; - O << " StringRef::iterator Start = ++I;\n"; - O << " while (I != E &&\n"; - O << " ((*I >= 'a' && *I <= 'z') ||\n"; - O << " (*I >= 'A' && *I <= 'Z') ||\n"; - O << " (*I >= '0' && *I <= '9') ||\n"; - O << " *I == '_'))\n"; - O << " ++I;\n"; - O << " StringRef Name(Start, I - Start);\n"; - O << " printOperand(MI, getMapOperandNumber(OpMap, Name), OS);\n"; + O << " do {\n"; + O << " if (AsmString[I] == '$') {\n"; + O << " ++I;\n"; + O << " printOperand(MI, unsigned(AsmString[I++]) - 1, OS);\n"; O << " } else {\n"; - O << " OS << *I++;\n"; + O << " OS << AsmString[I++];\n"; O << " }\n"; - O << " }\n"; + O << " } while (AsmString[I] != '\\0');\n"; O << " }\n\n"; O << " return true;\n"; -- cgit v1.1 From ff058f0a701b601f1593f2a9c8030acb652fdba6 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 11 Sep 2013 17:45:11 +0000 Subject: [lit] Add support for attach arbitrary metrics to test results. - This is a work-in-progress and all details are subject to change, but I am trying to build up support for allowing lit to be used as a driver for performance tests (or other tests which might want to record information beyond simple PASS/FAIL). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190535 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/Test.py | 43 ++++++++++++++++++++++++++- utils/lit/lit/main.py | 15 +++++++++- utils/lit/tests/Inputs/test-data/lit.cfg | 44 ++++++++++++++++++++++++++++ utils/lit/tests/Inputs/test-data/metrics.ini | 7 +++++ utils/lit/tests/test-data.py | 12 ++++++++ 5 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 utils/lit/tests/Inputs/test-data/lit.cfg create mode 100644 utils/lit/tests/Inputs/test-data/metrics.ini create mode 100644 utils/lit/tests/test-data.py (limited to 'utils') diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py index 05cae99..d84eb47 100644 --- a/utils/lit/lit/Test.py +++ b/utils/lit/lit/Test.py @@ -1,6 +1,6 @@ import os -# Test results. +# Test result codes. class ResultCode(object): """Test result codes.""" @@ -31,6 +31,28 @@ XPASS = ResultCode('XPASS', True) UNRESOLVED = ResultCode('UNRESOLVED', True) UNSUPPORTED = ResultCode('UNSUPPORTED', False) +# Test metric values. + +class MetricValue(object): + def format(self): + raise RuntimeError("abstract method") + +class IntMetricValue(MetricValue): + def __init__(self, value): + self.value = value + + def format(self): + return str(self.value) + +class RealMetricValue(MetricValue): + def __init__(self, value): + self.value = value + + def format(self): + return '%.4f' % self.value + +# Test results. + class Result(object): """Wrapper for the results of executing an individual test.""" @@ -41,6 +63,25 @@ class Result(object): self.output = output # The wall timing to execute the test, if timing. self.elapsed = elapsed + # The metrics reported by this test. + self.metrics = {} + + def addMetric(self, name, value): + """ + addMetric(name, value) + + Attach a test metric to the test result, with the given name and list of + values. It is an error to attempt to attach the metrics with the same + name multiple times. + + Each value must be an instance of a MetricValue subclass. + """ + if name in self.metrics: + raise ValueError("result already includes metrics for %r" % ( + name,)) + if not isinstance(value, MetricValue): + raise TypeError("unexpected metric value: %r" % (value,)) + self.metrics[name] = value # Test classes. diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 50c9a66..b93aa6f 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -45,15 +45,28 @@ class TestingProgressDisplay(object): if self.progressBar: self.progressBar.clear() - print('%s: %s (%d of %d)' % (test.result.code.name, test.getFullName(), + # Show the test result line. + test_name = test.getFullName() + print('%s: %s (%d of %d)' % (test.result.code.name, test_name, self.completed, self.numTests)) + # Show the test failure output, if requested. if test.result.code.isFailure and self.opts.showOutput: print("%s TEST '%s' FAILED %s" % ('*'*20, test.getFullName(), '*'*20)) print(test.result.output) print("*" * 20) + # Report test metrics, if present. + if test.result.metrics: + print("%s TEST '%s' RESULTS %s" % ('*'*10, test.getFullName(), + '*'*10)) + items = sorted(test.result.metrics.items()) + for metric_name, value in items: + print('%s: %s ' % (metric_name, value.format())) + print("*" * 10) + + # Ensure the output is flushed. sys.stdout.flush() def main(builtinParameters = {}): diff --git a/utils/lit/tests/Inputs/test-data/lit.cfg b/utils/lit/tests/Inputs/test-data/lit.cfg new file mode 100644 index 0000000..f5aba7b --- /dev/null +++ b/utils/lit/tests/Inputs/test-data/lit.cfg @@ -0,0 +1,44 @@ +import os +try: + import ConfigParser +except ImportError: + import configparser as ConfigParser + +import lit.formats +import lit.Test + +class DummyFormat(lit.formats.FileBasedTest): + def execute(self, test, lit_config): + # In this dummy format, expect that each test file is actually just a + # .ini format dump of the results to report. + + source_path = test.getSourcePath() + + cfg = ConfigParser.ConfigParser() + cfg.read(source_path) + + # Create the basic test result. + result_code = cfg.get('global', 'result_code') + result_output = cfg.get('global', 'result_output') + result = lit.Test.Result(getattr(lit.Test, result_code), + result_output) + + # Load additional metrics. + for key,value_str in cfg.items('results'): + value = eval(value_str) + if isinstance(value, int): + metric = lit.Test.IntMetricValue(value) + elif isinstance(value, float): + metric = lit.Test.RealMetricValue(value) + else: + raise RuntimeError("unsupported result type") + result.addMetric(key, metric) + + return result + +config.name = 'test-data' +config.suffixes = ['.ini'] +config.test_format = DummyFormat() +config.test_source_root = None +config.test_exec_root = None +config.target_triple = None diff --git a/utils/lit/tests/Inputs/test-data/metrics.ini b/utils/lit/tests/Inputs/test-data/metrics.ini new file mode 100644 index 0000000..267e516 --- /dev/null +++ b/utils/lit/tests/Inputs/test-data/metrics.ini @@ -0,0 +1,7 @@ +[global] +result_code = PASS +result_output = 'Test passed.' + +[results] +value0 = 1 +value1 = 2.3456 \ No newline at end of file diff --git a/utils/lit/tests/test-data.py b/utils/lit/tests/test-data.py new file mode 100644 index 0000000..54909d7 --- /dev/null +++ b/utils/lit/tests/test-data.py @@ -0,0 +1,12 @@ +# Test features related to formats which support reporting additional test data. + +# RUN: %{lit} -j 1 -v %{inputs}/test-data > %t.out +# RUN: FileCheck < %t.out %s + +# CHECK: -- Testing: + +# CHECK: PASS: test-data :: metrics.ini +# CHECK-NEXT: *** TEST 'test-data :: metrics.ini' RESULTS *** +# CHECK-NEXT: value0: 1 +# CHECK-NEXT: value1: 2.3456 +# CHECK-NEXT: *** -- cgit v1.1 From 715d98d657491b3fb8ea0e14643e9801b2f9628c Mon Sep 17 00:00:00 2001 From: Joey Gouly Date: Thu, 12 Sep 2013 10:28:05 +0000 Subject: Add an instruction deprecation feature to TableGen. The 'Deprecated' class allows you to specify a SubtargetFeature that the instruction is deprecated on. The 'ComplexDeprecationPredicate' class allows you to define a custom predicate that is called to check for deprecation. For example: ComplexDeprecationPredicate<"MCR"> would mean you would have to define the following function: bool getMCRDeprecationInfo(MCInst &MI, MCSubtargetInfo &STI, std::string &Info) Which returns 'false' for not deprecated, and 'true' for deprecated and store the warning message in 'Info'. The MCTargetAsmParser constructor was chaned to take an extra argument of the MCInstrInfo class, so out-of-tree targets will need to be changed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190598 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/AsmMatcherEmitter.cpp | 20 ++++++++++++++++++++ utils/TableGen/CodeGenInstruction.cpp | 14 ++++++++++++++ utils/TableGen/CodeGenInstruction.h | 3 +++ utils/TableGen/InstrInfoEmitter.cpp | 13 +++++++++++++ 4 files changed, 50 insertions(+) (limited to 'utils') diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 31c17fb..c827525 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -430,6 +430,9 @@ struct MatchableInfo { /// function. std::string ConversionFnKind; + /// If this instruction is deprecated in some form. + bool HasDeprecation; + MatchableInfo(const CodeGenInstruction &CGI) : AsmVariantID(0), TheDef(CGI.TheDef), DefRec(&CGI), AsmString(CGI.AsmString) { @@ -779,6 +782,13 @@ void MatchableInfo::initialize(const AsmMatcherInfo &Info, if (Record *Reg = AsmOperands[i].SingletonReg) SingletonRegisters.insert(Reg); } + + const RecordVal *DepMask = TheDef->getValue("DeprecatedFeatureMask"); + if (!DepMask) + DepMask = TheDef->getValue("ComplexDeprecationPredicate"); + + HasDeprecation = + DepMask ? !DepMask->getValue()->getAsUnquotedString().empty() : false; } /// tokenizeAsmString - Tokenize a simplified assembly string. @@ -2743,11 +2753,13 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { size_t MaxNumOperands = 0; unsigned MaxMnemonicIndex = 0; + bool HasDeprecation = false; for (std::vector::const_iterator it = Info.Matchables.begin(), ie = Info.Matchables.end(); it != ie; ++it) { MatchableInfo &II = **it; MaxNumOperands = std::max(MaxNumOperands, II.AsmOperands.size()); + HasDeprecation |= II.HasDeprecation; // Store a pascal-style length byte in the mnemonic. std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str(); @@ -3018,6 +3030,14 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (!InsnCleanupFn.empty()) OS << " " << InsnCleanupFn << "(Inst);\n"; + if (HasDeprecation) { + OS << " std::string Info;\n"; + OS << " if (MII.get(Inst.getOpcode()).getDeprecatedInfo(Inst, STI, Info)) {\n"; + OS << " SMLoc Loc = ((" << Target.getName() << "Operand*)Operands[0])->getStartLoc();\n"; + OS << " Parser.Warning(Loc, Info, None);\n"; + OS << " }\n"; + } + OS << " return Match_Success;\n"; OS << " }\n\n"; diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp index bf59d3a..576388b 100644 --- a/utils/TableGen/CodeGenInstruction.cpp +++ b/utils/TableGen/CodeGenInstruction.cpp @@ -337,6 +337,20 @@ CodeGenInstruction::CodeGenInstruction(Record *R) // Parse the DisableEncoding field. Operands.ProcessDisableEncoding(R->getValueAsString("DisableEncoding")); + + // First check for a ComplexDeprecationPredicate. + if (R->getValue("ComplexDeprecationPredicate")) { + HasComplexDeprecationPredicate = true; + DeprecatedReason = R->getValueAsString("ComplexDeprecationPredicate"); + } else if (RecordVal *Dep = R->getValue("DeprecatedFeatureMask")) { + // Check if we have a Subtarget feature mask. + HasComplexDeprecationPredicate = false; + DeprecatedReason = Dep->getValue()->getAsString(); + } else { + // This instruction isn't deprecated. + HasComplexDeprecationPredicate = false; + DeprecatedReason = ""; + } } /// HasOneImplicitDefWithKnownVT - If the instruction has at least one diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h index d1e1153..6004f66 100644 --- a/utils/TableGen/CodeGenInstruction.h +++ b/utils/TableGen/CodeGenInstruction.h @@ -248,6 +248,9 @@ namespace llvm { bool isCodeGenOnly; bool isPseudo; + std::string DeprecatedReason; + bool HasComplexDeprecationPredicate; + /// Are there any undefined flags? bool hasUndefFlags() const { return mayLoad_Unset || mayStore_Unset || hasSideEffects_Unset; diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index 84bd4de..af26353 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -514,6 +514,19 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, else OS << "OperandInfo" << OpInfo.find(OperandInfo)->second; + CodeGenTarget &Target = CDP.getTargetInfo(); + if (Inst.HasComplexDeprecationPredicate) + // Emit a function pointer to the complex predicate method. + OS << ",0" + << ",&get" << Inst.DeprecatedReason << "DeprecationInfo"; + else if (!Inst.DeprecatedReason.empty()) + // Emit the Subtarget feature. + OS << "," << Target.getInstNamespace() << "::" << Inst.DeprecatedReason + << ",0"; + else + // Instruction isn't deprecated. + OS << ",0,0"; + OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n"; } -- cgit v1.1 From 9c38ba4f9f2cf69ed21cf4c31141273d58f5cf6b Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Fri, 13 Sep 2013 12:41:38 +0000 Subject: Fix build failure reported by Tobias Markmann in bug 17203. svn 1.8.0 emits an additional line matching 'URL:' in its 'svn info' command ('Relative URL:'). Changed the grep to match only the intended line so that a valid SVNVersion.inc is generated. The problem doesnt occur with the svn version I'm using (1.7.5) but Tobias has confirmed that the change fixes the problem. See http://llvm.org/bugs/show_bug.cgi?id=17203 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190685 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/GetRepositoryPath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/GetRepositoryPath b/utils/GetRepositoryPath index f3b0cc5..b915251 100755 --- a/utils/GetRepositoryPath +++ b/utils/GetRepositoryPath @@ -15,7 +15,7 @@ fi cd $1 if [ -d .svn ]; then - svn info | grep 'URL:' | cut -d: -f2- + svn info | grep '^URL:' | cut -d: -f2- elif [ -f .git/svn/.metadata ]; then git svn info | grep 'URL:' | cut -d: -f2- elif [ -d .git ]; then -- cgit v1.1 From 2849503ab240a2dab6f2e3c5a029e3416165554f Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Sat, 14 Sep 2013 01:19:17 +0000 Subject: [lit] Add an --output option, for writing results in a machine readable form. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190738 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/Test.py | 21 ++++++++++++ utils/lit/lit/main.py | 49 +++++++++++++++++++++++++++- utils/lit/tests/Inputs/test-data/metrics.ini | 2 +- utils/lit/tests/lit.cfg | 6 +++- utils/lit/tests/test-output.py | 21 ++++++++++++ 5 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 utils/lit/tests/test-output.py (limited to 'utils') diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py index d84eb47..b4988f5 100644 --- a/utils/lit/lit/Test.py +++ b/utils/lit/lit/Test.py @@ -35,6 +35,21 @@ UNSUPPORTED = ResultCode('UNSUPPORTED', False) class MetricValue(object): def format(self): + """ + format() -> str + + Convert this metric to a string suitable for displaying as part of the + console output. + """ + raise RuntimeError("abstract method") + + def todata(self): + """ + todata() -> json-serializable data + + Convert this metric to content suitable for serializing in the JSON test + output. + """ raise RuntimeError("abstract method") class IntMetricValue(MetricValue): @@ -44,6 +59,9 @@ class IntMetricValue(MetricValue): def format(self): return str(self.value) + def todata(self): + return self.value + class RealMetricValue(MetricValue): def __init__(self, value): self.value = value @@ -51,6 +69,9 @@ class RealMetricValue(MetricValue): def format(self): return '%.4f' % self.value + def todata(self): + return self.value + # Test results. class Result(object): diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index b93aa6f..ba2490e 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -69,6 +69,45 @@ class TestingProgressDisplay(object): # Ensure the output is flushed. sys.stdout.flush() +def write_test_results(run, lit_config, testing_time, output_path): + try: + import json + except ImportError: + lit_config.fatal('test output unsupported with Python 2.5') + + # Construct the data we will write. + data = {} + # Encode the current lit version as a schema version. + data['__version__'] = lit.__versioninfo__ + data['elapsed'] = testing_time + # FIXME: Record some information on the lit configuration used? + # FIXME: Record information from the individual test suites? + + # Encode the tests. + data['tests'] = tests_data = [] + for test in run.tests: + test_data = { + 'name' : test.getFullName(), + 'code' : test.result.code.name, + 'output' : test.result.output, + 'elapsed' : test.result.elapsed } + + # Add test metrics, if present. + if test.result.metrics: + test_data['metrics'] = metrics_data = {} + for key, value in test.result.metrics.items(): + metrics_data[key] = value.todata() + + tests_data.append(test_data) + + # Write the output. + f = open(output_path, 'w') + try: + json.dump(data, f, indent=2, sort_keys=True) + f.write('\n') + finally: + f.close() + def main(builtinParameters = {}): # Bump the GIL check interval, its more important to get any one thread to a # blocking operation (hopefully exec) than to try and unblock other threads. @@ -103,6 +142,9 @@ def main(builtinParameters = {}): group.add_option("-v", "--verbose", dest="showOutput", help="Show all test output", action="store_true", default=False) + group.add_option("-o", "--output", dest="output_path", + help="Write test results to the provided path", + action="store", type=str, metavar="PATH") group.add_option("", "--no-progress-bar", dest="useProgressBar", help="Do not use curses based progress bar", action="store_false", default=True) @@ -289,8 +331,13 @@ def main(builtinParameters = {}): sys.exit(2) display.finish() + testing_time = time.time() - startTime if not opts.quiet: - print('Testing Time: %.2fs'%(time.time() - startTime)) + print('Testing Time: %.2fs' % (testing_time,)) + + # Write out the test data, if requested. + if opts.output_path is not None: + write_test_results(run, litConfig, testing_time, opts.output_path) # List test results organized by kind. hasFailures = False diff --git a/utils/lit/tests/Inputs/test-data/metrics.ini b/utils/lit/tests/Inputs/test-data/metrics.ini index 267e516..01b09c5 100644 --- a/utils/lit/tests/Inputs/test-data/metrics.ini +++ b/utils/lit/tests/Inputs/test-data/metrics.ini @@ -1,6 +1,6 @@ [global] result_code = PASS -result_output = 'Test passed.' +result_output = Test passed. [results] value0 = 1 diff --git a/utils/lit/tests/lit.cfg b/utils/lit/tests/lit.cfg index a8d2591..2111b72 100644 --- a/utils/lit/tests/lit.cfg +++ b/utils/lit/tests/lit.cfg @@ -23,7 +23,7 @@ config.excludes = ['Inputs'] config.test_source_root = os.path.dirname(__file__) config.test_exec_root = config.test_source_root -config.target_triple = None +config.target_triple = '(unused)' src_root = os.path.join(config.test_source_root, '..') config.environment['PYTHONPATH'] = src_root @@ -39,3 +39,7 @@ config.substitutions.append(('%{python}', sys.executable)) if lit_config.params.get('check-coverage', None): config.environment['COVERAGE_PROCESS_START'] = os.path.join( os.path.dirname(__file__), ".coveragerc") + +# Add a feature to detect the Python version. +config.available_features.add("python%d.%d" % (sys.version_info[0], + sys.version_info[1])) diff --git a/utils/lit/tests/test-output.py b/utils/lit/tests/test-output.py new file mode 100644 index 0000000..adfbcd8 --- /dev/null +++ b/utils/lit/tests/test-output.py @@ -0,0 +1,21 @@ +# XFAIL: python2.5 + +# RUN: %{lit} -j 1 -v %{inputs}/test-data --output %t.results.out > %t.out +# RUN: FileCheck < %t.results.out %s + +# CHECK: { +# CHECK: "__version__" +# CHECK: "elapsed" +# CHECK-NEXT: "tests": [ +# CHECK-NEXT: { +# CHECK-NEXT: "code": "PASS", +# CHECK-NEXT: "elapsed": {{[0-9.]+}}, +# CHECK-NEXT: "metrics": { +# CHECK-NEXT: "value0": 1, +# CHECK-NEXT: "value1": 2.3456 +# CHECK-NEXT: } +# CHECK-NEXT: "name": "test-data :: metrics.ini", +# CHECK-NEXT: "output": "Test passed." +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } -- cgit v1.1 From 94ee55d4b39d6506cf4e0f4e4b1c0b7fbbfeaed5 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Sun, 15 Sep 2013 22:04:42 +0000 Subject: Replace some unnecessary vector copies with references. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190770 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/RegisterInfoEmitter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index ee417bc..cc08df9 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -121,7 +121,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, OS << "}\n"; } - const std::vector RegAltNameIndices = Target.getRegAltNameIndices(); + const std::vector &RegAltNameIndices = Target.getRegAltNameIndices(); // If the only definition is the default NoRegAltName, we don't need to // emit anything. if (RegAltNameIndices.size() > 1) { -- cgit v1.1 From 280d13f6072e3dca800d19d9b66fa5a7e1d831be Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Mon, 16 Sep 2013 09:25:49 +0000 Subject: Fix the build for git repositories with multiple remotes. Summary: When a git repository had multiple remotes, ${repository} will be set to a multiline string. This causes compilation errors in SVNVersion.inc. Fix this by limiting the output of utils/GetRepositoryPath to the first remote (which is reasonably likely to be 'origin'). Reviewers: jordan_rose CC: llvm-commits, t.p.northover Differential Revision: http://llvm-reviews.chandlerc.com/D1659 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190778 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/GetRepositoryPath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/GetRepositoryPath b/utils/GetRepositoryPath index b915251..2d1122e 100755 --- a/utils/GetRepositoryPath +++ b/utils/GetRepositoryPath @@ -19,7 +19,7 @@ if [ -d .svn ]; then elif [ -f .git/svn/.metadata ]; then git svn info | grep 'URL:' | cut -d: -f2- elif [ -d .git ]; then - git remote -v | grep 'fetch' | awk '{ print $2 }' + git remote -v | grep 'fetch' | awk '{ print $2 }' | head -n1 else exit 1; fi -- cgit v1.1 From 6dd670af758ee111593f81f355325e1b5960b870 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Mon, 16 Sep 2013 16:43:16 +0000 Subject: AsmMatcher: emit subtarget feature enum in deterministic order. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190792 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/AsmMatcherEmitter.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index c827525..0974b94 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -616,7 +616,7 @@ public: RegisterClassesTy RegisterClasses; /// Map of Predicate records to their subtarget information. - std::map SubtargetFeatures; + std::map SubtargetFeatures; /// Map of AsmOperandClass records to their class information. std::map AsmOperandClasses; @@ -666,7 +666,7 @@ public: /// given operand. SubtargetFeatureInfo *getSubtargetFeature(Record *Def) const { assert(Def->isSubClassOf("Predicate") && "Invalid predicate type!"); - std::map::const_iterator I = + std::map::const_iterator I = SubtargetFeatures.find(Def); return I == SubtargetFeatures.end() ? 0 : I->second; } @@ -2189,7 +2189,7 @@ static void emitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info, OS << "// Flags for subtarget features that participate in " << "instruction matching.\n"; OS << "enum SubtargetFeatureFlag {\n"; - for (std::map::const_iterator + for (std::map::const_iterator it = Info.SubtargetFeatures.begin(), ie = Info.SubtargetFeatures.end(); it != ie; ++it) { SubtargetFeatureInfo &SFI = *it->second; @@ -2227,9 +2227,9 @@ static void emitGetSubtargetFeatureName(AsmMatcherInfo &Info, raw_ostream &OS) { << "static const char *getSubtargetFeatureName(unsigned Val) {\n"; if (!Info.SubtargetFeatures.empty()) { OS << " switch(Val) {\n"; - for (std::map::const_iterator - it = Info.SubtargetFeatures.begin(), - ie = Info.SubtargetFeatures.end(); it != ie; ++it) { + typedef std::map RecFeatMap; + for (RecFeatMap::const_iterator it = Info.SubtargetFeatures.begin(), + ie = Info.SubtargetFeatures.end(); it != ie; ++it) { SubtargetFeatureInfo &SFI = *it->second; // FIXME: Totally just a placeholder name to get the algorithm working. OS << " case " << SFI.getEnumName() << ": return \"" @@ -2254,7 +2254,7 @@ static void emitComputeAvailableFeatures(AsmMatcherInfo &Info, OS << "unsigned " << Info.Target.getName() << ClassName << "::\n" << "ComputeAvailableFeatures(uint64_t FB) const {\n"; OS << " unsigned Features = 0;\n"; - for (std::map::const_iterator + for (std::map::const_iterator it = Info.SubtargetFeatures.begin(), ie = Info.SubtargetFeatures.end(); it != ie; ++it) { SubtargetFeatureInfo &SFI = *it->second; -- cgit v1.1 From 03f9197d62dddfb70e70acb5563518f589d29251 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Mon, 16 Sep 2013 16:43:19 +0000 Subject: TableGen: give asm match classes deterministic order. TableGen was sorting the entries in some of its internal data structures by pointer. This order filtered through to the final matching table and affected the diagnostics produced on bad assembly occasionally. It also turns out STL algorithms are ridiculously easy to misuse on containers with custom order methods. (No bugs before, or now that I know of, but plenty in the middle). This should fix the sanitizer bot, which ends up with weird pointers. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190793 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/AsmMatcherEmitter.cpp | 69 ++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 23 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 0974b94..ff04d63 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -125,6 +125,13 @@ namespace { class AsmMatcherInfo; struct SubtargetFeatureInfo; +// Register sets are used as keys in some second-order sets TableGen creates +// when generating its data structures. This means that the order of two +// RegisterSets can be seen in the outputted AsmMatcher tables occasionally, and +// can even affect compiler output (at least seen in diagnostics produced when +// all matches fail). So we use a type that sorts them consistently. +typedef std::set RegisterSet; + class AsmMatcherEmitter { RecordKeeper &Records; public: @@ -185,7 +192,7 @@ struct ClassInfo { std::string ParserMethod; /// For register classes, the records for all the registers in this class. - std::set Registers; + RegisterSet Registers; /// For custom match classes, he diagnostic kind for when the predicate fails. std::string DiagnosticType; @@ -213,11 +220,11 @@ public: if (!isRegisterClass() || !RHS.isRegisterClass()) return false; - std::set Tmp; - std::insert_iterator< std::set > II(Tmp, Tmp.begin()); + RegisterSet Tmp; + std::insert_iterator II(Tmp, Tmp.begin()); std::set_intersection(Registers.begin(), Registers.end(), RHS.Registers.begin(), RHS.Registers.end(), - II); + II, LessRecordByID()); return !Tmp.empty(); } @@ -1057,6 +1064,18 @@ AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) { PrintFatalError(Rec->getLoc(), "operand has no match class!"); } +struct LessRegisterSet { + bool operator() (const RegisterSet &LHS, const RegisterSet & RHS) { + // std::set defines its own compariso "operator<", but it + // performs a lexicographical comparison by T's innate comparison + // for some reason. We don't want non-deterministic pointer + // comparisons so use this instead. + return std::lexicographical_compare(LHS.begin(), LHS.end(), + RHS.begin(), RHS.end(), + LessRecordByID()); + } +}; + void AsmMatcherInfo:: buildRegisterClasses(SmallPtrSet &SingletonRegisters) { const std::vector &Registers = @@ -1064,33 +1083,35 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { ArrayRef RegClassList = Target.getRegBank().getRegClasses(); + typedef std::set RegisterSetSet; + // The register sets used for matching. - std::set< std::set > RegisterSets; + RegisterSetSet RegisterSets; // Gather the defined sets. for (ArrayRef::const_iterator it = - RegClassList.begin(), ie = RegClassList.end(); it != ie; ++it) - RegisterSets.insert(std::set( + RegClassList.begin(), ie = RegClassList.end(); it != ie; ++it) + RegisterSets.insert(RegisterSet( (*it)->getOrder().begin(), (*it)->getOrder().end())); // Add any required singleton sets. for (SmallPtrSet::iterator it = SingletonRegisters.begin(), ie = SingletonRegisters.end(); it != ie; ++it) { Record *Rec = *it; - RegisterSets.insert(std::set(&Rec, &Rec + 1)); + RegisterSets.insert(RegisterSet(&Rec, &Rec + 1)); } // Introduce derived sets where necessary (when a register does not determine // a unique register set class), and build the mapping of registers to the set // they should classify to. - std::map > RegisterMap; + std::map RegisterMap; for (std::vector::const_iterator it = Registers.begin(), ie = Registers.end(); it != ie; ++it) { const CodeGenRegister &CGR = **it; // Compute the intersection of all sets containing this register. - std::set ContainingSet; + RegisterSet ContainingSet; - for (std::set< std::set >::iterator it = RegisterSets.begin(), + for (RegisterSetSet::iterator it = RegisterSets.begin(), ie = RegisterSets.end(); it != ie; ++it) { if (!it->count(CGR.TheDef)) continue; @@ -1100,11 +1121,12 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { continue; } - std::set Tmp; + RegisterSet Tmp; std::swap(Tmp, ContainingSet); - std::insert_iterator< std::set > II(ContainingSet, - ContainingSet.begin()); - std::set_intersection(Tmp.begin(), Tmp.end(), it->begin(), it->end(), II); + std::insert_iterator II(ContainingSet, + ContainingSet.begin()); + std::set_intersection(Tmp.begin(), Tmp.end(), it->begin(), it->end(), II, + LessRecordByID()); } if (!ContainingSet.empty()) { @@ -1114,9 +1136,9 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { } // Construct the register classes. - std::map, ClassInfo*> RegisterSetClasses; + std::map RegisterSetClasses; unsigned Index = 0; - for (std::set< std::set >::iterator it = RegisterSets.begin(), + for (RegisterSetSet::iterator it = RegisterSets.begin(), ie = RegisterSets.end(); it != ie; ++it, ++Index) { ClassInfo *CI = new ClassInfo(); CI->Kind = ClassInfo::RegisterClass0 + Index; @@ -1134,13 +1156,14 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { // Find the superclasses; we could compute only the subgroup lattice edges, // but there isn't really a point. - for (std::set< std::set >::iterator it = RegisterSets.begin(), + for (RegisterSetSet::iterator it = RegisterSets.begin(), ie = RegisterSets.end(); it != ie; ++it) { ClassInfo *CI = RegisterSetClasses[*it]; - for (std::set< std::set >::iterator it2 = RegisterSets.begin(), + for (RegisterSetSet::iterator it2 = RegisterSets.begin(), ie2 = RegisterSets.end(); it2 != ie2; ++it2) if (*it != *it2 && - std::includes(it2->begin(), it2->end(), it->begin(), it->end())) + std::includes(it2->begin(), it2->end(), it->begin(), it->end(), + LessRecordByID())) CI->SuperClasses.push_back(RegisterSetClasses[*it2]); } @@ -1152,8 +1175,8 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { Record *Def = RC.getDef(); if (!Def) continue; - ClassInfo *CI = RegisterSetClasses[std::set(RC.getOrder().begin(), - RC.getOrder().end())]; + ClassInfo *CI = RegisterSetClasses[RegisterSet(RC.getOrder().begin(), + RC.getOrder().end())]; if (CI->ValueName.empty()) { CI->ClassName = RC.getName(); CI->Name = "MCK_" + RC.getName(); @@ -1165,7 +1188,7 @@ buildRegisterClasses(SmallPtrSet &SingletonRegisters) { } // Populate the map for individual registers. - for (std::map >::iterator it = RegisterMap.begin(), + for (std::map::iterator it = RegisterMap.begin(), ie = RegisterMap.end(); it != ie; ++it) RegisterClasses[it->first] = RegisterSetClasses[it->second]; -- cgit v1.1 From 107cfa2169299fe67caebe7d1f0d405ce727e420 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Mon, 16 Sep 2013 17:33:40 +0000 Subject: TableGen: fix constness of new comparison function. libc++ didn't seem to like a non-const call operator. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190797 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/AsmMatcherEmitter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index ff04d63..558090b 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -1065,7 +1065,7 @@ AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) { } struct LessRegisterSet { - bool operator() (const RegisterSet &LHS, const RegisterSet & RHS) { + bool operator() (const RegisterSet &LHS, const RegisterSet & RHS) const { // std::set defines its own compariso "operator<", but it // performs a lexicographical comparison by T's innate comparison // for some reason. We don't want non-deterministic pointer -- cgit v1.1 From 4f67afc3d67d9a68f1b37767c9c2966a775186bd Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Tue, 17 Sep 2013 22:30:02 +0000 Subject: FileCheck refactor: use enum instead of bunch of bools git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190893 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/FileCheck.cpp | 164 ++++++++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 76 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 37c7874..769749e 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -53,18 +53,25 @@ NoCanonicalizeWhiteSpace("strict-whitespace", // Pattern Handling Code. //===----------------------------------------------------------------------===// +namespace Check { + enum CheckType { + CheckNone = 0, + CheckPlain, + CheckNext, + CheckNot, + CheckDAG, + CheckLabel, + + /// MatchEOF - When set, this pattern only matches the end of file. This is + /// used for trailing CHECK-NOTs. + CheckEOF + }; +} + class Pattern { SMLoc PatternLoc; - /// MatchEOF - When set, this pattern only matches the end of file. This is - /// used for trailing CHECK-NOTs. - bool MatchEOF; - - /// MatchNot - bool MatchNot; - - /// MatchDag - bool MatchDag; + Check::CheckType CheckTy; /// FixedStr - If non-empty, this pattern is a fixed string match with the /// specified fixed string. @@ -89,8 +96,8 @@ class Pattern { public: - Pattern(bool matchEOF = false) - : MatchEOF(matchEOF), MatchNot(false), MatchDag(false) { } + Pattern(Check::CheckType Ty) + : CheckTy(Ty) { } /// getLoc - Return the location in source code. SMLoc getLoc() const { return PatternLoc; } @@ -118,11 +125,7 @@ public: bool hasVariable() const { return !(VariableUses.empty() && VariableDefs.empty()); } - void setMatchNot(bool Not) { MatchNot = Not; } - bool getMatchNot() const { return MatchNot; } - - void setMatchDag(bool Dag) { MatchDag = Dag; } - bool getMatchDag() const { return MatchDag; } + Check::CheckType getCheckTy() const { return CheckTy; } private: static void AddFixedStringToRegEx(StringRef FixedStr, std::string &TheStr); @@ -381,7 +384,7 @@ bool Pattern::EvaluateExpression(StringRef Expr, std::string &Value) const { size_t Pattern::Match(StringRef Buffer, size_t &MatchLen, StringMap &VariableTable) const { // If this is the EOF pattern, match it immediately. - if (MatchEOF) { + if (CheckTy == Check::CheckEOF) { MatchLen = 0; return Buffer.size(); } @@ -593,21 +596,17 @@ struct CheckString { /// Loc - The location in the match file that the check string was specified. SMLoc Loc; - /// IsCheckNext - This is true if this is a CHECK-NEXT: directive (as opposed - /// to a CHECK: directive. - bool IsCheckNext; - - /// IsCheckLabel - This is true if this is a CHECK-LABEL: directive (as - /// opposed to a CHECK: directive. - bool IsCheckLabel; + /// CheckTy - Specify what kind of check this is. e.g. CHECK-NEXT: directive, + /// as opposed to a CHECK: directive. + Check::CheckType CheckTy; /// DagNotStrings - These are all of the strings that are disallowed from /// occurring between this match string and the previous one (or start of /// file). std::vector DagNotStrings; - CheckString(const Pattern &P, SMLoc L, bool isCheckNext, bool isCheckLabel) - : Pat(P), Loc(L), IsCheckNext(isCheckNext), IsCheckLabel(isCheckLabel) {} + CheckString(const Pattern &P, SMLoc L, Check::CheckType Ty) + : Pat(P), Loc(L), CheckTy(Ty) {} /// Check - Match check string and its "not strings" and/or "dag strings". size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabel, @@ -666,6 +665,48 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB, return MB2; } +static bool IsPartOfWord(char c) { + return (isalnum(c) || c == '-' || c == '_'); +} + +static Check::CheckType FindCheckType(StringRef &Buffer, StringRef Prefix) { + char NextChar = Buffer[CheckPrefix.size()]; + + // Verify that the : is present after the prefix. + if (NextChar == ':') { + Buffer = Buffer.substr(CheckPrefix.size() + 1); + return Check::CheckPlain; + } + + if (NextChar != '-') { + Buffer = Buffer.drop_front(1); + return Check::CheckNone; + } + + StringRef Rest = Buffer.drop_front(CheckPrefix.size() + 1); + if (Rest.startswith("NEXT:")) { + Buffer = Rest.drop_front(sizeof("NEXT:") - 1); + return Check::CheckNext; + } + + if (Rest.startswith("NOT:")) { + Buffer = Rest.drop_front(sizeof("NOT:") - 1); + return Check::CheckNot; + } + + if (Rest.startswith("DAG:")) { + Buffer = Rest.drop_front(sizeof("DAG:") - 1); + return Check::CheckDAG; + } + + if (Rest.startswith("LABEL:")) { + Buffer = Rest.drop_front(sizeof("LABEL:") - 1); + return Check::CheckLabel; + } + + Buffer = Buffer.drop_front(1); + return Check::CheckNone; +} /// ReadCheckFile - Read the check file, which specifies the sequence of /// expected strings. The strings are added to the CheckStrings vector. @@ -710,46 +751,21 @@ static bool ReadCheckFile(SourceMgr &SM, const char *CheckPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); - // When we find a check prefix, keep track of whether we find CHECK: or - // CHECK-NEXT: - bool IsCheckNext = false, IsCheckNot = false, IsCheckDag = false, - IsCheckLabel = false; - // Make sure we have actually found our prefix, and not a word containing // our prefix. - if (PrefixLoc != 0 && (isalnum(Buffer[0]) || - Buffer[0] == '-' || - Buffer[0] == '_')) { + if (PrefixLoc != 0 && IsPartOfWord(Buffer[0])) { Buffer = Buffer.substr(CheckPrefix.size()); continue; } - // Verify that the : is present after the prefix. - if (Buffer[CheckPrefix.size()] == ':') { - Buffer = Buffer.substr(CheckPrefix.size()+1); - } else if (Buffer.size() > CheckPrefix.size()+6 && - memcmp(Buffer.data()+CheckPrefix.size(), "-NEXT:", 6) == 0) { - Buffer = Buffer.substr(CheckPrefix.size()+6); - IsCheckNext = true; - } else if (Buffer.size() > CheckPrefix.size()+5 && - memcmp(Buffer.data()+CheckPrefix.size(), "-NOT:", 5) == 0) { - Buffer = Buffer.substr(CheckPrefix.size()+5); - IsCheckNot = true; - } else if (Buffer.size() > CheckPrefix.size()+5 && - memcmp(Buffer.data()+CheckPrefix.size(), "-DAG:", 5) == 0) { - Buffer = Buffer.substr(CheckPrefix.size()+5); - IsCheckDag = true; - } else if (Buffer.size() > CheckPrefix.size()+7 && - memcmp(Buffer.data()+CheckPrefix.size(), "-LABEL:", 7) == 0) { - Buffer = Buffer.substr(CheckPrefix.size()+7); - IsCheckLabel = true; - } else { - Buffer = Buffer.substr(1); + // When we find a check prefix, keep track of what kind of type of CHECK we + // have. + Check::CheckType CheckTy = FindCheckType(Buffer, CheckPrefix); + if (CheckTy == Check::CheckNone) continue; - } - // Okay, we found the prefix, yay. Remember the rest of the line, but - // ignore leading and trailing whitespace. + // Okay, we found the prefix, yay. Remember the rest of the line, but ignore + // leading and trailing whitespace. Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); // Scan ahead to the end of line. @@ -759,12 +775,12 @@ static bool ReadCheckFile(SourceMgr &SM, SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); // Parse the pattern. - Pattern P; + Pattern P(CheckTy); if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber)) return true; // Verify that CHECK-LABEL lines do not define or use variables - if (IsCheckLabel && P.hasVariable()) { + if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), SourceMgr::DK_Error, "found '"+CheckPrefix+"-LABEL:' with variable definition" @@ -772,13 +788,10 @@ static bool ReadCheckFile(SourceMgr &SM, return true; } - P.setMatchNot(IsCheckNot); - P.setMatchDag(IsCheckDag); - Buffer = Buffer.substr(EOL); // Verify that CHECK-NEXT lines have at least one CHECK line before them. - if (IsCheckNext && CheckStrings.empty()) { + if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) { SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), SourceMgr::DK_Error, "found '"+CheckPrefix+"-NEXT:' without previous '"+ @@ -787,7 +800,7 @@ static bool ReadCheckFile(SourceMgr &SM, } // Handle CHECK-DAG/-NOT. - if (IsCheckDag || IsCheckNot) { + if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) { DagNotMatches.push_back(P); continue; } @@ -795,17 +808,15 @@ static bool ReadCheckFile(SourceMgr &SM, // Okay, add the string we captured to the output vector and move on. CheckStrings.push_back(CheckString(P, PatternLoc, - IsCheckNext, - IsCheckLabel)); + CheckTy)); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } // Add an EOF pattern for any trailing CHECK-DAG/-NOTs. if (!DagNotMatches.empty()) { - CheckStrings.push_back(CheckString(Pattern(true), + CheckStrings.push_back(CheckString(Pattern(Check::CheckEOF), SMLoc::getFromPointer(Buffer.data()), - false, - false)); + Check::CheckEOF)); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } @@ -902,7 +913,7 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, } bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { - if (!IsCheckNext) + if (CheckTy != Check::CheckNext) return false; // Count the number of newlines between the previous match and this one. @@ -943,7 +954,7 @@ bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, for (unsigned ChunkNo = 0, e = NotStrings.size(); ChunkNo != e; ++ChunkNo) { const Pattern *Pat = NotStrings[ChunkNo]; - assert(Pat->getMatchNot() && "Expect CHECK-NOT!"); + assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!"); size_t MatchLen = 0; size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable); @@ -974,15 +985,16 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, ChunkNo != e; ++ChunkNo) { const Pattern &Pat = DagNotStrings[ChunkNo]; - assert((Pat.getMatchDag() ^ Pat.getMatchNot()) && + assert((Pat.getCheckTy() == Check::CheckDAG || + Pat.getCheckTy() == Check::CheckNot) && "Invalid CHECK-DAG or CHECK-NOT!"); - if (Pat.getMatchNot()) { + if (Pat.getCheckTy() == Check::CheckNot) { NotStrings.push_back(&Pat); continue; } - assert(Pat.getMatchDag() && "Expect CHECK-DAG!"); + assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!"); size_t MatchLen = 0, MatchPos; @@ -1100,7 +1112,7 @@ int main(int argc, char **argv) { CheckRegion = Buffer; } else { const CheckString &CheckLabelStr = CheckStrings[j]; - if (!CheckLabelStr.IsCheckLabel) { + if (CheckLabelStr.CheckTy != Check::CheckLabel) { ++j; continue; } -- cgit v1.1 From 53bb26f61c65b6f63e9aa2950429bb889683bc11 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Tue, 17 Sep 2013 22:45:57 +0000 Subject: Use function's argument instead of the global flag. For now it happens the argument is always the same. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190896 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/FileCheck.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 769749e..c915653 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -670,11 +670,11 @@ static bool IsPartOfWord(char c) { } static Check::CheckType FindCheckType(StringRef &Buffer, StringRef Prefix) { - char NextChar = Buffer[CheckPrefix.size()]; + char NextChar = Buffer[Prefix.size()]; // Verify that the : is present after the prefix. if (NextChar == ':') { - Buffer = Buffer.substr(CheckPrefix.size() + 1); + Buffer = Buffer.substr(Prefix.size() + 1); return Check::CheckPlain; } @@ -683,7 +683,7 @@ static Check::CheckType FindCheckType(StringRef &Buffer, StringRef Prefix) { return Check::CheckNone; } - StringRef Rest = Buffer.drop_front(CheckPrefix.size() + 1); + StringRef Rest = Buffer.drop_front(Prefix.size() + 1); if (Rest.startswith("NEXT:")) { Buffer = Rest.drop_front(sizeof("NEXT:") - 1); return Check::CheckNext; -- cgit v1.1 From c61c8116212c68ebc81a9dc06327d6cc806b1f08 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Tue, 17 Sep 2013 23:15:35 +0000 Subject: Missed using check type enum in one place git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190897 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/FileCheck.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index c915653..120fdd7 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -609,7 +609,7 @@ struct CheckString { : Pat(P), Loc(L), CheckTy(Ty) {} /// Check - Match check string and its "not strings" and/or "dag strings". - size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabel, + size_t Check(const SourceMgr &SM, StringRef Buffer, size_t &MatchLen, StringMap &VariableTable) const; /// CheckNext - Verify there is a single line in the given buffer. @@ -874,12 +874,12 @@ static unsigned CountNumNewlinesBetween(StringRef Range) { } size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, - bool IsLabel, size_t &MatchLen, + size_t &MatchLen, StringMap &VariableTable) const { size_t LastPos = 0; std::vector NotStrings; - if (!IsLabel) { + if (CheckTy != Check::CheckLabel) { // Match "dag strings" (with mixed "not strings" if any). LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable); if (LastPos == StringRef::npos) @@ -895,7 +895,7 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, } MatchPos += LastPos; - if (!IsLabel) { + if (CheckTy != Check::CheckLabel) { StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos); // If this check is a "CHECK-NEXT", verify that the previous match was on @@ -1119,7 +1119,7 @@ int main(int argc, char **argv) { // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG size_t MatchLabelLen = 0; - size_t MatchLabelPos = CheckLabelStr.Check(SM, Buffer, true, + size_t MatchLabelPos = CheckLabelStr.Check(SM, Buffer, MatchLabelLen, VariableTable); if (MatchLabelPos == StringRef::npos) { hasError = true; @@ -1137,7 +1137,7 @@ int main(int argc, char **argv) { // Check each string within the scanned region, including a second check // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) size_t MatchLen = 0; - size_t MatchPos = CheckStr.Check(SM, CheckRegion, false, MatchLen, + size_t MatchPos = CheckStr.Check(SM, CheckRegion, MatchLen, VariableTable); if (MatchPos == StringRef::npos) { -- cgit v1.1 From 0d293e45b66c742fdbc3998209bb20ed6c5806bf Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Sun, 22 Sep 2013 14:09:50 +0000 Subject: Provide basic type safety for array_pod_sort comparators. This makes using array_pod_sort significantly safer. The implementation relies on function pointer casting but that should be safe as we're dealing with void* here. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191175 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenRegisters.cpp | 7 ++++--- utils/TableGen/OptParserEmitter.cpp | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp index 43de2be..f2eef4f 100644 --- a/utils/TableGen/CodeGenRegisters.cpp +++ b/utils/TableGen/CodeGenRegisters.cpp @@ -813,9 +813,10 @@ static bool testSubClass(const CodeGenRegisterClass *A, /// Register classes with the same registers, spill size, and alignment form a /// clique. They will be ordered alphabetically. /// -static int TopoOrderRC(const void *PA, const void *PB) { - const CodeGenRegisterClass *A = *(const CodeGenRegisterClass* const*)PA; - const CodeGenRegisterClass *B = *(const CodeGenRegisterClass* const*)PB; +static int TopoOrderRC(CodeGenRegisterClass *const *PA, + CodeGenRegisterClass *const *PB) { + const CodeGenRegisterClass *A = *PA; + const CodeGenRegisterClass *B = *PB; if (A == B) return 0; diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp index 7fb7d65..cff004f 100644 --- a/utils/TableGen/OptParserEmitter.cpp +++ b/utils/TableGen/OptParserEmitter.cpp @@ -41,9 +41,9 @@ static int StrCmpOptionName(const char *A, const char *B) { return (a < b) ? -1 : 1; } -static int CompareOptionRecords(const void *Av, const void *Bv) { - const Record *A = *(const Record*const*) Av; - const Record *B = *(const Record*const*) Bv; +static int CompareOptionRecords(Record *const *Av, Record *const *Bv) { + const Record *A = *Av; + const Record *B = *Bv; // Sentinel options precede all others and are only ordered by precedence. bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel"); -- cgit v1.1 From cf458e91da31339f62130a1456f01d359ad433cb Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Sun, 22 Sep 2013 23:18:50 +0000 Subject: Add missing index comments to the left side of the DAG ISel matcher table for each individual case of SwitchOpcode/Type. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191181 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/DAGISelMatcherEmitter.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp index 93f84ce..ba1b358 100644 --- a/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -315,10 +315,12 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, assert(ChildSize != 0 && "Should not have a zero-sized child!"); if (i != 0) { + if (!OmitComments) + OS << "/*" << CurrentIdx << "*/"; OS.PadToColumn(Indent*2); if (!OmitComments) - OS << (isa(N) ? - "/*SwitchOpcode*/ " : "/*SwitchType*/ "); + OS << (isa(N) ? + "/*SwitchOpcode*/ " : "/*SwitchType*/ "); } // Emit the VBR. @@ -340,6 +342,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, } // Emit the final zero to terminate the switch. + if (!OmitComments) + OS << "/*" << CurrentIdx << "*/"; OS.PadToColumn(Indent*2) << "0, "; if (!OmitComments) OS << (isa(N) ? -- cgit v1.1 From 477fc628b3c9ce1c970d4a678dd5607b15242cc8 Mon Sep 17 00:00:00 2001 From: Jiangning Liu Date: Tue, 24 Sep 2013 02:47:27 +0000 Subject: Initial support for Neon scalar instructions. Patch by Ana Pazos. 1.Added support for v1ix and v1fx types. 2.Added Scalar Pairwise Reduce instructions. 3.Added initial implementation of Scalar Arithmetic instructions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191263 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenTarget.cpp | 3 +++ utils/TableGen/IntrinsicEmitter.cpp | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index 72fa9ec..c8290da 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -75,6 +75,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v16i1: return "MVT::v16i1"; case MVT::v32i1: return "MVT::v32i1"; case MVT::v64i1: return "MVT::v64i1"; + case MVT::v1i8: return "MVT::v1i8"; case MVT::v2i8: return "MVT::v2i8"; case MVT::v4i8: return "MVT::v4i8"; case MVT::v8i8: return "MVT::v8i8"; @@ -99,10 +100,12 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v16i64: return "MVT::v16i64"; case MVT::v2f16: return "MVT::v2f16"; case MVT::v8f16: return "MVT::v8f16"; + case MVT::v1f32: return "MVT::v1f32"; case MVT::v2f32: return "MVT::v2f32"; case MVT::v4f32: return "MVT::v4f32"; case MVT::v8f32: return "MVT::v8f32"; case MVT::v16f32: return "MVT::v16f32"; + case MVT::v1f64: return "MVT::v1f64"; case MVT::v2f64: return "MVT::v2f64"; case MVT::v4f64: return "MVT::v4f64"; case MVT::v8f64: return "MVT::v8f64"; diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index c508795..f6ea69c 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -260,7 +260,8 @@ enum IIT_Info { IIT_STRUCT5 = 22, IIT_EXTEND_VEC_ARG = 23, IIT_TRUNC_VEC_ARG = 24, - IIT_ANYPTR = 25 + IIT_ANYPTR = 25, + IIT_V1 = 26 }; @@ -350,6 +351,7 @@ static void EncodeFixedType(Record *R, std::vector &ArgCodes, EVT VVT = VT; switch (VVT.getVectorNumElements()) { default: PrintFatalError("unhandled vector type width in intrinsic!"); + case 1: Sig.push_back(IIT_V1); break; case 2: Sig.push_back(IIT_V2); break; case 4: Sig.push_back(IIT_V4); break; case 8: Sig.push_back(IIT_V8); break; -- cgit v1.1 From fb2d8e137e8f19bd638aff07d507e26849e31dbc Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Tue, 24 Sep 2013 06:21:04 +0000 Subject: Fix formatting to match coding standards. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191280 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenDAGPatterns.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index ee025a0..67cefb4 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -397,8 +397,7 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { Other.getName() +"'!"); return false; } - } - else + } else // For scalar types, the bitsize of this type must be larger // than that of the other. if (Type.getSizeInBits() >= OtherType.getSizeInBits()) { @@ -450,8 +449,7 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { MadeChange = true; continue; } - } - else if (isFloatingPoint(*TVI)) { + } else if (isFloatingPoint(*TVI)) { ++OtherFPSize; if (*TVI == SmallestFP) { TVI = Other.TypeVec.erase(TVI); @@ -465,8 +463,8 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { // If this is the only type in the large set, the constraint can never be // satisfied. - if ((Other.hasIntegerTypes() && OtherIntSize == 0) - || (Other.hasFloatingPointTypes() && OtherFPSize == 0)) { + if ((Other.hasIntegerTypes() && OtherIntSize == 0) || + (Other.hasFloatingPointTypes() && OtherFPSize == 0)) { TP.error("Type inference contradiction found, '" + Other.getName() + "' has nothing larger than '" + getName() +"'!"); return false; @@ -508,8 +506,7 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { MadeChange = true; continue; } - } - else if (isFloatingPoint(*TVI)) { + } else if (isFloatingPoint(*TVI)) { ++FPSize; if (*TVI == LargestFP) { TVI = TypeVec.erase(TVI); @@ -523,8 +520,8 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { // If this is the only type in the small set, the constraint can never be // satisfied. - if ((hasIntegerTypes() && IntSize == 0) - || (hasFloatingPointTypes() && FPSize == 0)) { + if ((hasIntegerTypes() && IntSize == 0) || + (hasFloatingPointTypes() && FPSize == 0)) { TP.error("Type inference contradiction found, '" + getName() + "' has nothing smaller than '" + Other.getName()+"'!"); return false; -- cgit v1.1 From 33300d91b66a86fc39482dd262fb735ca54d92e1 Mon Sep 17 00:00:00 2001 From: Stepan Dyatkovskiy Date: Tue, 24 Sep 2013 20:06:31 +0000 Subject: Patch that forces MergeFunctions pass for clang. It is temporary patch. We need to keep it in trunk, since it makes easer to test it on buildbots on different platforms. Once we see stable MergeFunctions behaviour with satisfied perfomance, this patch will be removed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191331 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/Misc/mergefunctions.clang.svn.patch | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 utils/Misc/mergefunctions.clang.svn.patch (limited to 'utils') diff --git a/utils/Misc/mergefunctions.clang.svn.patch b/utils/Misc/mergefunctions.clang.svn.patch new file mode 100644 index 0000000..6e2f0f5 --- /dev/null +++ b/utils/Misc/mergefunctions.clang.svn.patch @@ -0,0 +1,14 @@ +Index: lib/CodeGen/BackendUtil.cpp +=================================================================== +--- lib/CodeGen/BackendUtil.cpp (revision 191330) ++++ lib/CodeGen/BackendUtil.cpp (working copy) +@@ -336,6 +336,9 @@ + MPM->add(createStripSymbolsPass(true)); + } + ++ // Force MergeFunctions pass. ++ MPM->add(createMergeFunctionsPass()); ++ + PMBuilder.populateModulePassManager(*MPM); + } + -- cgit v1.1 From 49909415ca9c674a459718895e8e99053e11f143 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Wed, 25 Sep 2013 06:37:18 +0000 Subject: Replace EVT with MVT in CodeGenDAGAPatterns.cpp. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191355 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenDAGPatterns.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index 67cefb4..4396297 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -30,16 +30,16 @@ using namespace llvm; //===----------------------------------------------------------------------===// static inline bool isInteger(MVT::SimpleValueType VT) { - return EVT(VT).isInteger(); + return MVT(VT).isInteger(); } static inline bool isFloatingPoint(MVT::SimpleValueType VT) { - return EVT(VT).isFloatingPoint(); + return MVT(VT).isFloatingPoint(); } static inline bool isVector(MVT::SimpleValueType VT) { - return EVT(VT).isVector(); + return MVT(VT).isVector(); } static inline bool isScalar(MVT::SimpleValueType VT) { - return !EVT(VT).isVector(); + return !MVT(VT).isVector(); } EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) { @@ -385,8 +385,8 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { // Otherwise, if these are both vector types, either this vector // must have a larger bitsize than the other, or this element type // must be larger than the other. - EVT Type(TypeVec[0]); - EVT OtherType(Other.TypeVec[0]); + MVT Type(TypeVec[0]); + MVT OtherType(Other.TypeVec[0]); if (hasVectorTypes() && Other.hasVectorTypes()) { if (Type.getSizeInBits() >= OtherType.getSizeInBits()) @@ -544,10 +544,10 @@ bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand, // If we know the vector type, it forces the scalar to agree. if (isConcrete()) { - EVT IVT = getConcrete(); + MVT IVT = getConcrete(); IVT = IVT.getVectorElementType(); return MadeChange | - VTOperand.MergeInTypeInfo(IVT.getSimpleVT().SimpleTy, TP); + VTOperand.MergeInTypeInfo(IVT.SimpleTy, TP); } // If the scalar type is known, filter out vector types whose element types @@ -562,7 +562,7 @@ bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand, // Filter out all the types which don't have the right element type. for (unsigned i = 0; i != TypeVec.size(); ++i) { assert(isVector(TypeVec[i]) && "EnforceVector didn't work"); - if (EVT(TypeVec[i]).getVectorElementType().getSimpleVT().SimpleTy != VT) { + if (MVT(TypeVec[i]).getVectorElementType().SimpleTy != VT) { TypeVec.erase(TypeVec.begin()+i--); MadeChange = true; } @@ -590,16 +590,16 @@ bool EEVT::TypeSet::EnforceVectorSubVectorTypeIs(EEVT::TypeSet &VTOperand, // If we know the vector type, it forces the scalar types to agree. if (isConcrete()) { - EVT IVT = getConcrete(); + MVT IVT = getConcrete(); IVT = IVT.getVectorElementType(); - EEVT::TypeSet EltTypeSet(IVT.getSimpleVT().SimpleTy, TP); + EEVT::TypeSet EltTypeSet(IVT.SimpleTy, TP); MadeChange |= VTOperand.EnforceVectorEltTypeIs(EltTypeSet, TP); } else if (VTOperand.isConcrete()) { - EVT IVT = VTOperand.getConcrete(); + MVT IVT = VTOperand.getConcrete(); IVT = IVT.getVectorElementType(); - EEVT::TypeSet EltTypeSet(IVT.getSimpleVT().SimpleTy, TP); + EEVT::TypeSet EltTypeSet(IVT.SimpleTy, TP); MadeChange |= EnforceVectorEltTypeIs(EltTypeSet, TP); } @@ -1519,7 +1519,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { if (VT == MVT::iPTR || VT == MVT::iPTRAny) return MadeChange; - unsigned Size = EVT(VT).getSizeInBits(); + unsigned Size = MVT(VT).getSizeInBits(); // Make sure that the value is representable for this type. if (Size >= 32) return MadeChange; -- cgit v1.1 From 78099d11ffffee2f01fd06fc8d0904858acd5047 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Wed, 25 Sep 2013 06:40:22 +0000 Subject: Fix doxygen comments to use correct function name. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191356 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/DAGISelMatcher.cpp | 2 +- utils/TableGen/DAGISelMatcher.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp index d173cf0..af0eb97 100644 --- a/utils/TableGen/DAGISelMatcher.cpp +++ b/utils/TableGen/DAGISelMatcher.cpp @@ -63,7 +63,7 @@ bool Matcher::canMoveBefore(const Matcher *Other) const { } } -/// canMoveBefore - Return true if it is safe to move the current matcher +/// canMoveBeforeNode - Return true if it is safe to move the current matcher /// across the specified one. bool Matcher::canMoveBeforeNode(const Matcher *Other) const { // We can move simple predicates before record nodes. diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h index f978188..ebac790 100644 --- a/utils/TableGen/DAGISelMatcher.h +++ b/utils/TableGen/DAGISelMatcher.h @@ -154,7 +154,7 @@ public: /// node. Other must be equal to or before this. bool canMoveBefore(const Matcher *Other) const; - /// canMoveBefore - Return true if it is safe to move the current matcher + /// canMoveBeforeNode - Return true if it is safe to move the current matcher /// across the specified one. bool canMoveBeforeNode(const Matcher *Other) const; -- cgit v1.1 From 070156437752179833b1e5fddd50caa03fd7c12f Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Wed, 25 Sep 2013 18:14:12 +0000 Subject: Mark the x86 machine model as incomplete. PR17367. Ideally, the machinel model is added at the time the instructions are defined. But many instructions in X86InstrSSE.td still need a model. Without this workaround the scheduler asserts because x86 already has itinerary classes for these instructions, indicating they should be modeled by the scheduler. Since we use the new machine model for other instructions, it expects a new machine model for these too. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191391 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/SubtargetEmitter.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'utils') diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 81bb6f8..b9f9d06 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -1198,6 +1198,11 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ','); EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ','); EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ','); + + OS << " " << (bool)(PI->ModelDef ? + PI->ModelDef->getValueAsBit("CompleteModel") : 0) + << ", // " << "CompleteModel\n"; + OS << " " << PI->Index << ", // Processor ID\n"; if (PI->hasInstrSchedModel()) OS << " " << PI->ModelName << "ProcResources" << ",\n" -- cgit v1.1 From 92b45819531966f2d1365ab3564342a561f3b949 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 30 Sep 2013 02:46:36 +0000 Subject: Various x86 disassembler fixes. Add VEX_LIG to scalar FMA4 instructions. Use VEX_LIG in some of the inheriting checks in disassembler table generator. Make use of VEX_L_W, VEX_L_W_XS, VEX_L_W_XD contexts. Don't let VEX_L_W, VEX_L_W_XS, VEX_L_W_XD, VEX_L_W_OPSIZE inherit from their non-L forms unless VEX_LIG is set. Let VEX_L_W, VEX_L_W_XS, VEX_L_W_XD, VEX_L_W_OPSIZE inherit from all of their non-L or non-W cases. Increase ranking on VEX_L_W, VEX_L_W_XS, VEX_L_W_XD, VEX_L_W_OPSIZE so they get chosen over non-L/non-W forms. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191649 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86DisassemblerTables.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index 0838ac4..db0964f 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -81,31 +81,37 @@ static inline bool inheritsFrom(InstructionContext child, case IC_64BIT_REXW_OPSIZE: return false; case IC_VEX: - return inheritsFrom(child, IC_VEX_L_W) || + return (VEX_LIG && inheritsFrom(child, IC_VEX_L_W)) || inheritsFrom(child, IC_VEX_W) || (VEX_LIG && inheritsFrom(child, IC_VEX_L)); case IC_VEX_XS: - return inheritsFrom(child, IC_VEX_L_W_XS) || + return (VEX_LIG && inheritsFrom(child, IC_VEX_L_W_XS)) || inheritsFrom(child, IC_VEX_W_XS) || (VEX_LIG && inheritsFrom(child, IC_VEX_L_XS)); case IC_VEX_XD: - return inheritsFrom(child, IC_VEX_L_W_XD) || + return (VEX_LIG && inheritsFrom(child, IC_VEX_L_W_XD)) || inheritsFrom(child, IC_VEX_W_XD) || (VEX_LIG && inheritsFrom(child, IC_VEX_L_XD)); case IC_VEX_OPSIZE: - return inheritsFrom(child, IC_VEX_L_W_OPSIZE) || + return (VEX_LIG && inheritsFrom(child, IC_VEX_L_W_OPSIZE)) || inheritsFrom(child, IC_VEX_W_OPSIZE) || (VEX_LIG && inheritsFrom(child, IC_VEX_L_OPSIZE)); case IC_VEX_W: + return VEX_LIG && inheritsFrom(child, IC_VEX_L_W); case IC_VEX_W_XS: + return VEX_LIG && inheritsFrom(child, IC_VEX_L_W_XS); case IC_VEX_W_XD: + return VEX_LIG && inheritsFrom(child, IC_VEX_L_W_XD); case IC_VEX_W_OPSIZE: - return false; + return VEX_LIG && inheritsFrom(child, IC_VEX_L_W_OPSIZE); case IC_VEX_L: + return inheritsFrom(child, IC_VEX_L_W); case IC_VEX_L_XS: + return inheritsFrom(child, IC_VEX_L_W_XS); case IC_VEX_L_XD: + return inheritsFrom(child, IC_VEX_L_W_XD); case IC_VEX_L_OPSIZE: - return false; + return inheritsFrom(child, IC_VEX_L_W_OPSIZE); case IC_VEX_L_W: case IC_VEX_L_W_XS: case IC_VEX_L_W_XD: @@ -622,6 +628,12 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const { if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_OPSIZE)) o << "IC_VEX_L_W_OPSIZE"; + else if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_XD)) + o << "IC_VEX_L_W_XD"; + else if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_XS)) + o << "IC_VEX_L_W_XS"; + else if ((index & ATTR_VEXL) && (index & ATTR_REXW)) + o << "IC_VEX_L_W"; else if ((index & ATTR_VEXL) && (index & ATTR_OPSIZE)) o << "IC_VEX_L_OPSIZE"; else if ((index & ATTR_VEXL) && (index & ATTR_XD)) -- cgit v1.1 From 39004b537beb1acc26675c8943c2cce4ca8a0499 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 30 Sep 2013 06:23:19 +0000 Subject: Filter out repeated sections from the X86 disassembler modRMTable. Saves about ~43K from a released build. Unfortunately the disassembler tables are still upwards of 800K. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191652 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86DisassemblerTables.cpp | 99 +++++++++++++++----------------- utils/TableGen/X86DisassemblerTables.h | 55 +++++++----------- 2 files changed, 67 insertions(+), 87 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index db0964f..98a4797 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -265,35 +265,6 @@ static inline const char* stringForOperandEncoding(OperandEncoding encoding) { } } -void DisassemblerTables::emitOneID(raw_ostream &o, unsigned &i, InstrUID id, - bool addComma) const { - if (id) - o.indent(i * 2) << format("0x%hx", id); - else - o.indent(i * 2) << 0; - - if (addComma) - o << ", "; - else - o << " "; - - o << "/* "; - o << InstructionSpecifiers[id].name; - o << "*/"; - - o << "\n"; -} - -/// emitEmptyTable - Emits the modRMEmptyTable, which is used as a ID table by -/// all ModR/M decisions for instructions that are invalid for all possible -/// ModR/M byte values. -/// -/// @param o - The output stream on which to emit the table. -/// @param i - The indentation level for that output stream. -static void emitEmptyTable(raw_ostream &o, unsigned &i) { - o.indent(i * 2) << "0x0, /* EmptyTable */\n"; -} - /// getDecisionType - Determines whether a ModRM decision with 255 entries can /// be compacted by eliminating redundant information. /// @@ -393,6 +364,7 @@ DisassemblerTables::~DisassemblerTables() { void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2, unsigned &i1, unsigned &i2, + unsigned &ModRMTableNum, ModRMDecision &decision) const { static uint32_t sTableNumber = 0; static uint32_t sEntryNumber = 1; @@ -411,44 +383,56 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2, return; } - o1 << "/* Table" << sTableNumber << " */\n"; - i1++; + std::vector ModRMDecision; switch (dt) { default: llvm_unreachable("Unknown decision type"); case MODRM_ONEENTRY: - emitOneID(o1, i1, decision.instructionIDs[0], true); + ModRMDecision.push_back(decision.instructionIDs[0]); break; case MODRM_SPLITRM: - emitOneID(o1, i1, decision.instructionIDs[0x00], true); // mod = 0b00 - emitOneID(o1, i1, decision.instructionIDs[0xc0], true); // mod = 0b11 + ModRMDecision.push_back(decision.instructionIDs[0x00]); + ModRMDecision.push_back(decision.instructionIDs[0xc0]); break; case MODRM_SPLITREG: for (unsigned index = 0; index < 64; index += 8) - emitOneID(o1, i1, decision.instructionIDs[index], true); + ModRMDecision.push_back(decision.instructionIDs[index]); for (unsigned index = 0xc0; index < 256; index += 8) - emitOneID(o1, i1, decision.instructionIDs[index], true); + ModRMDecision.push_back(decision.instructionIDs[index]); break; case MODRM_SPLITMISC: for (unsigned index = 0; index < 64; index += 8) - emitOneID(o1, i1, decision.instructionIDs[index], true); + ModRMDecision.push_back(decision.instructionIDs[index]); for (unsigned index = 0xc0; index < 256; ++index) - emitOneID(o1, i1, decision.instructionIDs[index], true); + ModRMDecision.push_back(decision.instructionIDs[index]); break; case MODRM_FULL: for (unsigned index = 0; index < 256; ++index) - emitOneID(o1, i1, decision.instructionIDs[index], true); + ModRMDecision.push_back(decision.instructionIDs[index]); break; } - i1--; + unsigned &EntryNumber = ModRMTable[ModRMDecision]; + if (EntryNumber == 0) { + EntryNumber = ModRMTableNum; + + ModRMTableNum += ModRMDecision.size(); + o1 << "/* Table" << EntryNumber << " */\n"; + i1++; + for (std::vector::const_iterator I = ModRMDecision.begin(), + E = ModRMDecision.end(); I != E; ++I) { + o1.indent(i1 * 2) << format("0x%hx", *I) << ", /* " + << InstructionSpecifiers[*I].name << " */\n"; + } + i1--; + } o2.indent(i2) << "{ /* struct ModRMDecision */" << "\n"; i2++; o2.indent(i2) << stringForDecisionType(dt) << "," << "\n"; - o2.indent(i2) << sEntryNumber << " /* Table" << sTableNumber << " */\n"; + o2.indent(i2) << EntryNumber << " /* Table" << EntryNumber << " */\n"; i2--; o2.indent(i2) << "}"; @@ -482,6 +466,7 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2, void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2, unsigned &i1, unsigned &i2, + unsigned &ModRMTableNum, OpcodeDecision &decision) const { o2.indent(i2) << "{ /* struct OpcodeDecision */" << "\n"; i2++; @@ -493,7 +478,8 @@ void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2, o2 << "/* 0x" << format("%02hhx", index) << " */" << "\n"; - emitModRMDecision(o1, o2, i1, i2, decision.modRMDecisions[index]); + emitModRMDecision(o1, o2, i1, i2, ModRMTableNum, + decision.modRMDecisions[index]); if (index < 255) o2 << ","; @@ -509,6 +495,7 @@ void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2, void DisassemblerTables::emitContextDecision(raw_ostream &o1, raw_ostream &o2, unsigned &i1, unsigned &i2, + unsigned &ModRMTableNum, ContextDecision &decision, const char* name) const { o2.indent(i2) << "static const struct ContextDecision " << name << " = {\n"; @@ -522,7 +509,8 @@ void DisassemblerTables::emitContextDecision(raw_ostream &o1, raw_ostream &o2, o2 << " */"; o2 << "\n"; - emitOpcodeDecision(o1, o2, i1, i2, decision.opcodeDecisions[index]); + emitOpcodeDecision(o1, o2, i1, i2, ModRMTableNum, + decision.opcodeDecisions[index]); if (index + 1 < IC_max) o2 << ", "; @@ -711,13 +699,14 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const { } void DisassemblerTables::emitContextDecisions(raw_ostream &o1, raw_ostream &o2, - unsigned &i1, unsigned &i2) const { - emitContextDecision(o1, o2, i1, i2, *Tables[0], ONEBYTE_STR); - emitContextDecision(o1, o2, i1, i2, *Tables[1], TWOBYTE_STR); - emitContextDecision(o1, o2, i1, i2, *Tables[2], THREEBYTE38_STR); - emitContextDecision(o1, o2, i1, i2, *Tables[3], THREEBYTE3A_STR); - emitContextDecision(o1, o2, i1, i2, *Tables[4], THREEBYTEA6_STR); - emitContextDecision(o1, o2, i1, i2, *Tables[5], THREEBYTEA7_STR); + unsigned &i1, unsigned &i2, + unsigned &ModRMTableNum) const { + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[0], ONEBYTE_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[1], TWOBYTE_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[2], THREEBYTE38_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[3], THREEBYTE3A_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[4], THREEBYTEA6_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[5], THREEBYTEA7_STR); } void DisassemblerTables::emit(raw_ostream &o) const { @@ -736,11 +725,17 @@ void DisassemblerTables::emit(raw_ostream &o) const { emitContextTable(o, i2); o << "\n"; + unsigned ModRMTableNum = 0; + o << "static const InstrUID modRMTable[] = {\n"; i1++; - emitEmptyTable(o1, i1); + std::vector EmptyTable(1, 0); + ModRMTable[EmptyTable] = ModRMTableNum; + ModRMTableNum += EmptyTable.size(); + o1 << "/* EmptyTable */\n"; + o1.indent(i1 * 2) << "0x0,\n"; i1--; - emitContextDecisions(o1, o2, i1, i2); + emitContextDecisions(o1, o2, i1, i2, ModRMTableNum); o << o1.str(); o << " 0x0\n"; diff --git a/utils/TableGen/X86DisassemblerTables.h b/utils/TableGen/X86DisassemblerTables.h index 01aeaaf..3861b74 100644 --- a/utils/TableGen/X86DisassemblerTables.h +++ b/utils/TableGen/X86DisassemblerTables.h @@ -20,6 +20,7 @@ #include "X86DisassemblerShared.h" #include "X86ModRMFilters.h" #include "llvm/Support/raw_ostream.h" +#include #include namespace llvm { @@ -41,28 +42,16 @@ private: /// [5] three-byte opcodes of the form 0f a7 __ ContextDecision* Tables[6]; + // Table of ModRM encodings. + typedef std::map, unsigned> ModRMMapTy; + mutable ModRMMapTy ModRMTable; + /// The instruction information table std::vector InstructionSpecifiers; /// True if there are primary decode conflicts in the instruction set bool HasConflicts; - /// emitOneID - Emits a table entry for a single instruction entry, at the - /// innermost level of the structure hierarchy. The entry is printed out - /// in the format "nnnn, /* MNEMONIC */" where nnnn is the ID in decimal, - /// the comma is printed if addComma is true, and the menonic is the name - /// of the instruction as listed in the LLVM tables. - /// - /// @param o - The output stream to print the entry on. - /// @param i - The indentation level for o. - /// @param id - The unique ID of the instruction to print. - /// @param addComma - Whether or not to print a comma after the ID. True if - /// additional items will follow. - void emitOneID(raw_ostream &o, - uint32_t &i, - InstrUID id, - bool addComma) const; - /// emitModRMDecision - Emits a table of entries corresponding to a single /// ModR/M decision. Compacts the ModR/M decision if possible. ModR/M /// decisions are printed as: @@ -91,12 +80,11 @@ private: /// @param o2 - The output stream to print the decision structure to. /// @param i1 - The indentation level to use with stream o1. /// @param i2 - The indentation level to use with stream o2. + /// @param ModRMTableNum - next table number for adding to ModRMTable. /// @param decision - The ModR/M decision to emit. This decision has 256 /// entries - emitModRMDecision decides how to compact it. - void emitModRMDecision(raw_ostream &o1, - raw_ostream &o2, - uint32_t &i1, - uint32_t &i2, + void emitModRMDecision(raw_ostream &o1, raw_ostream &o2, + unsigned &i1, unsigned &i2, unsigned &ModRMTableNum, ModRMDecision &decision) const; /// emitOpcodeDecision - Emits an OpcodeDecision and all its subsidiary ModR/M @@ -120,12 +108,11 @@ private: /// @param o2 - The output stream for the decision structure itself. /// @param i1 - The indent level to use with stream o1. /// @param i2 - The indent level to use with stream o2. + /// @param ModRMTableNum - next table number for adding to ModRMTable. /// @param decision - The OpcodeDecision to emit along with its subsidiary /// structures. - void emitOpcodeDecision(raw_ostream &o1, - raw_ostream &o2, - uint32_t &i1, - uint32_t &i2, + void emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2, + unsigned &i1, unsigned &i2, unsigned &ModRMTableNum, OpcodeDecision &decision) const; /// emitContextDecision - Emits a ContextDecision and all its subsidiary @@ -155,15 +142,13 @@ private: /// @param o2 - The output stream to print the decision structure to. /// @param i1 - The indent level to use with stream o1. /// @param i2 - The indent level to use with stream o2. + /// @param ModRMTableNum - next table number for adding to ModRMTable. /// @param decision - The ContextDecision to emit along with its subsidiary /// structures. /// @param name - The name for the ContextDecision. - void emitContextDecision(raw_ostream &o1, - raw_ostream &o2, - uint32_t &i1, - uint32_t &i2, - ContextDecision &decision, - const char* name) const; + void emitContextDecision(raw_ostream &o1, raw_ostream &o2, + unsigned &i1, unsigned &i2, unsigned &ModRMTableNum, + ContextDecision &decision, const char* name) const; /// emitInstructionInfo - Prints the instruction specifier table, which has /// one entry for each instruction, and contains name and operand @@ -194,7 +179,7 @@ private: /// @param o - The output stream to which the instruction table should be /// written. /// @param i - The indent level for use with the stream. - void emitInstructionInfo(raw_ostream &o, uint32_t &i) const; + void emitInstructionInfo(raw_ostream &o, unsigned &i) const; /// emitContextTable - Prints the table that is used to translate from an /// instruction attribute mask to an instruction context. This table is @@ -220,10 +205,10 @@ private: /// @param o2 - The output stream to print the decision structures to. /// @param i1 - The indent level to use with stream o1. /// @param i2 - The indent level to use with stream o2. - void emitContextDecisions(raw_ostream &o1, - raw_ostream &o2, - uint32_t &i1, - uint32_t &i2) const; + /// @param ModRMTableNum - next table number for adding to ModRMTable. + void emitContextDecisions(raw_ostream &o1, raw_ostream &o2, + unsigned &i1, unsigned &i2, + unsigned &ModRMTableNum) const; /// setTableFields - Uses a ModRMFilter to set the appropriate entries in a /// ModRMDecision to refer to a particular instruction ID. -- cgit v1.1 From 737ca5f7ab631411ff9bd5b3fdd86b6cb17180fb Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 1 Oct 2013 09:49:01 +0000 Subject: Fix pattern sort in DAGISelEmitter.cpp The old code skipped one of the sorting criteria if either pattern had no types. This could lead to cycles of the form X < Y, Y < Z, Z < X. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191735 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/DAGISelEmitter.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp index b47dd71..a76ea32 100644 --- a/utils/TableGen/DAGISelEmitter.cpp +++ b/utils/TableGen/DAGISelEmitter.cpp @@ -81,15 +81,13 @@ struct PatternSortingPredicate { const TreePatternNode *LHSSrc = LHS->getSrcPattern(); const TreePatternNode *RHSSrc = RHS->getSrcPattern(); - if (LHSSrc->getNumTypes() != 0 && RHSSrc->getNumTypes() != 0 && - LHSSrc->getType(0) != RHSSrc->getType(0)) { - MVT::SimpleValueType V1 = LHSSrc->getType(0), V2 = RHSSrc->getType(0); - if (MVT(V1).isVector() != MVT(V2).isVector()) - return MVT(V2).isVector(); - - if (MVT(V1).isFloatingPoint() != MVT(V2).isFloatingPoint()) - return MVT(V2).isFloatingPoint(); - } + MVT LHSVT = (LHSSrc->getNumTypes() != 0 ? LHSSrc->getType(0) : MVT::Other); + MVT RHSVT = (RHSSrc->getNumTypes() != 0 ? RHSSrc->getType(0) : MVT::Other); + if (LHSVT.isVector() != RHSVT.isVector()) + return RHSVT.isVector(); + + if (LHSVT.isFloatingPoint() != RHSVT.isFloatingPoint()) + return RHSVT.isFloatingPoint(); // Otherwise, if the patterns might both match, sort based on complexity, // which means that we prefer to match patterns that cover more nodes in the -- cgit v1.1 From 8819c84aed10777ba91d4e862229882b8da0b272 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Tue, 1 Oct 2013 13:32:03 +0000 Subject: Remove several unused variables. Patch by Alp Toker. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191757 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/AsmMatcherEmitter.cpp | 9 --------- utils/TableGen/AsmWriterEmitter.cpp | 1 - utils/TableGen/CodeGenMapTable.cpp | 1 - utils/TableGen/FixedLenDecoderEmitter.cpp | 1 - 4 files changed, 12 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 558090b..a19df79 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -2839,9 +2839,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { unsigned VariantCount = Target.getAsmParserVariantCount(); for (unsigned VC = 0; VC != VariantCount; ++VC) { Record *AsmVariant = Target.getAsmParserVariant(VC); - std::string CommentDelimiter = - AsmVariant->getValueAsString("CommentDelimiter"); - std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix"); int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); OS << "static const MatchEntry MatchTable" << VC << "[] = {\n"; @@ -2892,9 +2889,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " default: // unreachable\n"; for (unsigned VC = 0; VC != VariantCount; ++VC) { Record *AsmVariant = Target.getAsmParserVariant(VC); - std::string CommentDelimiter = - AsmVariant->getValueAsString("CommentDelimiter"); - std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix"); int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); OS << " case " << AsmVariantNo << ": Start = MatchTable" << VC << "; End = array_endof(MatchTable" << VC << "); break;\n"; @@ -2950,9 +2944,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " default: // unreachable\n"; for (unsigned VC = 0; VC != VariantCount; ++VC) { Record *AsmVariant = Target.getAsmParserVariant(VC); - std::string CommentDelimiter = - AsmVariant->getValueAsString("CommentDelimiter"); - std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix"); int AsmVariantNo = AsmVariant->getValueAsInt("Variant"); OS << " case " << AsmVariantNo << ": Start = MatchTable" << VC << "; End = array_endof(MatchTable" << VC << "); break;\n"; diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index 13b28df..a6d1daf 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -836,7 +836,6 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { Cond = std::string("MI->getNumOperands() == ") + llvm::utostr(LastOpNo); IAP->addCond(Cond); - std::map OpMap; bool CantHandle = false; for (unsigned i = 0, e = LastOpNo; i != e; ++i) { diff --git a/utils/TableGen/CodeGenMapTable.cpp b/utils/TableGen/CodeGenMapTable.cpp index ee32aa1..cb7ec3e 100644 --- a/utils/TableGen/CodeGenMapTable.cpp +++ b/utils/TableGen/CodeGenMapTable.cpp @@ -240,7 +240,6 @@ public: void MapTableEmitter::buildRowInstrMap() { for (unsigned i = 0, e = InstrDefs.size(); i < e; i++) { - std::vector InstrList; Record *CurInstr = InstrDefs[i]; std::vector KeyValue; ListInit *RowFields = InstrMapDesc.getRowFields(); diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp index 6e45240..87d18cd 100644 --- a/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -2038,7 +2038,6 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) { } DecoderTableInfo TableInfo; - std::set Sizes; for (std::map, std::vector >::const_iterator I = OpcMap.begin(), E = OpcMap.end(); I != E; ++I) { -- cgit v1.1 From da750239bd1f02aef403baa4805805fb580e78e1 Mon Sep 17 00:00:00 2001 From: Pete Cooper Date: Thu, 3 Oct 2013 03:29:21 +0000 Subject: Add v4f16 to supported value types. This is useful for some ARM intrinsics such as VCVTN which does a <4 x float> <-> <4 x half> conversion. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191870 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenTarget.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'utils') diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index c8290da..cd0b8c7 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -99,6 +99,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v8i64: return "MVT::v8i64"; case MVT::v16i64: return "MVT::v16i64"; case MVT::v2f16: return "MVT::v2f16"; + case MVT::v4f16: return "MVT::v4f16"; case MVT::v8f16: return "MVT::v8f16"; case MVT::v1f32: return "MVT::v1f32"; case MVT::v2f32: return "MVT::v2f32"; -- cgit v1.1 From 279d28265dccc2a7c56f9ea04917c87dc50c1578 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Thu, 3 Oct 2013 05:17:48 +0000 Subject: Add XOP disassembler support. Fixes PR13933. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191874 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86DisassemblerTables.cpp | 3 ++ utils/TableGen/X86DisassemblerTables.h | 5 ++- utils/TableGen/X86RecognizableInstr.cpp | 67 +++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index 98a4797..026870e 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -707,6 +707,9 @@ void DisassemblerTables::emitContextDecisions(raw_ostream &o1, raw_ostream &o2, emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[3], THREEBYTE3A_STR); emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[4], THREEBYTEA6_STR); emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[5], THREEBYTEA7_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[6], XOP8_MAP_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[7], XOP9_MAP_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[8], XOPA_MAP_STR); } void DisassemblerTables::emit(raw_ostream &o) const { diff --git a/utils/TableGen/X86DisassemblerTables.h b/utils/TableGen/X86DisassemblerTables.h index 3861b74..bf8b127 100644 --- a/utils/TableGen/X86DisassemblerTables.h +++ b/utils/TableGen/X86DisassemblerTables.h @@ -40,7 +40,10 @@ private: /// [3] three-byte opcodes of the form 0f 3a __ /// [4] three-byte opcodes of the form 0f a6 __ /// [5] three-byte opcodes of the form 0f a7 __ - ContextDecision* Tables[6]; + /// [6] XOP8 map opcode + /// [7] XOP9 map opcode + /// [8] XOPA map opcode + ContextDecision* Tables[9]; // Table of ModRM encodings. typedef std::map, unsigned> ModRMMapTy; diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index d2675d7..7c8b84e 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -79,7 +79,8 @@ namespace X86Local { DC = 7, DD = 8, DE = 9, DF = 10, XD = 11, XS = 12, T8 = 13, P_TA = 14, - A6 = 15, A7 = 16, T8XD = 17, T8XS = 18, TAXD = 19 + A6 = 15, A7 = 16, T8XD = 17, T8XS = 18, TAXD = 19, + XOP8 = 20, XOP9 = 21, XOPA = 22 }; } @@ -134,6 +135,10 @@ namespace X86Local { #define THREE_BYTE_38_EXTENSION_TABLES \ EXTENSION_TABLE(F3) +#define XOP9_MAP_EXTENSION_TABLES \ + EXTENSION_TABLE(01) \ + EXTENSION_TABLE(02) + using namespace X86Disassembler; /// needsModRMForDecode - Indicates whether a particular instruction requires a @@ -908,6 +913,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { uint8_t opcodeToSet = 0; switch (Prefix) { + default: llvm_unreachable("Invalid prefix!"); // Extended two-byte opcodes can start with f2 0f, f3 0f, or 0f case X86Local::XD: case X86Local::XS: @@ -1021,6 +1027,63 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { filter = new DumbFilter(); opcodeToSet = Opcode; break; + case X86Local::XOP8: + opcodeType = XOP8_MAP; + if (needsModRMForDecode(Form)) + filter = new ModFilter(isRegFormat(Form)); + else + filter = new DumbFilter(); + opcodeToSet = Opcode; + break; + case X86Local::XOP9: + opcodeType = XOP9_MAP; + switch (Opcode) { + default: + if (needsModRMForDecode(Form)) + filter = new ModFilter(isRegFormat(Form)); + else + filter = new DumbFilter(); + break; +#define EXTENSION_TABLE(n) case 0x##n: + XOP9_MAP_EXTENSION_TABLES +#undef EXTENSION_TABLE + switch (Form) { + default: + llvm_unreachable("Unhandled XOP9 extended opcode"); + case X86Local::MRM0r: + case X86Local::MRM1r: + case X86Local::MRM2r: + case X86Local::MRM3r: + case X86Local::MRM4r: + case X86Local::MRM5r: + case X86Local::MRM6r: + case X86Local::MRM7r: + filter = new ExtendedFilter(true, Form - X86Local::MRM0r); + break; + case X86Local::MRM0m: + case X86Local::MRM1m: + case X86Local::MRM2m: + case X86Local::MRM3m: + case X86Local::MRM4m: + case X86Local::MRM5m: + case X86Local::MRM6m: + case X86Local::MRM7m: + filter = new ExtendedFilter(false, Form - X86Local::MRM0m); + break; + MRM_MAPPING + } // switch (Form) + break; + } // switch (Opcode) + opcodeToSet = Opcode; + break; + case X86Local::XOPA: + opcodeType = XOPA_MAP; + if (needsModRMForDecode(Form)) + filter = new ModFilter(isRegFormat(Form)); + else + filter = new DumbFilter(); + opcodeToSet = Opcode; + break; case X86Local::D8: case X86Local::D9: case X86Local::DA: @@ -1041,7 +1104,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { opcodeToSet = 0xd8 + (Prefix - X86Local::D8); break; case X86Local::REP: - default: + case 0: opcodeType = ONEBYTE; switch (Opcode) { #define EXTENSION_TABLE(n) case 0x##n: -- cgit v1.1 From d3562956789dbd0571a7e46052bee64b153fa7c4 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Fri, 4 Oct 2013 05:22:20 +0000 Subject: Add OPC_CheckChildSame0-3 to the DAG isel matcher. This replaces sequences of MoveChild, CheckSame, MoveParent. Saves 846 bytes from the X86 DAG isel matcher, ~300 from ARM, ~840 from Hexagon. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191940 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/DAGISelMatcher.cpp | 4 ++++ utils/TableGen/DAGISelMatcher.h | 30 ++++++++++++++++++++++++++++++ utils/TableGen/DAGISelMatcherEmitter.cpp | 7 +++++++ utils/TableGen/DAGISelMatcherOpt.cpp | 6 +++++- 4 files changed, 46 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp index af0eb97..5d6a11a 100644 --- a/utils/TableGen/DAGISelMatcher.cpp +++ b/utils/TableGen/DAGISelMatcher.cpp @@ -134,6 +134,10 @@ void CheckSameMatcher::printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "CheckSame " << MatchNumber << '\n'; } +void CheckChildSameMatcher::printImpl(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckChild" << ChildNo << "Same\n"; +} + void CheckPatternPredicateMatcher:: printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "CheckPatternPredicate " << Predicate << '\n'; diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h index ebac790..70031fa 100644 --- a/utils/TableGen/DAGISelMatcher.h +++ b/utils/TableGen/DAGISelMatcher.h @@ -55,6 +55,7 @@ public: // Predicate checking. CheckSame, // Fail if not same as prev match. + CheckChildSame, // Fail if child not same as prev match. CheckPatternPredicate, CheckPredicate, // Fail if node predicate fails. CheckOpcode, // Fail if not opcode. @@ -122,6 +123,7 @@ public: switch (getKind()) { default: return false; case CheckSame: + case CheckChildSame: case CheckPatternPredicate: case CheckPredicate: case CheckOpcode: @@ -392,6 +394,34 @@ private: virtual unsigned getHashImpl() const { return getMatchNumber(); } }; +/// CheckChildSameMatcher - This checks to see if child node is exactly the same +/// node as the specified match that was recorded with 'Record'. This is used +/// when patterns have the same name in them, like '(mul GPR:$in, GPR:$in)'. +class CheckChildSameMatcher : public Matcher { + unsigned ChildNo; + unsigned MatchNumber; +public: + CheckChildSameMatcher(unsigned childno, unsigned matchnumber) + : Matcher(CheckChildSame), ChildNo(childno), MatchNumber(matchnumber) {} + + unsigned getChildNo() const { return ChildNo; } + unsigned getMatchNumber() const { return MatchNumber; } + + static inline bool classof(const Matcher *N) { + return N->getKind() == CheckChildSame; + } + + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } + +private: + virtual void printImpl(raw_ostream &OS, unsigned indent) const; + virtual bool isEqualImpl(const Matcher *M) const { + return cast(M)->ChildNo == ChildNo && + cast(M)->MatchNumber == MatchNumber; + } + virtual unsigned getHashImpl() const { return (MatchNumber << 2) | ChildNo; } +}; + /// CheckPatternPredicateMatcher - This checks the target-specific predicate /// to see if the entire pattern is capable of matching. This predicate does /// not take a node as input. This is used for subtarget feature checks etc. diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp index ba1b358..04fe0d1 100644 --- a/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -242,6 +242,12 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, << cast(N)->getMatchNumber() << ",\n"; return 2; + case Matcher::CheckChildSame: + OS << "OPC_CheckChild" + << cast(N)->getChildNo() << "Same, " + << cast(N)->getMatchNumber() << ",\n"; + return 2; + case Matcher::CheckPatternPredicate: { StringRef Pred =cast(N)->getPredicate(); OS << "OPC_CheckPatternPredicate, " << getPatternPredicate(Pred) << ','; @@ -753,6 +759,7 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M, case Matcher::MoveChild: OS << "OPC_MoveChild"; break; case Matcher::MoveParent: OS << "OPC_MoveParent"; break; case Matcher::CheckSame: OS << "OPC_CheckSame"; break; + case Matcher::CheckChildSame: OS << "OPC_CheckChildSame"; break; case Matcher::CheckPatternPredicate: OS << "OPC_CheckPatternPredicate"; break; case Matcher::CheckPredicate: OS << "OPC_CheckPredicate"; break; diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp index f996422..82e5d63 100644 --- a/utils/TableGen/DAGISelMatcherOpt.cpp +++ b/utils/TableGen/DAGISelMatcherOpt.cpp @@ -51,7 +51,11 @@ static void ContractNodes(OwningPtr &MatcherPtr, if (MC->getChildNo() < 8 && // Only have CheckChildType0...7 CT->getResNo() == 0) // CheckChildType checks res #0 New = new CheckChildTypeMatcher(MC->getChildNo(), CT->getType()); - + + if (CheckSameMatcher *CS = dyn_cast(MC->getNext())) + if (MC->getChildNo() < 4) // Only have CheckChildSame0...3 + New = new CheckChildSameMatcher(MC->getChildNo(), CS->getMatchNumber()); + if (New) { // Insert the new node. New->setNext(MatcherPtr.take()); -- cgit v1.1 From 596cfd045fa05c249083b5ff7cdb5e32f4d92b97 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Fri, 4 Oct 2013 05:52:17 +0000 Subject: Revert r191940 to see if it fixes the build bots. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191941 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/DAGISelMatcher.cpp | 4 ---- utils/TableGen/DAGISelMatcher.h | 30 ------------------------------ utils/TableGen/DAGISelMatcherEmitter.cpp | 7 ------- utils/TableGen/DAGISelMatcherOpt.cpp | 6 +----- 4 files changed, 1 insertion(+), 46 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp index 5d6a11a..af0eb97 100644 --- a/utils/TableGen/DAGISelMatcher.cpp +++ b/utils/TableGen/DAGISelMatcher.cpp @@ -134,10 +134,6 @@ void CheckSameMatcher::printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "CheckSame " << MatchNumber << '\n'; } -void CheckChildSameMatcher::printImpl(raw_ostream &OS, unsigned indent) const { - OS.indent(indent) << "CheckChild" << ChildNo << "Same\n"; -} - void CheckPatternPredicateMatcher:: printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "CheckPatternPredicate " << Predicate << '\n'; diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h index 70031fa..ebac790 100644 --- a/utils/TableGen/DAGISelMatcher.h +++ b/utils/TableGen/DAGISelMatcher.h @@ -55,7 +55,6 @@ public: // Predicate checking. CheckSame, // Fail if not same as prev match. - CheckChildSame, // Fail if child not same as prev match. CheckPatternPredicate, CheckPredicate, // Fail if node predicate fails. CheckOpcode, // Fail if not opcode. @@ -123,7 +122,6 @@ public: switch (getKind()) { default: return false; case CheckSame: - case CheckChildSame: case CheckPatternPredicate: case CheckPredicate: case CheckOpcode: @@ -394,34 +392,6 @@ private: virtual unsigned getHashImpl() const { return getMatchNumber(); } }; -/// CheckChildSameMatcher - This checks to see if child node is exactly the same -/// node as the specified match that was recorded with 'Record'. This is used -/// when patterns have the same name in them, like '(mul GPR:$in, GPR:$in)'. -class CheckChildSameMatcher : public Matcher { - unsigned ChildNo; - unsigned MatchNumber; -public: - CheckChildSameMatcher(unsigned childno, unsigned matchnumber) - : Matcher(CheckChildSame), ChildNo(childno), MatchNumber(matchnumber) {} - - unsigned getChildNo() const { return ChildNo; } - unsigned getMatchNumber() const { return MatchNumber; } - - static inline bool classof(const Matcher *N) { - return N->getKind() == CheckChildSame; - } - - virtual bool isSafeToReorderWithPatternPredicate() const { return true; } - -private: - virtual void printImpl(raw_ostream &OS, unsigned indent) const; - virtual bool isEqualImpl(const Matcher *M) const { - return cast(M)->ChildNo == ChildNo && - cast(M)->MatchNumber == MatchNumber; - } - virtual unsigned getHashImpl() const { return (MatchNumber << 2) | ChildNo; } -}; - /// CheckPatternPredicateMatcher - This checks the target-specific predicate /// to see if the entire pattern is capable of matching. This predicate does /// not take a node as input. This is used for subtarget feature checks etc. diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp index 04fe0d1..ba1b358 100644 --- a/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -242,12 +242,6 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, << cast(N)->getMatchNumber() << ",\n"; return 2; - case Matcher::CheckChildSame: - OS << "OPC_CheckChild" - << cast(N)->getChildNo() << "Same, " - << cast(N)->getMatchNumber() << ",\n"; - return 2; - case Matcher::CheckPatternPredicate: { StringRef Pred =cast(N)->getPredicate(); OS << "OPC_CheckPatternPredicate, " << getPatternPredicate(Pred) << ','; @@ -759,7 +753,6 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M, case Matcher::MoveChild: OS << "OPC_MoveChild"; break; case Matcher::MoveParent: OS << "OPC_MoveParent"; break; case Matcher::CheckSame: OS << "OPC_CheckSame"; break; - case Matcher::CheckChildSame: OS << "OPC_CheckChildSame"; break; case Matcher::CheckPatternPredicate: OS << "OPC_CheckPatternPredicate"; break; case Matcher::CheckPredicate: OS << "OPC_CheckPredicate"; break; diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp index 82e5d63..f996422 100644 --- a/utils/TableGen/DAGISelMatcherOpt.cpp +++ b/utils/TableGen/DAGISelMatcherOpt.cpp @@ -51,11 +51,7 @@ static void ContractNodes(OwningPtr &MatcherPtr, if (MC->getChildNo() < 8 && // Only have CheckChildType0...7 CT->getResNo() == 0) // CheckChildType checks res #0 New = new CheckChildTypeMatcher(MC->getChildNo(), CT->getType()); - - if (CheckSameMatcher *CS = dyn_cast(MC->getNext())) - if (MC->getChildNo() < 4) // Only have CheckChildSame0...3 - New = new CheckChildSameMatcher(MC->getChildNo(), CS->getMatchNumber()); - + if (New) { // Insert the new node. New->setNext(MatcherPtr.take()); -- cgit v1.1 From 936910d9293f7118056498c75c7bca79a7fc579c Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Sat, 5 Oct 2013 05:38:16 +0000 Subject: Add OPC_CheckChildSame0-3 to the DAG isel matcher. This replaces sequences of MoveChild, CheckSame, MoveParent. Saves 846 bytes from the X86 DAG isel matcher, ~300 from ARM, ~840 from Hexagon. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192026 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/DAGISelMatcher.cpp | 4 ++++ utils/TableGen/DAGISelMatcher.h | 30 ++++++++++++++++++++++++++++++ utils/TableGen/DAGISelMatcherEmitter.cpp | 7 +++++++ utils/TableGen/DAGISelMatcherOpt.cpp | 6 +++++- 4 files changed, 46 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp index af0eb97..5d6a11a 100644 --- a/utils/TableGen/DAGISelMatcher.cpp +++ b/utils/TableGen/DAGISelMatcher.cpp @@ -134,6 +134,10 @@ void CheckSameMatcher::printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "CheckSame " << MatchNumber << '\n'; } +void CheckChildSameMatcher::printImpl(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckChild" << ChildNo << "Same\n"; +} + void CheckPatternPredicateMatcher:: printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "CheckPatternPredicate " << Predicate << '\n'; diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h index ebac790..70031fa 100644 --- a/utils/TableGen/DAGISelMatcher.h +++ b/utils/TableGen/DAGISelMatcher.h @@ -55,6 +55,7 @@ public: // Predicate checking. CheckSame, // Fail if not same as prev match. + CheckChildSame, // Fail if child not same as prev match. CheckPatternPredicate, CheckPredicate, // Fail if node predicate fails. CheckOpcode, // Fail if not opcode. @@ -122,6 +123,7 @@ public: switch (getKind()) { default: return false; case CheckSame: + case CheckChildSame: case CheckPatternPredicate: case CheckPredicate: case CheckOpcode: @@ -392,6 +394,34 @@ private: virtual unsigned getHashImpl() const { return getMatchNumber(); } }; +/// CheckChildSameMatcher - This checks to see if child node is exactly the same +/// node as the specified match that was recorded with 'Record'. This is used +/// when patterns have the same name in them, like '(mul GPR:$in, GPR:$in)'. +class CheckChildSameMatcher : public Matcher { + unsigned ChildNo; + unsigned MatchNumber; +public: + CheckChildSameMatcher(unsigned childno, unsigned matchnumber) + : Matcher(CheckChildSame), ChildNo(childno), MatchNumber(matchnumber) {} + + unsigned getChildNo() const { return ChildNo; } + unsigned getMatchNumber() const { return MatchNumber; } + + static inline bool classof(const Matcher *N) { + return N->getKind() == CheckChildSame; + } + + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } + +private: + virtual void printImpl(raw_ostream &OS, unsigned indent) const; + virtual bool isEqualImpl(const Matcher *M) const { + return cast(M)->ChildNo == ChildNo && + cast(M)->MatchNumber == MatchNumber; + } + virtual unsigned getHashImpl() const { return (MatchNumber << 2) | ChildNo; } +}; + /// CheckPatternPredicateMatcher - This checks the target-specific predicate /// to see if the entire pattern is capable of matching. This predicate does /// not take a node as input. This is used for subtarget feature checks etc. diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp index ba1b358..04fe0d1 100644 --- a/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -242,6 +242,12 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, << cast(N)->getMatchNumber() << ",\n"; return 2; + case Matcher::CheckChildSame: + OS << "OPC_CheckChild" + << cast(N)->getChildNo() << "Same, " + << cast(N)->getMatchNumber() << ",\n"; + return 2; + case Matcher::CheckPatternPredicate: { StringRef Pred =cast(N)->getPredicate(); OS << "OPC_CheckPatternPredicate, " << getPatternPredicate(Pred) << ','; @@ -753,6 +759,7 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M, case Matcher::MoveChild: OS << "OPC_MoveChild"; break; case Matcher::MoveParent: OS << "OPC_MoveParent"; break; case Matcher::CheckSame: OS << "OPC_CheckSame"; break; + case Matcher::CheckChildSame: OS << "OPC_CheckChildSame"; break; case Matcher::CheckPatternPredicate: OS << "OPC_CheckPatternPredicate"; break; case Matcher::CheckPredicate: OS << "OPC_CheckPredicate"; break; diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp index f996422..82e5d63 100644 --- a/utils/TableGen/DAGISelMatcherOpt.cpp +++ b/utils/TableGen/DAGISelMatcherOpt.cpp @@ -51,7 +51,11 @@ static void ContractNodes(OwningPtr &MatcherPtr, if (MC->getChildNo() < 8 && // Only have CheckChildType0...7 CT->getResNo() == 0) // CheckChildType checks res #0 New = new CheckChildTypeMatcher(MC->getChildNo(), CT->getType()); - + + if (CheckSameMatcher *CS = dyn_cast(MC->getNext())) + if (MC->getChildNo() < 4) // Only have CheckChildSame0...3 + New = new CheckChildSameMatcher(MC->getChildNo(), CS->getMatchNumber()); + if (New) { // Insert the new node. New->setNext(MatcherPtr.take()); -- cgit v1.1 From 5a1a1856a4dfa1335d937437fade5c0bbab06560 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Sun, 6 Oct 2013 20:25:49 +0000 Subject: Windows: Add support for unicode command lines Summary: The MSVCRT deliberately sends main() code-page specific characters. This isn't too useful to LLVM as we end up converting the arguments to UTF-16 and subsequently attempt to use the result as, for example, a file name. Instead, we need to have the ability to access the Unicode command line and transform it to UTF-8. This has the distinct advantage over using the MSVC-specific wmain() function as our entry point because: - It doesn't work on cygwin. - It only work on MinGW with caveats and only then on certain versions. - We get to keep our entry point as main(). :) N.B. This patch includes fixes to other parts of lib/Support/Windows s.t. we would be able to take advantage of getting the Unicode paths. E.G. clang spawning clang -cc1 would want to give it Unicode arguments. Reviewers: aaron.ballman, Bigcheese, rnk, ruiu Reviewed By: rnk CC: llvm-commits, ygao Differential Revision: http://llvm-reviews.chandlerc.com/D1834 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192069 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/CMakeLists.txt | 2 +- utils/FileUpdate/CMakeLists.txt | 2 +- utils/not/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/CMakeLists.txt b/utils/FileCheck/CMakeLists.txt index fa56f92..d691ceb 100644 --- a/utils/FileCheck/CMakeLists.txt +++ b/utils/FileCheck/CMakeLists.txt @@ -4,7 +4,7 @@ add_llvm_utility(FileCheck target_link_libraries(FileCheck LLVMSupport) if( MINGW ) - target_link_libraries(FileCheck imagehlp psapi) + target_link_libraries(FileCheck imagehlp psapi shell32) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(FileCheck pthread) diff --git a/utils/FileUpdate/CMakeLists.txt b/utils/FileUpdate/CMakeLists.txt index 655aaec..0114e50 100644 --- a/utils/FileUpdate/CMakeLists.txt +++ b/utils/FileUpdate/CMakeLists.txt @@ -4,7 +4,7 @@ add_llvm_utility(FileUpdate target_link_libraries(FileUpdate LLVMSupport) if( MINGW ) - target_link_libraries(FileUpdate imagehlp psapi) + target_link_libraries(FileUpdate imagehlp psapi shell32) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(FileUpdate pthread) diff --git a/utils/not/CMakeLists.txt b/utils/not/CMakeLists.txt index f4c0229..5ff14d6 100644 --- a/utils/not/CMakeLists.txt +++ b/utils/not/CMakeLists.txt @@ -4,7 +4,7 @@ add_llvm_utility(not target_link_libraries(not LLVMSupport) if( MINGW ) - target_link_libraries(not imagehlp psapi) + target_link_libraries(not imagehlp psapi shell32) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(not pthread) -- cgit v1.1 From b262556c45bb7b3add826bc3f050c99db6990c37 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Sun, 6 Oct 2013 20:44:34 +0000 Subject: Revert "Windows: Add support for unicode command lines" This is causing MinGW bots to fail. This reverts commit r192069. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192070 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/CMakeLists.txt | 2 +- utils/FileUpdate/CMakeLists.txt | 2 +- utils/not/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/CMakeLists.txt b/utils/FileCheck/CMakeLists.txt index d691ceb..fa56f92 100644 --- a/utils/FileCheck/CMakeLists.txt +++ b/utils/FileCheck/CMakeLists.txt @@ -4,7 +4,7 @@ add_llvm_utility(FileCheck target_link_libraries(FileCheck LLVMSupport) if( MINGW ) - target_link_libraries(FileCheck imagehlp psapi shell32) + target_link_libraries(FileCheck imagehlp psapi) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(FileCheck pthread) diff --git a/utils/FileUpdate/CMakeLists.txt b/utils/FileUpdate/CMakeLists.txt index 0114e50..655aaec 100644 --- a/utils/FileUpdate/CMakeLists.txt +++ b/utils/FileUpdate/CMakeLists.txt @@ -4,7 +4,7 @@ add_llvm_utility(FileUpdate target_link_libraries(FileUpdate LLVMSupport) if( MINGW ) - target_link_libraries(FileUpdate imagehlp psapi shell32) + target_link_libraries(FileUpdate imagehlp psapi) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(FileUpdate pthread) diff --git a/utils/not/CMakeLists.txt b/utils/not/CMakeLists.txt index 5ff14d6..f4c0229 100644 --- a/utils/not/CMakeLists.txt +++ b/utils/not/CMakeLists.txt @@ -4,7 +4,7 @@ add_llvm_utility(not target_link_libraries(not LLVMSupport) if( MINGW ) - target_link_libraries(not imagehlp psapi shell32) + target_link_libraries(not imagehlp psapi) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(not pthread) -- cgit v1.1 From 6a971bb8f59f4e20c953a2cc360cab7bae8642e4 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Mon, 7 Oct 2013 01:00:07 +0000 Subject: Revert "Revert "Windows: Add support for unicode command lines"" This reverts commit r192070 which reverted r192069, I forgot to regenerate the configure scripts. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192079 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/CMakeLists.txt | 2 +- utils/FileUpdate/CMakeLists.txt | 2 +- utils/not/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/CMakeLists.txt b/utils/FileCheck/CMakeLists.txt index fa56f92..d691ceb 100644 --- a/utils/FileCheck/CMakeLists.txt +++ b/utils/FileCheck/CMakeLists.txt @@ -4,7 +4,7 @@ add_llvm_utility(FileCheck target_link_libraries(FileCheck LLVMSupport) if( MINGW ) - target_link_libraries(FileCheck imagehlp psapi) + target_link_libraries(FileCheck imagehlp psapi shell32) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(FileCheck pthread) diff --git a/utils/FileUpdate/CMakeLists.txt b/utils/FileUpdate/CMakeLists.txt index 655aaec..0114e50 100644 --- a/utils/FileUpdate/CMakeLists.txt +++ b/utils/FileUpdate/CMakeLists.txt @@ -4,7 +4,7 @@ add_llvm_utility(FileUpdate target_link_libraries(FileUpdate LLVMSupport) if( MINGW ) - target_link_libraries(FileUpdate imagehlp psapi) + target_link_libraries(FileUpdate imagehlp psapi shell32) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(FileUpdate pthread) diff --git a/utils/not/CMakeLists.txt b/utils/not/CMakeLists.txt index f4c0229..5ff14d6 100644 --- a/utils/not/CMakeLists.txt +++ b/utils/not/CMakeLists.txt @@ -4,7 +4,7 @@ add_llvm_utility(not target_link_libraries(not LLVMSupport) if( MINGW ) - target_link_libraries(not imagehlp psapi) + target_link_libraries(not imagehlp psapi shell32) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(not pthread) -- cgit v1.1 From 36a9b31b981553350f5cc4adad9917656c20e96e Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 7 Oct 2013 04:28:06 +0000 Subject: Add disassembler support for long encodings for INC/DEC in 32-bit mode. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192086 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 7c8b84e..fed3f77 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -491,7 +491,8 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { assert(Rec->isSubClassOf("X86Inst") && "Can only filter X86 instructions"); if (Form == X86Local::Pseudo || - (IsCodeGenOnly && Name.find("_REV") == Name.npos)) + (IsCodeGenOnly && Name.find("_REV") == Name.npos && + Name.find("INC32") == Name.npos && Name.find("DEC32") == Name.npos)) return FILTER_STRONG; -- cgit v1.1 From e778f82a1e33826ab012bb970a406c9acf37349b Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 7 Oct 2013 07:19:47 +0000 Subject: Remove some instructions that seem to only exist to trick the filtering checks in the disassembler table creation. Just fix up the filter to let the real instruction through instead. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192090 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index fed3f77..d342720 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -538,7 +538,8 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { if (Name.find("MOV") != Name.npos && Name.find("r0") != Name.npos) return FILTER_WEAK; - if (Name.find("MOVZ") != Name.npos && Name.find("MOVZX") == Name.npos) + if (Name.find("MOVZ") != Name.npos && Name.find("MOVZX") == Name.npos && + Name != "MOVZPQILo2PQIrr") return FILTER_WEAK; if (Name.find("Fs") != Name.npos) return FILTER_WEAK; -- cgit v1.1 From b9bc43852ceb74c845d28b96594e1ef4ae41329f Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Tue, 8 Oct 2013 05:53:50 +0000 Subject: Remove some instructions that existed to provide aliases to the assembler. Can be done with InstAlias instead. Unfortunately, this was causing printer to use 'vmovq' or 'vmovd' based on what was parsed. To cleanup the inconsistencies convert all 'vmovd' with 64-bit registers to 'vmovq', but provide an alias so that 'vmovd' will still parse. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192171 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index d342720..8a32ab1 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -549,9 +549,7 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { Name == "MMX_MOVD64rrv164" || Name == "MOV64ri64i32" || Name == "VMASKMOVDQU64" || - Name == "VEXTRACTPSrr64" || - Name == "VMOVQd64rr" || - Name == "VMOVQs64rr") + Name == "VEXTRACTPSrr64") return FILTER_WEAK; // XACQUIRE and XRELEASE reuse REPNE and REP respectively. -- cgit v1.1 From d55fed16a44366f8d9800197ffa67bbd7189568b Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Tue, 8 Oct 2013 06:30:39 +0000 Subject: Remove unneeded MMX instruction definition by moving pattern to an equivalent instruction definition and removing the filtering from the disassembler table building. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192175 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 8a32ab1..777afaa 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -546,7 +546,6 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { if (Name == "PUSH64i16" || Name == "MOVPQI2QImr" || Name == "VMOVPQI2QImr" || - Name == "MMX_MOVD64rrv164" || Name == "MOV64ri64i32" || Name == "VMASKMOVDQU64" || Name == "VEXTRACTPSrr64") -- cgit v1.1 From 10c7925d69437e2bd182eb4cc47eb4bdfb3af900 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Wed, 9 Oct 2013 05:02:29 +0000 Subject: Remove some old filters from the x86 disassembler table builder. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192275 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 777afaa..7d77b8c 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -531,11 +531,6 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { // Special cases. - if (Name.find("PCMPISTRI") != Name.npos && Name != "PCMPISTRI") - return FILTER_WEAK; - if (Name.find("PCMPESTRI") != Name.npos && Name != "PCMPESTRI") - return FILTER_WEAK; - if (Name.find("MOV") != Name.npos && Name.find("r0") != Name.npos) return FILTER_WEAK; if (Name.find("MOVZ") != Name.npos && Name.find("MOVZX") == Name.npos && @@ -546,7 +541,6 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { if (Name == "PUSH64i16" || Name == "MOVPQI2QImr" || Name == "VMOVPQI2QImr" || - Name == "MOV64ri64i32" || Name == "VMASKMOVDQU64" || Name == "VEXTRACTPSrr64") return FILTER_WEAK; -- cgit v1.1 From 5747f946ec810d22d36260a4b18114d5673fd55f Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Wed, 9 Oct 2013 06:12:53 +0000 Subject: More x86 disassembler filtering cleanup. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192279 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 7d77b8c..8de948a 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -522,10 +522,8 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { // Filter out alternate forms of AVX instructions if (Name.find("_alt") != Name.npos || - Name.find("XrYr") != Name.npos || (Name.find("r64r") != Name.npos && Name.find("r64r64") == Name.npos) || Name.find("_64mr") != Name.npos || - Name.find("Xrr") != Name.npos || Name.find("rr64") != Name.npos) return FILTER_WEAK; @@ -541,8 +539,7 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { if (Name == "PUSH64i16" || Name == "MOVPQI2QImr" || Name == "VMOVPQI2QImr" || - Name == "VMASKMOVDQU64" || - Name == "VEXTRACTPSrr64") + Name == "VMASKMOVDQU64") return FILTER_WEAK; // XACQUIRE and XRELEASE reuse REPNE and REP respectively. -- cgit v1.1 From be5c1fd43fd1cef8a18f41978d147190b50f5510 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Thu, 10 Oct 2013 04:26:52 +0000 Subject: Fix so CRC32r64r8 isn't accidentally filtered from the disassembler tables. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192339 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 8de948a..a7ce657 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -522,7 +522,7 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { // Filter out alternate forms of AVX instructions if (Name.find("_alt") != Name.npos || - (Name.find("r64r") != Name.npos && Name.find("r64r64") == Name.npos) || + (Name.find("r64r") != Name.npos && Name.find("r64r64") == Name.npos && Name.find("r64r8") == Name.npos) || Name.find("_64mr") != Name.npos || Name.find("rr64") != Name.npos) return FILTER_WEAK; -- cgit v1.1 From e799dbc4bdfd5f3c7856fbcfe0fac56000401f1f Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Fri, 11 Oct 2013 06:59:57 +0000 Subject: Remove another unnecessary filter from the disassembler. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192425 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index a7ce657..1415295 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -531,9 +531,6 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { if (Name.find("MOV") != Name.npos && Name.find("r0") != Name.npos) return FILTER_WEAK; - if (Name.find("MOVZ") != Name.npos && Name.find("MOVZX") == Name.npos && - Name != "MOVZPQILo2PQIrr") - return FILTER_WEAK; if (Name.find("Fs") != Name.npos) return FILTER_WEAK; if (Name == "PUSH64i16" || -- cgit v1.1 From 563c18283926b18bbdb6d3ad6cf02594399e2baf Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 11 Oct 2013 16:48:02 +0000 Subject: Fix handling of CHECK-DAG inside of CHECK-LABEL. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192463 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/FileCheck.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 120fdd7..37a1a2f 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -879,12 +879,10 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, size_t LastPos = 0; std::vector NotStrings; - if (CheckTy != Check::CheckLabel) { - // Match "dag strings" (with mixed "not strings" if any). - LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable); - if (LastPos == StringRef::npos) - return StringRef::npos; - } + // Match "dag strings" (with mixed "not strings" if any). + LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable); + if (LastPos == StringRef::npos) + return StringRef::npos; // Match itself from the last position after matching CHECK-DAG. StringRef MatchBuffer = Buffer.substr(LastPos); -- cgit v1.1 From e5f740cc4f994c0db13a66de699bf95ccf24130e Mon Sep 17 00:00:00 2001 From: Stephen Lin Date: Fri, 11 Oct 2013 18:38:36 +0000 Subject: Really fix CHECK-LABEL and CHECK-DAG interaction. This actually just restores the initial implementation that was in r186162 but got lost in some subsequent refactoring. More explicit variable names and comments are present now to hopefully prevent repeat regression, as well as another test. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192477 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/FileCheck.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 37a1a2f..43e8c79 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -609,7 +609,7 @@ struct CheckString { : Pat(P), Loc(L), CheckTy(Ty) {} /// Check - Match check string and its "not strings" and/or "dag strings". - size_t Check(const SourceMgr &SM, StringRef Buffer, + size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, size_t &MatchLen, StringMap &VariableTable) const; /// CheckNext - Verify there is a single line in the given buffer. @@ -874,15 +874,21 @@ static unsigned CountNumNewlinesBetween(StringRef Range) { } size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, - size_t &MatchLen, + bool IsLabelScanMode, size_t &MatchLen, StringMap &VariableTable) const { size_t LastPos = 0; std::vector NotStrings; - // Match "dag strings" (with mixed "not strings" if any). - LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable); - if (LastPos == StringRef::npos) - return StringRef::npos; + // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL + // bounds; we have not processed variable definitions within the bounded block + // yet so cannot handle any final CHECK-DAG yet; this is handled when going + // over the block again (including the last CHECK-LABEL) in normal mode. + if (!IsLabelScanMode) { + // Match "dag strings" (with mixed "not strings" if any). + LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable); + if (LastPos == StringRef::npos) + return StringRef::npos; + } // Match itself from the last position after matching CHECK-DAG. StringRef MatchBuffer = Buffer.substr(LastPos); @@ -893,7 +899,9 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, } MatchPos += LastPos; - if (CheckTy != Check::CheckLabel) { + // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT + // or CHECK-NOT + if (!IsLabelScanMode) { StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos); // If this check is a "CHECK-NEXT", verify that the previous match was on @@ -1117,7 +1125,7 @@ int main(int argc, char **argv) { // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG size_t MatchLabelLen = 0; - size_t MatchLabelPos = CheckLabelStr.Check(SM, Buffer, + size_t MatchLabelPos = CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, VariableTable); if (MatchLabelPos == StringRef::npos) { hasError = true; @@ -1135,7 +1143,7 @@ int main(int argc, char **argv) { // Check each string within the scanned region, including a second check // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) size_t MatchLen = 0; - size_t MatchPos = CheckStr.Check(SM, CheckRegion, MatchLen, + size_t MatchPos = CheckStr.Check(SM, CheckRegion, false, MatchLen, VariableTable); if (MatchPos == StringRef::npos) { -- cgit v1.1 From e3ba15c794839abe076e3e2bdf6c626396a19d4d Mon Sep 17 00:00:00 2001 From: Will Dietz Date: Sat, 12 Oct 2013 00:55:57 +0000 Subject: Add missing #include's to cctype when using isdigit/alpha/etc. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192519 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/FileCheck.cpp | 1 + utils/TableGen/AsmMatcherEmitter.cpp | 1 + 2 files changed, 2 insertions(+) (limited to 'utils') diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 43e8c79..77721f9 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -29,6 +29,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" #include +#include #include #include #include diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index a19df79..de24cde 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -112,6 +112,7 @@ #include "llvm/TableGen/StringToOffsetTable.h" #include "llvm/TableGen/TableGenBackend.h" #include +#include #include #include #include -- cgit v1.1 From c429b5cca1a2710657b746b774e606f10200d89e Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Sat, 12 Oct 2013 04:46:18 +0000 Subject: Mark some more instructions as CodeGenOnly. Remove filters from the disassembler. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192522 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 1415295..c6770b8 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -529,10 +529,6 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { // Special cases. - if (Name.find("MOV") != Name.npos && Name.find("r0") != Name.npos) - return FILTER_WEAK; - if (Name.find("Fs") != Name.npos) - return FILTER_WEAK; if (Name == "PUSH64i16" || Name == "MOVPQI2QImr" || Name == "VMOVPQI2QImr" || -- cgit v1.1 From 017d8a3e23b719ece59f2498582db7f25d65c1b9 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Sat, 12 Oct 2013 05:41:08 +0000 Subject: Remove more filters from the disassembler. Mark some AVX512 instructions as CodeGenOnly. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192525 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index c6770b8..d3320f9 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -541,11 +541,6 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { Name == "XRELEASE_PREFIX") return FILTER_WEAK; - if (HasFROperands && Name.find("MOV") != Name.npos && - ((Name.find("2") != Name.npos && Name.find("32") == Name.npos) || - (Name.find("to") != Name.npos))) - return FILTER_STRONG; - return FILTER_NORMAL; } -- cgit v1.1 From c6f7c99809cece8c85e180c1b95e6159d8ea9613 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 14 Oct 2013 04:55:01 +0000 Subject: Allow pinsrw/pinsrb/pextrb/pextrw/movmskps/movmskpd/pmovmskb/extractps instructions to parse either GR32 or GR64 without resorting to duplicating instructions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192567 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86RecognizableInstr.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'utils') diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index d3320f9..b9666f1 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -1213,6 +1213,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("i32i8imm", TYPE_IMM32) TYPE("u32u8imm", TYPE_IMM32) TYPE("GR32", TYPE_Rv) + TYPE("GR32orGR64", TYPE_R32) TYPE("i64mem", TYPE_Mv) TYPE("i64i32imm", TYPE_IMM64) TYPE("i64i8imm", TYPE_IMM64) @@ -1323,6 +1324,7 @@ OperandEncoding RecognizableInstr::rmRegisterEncodingFromString bool hasOpSizePrefix) { ENCODING("GR16", ENCODING_RM) ENCODING("GR32", ENCODING_RM) + ENCODING("GR32orGR64", ENCODING_RM) ENCODING("GR64", ENCODING_RM) ENCODING("GR8", ENCODING_RM) ENCODING("VR128", ENCODING_RM) @@ -1346,6 +1348,7 @@ OperandEncoding RecognizableInstr::roRegisterEncodingFromString bool hasOpSizePrefix) { ENCODING("GR16", ENCODING_REG) ENCODING("GR32", ENCODING_REG) + ENCODING("GR32orGR64", ENCODING_REG) ENCODING("GR64", ENCODING_REG) ENCODING("GR8", ENCODING_REG) ENCODING("VR128", ENCODING_REG) -- cgit v1.1 From 1e422bf49dfde2070b2c0c402d3df2666550551d Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Mon, 14 Oct 2013 16:48:32 +0000 Subject: Remove utils/profile.pl. It uses now removed opt options. Patch by Alastair Murray! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192606 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/profile.pl | 74 -------------------------------------------------------- 1 file changed, 74 deletions(-) delete mode 100755 utils/profile.pl (limited to 'utils') diff --git a/utils/profile.pl b/utils/profile.pl deleted file mode 100755 index 782e5dc..0000000 --- a/utils/profile.pl +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/perl -w -# -# Program: profile.pl -# -# Synopsis: Insert instrumentation code into a program, run it with the JIT, -# then print out a profile report. -# -# Syntax: profile.pl [OPTIONS] bitcodefile -# -# OPTIONS may include one or more of the following: -# -block - Enable basicblock profiling -# -edge - Enable edge profiling -# -function - Enable function profiling -# -o - Emit profiling information to the specified file, instead -# of llvmprof.out -# -# Any unrecognized options are passed into the invocation of llvm-prof -# - -my $ProfilePass = "-insert-edge-profiling"; - -my $LLVMProfOpts = ""; -my $ProgramOpts = ""; -my $ProfileFile = ""; - -# Parse arguments... -while (scalar(@ARGV) and ($_ = $ARGV[0], /^[-+]/)) { - shift; - last if /^--$/; # Stop processing arguments on -- - - # List command line options here... - if (/^-?-block$/) { $ProfilePass = "-insert-block-profiling"; next; } - if (/^-?-edge$/) { $ProfilePass = "-insert-edge-profiling"; next; } - if (/^-?-function$/) { $ProfilePass = "-insert-function-profiling"; next; } - if (/^-?-o$/) { # Read -o filename... - die "-o option requires a filename argument!" if (!scalar(@ARGV)); - $ProgramOpts .= " -llvmprof-output $ARGV[0]"; - $ProfileFile = $ARGV[0]; - shift; - next; - } - if (/^-?-help$/) { - print "OVERVIEW: profile.pl - Instrumentation and profile printer.\n\n"; - print "USAGE: profile.pl [options] program.bc \n\n"; - print "OPTIONS:\n"; - print " -block - Enable basicblock profiling\n"; - print " -edge - Enable edge profiling\n"; - print " -function - Enable function profiling\n"; - print " -o - Specify an output file other than llvm-prof.out.\n"; - print " -help - Print this usage information\n"; - print "\nAll other options are passed into llvm-prof.\n"; - exit 1; - } - - # Otherwise, pass the option on to llvm-prof - $LLVMProfOpts .= " " . $_; -} - -die "Must specify LLVM bitcode file as first argument!" if (@ARGV == 0); - -my $BytecodeFile = $ARGV[0]; - -shift @ARGV; - -my $libdir = `llvm-config --libdir`; -chomp $libdir; - -my $LibProfPath = $libdir . "/libprofile_rt.so"; - -system "opt -q -f $ProfilePass $BytecodeFile -o $BytecodeFile.inst"; -system "lli -fake-argv0 '$BytecodeFile' -load $LibProfPath " . - "$BytecodeFile.inst $ProgramOpts " . (join ' ', @ARGV); -system "rm $BytecodeFile.inst"; -system "llvm-prof $LLVMProfOpts $BytecodeFile $ProfileFile"; -- cgit v1.1 From 9f64a56ababffecbe5a818ecbe5b6fbfc1d7b974 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Thu, 17 Oct 2013 12:10:12 +0000 Subject: Lit: Introduce an environment variable, $LIT_PRESERVES_TMP, to preserve TMP (and TEMP). This is intended to check how many temporary files would be generated in automated builders. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192887 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestingConfig.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'utils') diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index d541539..748cf1f 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -35,6 +35,15 @@ class TestingConfig: 'TMP' : os.environ.get('TMP',''), }) + # The option to preserve TMP (and TEMP). + # This is intended to check how many temporary files would be generated + # in automated builders. + if os.environ.has_key('LIT_PRESERVES_TMP'): + environment.update({ + 'TEMP' : os.environ.get('TEMP',''), + 'TMP' : os.environ.get('TMP',''), + }) + # Set the default available features based on the LitConfig. available_features = [] if litConfig.useValgrind: -- cgit v1.1 From 651ffc703e4ae78c4416e6c360b1182bbd30849a Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Thu, 17 Oct 2013 13:11:13 +0000 Subject: Lit: LIT_PRESERVES_TMP should be aware of TMPDIR, too. TMPDIR is preferred in Unix. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192891 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/TestingConfig.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index 748cf1f..4a34b77 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -35,13 +35,14 @@ class TestingConfig: 'TMP' : os.environ.get('TMP',''), }) - # The option to preserve TMP (and TEMP). + # The option to preserve TEMP, TMP, and TMPDIR. # This is intended to check how many temporary files would be generated - # in automated builders. + # (and be not cleaned up) in automated builders. if os.environ.has_key('LIT_PRESERVES_TMP'): environment.update({ 'TEMP' : os.environ.get('TEMP',''), 'TMP' : os.environ.get('TMP',''), + 'TMPDIR' : os.environ.get('TMPDIR',''), }) # Set the default available features based on the LitConfig. -- cgit v1.1 From 44a4cfb63d87dc0ba778982a1796673ca1513e90 Mon Sep 17 00:00:00 2001 From: "Michael J. Spencer" Date: Fri, 18 Oct 2013 22:38:04 +0000 Subject: [Support][YAML] Add support for accessing tags and tag handle substitution. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193004 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/yaml-bench/YAMLBench.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'utils') diff --git a/utils/yaml-bench/YAMLBench.cpp b/utils/yaml-bench/YAMLBench.cpp index eef4a72..f20a4cc 100644 --- a/utils/yaml-bench/YAMLBench.cpp +++ b/utils/yaml-bench/YAMLBench.cpp @@ -63,6 +63,20 @@ static raw_ostream &operator <<(raw_ostream &os, const indent &in) { return os; } +/// \brief Pretty print a tag by replacing tag:yaml.org,2002: with !!. +static std::string prettyTag(yaml::Node *N) { + std::string Tag = N->getVerbatimTag(); + if (StringRef(Tag).startswith("tag:yaml.org,2002:")) { + std::string Ret = "!!"; + Ret += StringRef(Tag).substr(18); + return std::move(Ret); + } + std::string Ret = "!<"; + Ret += Tag; + Ret += ">"; + return Ret; +} + static void dumpNode( yaml::Node *n , unsigned Indent = 0 , bool SuppressFirstIndent = false) { @@ -76,9 +90,9 @@ static void dumpNode( yaml::Node *n if (yaml::ScalarNode *sn = dyn_cast(n)) { SmallString<32> Storage; StringRef Val = sn->getValue(Storage); - outs() << "!!str \"" << yaml::escape(Val) << "\""; + outs() << prettyTag(n) << " \"" << yaml::escape(Val) << "\""; } else if (yaml::SequenceNode *sn = dyn_cast(n)) { - outs() << "!!seq [\n"; + outs() << prettyTag(n) << " [\n"; ++Indent; for (yaml::SequenceNode::iterator i = sn->begin(), e = sn->end(); i != e; ++i) { @@ -88,7 +102,7 @@ static void dumpNode( yaml::Node *n --Indent; outs() << indent(Indent) << "]"; } else if (yaml::MappingNode *mn = dyn_cast(n)) { - outs() << "!!map {\n"; + outs() << prettyTag(n) << " {\n"; ++Indent; for (yaml::MappingNode::iterator i = mn->begin(), e = mn->end(); i != e; ++i) { @@ -104,7 +118,7 @@ static void dumpNode( yaml::Node *n } else if (yaml::AliasNode *an = dyn_cast(n)){ outs() << "*" << an->getName(); } else if (dyn_cast(n)) { - outs() << "!!null null"; + outs() << prettyTag(n) << " null"; } } -- cgit v1.1 From 31544debc325ed996ccdd0c3e05d42afc9f56f77 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Fri, 18 Oct 2013 23:25:39 +0000 Subject: YAMLBench.cpp: Use llvm_move instead of std::move also here. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193011 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/yaml-bench/YAMLBench.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/yaml-bench/YAMLBench.cpp b/utils/yaml-bench/YAMLBench.cpp index f20a4cc..f335605 100644 --- a/utils/yaml-bench/YAMLBench.cpp +++ b/utils/yaml-bench/YAMLBench.cpp @@ -69,7 +69,7 @@ static std::string prettyTag(yaml::Node *N) { if (StringRef(Tag).startswith("tag:yaml.org,2002:")) { std::string Ret = "!!"; Ret += StringRef(Tag).substr(18); - return std::move(Ret); + return llvm_move(Ret); } std::string Ret = "!<"; Ret += Tag; -- cgit v1.1 From 8f70847f98925153ad48fdeea1a8e72ee08d78eb Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Sun, 20 Oct 2013 03:19:25 +0000 Subject: Typo. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193043 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/OptParserEmitter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp index cff004f..9c4daaf 100644 --- a/utils/TableGen/OptParserEmitter.cpp +++ b/utils/TableGen/OptParserEmitter.cpp @@ -79,7 +79,7 @@ static int CompareOptionRecords(Record *const *Av, Record *const *Bv) { if (APrec == BPrec && A->getValueAsListOfStrings("Prefixes") == B->getValueAsListOfStrings("Prefixes")) { - PrintError(A->getLoc(), Twine("Option is equivilent to")); + PrintError(A->getLoc(), Twine("Option is equivalent to")); PrintError(B->getLoc(), Twine("Other defined here")); PrintFatalError("Equivalent Options found."); } -- cgit v1.1 From a0d3bcfd8cf26f2849e0ea48419f31659dacb0bf Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 23 Oct 2013 22:19:07 +0000 Subject: [lit] Use multiprocessing based parallelism by default, on Unix. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193279 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index ba2490e..3d18707 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -115,6 +115,10 @@ def main(builtinParameters = {}): # FIXME: This is a hack. sys.setcheckinterval(1000) + # Use processes by default on Unix platforms. + isWindows = platform.system() == 'Windows' + useProcessesIsDefault = not isWindows + global options from optparse import OptionParser, OptionGroup parser = OptionParser("usage: %prog [options] {file-or-path}") @@ -199,10 +203,10 @@ def main(builtinParameters = {}): action="store_true", default=False) group.add_option("", "--use-processes", dest="useProcesses", help="Run tests in parallel with processes (not threads)", - action="store_true", default=False) + action="store_true", default=useProcessesIsDefault) group.add_option("", "--use-threads", dest="useProcesses", help="Run tests in parallel with threads (not processes)", - action="store_false", default=False) + action="store_false", default=not useProcessesIsDefault) parser.add_option_group(group) (opts, args) = parser.parse_args() @@ -241,7 +245,7 @@ def main(builtinParameters = {}): valgrindArgs = opts.valgrindArgs, noExecute = opts.noExecute, debug = opts.debug, - isWindows = (platform.system()=='Windows'), + isWindows = isWindows, params = userParams, config_prefix = opts.configPrefix) -- cgit v1.1 From 279a89ebdbbd7b85a2498066da8df7a871f7f20c Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 23 Oct 2013 22:19:32 +0000 Subject: [lit] Stop hacking the GIL check interval. - This was never a big win, and is irrelevant now that we commonly use multiprocessing based parallelism. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193280 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 6 ------ 1 file changed, 6 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 3d18707..dcf0c9f 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -109,12 +109,6 @@ def write_test_results(run, lit_config, testing_time, output_path): f.close() def main(builtinParameters = {}): - # Bump the GIL check interval, its more important to get any one thread to a - # blocking operation (hopefully exec) than to try and unblock other threads. - # - # FIXME: This is a hack. - sys.setcheckinterval(1000) - # Use processes by default on Unix platforms. isWindows = platform.system() == 'Windows' useProcessesIsDefault = not isWindows -- cgit v1.1 From d80961c91f5318cdbbd5150f54ddad04102b769a Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Wed, 23 Oct 2013 22:32:53 +0000 Subject: Actually switch the default to use multiprocessing git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193282 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index dcf0c9f..6f672a0 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -200,7 +200,7 @@ def main(builtinParameters = {}): action="store_true", default=useProcessesIsDefault) group.add_option("", "--use-threads", dest="useProcesses", help="Run tests in parallel with threads (not processes)", - action="store_false", default=not useProcessesIsDefault) + action="store_false", default=useProcessesIsDefault) parser.add_option_group(group) (opts, args) = parser.parse_args() -- cgit v1.1 From b94be5f21eb43f057a8ea2f8afda3c5fecf9e2d8 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 25 Oct 2013 15:07:59 +0000 Subject: Try to fix the openbsd bot. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193413 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 6f672a0..44042a3 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -111,7 +111,7 @@ def write_test_results(run, lit_config, testing_time, output_path): def main(builtinParameters = {}): # Use processes by default on Unix platforms. isWindows = platform.system() == 'Windows' - useProcessesIsDefault = not isWindows + useProcessesIsDefault = (not isWindows) and platform.system() != 'OpenBSD' global options from optparse import OptionParser, OptionGroup -- cgit v1.1 From 59b8e0419ce873f62df0cc1fd14d193d7b63f8a5 Mon Sep 17 00:00:00 2001 From: Alp Toker Date: Sat, 26 Oct 2013 02:43:08 +0000 Subject: Attempt to fix the FreeBSD build, disable multiprocessing Speculative quick fix based on clang-X86_64-freebsd output: File "/usr/local/lib/python2.6/multiprocessing/synchronize.py", line 33, in " function, see issue 3770.") ImportError: This platform lacks a functioning sem_open implementation, therefore, the required synchronization primitives needed will not function, see issue 3770. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193457 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 44042a3..9754f2f 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -111,7 +111,8 @@ def write_test_results(run, lit_config, testing_time, output_path): def main(builtinParameters = {}): # Use processes by default on Unix platforms. isWindows = platform.system() == 'Windows' - useProcessesIsDefault = (not isWindows) and platform.system() != 'OpenBSD' + # multiprocessing is broken on various BSD Python versions: http://bugs.python.org/issue3770 + useProcessesIsDefault = (not isWindows) and ('BSD' not in platform.system()) global options from optparse import OptionParser, OptionGroup -- cgit v1.1 From a4e71dea487750cd13a5a5821df3acee32988bf4 Mon Sep 17 00:00:00 2001 From: Alp Toker Date: Sat, 26 Oct 2013 08:22:44 +0000 Subject: lit: handle late multiprocessing errors gracefully This should be a better fix for lit multiprocessing failures, replacing the OpenBSD and FreeBSD workarounds in r193413 and r193457. Reference: http://bugs.python.org/issue3770 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193463 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/main.py | 3 +-- utils/lit/lit/run.py | 16 ++++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 9754f2f..6f672a0 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -111,8 +111,7 @@ def write_test_results(run, lit_config, testing_time, output_path): def main(builtinParameters = {}): # Use processes by default on Unix platforms. isWindows = platform.system() == 'Windows' - # multiprocessing is broken on various BSD Python versions: http://bugs.python.org/issue3770 - useProcessesIsDefault = (not isWindows) and ('BSD' not in platform.system()) + useProcessesIsDefault = not isWindows global options from optparse import OptionParser, OptionGroup diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py index 8642ff1..8aaf52f 100644 --- a/utils/lit/lit/run.py +++ b/utils/lit/lit/run.py @@ -209,16 +209,20 @@ class Run(object): """ # Choose the appropriate parallel execution implementation. - if jobs == 1 or not use_processes or multiprocessing is None: + if jobs != 1 and use_processes and multiprocessing: + try: + task_impl = multiprocessing.Process + queue_impl = multiprocessing.Queue + canceled_flag = multiprocessing.Value('i', 0) + consumer = MultiprocessResultsConsumer(self, display, jobs) + except ImportError: + # Workaround for BSD: http://bugs.python.org/issue3770 + consumer = None + if not consumer: task_impl = threading.Thread queue_impl = queue.Queue canceled_flag = LockedValue(0) consumer = ThreadResultsConsumer(display) - else: - task_impl = multiprocessing.Process - queue_impl = multiprocessing.Queue - canceled_flag = multiprocessing.Value('i', 0) - consumer = MultiprocessResultsConsumer(self, display, jobs) # Create the test provider. provider = TestProvider(self.tests, jobs, queue_impl, canceled_flag) -- cgit v1.1 From 8d93aa0de330e24fe1cec7a915bdf1354da377fa Mon Sep 17 00:00:00 2001 From: Alp Toker Date: Sat, 26 Oct 2013 08:46:05 +0000 Subject: Fix a referenced before assignment in r193463 Some versions of Python on the builders seem strict about this. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193464 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/run.py | 1 + 1 file changed, 1 insertion(+) (limited to 'utils') diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py index 8aaf52f..ed39c40 100644 --- a/utils/lit/lit/run.py +++ b/utils/lit/lit/run.py @@ -209,6 +209,7 @@ class Run(object): """ # Choose the appropriate parallel execution implementation. + consumer = None if jobs != 1 and use_processes and multiprocessing: try: task_impl = multiprocessing.Process -- cgit v1.1 From a685c139182519ed29c3cddd848649f533070004 Mon Sep 17 00:00:00 2001 From: Alp Toker Date: Sat, 26 Oct 2013 09:29:58 +0000 Subject: lit: Issue a note when multiprocessing fails to load If multiprocessing was requested, detected as available and subsequently failed to initialize it's worth letting the user know about it before falling back to threads. This condition can arise in certain OpenBSD / FreeBSD Python versions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193465 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/run.py | 1 + 1 file changed, 1 insertion(+) (limited to 'utils') diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py index ed39c40..97f8c6f 100644 --- a/utils/lit/lit/run.py +++ b/utils/lit/lit/run.py @@ -218,6 +218,7 @@ class Run(object): consumer = MultiprocessResultsConsumer(self, display, jobs) except ImportError: # Workaround for BSD: http://bugs.python.org/issue3770 + self.lit_config.note('failed to initialize multiprocessing') consumer = None if not consumer: task_impl = threading.Thread -- cgit v1.1 From 0435c5dbec925f6c33a5920b63b2bcb0873efe75 Mon Sep 17 00:00:00 2001 From: Joerg Sonnenberger Date: Sat, 26 Oct 2013 13:25:45 +0000 Subject: self.path may be empty or otherwise miss the normal system directories, so try PATH next. Assume it is sane enough to cover the usual system bash locations too, but the old list is not good enough for NetBSD. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193471 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/LitConfig.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'utils') diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index ed75e34..b0dde5d 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -73,11 +73,7 @@ class LitConfig: self.bashPath = lit.util.which('bash', os.pathsep.join(self.path)) if self.bashPath is None: - # Check some known paths. - for path in ('/bin/bash', '/usr/bin/bash', '/usr/local/bin/bash'): - if os.path.exists(path): - self.bashPath = path - break + self.bashPath = lit.util.which('bash') if self.bashPath is None: self.warning("Unable to find 'bash'.") -- cgit v1.1 From bbe8f3b0e19f9bcca6e739fd92cbae6d570cab93 Mon Sep 17 00:00:00 2001 From: Alp Toker Date: Sun, 27 Oct 2013 20:49:19 +0000 Subject: Clarify the comment about BSD versions in r193465 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193508 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/run.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py index 97f8c6f..e3d9344 100644 --- a/utils/lit/lit/run.py +++ b/utils/lit/lit/run.py @@ -217,7 +217,8 @@ class Run(object): canceled_flag = multiprocessing.Value('i', 0) consumer = MultiprocessResultsConsumer(self, display, jobs) except ImportError: - # Workaround for BSD: http://bugs.python.org/issue3770 + # multiprocessing fails to initialize with certain OpenBSD and + # FreeBSD Python versions: http://bugs.python.org/issue3770 self.lit_config.note('failed to initialize multiprocessing') consumer = None if not consumer: -- cgit v1.1 From 188545867dbcd0a6870b19c6b06d49610e7cda93 Mon Sep 17 00:00:00 2001 From: Alp Toker Date: Mon, 28 Oct 2013 10:26:13 +0000 Subject: lit: multiprocessing platform fix attempt The error raised by Python varies by platform(!), so let's just catch any exception and fall back. Thanks to Sylvestre Ledru for noticing this on a Debian / Python 2.7 system running code coverage. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193516 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/run.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py index e3d9344..27c414d 100644 --- a/utils/lit/lit/run.py +++ b/utils/lit/lit/run.py @@ -216,9 +216,10 @@ class Run(object): queue_impl = multiprocessing.Queue canceled_flag = multiprocessing.Value('i', 0) consumer = MultiprocessResultsConsumer(self, display, jobs) - except ImportError: + except: # multiprocessing fails to initialize with certain OpenBSD and # FreeBSD Python versions: http://bugs.python.org/issue3770 + # Unfortunately the error raised also varies by platform. self.lit_config.note('failed to initialize multiprocessing') consumer = None if not consumer: -- cgit v1.1 From 254ce94c266c4bf18a3aacc0a49e962e6dc51336 Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Mon, 28 Oct 2013 18:07:17 +0000 Subject: TableGen: Refactor AsmWriterEmitter to keep AsmWriterInsts. These used to be referenced by the CGI->AWI map (in AsmWriterEmitter), but stored in a vector local to EmitPrintInstruction. Move the vector to AsmWriterEmitter too. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193525 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/AsmWriterEmitter.cpp | 52 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index a6d1daf..a18b6b5 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -32,10 +32,12 @@ using namespace llvm; namespace { class AsmWriterEmitter { RecordKeeper &Records; + CodeGenTarget Target; std::map CGIAWIMap; std::vector NumberedInstructions; + std::vector Instructions; public: - AsmWriterEmitter(RecordKeeper &R) : Records(R) {} + AsmWriterEmitter(RecordKeeper &R); void run(raw_ostream &o); @@ -273,9 +275,9 @@ static void UnescapeString(std::string &Str) { } /// EmitPrintInstruction - Generate the code for the "printInstruction" method -/// implementation. +/// implementation. Destroys all instances of AsmWriterInst information, by +/// clearing the Instructions vector. void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { - CodeGenTarget Target(Records); Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); bool isMC = AsmWriter->getValueAsBit("isMCAsmWriter"); @@ -288,27 +290,6 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { << "::printInstruction(const " << MachineInstrClassName << " *MI, raw_ostream &O) {\n"; - std::vector Instructions; - - for (CodeGenTarget::inst_iterator I = Target.inst_begin(), - E = Target.inst_end(); I != E; ++I) - if (!(*I)->AsmString.empty() && - (*I)->TheDef->getName() != "PHI") - Instructions.push_back( - AsmWriterInst(**I, - AsmWriter->getValueAsInt("Variant"), - AsmWriter->getValueAsInt("FirstOperandColumn"), - AsmWriter->getValueAsInt("OperandSpacing"))); - - // Get the instruction numbering. - NumberedInstructions = Target.getInstructionsByEnumValue(); - - // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not - // all machine instructions are necessarily being printed, so there may be - // target instructions not in this map. - for (unsigned i = 0, e = Instructions.size(); i != e; ++i) - CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i])); - // Build an aggregate string, and build a table of offsets into it. SequenceToOffsetTable StringTable; @@ -592,7 +573,6 @@ emitRegisterNameString(raw_ostream &O, StringRef AltName, } void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { - CodeGenTarget Target(Records); Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); const std::vector &Registers = @@ -782,7 +762,6 @@ static unsigned CountResultNumOperands(StringRef AsmString) { } void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { - CodeGenTarget Target(Records); Record *AsmWriter = Target.getAsmWriter(); if (!AsmWriter->getValueAsBit("isMCAsmWriter")) @@ -1000,6 +979,27 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { O << "#endif // PRINT_ALIAS_INSTR\n"; } +AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) { + Record *AsmWriter = Target.getAsmWriter(); + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); + I != E; ++I) + if (!(*I)->AsmString.empty() && (*I)->TheDef->getName() != "PHI") + Instructions.push_back( + AsmWriterInst(**I, AsmWriter->getValueAsInt("Variant"), + AsmWriter->getValueAsInt("FirstOperandColumn"), + AsmWriter->getValueAsInt("OperandSpacing"))); + + // Get the instruction numbering. + NumberedInstructions = Target.getInstructionsByEnumValue(); + + // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not + // all machine instructions are necessarily being printed, so there may be + // target instructions not in this map. + for (unsigned i = 0, e = Instructions.size(); i != e; ++i) + CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i])); +} + void AsmWriterEmitter::run(raw_ostream &O) { EmitPrintInstruction(O); EmitGetRegisterName(O); -- cgit v1.1 From 2b43ffff322899dec2f49cb3cc13037b60679f72 Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Mon, 28 Oct 2013 18:07:21 +0000 Subject: TableGen: Refactor DAG patterns to enable parsing one pattern at a time. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193526 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenDAGPatterns.cpp | 110 ++++++++++++++++++---------------- utils/TableGen/CodeGenDAGPatterns.h | 6 +- 2 files changed, 65 insertions(+), 51 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index 4396297..823f437 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -2675,54 +2675,13 @@ static bool checkOperandClass(CGIOperandList::OperandInfo &OI, return false; } -/// ParseInstructions - Parse all of the instructions, inlining and resolving -/// any fragments involved. This populates the Instructions list with fully -/// resolved instructions. -void CodeGenDAGPatterns::ParseInstructions() { - std::vector Instrs = Records.getAllDerivedDefinitions("Instruction"); - - for (unsigned i = 0, e = Instrs.size(); i != e; ++i) { - ListInit *LI = 0; - - if (isa(Instrs[i]->getValueInit("Pattern"))) - LI = Instrs[i]->getValueAsListInit("Pattern"); - - // If there is no pattern, only collect minimal information about the - // instruction for its operand list. We have to assume that there is one - // result, as we have no detailed info. A pattern which references the - // null_frag operator is as-if no pattern were specified. Normally this - // is from a multiclass expansion w/ a SDPatternOperator passed in as - // null_frag. - if (!LI || LI->getSize() == 0 || hasNullFragReference(LI)) { - std::vector Results; - std::vector Operands; - - CodeGenInstruction &InstInfo = Target.getInstruction(Instrs[i]); - - if (InstInfo.Operands.size() != 0) { - if (InstInfo.Operands.NumDefs == 0) { - // These produce no results - for (unsigned j = 0, e = InstInfo.Operands.size(); j < e; ++j) - Operands.push_back(InstInfo.Operands[j].Rec); - } else { - // Assume the first operand is the result. - Results.push_back(InstInfo.Operands[0].Rec); - - // The rest are inputs. - for (unsigned j = 1, e = InstInfo.Operands.size(); j < e; ++j) - Operands.push_back(InstInfo.Operands[j].Rec); - } - } +const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern( + CodeGenInstruction &CGI, ListInit *Pat, DAGInstMap &DAGInsts) { - // Create and insert the instruction. - std::vector ImpResults; - Instructions.insert(std::make_pair(Instrs[i], - DAGInstruction(0, Results, Operands, ImpResults))); - continue; // no pattern. - } + assert(!DAGInsts.count(CGI.TheDef) && "Instruction already parsed!"); // Parse the instruction. - TreePattern *I = new TreePattern(Instrs[i], LI, true, *this); + TreePattern *I = new TreePattern(CGI.TheDef, Pat, true, *this); // Inline pattern fragments into it. I->InlinePatternFragments(); @@ -2761,7 +2720,6 @@ void CodeGenDAGPatterns::ParseInstructions() { // Parse the operands list from the (ops) list, validating it. assert(I->getArgList().empty() && "Args list should still be empty here!"); - CodeGenInstruction &CGI = Target.getInstruction(Instrs[i]); // Check that all of the results occur first in the list. std::vector Results; @@ -2860,18 +2818,70 @@ void CodeGenDAGPatterns::ParseInstructions() { // Create and insert the instruction. // FIXME: InstImpResults should not be part of DAGInstruction. DAGInstruction TheInst(I, Results, Operands, InstImpResults); - Instructions.insert(std::make_pair(I->getRecord(), TheInst)); + DAGInsts.insert(std::make_pair(I->getRecord(), TheInst)); // Use a temporary tree pattern to infer all types and make sure that the // constructed result is correct. This depends on the instruction already - // being inserted into the Instructions map. + // being inserted into the DAGInsts map. TreePattern Temp(I->getRecord(), ResultPattern, false, *this); Temp.InferAllTypes(&I->getNamedNodesMap()); - DAGInstruction &TheInsertedInst = Instructions.find(I->getRecord())->second; + DAGInstruction &TheInsertedInst = DAGInsts.find(I->getRecord())->second; TheInsertedInst.setResultPattern(Temp.getOnlyTree()); - DEBUG(I->dump()); + return TheInsertedInst; + } + +/// ParseInstructions - Parse all of the instructions, inlining and resolving +/// any fragments involved. This populates the Instructions list with fully +/// resolved instructions. +void CodeGenDAGPatterns::ParseInstructions() { + std::vector Instrs = Records.getAllDerivedDefinitions("Instruction"); + + for (unsigned i = 0, e = Instrs.size(); i != e; ++i) { + ListInit *LI = 0; + + if (isa(Instrs[i]->getValueInit("Pattern"))) + LI = Instrs[i]->getValueAsListInit("Pattern"); + + // If there is no pattern, only collect minimal information about the + // instruction for its operand list. We have to assume that there is one + // result, as we have no detailed info. A pattern which references the + // null_frag operator is as-if no pattern were specified. Normally this + // is from a multiclass expansion w/ a SDPatternOperator passed in as + // null_frag. + if (!LI || LI->getSize() == 0 || hasNullFragReference(LI)) { + std::vector Results; + std::vector Operands; + + CodeGenInstruction &InstInfo = Target.getInstruction(Instrs[i]); + + if (InstInfo.Operands.size() != 0) { + if (InstInfo.Operands.NumDefs == 0) { + // These produce no results + for (unsigned j = 0, e = InstInfo.Operands.size(); j < e; ++j) + Operands.push_back(InstInfo.Operands[j].Rec); + } else { + // Assume the first operand is the result. + Results.push_back(InstInfo.Operands[0].Rec); + + // The rest are inputs. + for (unsigned j = 1, e = InstInfo.Operands.size(); j < e; ++j) + Operands.push_back(InstInfo.Operands[j].Rec); + } + } + + // Create and insert the instruction. + std::vector ImpResults; + Instructions.insert(std::make_pair(Instrs[i], + DAGInstruction(0, Results, Operands, ImpResults))); + continue; // no pattern. + } + + CodeGenInstruction &CGI = Target.getInstruction(Instrs[i]); + const DAGInstruction &DI = parseInstructionPattern(CGI, LI, Instructions); + + DEBUG(DI.getPattern()->dump()); } // If we can, convert the instructions to be patterns that are matched! diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h index 7c2fa36..6fbdd4f 100644 --- a/utils/TableGen/CodeGenDAGPatterns.h +++ b/utils/TableGen/CodeGenDAGPatterns.h @@ -778,7 +778,11 @@ public: ptm_iterator ptm_begin() const { return PatternsToMatch.begin(); } ptm_iterator ptm_end() const { return PatternsToMatch.end(); } - + /// Parse the Pattern for an instruction, and insert the result in DAGInsts. + typedef std::map DAGInstMap; + const DAGInstruction &parseInstructionPattern( + CodeGenInstruction &CGI, ListInit *Pattern, + DAGInstMap &DAGInsts); const DAGInstruction &getInstruction(Record *R) const { assert(Instructions.count(R) && "Unknown instruction!"); -- cgit v1.1 From 1799684671805069cecdc2765b00b751fdbce19b Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Mon, 28 Oct 2013 18:19:04 +0000 Subject: TableGen: remove unused variable. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193527 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenDAGPatterns.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'utils') diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index 823f437..717090a 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -2881,6 +2881,7 @@ void CodeGenDAGPatterns::ParseInstructions() { CodeGenInstruction &CGI = Target.getInstruction(Instrs[i]); const DAGInstruction &DI = parseInstructionPattern(CGI, LI, Instructions); + (void)DI; DEBUG(DI.getPattern()->dump()); } -- cgit v1.1 From cf940ceff73f567876f1a1f62d3acbf67c43ea90 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Thu, 31 Oct 2013 17:18:07 +0000 Subject: whitespace git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193765 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/IntrinsicEmitter.cpp | 98 ++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 49 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index f6ea69c..cd4f0e6 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -84,10 +84,10 @@ void IntrinsicEmitter::run(raw_ostream &OS) { // Emit the function name recognizer. EmitFnNameRecognizer(Ints, OS); - + // Emit the intrinsic declaration generator. EmitGenerator(Ints, OS); - + // Emit the intrinsic parameter attributes. EmitAttributes(Ints, OS); @@ -125,7 +125,7 @@ void IntrinsicEmitter::EmitEnumInfo(const std::vector &Ints, for (unsigned i = 0, e = Ints.size(); i != e; ++i) { OS << " " << Ints[i].EnumName; OS << ((i != e-1) ? ", " : " "); - OS << std::string(40-Ints[i].EnumName.size(), ' ') + OS << std::string(40-Ints[i].EnumName.size(), ' ') << "// " << Ints[i].Name << "\n"; } OS << "#endif\n\n"; @@ -146,13 +146,13 @@ private: }; void IntrinsicEmitter:: -EmitFnNameRecognizer(const std::vector &Ints, +EmitFnNameRecognizer(const std::vector &Ints, raw_ostream &OS) { // Build a 'first character of function name' -> intrinsic # mapping. std::map > IntMapping; for (unsigned i = 0, e = Ints.size(); i != e; ++i) IntMapping[Ints[i].Name[5]].push_back(i); - + OS << "// Function name -> enum value recognizer code.\n"; OS << "#ifdef GET_FUNCTION_RECOGNIZER\n"; OS << " StringRef NameR(Name+6, Len-6); // Skip over 'llvm.'\n"; @@ -171,7 +171,7 @@ EmitFnNameRecognizer(const std::vector &Ints, // Emit all the overloaded intrinsics first, build a table of the // non-overloaded ones. std::vector MatchTable; - + for (unsigned i = 0, e = IntList.size(); i != e; ++i) { unsigned IntNo = IntList[i]; std::string Result = "return " + TargetPrefix + "Intrinsic::" + @@ -188,18 +188,18 @@ EmitFnNameRecognizer(const std::vector &Ints, OS << " if (NameR.startswith(\"" << TheStr << "\")) " << Result << '\n'; } - + // Emit the matcher logic for the fixed length strings. StringMatcher("NameR", MatchTable, OS).Emit(1); OS << " break; // end of '" << I->first << "' case.\n"; } - + OS << " }\n"; OS << "#endif\n\n"; } void IntrinsicEmitter:: -EmitIntrinsicToNameTable(const std::vector &Ints, +EmitIntrinsicToNameTable(const std::vector &Ints, raw_ostream &OS) { OS << "// Intrinsic ID to name table\n"; OS << "#ifdef GET_INTRINSIC_NAME_TABLE\n"; @@ -210,7 +210,7 @@ EmitIntrinsicToNameTable(const std::vector &Ints, } void IntrinsicEmitter:: -EmitIntrinsicToOverloadTable(const std::vector &Ints, +EmitIntrinsicToOverloadTable(const std::vector &Ints, raw_ostream &OS) { OS << "// Intrinsic ID to overload bitset\n"; OS << "#ifdef GET_INTRINSIC_OVERLOAD_TABLE\n"; @@ -278,7 +278,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT, case 64: return Sig.push_back(IIT_I64); } } - + switch (VT) { default: PrintFatalError("unhandled MVT in intrinsic!"); case MVT::f16: return Sig.push_back(IIT_F16); @@ -293,11 +293,11 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT, #ifdef _MSC_VER #pragma optimize("",off) // MSVC 2010 optimizer can't deal with this function. -#endif +#endif static void EncodeFixedType(Record *R, std::vector &ArgCodes, std::vector &Sig) { - + if (R->isSubClassOf("LLVMMatchType")) { unsigned Number = R->getValueAsInt("Number"); assert(Number < ArgCodes.size() && "Invalid matching number!"); @@ -309,7 +309,7 @@ static void EncodeFixedType(Record *R, std::vector &ArgCodes, Sig.push_back(IIT_ARG); return Sig.push_back((Number << 2) | ArgCodes[Number]); } - + MVT::SimpleValueType VT = getValueType(R->getValueAsDef("VT")); unsigned Tmp = 0; @@ -320,17 +320,17 @@ static void EncodeFixedType(Record *R, std::vector &ArgCodes, case MVT::fAny: ++Tmp; // FALL THROUGH. case MVT::iAny: { // If this is an "any" valuetype, then the type is the type of the next - // type in the list specified to getIntrinsic(). + // type in the list specified to getIntrinsic(). Sig.push_back(IIT_ARG); - + // Figure out what arg # this is consuming, and remember what kind it was. unsigned ArgNo = ArgCodes.size(); ArgCodes.push_back(Tmp); - + // Encode what sort of argument it must be in the low 2 bits of the ArgNo. return Sig.push_back((ArgNo << 2) | Tmp); } - + case MVT::iPTR: { unsigned AddrSpace = 0; if (R->isSubClassOf("LLVMQualPointerType")) { @@ -346,7 +346,7 @@ static void EncodeFixedType(Record *R, std::vector &ArgCodes, return EncodeFixedType(R->getValueAsDef("ElTy"), ArgCodes, Sig); } } - + if (EVT(VT).isVector()) { EVT VVT = VT; switch (VVT.getVectorNumElements()) { @@ -358,7 +358,7 @@ static void EncodeFixedType(Record *R, std::vector &ArgCodes, case 16: Sig.push_back(IIT_V16); break; case 32: Sig.push_back(IIT_V32); break; } - + return EncodeFixedValueType(VVT.getVectorElementType(). getSimpleVT().SimpleTy, Sig); } @@ -375,7 +375,7 @@ static void EncodeFixedType(Record *R, std::vector &ArgCodes, static void ComputeFixedEncoding(const CodeGenIntrinsic &Int, std::vector &TypeSig) { std::vector ArgCodes; - + if (Int.IS.RetVTs.empty()) TypeSig.push_back(IIT_Done); else if (Int.IS.RetVTs.size() == 1 && @@ -390,11 +390,11 @@ static void ComputeFixedEncoding(const CodeGenIntrinsic &Int, case 5: TypeSig.push_back(IIT_STRUCT5); break; default: assert(0 && "Unhandled case in struct"); } - + for (unsigned i = 0, e = Int.IS.RetVTs.size(); i != e; ++i) EncodeFixedType(Int.IS.RetTypeDefs[i], ArgCodes, TypeSig); } - + for (unsigned i = 0, e = Int.IS.ParamTypeDefs.size(); i != e; ++i) EncodeFixedType(Int.IS.ParamTypeDefs[i], ArgCodes, TypeSig); } @@ -403,16 +403,16 @@ static void printIITEntry(raw_ostream &OS, unsigned char X) { OS << (unsigned)X; } -void IntrinsicEmitter::EmitGenerator(const std::vector &Ints, +void IntrinsicEmitter::EmitGenerator(const std::vector &Ints, raw_ostream &OS) { // If we can compute a 32-bit fixed encoding for this intrinsic, do so and // capture it in this vector, otherwise store a ~0U. std::vector FixedEncodings; - + SequenceToOffsetTable > LongEncodingTable; - + std::vector TypeSig; - + // Compute the unique argument type info. for (unsigned i = 0, e = Ints.size(); i != e; ++i) { // Get the signature for the intrinsic. @@ -432,7 +432,7 @@ void IntrinsicEmitter::EmitGenerator(const std::vector &Ints, } Result = (Result << 4) | TypeSig[e-i-1]; } - + // If this could be encoded into a 31-bit word, return it. if (!Failed && (Result >> 31) == 0) { FixedEncodings.push_back(Result); @@ -443,45 +443,45 @@ void IntrinsicEmitter::EmitGenerator(const std::vector &Ints, // Otherwise, we're going to unique the sequence into the // LongEncodingTable, and use its offset in the 32-bit table instead. LongEncodingTable.add(TypeSig); - + // This is a placehold that we'll replace after the table is laid out. FixedEncodings.push_back(~0U); } - + LongEncodingTable.layout(); - + OS << "// Global intrinsic function declaration type table.\n"; OS << "#ifdef GET_INTRINSIC_GENERATOR_GLOBAL\n"; OS << "static const unsigned IIT_Table[] = {\n "; - + for (unsigned i = 0, e = FixedEncodings.size(); i != e; ++i) { if ((i & 7) == 7) OS << "\n "; - + // If the entry fit in the table, just emit it. if (FixedEncodings[i] != ~0U) { OS << "0x" << utohexstr(FixedEncodings[i]) << ", "; continue; } - + TypeSig.clear(); ComputeFixedEncoding(Ints[i], TypeSig); - + // Otherwise, emit the offset into the long encoding table. We emit it this // way so that it is easier to read the offset in the .def file. OS << "(1U<<31) | " << LongEncodingTable.get(TypeSig) << ", "; } - + OS << "0\n};\n\n"; - + // Emit the shared table of register lists. OS << "static const unsigned char IIT_LongEncodingTable[] = {\n"; if (!LongEncodingTable.empty()) LongEncodingTable.emit(OS, printIITEntry); OS << " 255\n};\n\n"; - + OS << "#endif\n\n"; // End of GET_INTRINSIC_GENERATOR_GLOBAL } @@ -631,7 +631,7 @@ EmitAttributes(const std::vector &Ints, raw_ostream &OS) { OS << " AttrVec.push_back(Attribute::ReadOnly);\n"; break; case MRK_readnone: - OS << " AttrVec.push_back(Attribute::ReadNone);\n"; + OS << " AttrVec.push_back(Attribute::ReadNone);\n"; break; } OS << " AS[" << numAttrs++ << "] = AttributeSet::get(C, " @@ -645,7 +645,7 @@ EmitAttributes(const std::vector &Ints, raw_ostream &OS) { OS << " return AttributeSet();\n"; } } - + OS << " }\n"; OS << " }\n"; OS << " return AttributeSet::get(C, ArrayRef(AS, " @@ -694,9 +694,9 @@ EmitModRefBehavior(const std::vector &Ints, raw_ostream &OS){ static void EmitTargetBuiltins(const std::map &BIM, const std::string &TargetPrefix, raw_ostream &OS) { - + std::vector Results; - + for (std::map::const_iterator I = BIM.begin(), E = BIM.end(); I != E; ++I) { std::string ResultCode = @@ -707,9 +707,9 @@ static void EmitTargetBuiltins(const std::map &BIM, StringMatcher("BuiltinName", Results, OS).Emit(); } - + void IntrinsicEmitter:: -EmitIntrinsicToGCCBuiltinMap(const std::vector &Ints, +EmitIntrinsicToGCCBuiltinMap(const std::vector &Ints, raw_ostream &OS) { typedef std::map > BIMTy; BIMTy BuiltinMap; @@ -717,20 +717,20 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector &Ints, if (!Ints[i].GCCBuiltinName.empty()) { // Get the map for this target prefix. std::map &BIM =BuiltinMap[Ints[i].TargetPrefix]; - + if (!BIM.insert(std::make_pair(Ints[i].GCCBuiltinName, Ints[i].EnumName)).second) PrintFatalError("Intrinsic '" + Ints[i].TheDef->getName() + "': duplicate GCC builtin name!"); } } - + OS << "// Get the LLVM intrinsic that corresponds to a GCC builtin.\n"; OS << "// This is used by the C front-end. The GCC builtin name is passed\n"; OS << "// in as BuiltinName, and a target prefix (e.g. 'ppc') is passed\n"; OS << "// in as TargetPrefix. The result is assigned to 'IntrinsicID'.\n"; OS << "#ifdef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN\n"; - + if (TargetOnly) { OS << "static " << TargetPrefix << "Intrinsic::ID " << "getIntrinsicForGCCBuiltin(const char " @@ -739,10 +739,10 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector &Ints, OS << "Intrinsic::ID Intrinsic::getIntrinsicForGCCBuiltin(const char " << "*TargetPrefixStr, const char *BuiltinNameStr) {\n"; } - + OS << " StringRef BuiltinName(BuiltinNameStr);\n"; OS << " StringRef TargetPrefix(TargetPrefixStr);\n\n"; - + // Note: this could emit significantly better code if we cared. for (BIMTy::iterator I = BuiltinMap.begin(), E = BuiltinMap.end();I != E;++I){ OS << " "; -- cgit v1.1 From 2e50b8a08d40ce72ae35c73528140d3ee25209e0 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Thu, 31 Oct 2013 17:18:11 +0000 Subject: Enable variable arguments support for intrinsics. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193766 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/IntrinsicEmitter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index cd4f0e6..6531dcb 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -261,7 +261,8 @@ enum IIT_Info { IIT_EXTEND_VEC_ARG = 23, IIT_TRUNC_VEC_ARG = 24, IIT_ANYPTR = 25, - IIT_V1 = 26 + IIT_V1 = 26, + IIT_VARARG = 27 }; @@ -288,6 +289,8 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT, case MVT::x86mmx: return Sig.push_back(IIT_MMX); // MVT::OtherVT is used to mean the empty struct type here. case MVT::Other: return Sig.push_back(IIT_EMPTYSTRUCT); + // MVT::isVoid is used to represent varargs here. + case MVT::isVoid: return Sig.push_back(IIT_VARARG); } } -- cgit v1.1 From 2343e3b228c02896f4779962a91aaa659356fe2a Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Thu, 31 Oct 2013 17:18:24 +0000 Subject: Lower stackmap intrinsics directly to their target opcode in the DAG builder. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193769 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenTarget.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'utils') diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index cd0b8c7..dd17059 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -321,6 +321,8 @@ void CodeGenTarget::ComputeInstrsByEnum() const { "BUNDLE", "LIFETIME_START", "LIFETIME_END", + "STACKMAP", + "PATCHPOINT", 0 }; const DenseMap &Insts = getInstructions(); -- cgit v1.1 From 19794da02cc48a772ae6f4756b14b111a627170e Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 1 Nov 2013 17:09:14 +0000 Subject: Remove linkonce_odr_auto_hide. linkonce_odr_auto_hide was in incomplete attempt to implement a way for the linker to hide symbols that are known to be available in every TU and whose addresses are not relevant for a particular DSO. It was redundant in that it all its uses are equivalent to linkonce_odr+unnamed_addr. Unlike those, it has never been connected to clang or llvm's optimizers, so it was effectively dead. Given that nothing produces it, this patch just nukes it (other than the llvm-c enum value). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193865 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/kate/llvm.xml | 1 - utils/vim/llvm.vim | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/kate/llvm.xml b/utils/kate/llvm.xml index 3e32b50..7cea92a 100644 --- a/utils/kate/llvm.xml +++ b/utils/kate/llvm.xml @@ -41,7 +41,6 @@ private linker_private linker_private_weak - linker_private_weak_def_auto internal available_externally linkonce diff --git a/utils/vim/llvm.vim b/utils/vim/llvm.vim index b28c07f..c611ad8 100644 --- a/utils/vim/llvm.vim +++ b/utils/vim/llvm.vim @@ -43,8 +43,8 @@ syn keyword llvmKeyword constant datalayout declare default define deplibs syn keyword llvmKeyword dllexport dllimport except extern_weak external fastcc syn keyword llvmKeyword filter gc global hidden initialexec inlinehint inreg syn keyword llvmKeyword intel_ocl_bicc inteldialect internal linker_private -syn keyword llvmKeyword linker_private_weak linker_private_weak_def_auto -syn keyword llvmKeyword linkonce linkonce_odr linkonce_odr_auto_hide +syn keyword llvmKeyword linker_private_weak +syn keyword llvmKeyword linkonce linkonce_odr syn keyword llvmKeyword localdynamic localexec minsize module monotonic syn keyword llvmKeyword msp430_intrcc naked nest noalias nocapture syn keyword llvmKeyword noimplicitfloat noinline nonlazybind noredzone noreturn -- cgit v1.1 From d6b6425d3c576419cc5c570ae9e7711af49cf035 Mon Sep 17 00:00:00 2001 From: Bob Wilson Date: Sun, 3 Nov 2013 05:49:36 +0000 Subject: Configure with --enable-terminfo=no for Apple's llvmCore builds. Patch by Pete Cooper. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193940 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/buildit/build_llvm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/buildit/build_llvm b/utils/buildit/build_llvm index 4ed25f2..9e93216 100755 --- a/utils/buildit/build_llvm +++ b/utils/buildit/build_llvm @@ -104,7 +104,8 @@ COMMON_CONFIGURE_OPTS="\ --enable-assertions=$LLVM_ASSERTIONS \ --enable-optimized=$LLVM_OPTIMIZED \ --disable-bindings \ - --disable-zlib" + --disable-zlib \ + --enable-terminfo=no" COMMON_MAKEFLAGS="\ UNIVERSAL=1 \ -- cgit v1.1 From 633f98bdfa266871dcd17ab27af1594c6cc31d9e Mon Sep 17 00:00:00 2001 From: Elena Demikhovsky Date: Sun, 3 Nov 2013 13:46:31 +0000 Subject: AVX-512: added VPCONFLICT instruction and intrinsics, added EVEX_KZ to tablegen git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193959 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/X86DisassemblerTables.cpp | 35 +++++++++++++++++++++++++++++--- utils/TableGen/X86RecognizableInstr.cpp | 7 +++++-- utils/TableGen/X86RecognizableInstr.h | 2 ++ 3 files changed, 39 insertions(+), 5 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index 026870e..bdb4793 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -128,7 +128,7 @@ static inline bool inheritsFrom(InstructionContext child, inheritsFrom(child, IC_EVEX_L_W_XD); case IC_EVEX_OPSIZE: return inheritsFrom(child, IC_EVEX_W_OPSIZE) || - inheritsFrom(child, IC_EVEX_W_OPSIZE); + inheritsFrom(child, IC_EVEX_L_W_OPSIZE); case IC_EVEX_W: case IC_EVEX_W_XS: case IC_EVEX_W_XD: @@ -176,10 +176,24 @@ static inline bool inheritsFrom(InstructionContext child, case IC_EVEX_L_XD_K: case IC_EVEX_L_OPSIZE_K: return false; + case IC_EVEX_W_KZ: + case IC_EVEX_W_XS_KZ: + case IC_EVEX_W_XD_KZ: + case IC_EVEX_W_OPSIZE_KZ: + return false; + case IC_EVEX_L_KZ: + case IC_EVEX_L_XS_KZ: + case IC_EVEX_L_XD_KZ: + case IC_EVEX_L_OPSIZE_KZ: + return false; case IC_EVEX_L_W_K: case IC_EVEX_L_W_XS_K: case IC_EVEX_L_W_XD_K: case IC_EVEX_L_W_OPSIZE_K: + case IC_EVEX_L_W_KZ: + case IC_EVEX_L_W_XS_KZ: + case IC_EVEX_L_W_XD_KZ: + case IC_EVEX_L_W_OPSIZE_KZ: return false; case IC_EVEX_L2_K: case IC_EVEX_L2_B: @@ -187,12 +201,25 @@ static inline bool inheritsFrom(InstructionContext child, case IC_EVEX_L2_XD_K: case IC_EVEX_L2_OPSIZE_K: case IC_EVEX_L2_OPSIZE_B: + case IC_EVEX_L2_OPSIZE_K_B: + case IC_EVEX_L2_KZ: + case IC_EVEX_L2_XS_KZ: + case IC_EVEX_L2_XD_KZ: + case IC_EVEX_L2_OPSIZE_KZ: + case IC_EVEX_L2_OPSIZE_KZ_B: return false; case IC_EVEX_L2_W_K: + case IC_EVEX_L2_W_B: case IC_EVEX_L2_W_XS_K: case IC_EVEX_L2_W_XD_K: case IC_EVEX_L2_W_OPSIZE_K: case IC_EVEX_L2_W_OPSIZE_B: + case IC_EVEX_L2_W_OPSIZE_K_B: + case IC_EVEX_L2_W_KZ: + case IC_EVEX_L2_W_XS_KZ: + case IC_EVEX_L2_W_XD_KZ: + case IC_EVEX_L2_W_OPSIZE_KZ: + case IC_EVEX_L2_W_OPSIZE_KZ_B: return false; default: llvm_unreachable("Unknown instruction class"); @@ -213,7 +240,8 @@ static inline bool outranks(InstructionContext upper, #define ENUM_ENTRY(n, r, d) r, #define ENUM_ENTRY_K_B(n, r, d) ENUM_ENTRY(n, r, d) \ - ENUM_ENTRY(n##_K_B, r, d) ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d) + ENUM_ENTRY(n##_K_B, r, d) ENUM_ENTRY(n##_KZ_B, r, d) \ + ENUM_ENTRY(n##_KZ, r, d) ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d) static int ranks[IC_max] = { INSTRUCTION_CONTEXTS }; @@ -235,7 +263,8 @@ static inline const char* stringForContext(InstructionContext insnContext) { llvm_unreachable("Unhandled instruction class"); #define ENUM_ENTRY(n, r, d) case n: return #n; break; #define ENUM_ENTRY_K_B(n, r, d) ENUM_ENTRY(n, r, d) ENUM_ENTRY(n##_K_B, r, d)\ - ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d) + ENUM_ENTRY(n##_KZ, r, d) ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d)\ + ENUM_ENTRY(n##_KZ_B, r, d) INSTRUCTION_CONTEXTS #undef ENUM_ENTRY #undef ENUM_ENTRY_K_B diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index b9666f1..708e72d 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -244,6 +244,7 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, HasEVEXPrefix = Rec->getValueAsBit("hasEVEXPrefix"); HasEVEX_L2Prefix = Rec->getValueAsBit("hasEVEX_L2"); HasEVEX_K = Rec->getValueAsBit("hasEVEX_K"); + HasEVEX_KZ = Rec->getValueAsBit("hasEVEX_Z"); HasEVEX_B = Rec->getValueAsBit("hasEVEX_B"); HasLockPrefix = Rec->getValueAsBit("hasLockPrefix"); IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly"); @@ -304,8 +305,10 @@ void RecognizableInstr::processInstr(DisassemblerTables &tables, recogInstr.emitDecodePath(tables); } -#define EVEX_KB(n) (HasEVEX_K && HasEVEX_B? n##_K_B : \ - (HasEVEX_K? n##_K : (HasEVEX_B ? n##_B : n))) +#define EVEX_KB(n) (HasEVEX_KZ && HasEVEX_B ? n##_KZ_B : \ + (HasEVEX_K && HasEVEX_B ? n##_K_B : \ + (HasEVEX_KZ ? n##_KZ : \ + (HasEVEX_K? n##_K : (HasEVEX_B ? n##_B : n))))) InstructionContext RecognizableInstr::insnContext() const { InstructionContext insnContext; diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h index 7e1d362..4d4686e 100644 --- a/utils/TableGen/X86RecognizableInstr.h +++ b/utils/TableGen/X86RecognizableInstr.h @@ -72,6 +72,8 @@ private: bool HasEVEX_L2Prefix; /// The hasEVEX_K field from the record bool HasEVEX_K; + /// The hasEVEX_KZ field from the record + bool HasEVEX_KZ; /// The hasEVEX_B field from the record bool HasEVEX_B; /// The hasLockPrefix field from the record -- cgit v1.1 From ee4f5eae1c416eddbecbb2d742e2bb8dc0032bf6 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Sun, 10 Nov 2013 02:04:09 +0000 Subject: Allow multiple check prefixes in FileCheck. This is useful if you want to run multiple variations of a single test, and the majority of check lines should be the same. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194343 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/FileCheck.cpp | 317 +++++++++++++++++++++++++++++++----------- 1 file changed, 237 insertions(+), 80 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 77721f9..c9eb8a6 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" @@ -42,14 +43,16 @@ static cl::opt InputFilename("input-file", cl::desc("File to check (defaults to stdin)"), cl::init("-"), cl::value_desc("filename")); -static cl::opt -CheckPrefix("check-prefix", cl::init("CHECK"), - cl::desc("Prefix to use from check file (defaults to 'CHECK')")); +static cl::list +CheckPrefixes("check-prefix", + cl::desc("Prefix to use from check file (defaults to 'CHECK')")); static cl::opt NoCanonicalizeWhiteSpace("strict-whitespace", cl::desc("Do not treat all horizontal whitespace as equivalent")); +typedef cl::list::const_iterator prefix_iterator; + //===----------------------------------------------------------------------===// // Pattern Handling Code. //===----------------------------------------------------------------------===// @@ -103,11 +106,15 @@ public: /// getLoc - Return the location in source code. SMLoc getLoc() const { return PatternLoc; } - /// ParsePattern - Parse the given string into the Pattern. SM provides the - /// SourceMgr used for error reports, and LineNumber is the line number in - /// the input file from which the pattern string was read. - /// Returns true in case of an error, false otherwise. - bool ParsePattern(StringRef PatternStr, SourceMgr &SM, unsigned LineNumber); + /// ParsePattern - Parse the given string into the Pattern. Prefix provides + /// which prefix is being matched, SM provides the SourceMgr used for error + /// reports, and LineNumber is the line number in the input file from which + /// the pattern string was read. Returns true in case of an error, false + /// otherwise. + bool ParsePattern(StringRef PatternStr, + StringRef Prefix, + SourceMgr &SM, + unsigned LineNumber); /// Match - Match the pattern string against the input buffer Buffer. This /// returns the position that is matched or npos if there is no match. If @@ -152,7 +159,9 @@ private: }; -bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM, +bool Pattern::ParsePattern(StringRef PatternStr, + StringRef Prefix, + SourceMgr &SM, unsigned LineNumber) { this->LineNumber = LineNumber; PatternLoc = SMLoc::getFromPointer(PatternStr.data()); @@ -166,7 +175,7 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM, if (PatternStr.empty()) { SM.PrintMessage(PatternLoc, SourceMgr::DK_Error, "found empty check string with prefix '" + - CheckPrefix+":'"); + Prefix + ":'"); return true; } @@ -594,6 +603,9 @@ struct CheckString { /// Pat - The pattern to match. Pattern Pat; + /// Prefix - Which prefix name this check matched. + StringRef Prefix; + /// Loc - The location in the match file that the check string was specified. SMLoc Loc; @@ -606,8 +618,12 @@ struct CheckString { /// file). std::vector DagNotStrings; - CheckString(const Pattern &P, SMLoc L, Check::CheckType Ty) - : Pat(P), Loc(L), CheckTy(Ty) {} + + CheckString(const Pattern &P, + StringRef S, + SMLoc L, + Check::CheckType Ty) + : Pat(P), Prefix(S), Loc(L), CheckTy(Ty) {} /// Check - Match check string and its "not strings" and/or "dag strings". size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, @@ -670,45 +686,157 @@ static bool IsPartOfWord(char c) { return (isalnum(c) || c == '-' || c == '_'); } -static Check::CheckType FindCheckType(StringRef &Buffer, StringRef Prefix) { +// Get the size of the prefix extension. +static size_t CheckTypeSize(Check::CheckType Ty) { + switch (Ty) { + case Check::CheckNone: + return 0; + + case Check::CheckPlain: + return sizeof(":") - 1; + + case Check::CheckNext: + return sizeof("-NEXT:") - 1; + + case Check::CheckNot: + return sizeof("-NOT:") - 1; + + case Check::CheckDAG: + return sizeof("-DAG:") - 1; + + case Check::CheckLabel: + return sizeof("-LABEL:") - 1; + + case Check::CheckEOF: + llvm_unreachable("Should not be using EOF size"); + } + + llvm_unreachable("Bad check type"); +} + +static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) { char NextChar = Buffer[Prefix.size()]; // Verify that the : is present after the prefix. - if (NextChar == ':') { - Buffer = Buffer.substr(Prefix.size() + 1); + if (NextChar == ':') return Check::CheckPlain; - } - if (NextChar != '-') { - Buffer = Buffer.drop_front(1); + if (NextChar != '-') return Check::CheckNone; - } StringRef Rest = Buffer.drop_front(Prefix.size() + 1); - if (Rest.startswith("NEXT:")) { - Buffer = Rest.drop_front(sizeof("NEXT:") - 1); + if (Rest.startswith("NEXT:")) return Check::CheckNext; - } - if (Rest.startswith("NOT:")) { - Buffer = Rest.drop_front(sizeof("NOT:") - 1); + if (Rest.startswith("NOT:")) return Check::CheckNot; - } - if (Rest.startswith("DAG:")) { - Buffer = Rest.drop_front(sizeof("DAG:") - 1); + if (Rest.startswith("DAG:")) return Check::CheckDAG; - } - if (Rest.startswith("LABEL:")) { - Buffer = Rest.drop_front(sizeof("LABEL:") - 1); + if (Rest.startswith("LABEL:")) return Check::CheckLabel; - } - Buffer = Buffer.drop_front(1); return Check::CheckNone; } +// From the given position, find the next character after the word. +static size_t SkipWord(StringRef Str, size_t Loc) { + while (Loc < Str.size() && IsPartOfWord(Str[Loc])) + ++Loc; + return Loc; +} + +// Try to find the first match in buffer for any prefix. If a valid match is +// found, return that prefix and set its type and location. If there are almost +// matches (e.g. the actual prefix string is found, but is not an actual check +// string), but no valid match, return an empty string and set the position to +// resume searching from. If no partial matches are found, return an empty +// string and the location will be StringRef::npos. If one prefix is a substring +// of another, the maximal match should be found. e.g. if "A" and "AA" are +// prefixes then AA-CHECK: should match the second one. +static StringRef FindFirstCandidateMatch(StringRef &Buffer, + Check::CheckType &CheckTy, + size_t &CheckLoc) { + StringRef FirstPrefix; + size_t FirstLoc = StringRef::npos; + size_t SearchLoc = StringRef::npos; + Check::CheckType FirstTy = Check::CheckNone; + + CheckTy = Check::CheckNone; + CheckLoc = StringRef::npos; + + for (prefix_iterator I = CheckPrefixes.begin(), E = CheckPrefixes.end(); + I != E; ++I) { + StringRef Prefix(*I); + size_t PrefixLoc = Buffer.find(Prefix); + + if (PrefixLoc == StringRef::npos) + continue; + + // Track where we are searching for invalid prefixes that look almost right. + // We need to only advance to the first partial match on the next attempt + // since a partial match could be a substring of a later, valid prefix. + // Need to skip to the end of the word, otherwise we could end up + // matching a prefix in a substring later. + if (PrefixLoc < SearchLoc) + SearchLoc = SkipWord(Buffer, PrefixLoc); + + // We only want to find the first match to avoid skipping some. + if (PrefixLoc > FirstLoc) + continue; + + StringRef Rest = Buffer.drop_front(PrefixLoc); + // Make sure we have actually found the prefix, and not a word containing + // it. This should also prevent matching the wrong prefix when one is a + // substring of another. + if (PrefixLoc != 0 && IsPartOfWord(Buffer[PrefixLoc - 1])) + continue; + + Check::CheckType Ty = FindCheckType(Rest, Prefix); + if (Ty == Check::CheckNone) + continue; + + FirstLoc = PrefixLoc; + FirstTy = Ty; + FirstPrefix = Prefix; + } + + if (FirstPrefix.empty()) { + CheckLoc = SearchLoc; + } else { + CheckTy = FirstTy; + CheckLoc = FirstLoc; + } + + return FirstPrefix; +} + +static StringRef FindFirstMatchingPrefix(StringRef &Buffer, + unsigned &LineNumber, + Check::CheckType &CheckTy, + size_t &CheckLoc) { + while (!Buffer.empty()) { + StringRef Prefix = FindFirstCandidateMatch(Buffer, CheckTy, CheckLoc); + // If we found a real match, we are done. + if (!Prefix.empty()) { + LineNumber += Buffer.substr(0, CheckLoc).count('\n'); + return Prefix; + } + + // We didn't find any almost matches either, we are also done. + if (CheckLoc == StringRef::npos) + return StringRef(); + + LineNumber += Buffer.substr(0, CheckLoc + 1).count('\n'); + + // Advance to the last possible match we found and try again. + Buffer = Buffer.drop_front(CheckLoc + 1); + } + + return StringRef(); +} + /// ReadCheckFile - Read the check file, which specifies the sequence of /// expected strings. The strings are added to the CheckStrings vector. /// Returns true in case of an error, false otherwise. @@ -738,32 +866,24 @@ static bool ReadCheckFile(SourceMgr &SM, unsigned LineNumber = 1; while (1) { - // See if Prefix occurs in the memory buffer. - size_t PrefixLoc = Buffer.find(CheckPrefix); - // If we didn't find a match, we're done. - if (PrefixLoc == StringRef::npos) + Check::CheckType CheckTy; + size_t PrefixLoc; + + // See if a prefix occurs in the memory buffer. + StringRef UsedPrefix = FindFirstMatchingPrefix(Buffer, + LineNumber, + CheckTy, + PrefixLoc); + if (UsedPrefix.empty()) break; - LineNumber += Buffer.substr(0, PrefixLoc).count('\n'); + Buffer = Buffer.drop_front(PrefixLoc); - // Keep the charcter before our prefix so we can validate that we have - // found our prefix, and account for cases when PrefixLoc is 0. - Buffer = Buffer.substr(std::min(PrefixLoc-1, PrefixLoc)); + // Location to use for error messages. + const char *UsedPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); - const char *CheckPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); - - // Make sure we have actually found our prefix, and not a word containing - // our prefix. - if (PrefixLoc != 0 && IsPartOfWord(Buffer[0])) { - Buffer = Buffer.substr(CheckPrefix.size()); - continue; - } - - // When we find a check prefix, keep track of what kind of type of CHECK we - // have. - Check::CheckType CheckTy = FindCheckType(Buffer, CheckPrefix); - if (CheckTy == Check::CheckNone) - continue; + // PrefixLoc is to the start of the prefix. Skip to the end. + Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy)); // Okay, we found the prefix, yay. Remember the rest of the line, but ignore // leading and trailing whitespace. @@ -777,15 +897,15 @@ static bool ReadCheckFile(SourceMgr &SM, // Parse the pattern. Pattern P(CheckTy); - if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber)) + if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber)) return true; // Verify that CHECK-LABEL lines do not define or use variables if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { - SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), + SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, - "found '"+CheckPrefix+"-LABEL:' with variable definition" - " or use"); + "found '" + UsedPrefix + "-LABEL:'" + " with variable definition or use"); return true; } @@ -793,10 +913,10 @@ static bool ReadCheckFile(SourceMgr &SM, // Verify that CHECK-NEXT lines have at least one CHECK line before them. if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) { - SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), + SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, - "found '"+CheckPrefix+"-NEXT:' without previous '"+ - CheckPrefix+ ": line"); + "found '" + UsedPrefix + "-NEXT:' without previous '" + + UsedPrefix + ": line"); return true; } @@ -808,22 +928,33 @@ static bool ReadCheckFile(SourceMgr &SM, // Okay, add the string we captured to the output vector and move on. CheckStrings.push_back(CheckString(P, + UsedPrefix, PatternLoc, CheckTy)); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } - // Add an EOF pattern for any trailing CHECK-DAG/-NOTs. + // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first + // prefix as a filler for the error message. if (!DagNotMatches.empty()) { CheckStrings.push_back(CheckString(Pattern(Check::CheckEOF), + CheckPrefixes[0], SMLoc::getFromPointer(Buffer.data()), Check::CheckEOF)); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } if (CheckStrings.empty()) { - errs() << "error: no check strings found with prefix '" << CheckPrefix - << ":'\n"; + errs() << "error: no check strings found with prefix" + << (CheckPrefixes.size() > 1 ? "es " : " "); + for (size_t I = 0, N = CheckPrefixes.size(); I != N; ++I) { + StringRef Prefix(CheckPrefixes[I]); + errs() << '\'' << Prefix << ":'"; + if (I != N - 1) + errs() << ", "; + } + + errs() << '\n'; return true; } @@ -933,7 +1064,7 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { unsigned NumNewLines = CountNumNewlinesBetween(Buffer); if (NumNewLines == 0) { - SM.PrintMessage(Loc, SourceMgr::DK_Error, CheckPrefix+ + SM.PrintMessage(Loc, SourceMgr::DK_Error, Prefix + "-NEXT: is on the same line as previous match"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, "'next' match was here"); @@ -943,7 +1074,7 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { } if (NumNewLines != 1) { - SM.PrintMessage(Loc, SourceMgr::DK_Error, CheckPrefix+ + SM.PrintMessage(Loc, SourceMgr::DK_Error, Prefix + "-NEXT: is not on the line after the previous match"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, "'next' match was here"); @@ -970,9 +1101,9 @@ bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()+Pos), SourceMgr::DK_Error, - CheckPrefix+"-NOT: string occurred!"); + Prefix + "-NOT: string occurred!"); SM.PrintMessage(Pat->getLoc(), SourceMgr::DK_Note, - CheckPrefix+"-NOT: pattern specified here"); + Prefix + "-NOT: pattern specified here"); return true; } @@ -1022,17 +1153,17 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, // Reordered? SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + MatchPos), SourceMgr::DK_Error, - CheckPrefix+"-DAG: found a match of CHECK-DAG" + Prefix + "-DAG: found a match of CHECK-DAG" " reordering across a CHECK-NOT"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + LastPos), SourceMgr::DK_Note, - CheckPrefix+"-DAG: the farthest match of CHECK-DAG" + Prefix + "-DAG: the farthest match of CHECK-DAG" " is found here"); SM.PrintMessage(NotStrings[0]->getLoc(), SourceMgr::DK_Note, - CheckPrefix+"-NOT: the crossed pattern specified" + Prefix + "-NOT: the crossed pattern specified" " here"); SM.PrintMessage(Pat.getLoc(), SourceMgr::DK_Note, - CheckPrefix+"-DAG: the reordered pattern specified" + Prefix + "-DAG: the reordered pattern specified" " here"); return StringRef::npos; } @@ -1056,10 +1187,34 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, return LastPos; } -bool ValidateCheckPrefix() { - // The check prefix must contain only alphanumeric, hyphens and underscores. - Regex prefixValidator("^[a-zA-Z0-9_-]*$"); - return prefixValidator.match(CheckPrefix); +// A check prefix must contain only alphanumeric, hyphens and underscores. +static bool ValidateCheckPrefix(StringRef CheckPrefix) { + Regex Validator("^[a-zA-Z0-9_-]*$"); + return Validator.match(CheckPrefix); +} + +static bool ValidateCheckPrefixes() { + StringSet<> PrefixSet; + + for (prefix_iterator I = CheckPrefixes.begin(), E = CheckPrefixes.end(); + I != E; ++I) { + StringRef Prefix(*I); + + if (!PrefixSet.insert(Prefix)) + return false; + + if (!ValidateCheckPrefix(Prefix)) + return false; + } + + return true; +} + +// I don't think there's a way to specify an initial value for cl::list, +// so if nothing was specified, add the default +static void AddCheckPrefixIfNeeded() { + if (CheckPrefixes.empty()) + CheckPrefixes.push_back("CHECK"); } int main(int argc, char **argv) { @@ -1067,13 +1222,15 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); - if (!ValidateCheckPrefix()) { - errs() << "Supplied check-prefix is invalid! Prefixes must start with a " - "letter and contain only alphanumeric characters, hyphens and " - "underscores\n"; + if (!ValidateCheckPrefixes()) { + errs() << "Supplied check-prefix is invalid! Prefixes must be unique and " + "start with a letter and contain only alphanumeric characters, " + "hyphens and underscores\n"; return 2; } + AddCheckPrefixIfNeeded(); + SourceMgr SM; // Read the expected strings from the check file. -- cgit v1.1 From 7df66416541b2001f2eb34eda543e2202617ba85 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Wed, 13 Nov 2013 11:56:22 +0000 Subject: FileCheck: fix a bug with multiple --check-prefix options. Summary: This fixes a subtle bug in new FileCheck feature added in r194343. When we search for the first satisfying check-prefix, we should actually return the first encounter of some check-prefix as a substring, even if it's not a part of valid check-line. Otherwise "FileCheck --check-prefix=FOO --check-prefix=BAR" with check file: FOO not a vaild check-line FOO: foo BAR: bar incorrectly accepted file: fog bar as it skipped the first two encounters of FOO, matching only BAR: line. Reviewers: arsenm, dsanders Reviewed By: dsanders CC: llvm-commits Differential Revision: http://llvm-reviews.chandlerc.com/D2166 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194565 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/FileCheck.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index c9eb8a6..d5f7602 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -794,12 +794,12 @@ static StringRef FindFirstCandidateMatch(StringRef &Buffer, continue; Check::CheckType Ty = FindCheckType(Rest, Prefix); - if (Ty == Check::CheckNone) - continue; FirstLoc = PrefixLoc; FirstTy = Ty; - FirstPrefix = Prefix; + // We've found the first matching check prefix. If it is invalid, we should + // continue the search after it. + FirstPrefix = (Ty == Check::CheckNone) ? "" : Prefix; } if (FirstPrefix.empty()) { -- cgit v1.1 From 0ab53c711295f0469c86db088dc895238da801aa Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Wed, 13 Nov 2013 14:12:52 +0000 Subject: FileCheck: fix matching of one check-prefix is a prefix of another Summary: Fix a case when "FileCheck --check-prefix=CHECK --check-prefix=CHECKER" would silently ignore check-lines of the form: CHECKER: foo Reviewers: dsanders Reviewed By: dsanders CC: llvm-commits Differential Revision: http://llvm-reviews.chandlerc.com/D2168 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194577 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/FileCheck/FileCheck.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'utils') diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index d5f7602..f2510d7 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -785,6 +785,10 @@ static StringRef FindFirstCandidateMatch(StringRef &Buffer, // We only want to find the first match to avoid skipping some. if (PrefixLoc > FirstLoc) continue; + // If one matching check-prefix is a prefix of another, choose the + // longer one. + if (PrefixLoc == FirstLoc && Prefix.size() < FirstPrefix.size()) + continue; StringRef Rest = Buffer.drop_front(PrefixLoc); // Make sure we have actually found the prefix, and not a word containing @@ -793,22 +797,19 @@ static StringRef FindFirstCandidateMatch(StringRef &Buffer, if (PrefixLoc != 0 && IsPartOfWord(Buffer[PrefixLoc - 1])) continue; - Check::CheckType Ty = FindCheckType(Rest, Prefix); - FirstLoc = PrefixLoc; - FirstTy = Ty; - // We've found the first matching check prefix. If it is invalid, we should - // continue the search after it. - FirstPrefix = (Ty == Check::CheckNone) ? "" : Prefix; + FirstTy = FindCheckType(Rest, Prefix); + FirstPrefix = Prefix; } - if (FirstPrefix.empty()) { + // If the first prefix is invalid, we should continue the search after it. + if (FirstTy == Check::CheckNone) { CheckLoc = SearchLoc; - } else { - CheckTy = FirstTy; - CheckLoc = FirstLoc; + return ""; } + CheckTy = FirstTy; + CheckLoc = FirstLoc; return FirstPrefix; } -- cgit v1.1 From 0ea3ce91afadcbf46121dd4e6b6142c96330d71b Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Thu, 14 Nov 2013 02:03:02 +0000 Subject: Update emacs llvm mode. It seems this hasn't been done in a while. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194650 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/emacs/llvm-mode.el | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'utils') diff --git a/utils/emacs/llvm-mode.el b/utils/emacs/llvm-mode.el index 25d9742..3b8fbd7 100644 --- a/utils/emacs/llvm-mode.el +++ b/utils/emacs/llvm-mode.el @@ -32,16 +32,23 @@ "null" "undef" "to" "except" "not" "target" "endian" "little" "big" "pointersize" "volatile" "fastcc" "coldcc" "cc") 'words) . font-lock-keyword-face) ;; Arithmetic and Logical Operators - `(,(regexp-opt '("add" "sub" "mul" "div" "rem" "and" "or" "xor" + `(,(regexp-opt '("add" "sub" "mul" "sdiv" "udiv" "urem" "srem" "and" "or" "xor" "setne" "seteq" "setlt" "setgt" "setle" "setge") 'words) . font-lock-keyword-face) ;; Floating-point operators `(,(regexp-opt '("fadd" "fsub" "fmul" "fdiv" "frem") 'words) . font-lock-keyword-face) ;; Special instructions - `(,(regexp-opt '("phi" "tail" "call" "cast" "select" "to" "shl" "shr" "fcmp" "icmp" "vaarg" "vanext") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("phi" "tail" "call" "select" "to" "shl" "lshr" "ashr" "fcmp" "icmp" "va_arg" "landingpad") 'words) . font-lock-keyword-face) ;; Control instructions - `(,(regexp-opt '("ret" "br" "switch" "invoke" "unwind" "unreachable") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("ret" "br" "switch" "invoke" "resume" "unwind" "unreachable" "indirectbr") 'words) . font-lock-keyword-face) ;; Memory operators - `(,(regexp-opt '("malloc" "alloca" "free" "load" "store" "getelementptr") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("malloc" "alloca" "free" "load" "store" "getelementptr" "fence" "cmpxchg" "atomicrmw") 'words) . font-lock-keyword-face) + ;; Casts + `(,(regexp-opt '("bitcast" "inttoptr" "ptrtoint" "trunc" "zext" "sext" "fptrunc" "fpext" "fptoui" "fptosi" "uitofp" "sitofp") 'words) . font-lock-keyword-face) + ;; Vector ops + `(,(regexp-opt '("extractelement" "insertelement" "shufflevector") 'words) . font-lock-keyword-face) + ;; Aggregate ops + `(,(regexp-opt '("extractvalue" "insertvalue") 'words) . font-lock-keyword-face) + ) "Syntax highlighting for LLVM" ) -- cgit v1.1 From 59d3ae6cdc4316ad338cd848251f33a236ccb36c Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Fri, 15 Nov 2013 01:34:59 +0000 Subject: Add addrspacecast instruction. Patch by Michele Scandale! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194760 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/emacs/llvm-mode.el | 2 +- utils/kate/llvm.xml | 1 + utils/vim/llvm.vim | 23 ++++++++++++----------- 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'utils') diff --git a/utils/emacs/llvm-mode.el b/utils/emacs/llvm-mode.el index 3b8fbd7..99d3294 100644 --- a/utils/emacs/llvm-mode.el +++ b/utils/emacs/llvm-mode.el @@ -43,7 +43,7 @@ ;; Memory operators `(,(regexp-opt '("malloc" "alloca" "free" "load" "store" "getelementptr" "fence" "cmpxchg" "atomicrmw") 'words) . font-lock-keyword-face) ;; Casts - `(,(regexp-opt '("bitcast" "inttoptr" "ptrtoint" "trunc" "zext" "sext" "fptrunc" "fpext" "fptoui" "fptosi" "uitofp" "sitofp") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("bitcast" "inttoptr" "ptrtoint" "trunc" "zext" "sext" "fptrunc" "fpext" "fptoui" "fptosi" "uitofp" "sitofp" "addrspacecast") 'words) . font-lock-keyword-face) ;; Vector ops `(,(regexp-opt '("extractelement" "insertelement" "shufflevector") 'words) . font-lock-keyword-face) ;; Aggregate ops diff --git a/utils/kate/llvm.xml b/utils/kate/llvm.xml index 7cea92a..dfacfb5 100644 --- a/utils/kate/llvm.xml +++ b/utils/kate/llvm.xml @@ -157,6 +157,7 @@ ptrtoint inttoptr bitcast + addrspacecast icmp fcmp phi diff --git a/utils/vim/llvm.vim b/utils/vim/llvm.vim index c611ad8..c2ec57c 100644 --- a/utils/vim/llvm.vim +++ b/utils/vim/llvm.vim @@ -22,17 +22,18 @@ syn match llvmType /\/ " Instructions. " The true and false tokens can be used for comparison opcodes, but it's " much more common for these tokens to be used for boolean constants. -syn keyword llvmStatement add alloca and arcp ashr atomicrmw bitcast br call -syn keyword llvmStatement cmpxchg eq exact extractelement extractvalue fadd fast -syn keyword llvmStatement fcmp fdiv fence fmul fpext fptosi fptoui fptrunc free -syn keyword llvmStatement frem fsub getelementptr icmp inbounds indirectbr -syn keyword llvmStatement insertelement insertvalue inttoptr invoke landingpad -syn keyword llvmStatement load lshr malloc max min mul nand ne ninf nnan nsw nsz -syn keyword llvmStatement nuw oeq oge ogt ole olt one or ord phi ptrtoint resume -syn keyword llvmStatement ret sdiv select sext sge sgt shl shufflevector sitofp -syn keyword llvmStatement sle slt srem store sub switch trunc udiv ueq uge ugt -syn keyword llvmStatement uitofp ule ult umax umin une uno unreachable unwind -syn keyword llvmStatement urem va_arg xchg xor zext +syn keyword llvmStatement add addrspacecast alloca and arcp ashr atomicrmw +syn keyword llvmStatement bitcast br call cmpxchg eq exact extractelement +syn keyword llvmStatement extractvalue fadd fast fcmp fdiv fence fmul fpext +syn keyword llvmStatement fptosi fptoui fptrunc free frem fsub getelementptr +syn keyword llvmStatement icmp inbounds indirectbr insertelement insertvalue +syn keyword llvmStatement inttoptr invoke landingpad load lshr malloc max min +syn keyword llvmStatement mul nand ne ninf nnan nsw nsz nuw oeq oge ogt ole +syn keyword llvmStatement olt one or ord phi ptrtoint resume ret sdiv select +syn keyword llvmStatement sext sge sgt shl shufflevector sitofp sle slt srem +syn keyword llvmStatement store sub switch trunc udiv ueq uge ugt uitofp ule ult +syn keyword llvmStatement umax umin une uno unreachable unwind urem va_arg +syn keyword llvmStatement xchg xor zext " Keywords. syn keyword llvmKeyword acq_rel acquire sanitize_address addrspace alias align -- cgit v1.1 From efbdf7f2320649512569143611f53177c27ba9f6 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Fri, 15 Nov 2013 10:20:45 +0000 Subject: Move all of the GoogleTest files back to the same locations they occupy externally to simplify our integration of GoogleTest into LLVM. Also, build the single source file gtest-all.cc instead of the individual source files as we don't expect these to change and thus gain nothing from increased incrementality in compiles. This makes our standard build of googletest exactly like upstream's recommended build and the sanitizer's build. It also simplifies the steps of importing a new version should we ever want one. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194801 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/unittest/CMakeLists.txt | 9 +- utils/unittest/googletest/Makefile | 3 +- utils/unittest/googletest/README.LLVM | 16 +- utils/unittest/googletest/gtest-all.cc | 48 - utils/unittest/googletest/gtest-death-test.cc | 1233 ----- utils/unittest/googletest/gtest-filepath.cc | 378 -- utils/unittest/googletest/gtest-port.cc | 750 --- utils/unittest/googletest/gtest-printers.cc | 356 -- utils/unittest/googletest/gtest-test-part.cc | 110 - utils/unittest/googletest/gtest-typed-test.cc | 110 - utils/unittest/googletest/gtest.cc | 4866 -------------------- .../include/gtest/internal/gtest-internal-inl.h | 1037 ----- utils/unittest/googletest/src/gtest-all.cc | 48 + utils/unittest/googletest/src/gtest-death-test.cc | 1233 +++++ utils/unittest/googletest/src/gtest-filepath.cc | 378 ++ utils/unittest/googletest/src/gtest-internal-inl.h | 1037 +++++ utils/unittest/googletest/src/gtest-port.cc | 750 +++ utils/unittest/googletest/src/gtest-printers.cc | 356 ++ utils/unittest/googletest/src/gtest-test-part.cc | 110 + utils/unittest/googletest/src/gtest-typed-test.cc | 110 + utils/unittest/googletest/src/gtest.cc | 4866 ++++++++++++++++++++ 21 files changed, 8894 insertions(+), 8910 deletions(-) delete mode 100644 utils/unittest/googletest/gtest-all.cc delete mode 100644 utils/unittest/googletest/gtest-death-test.cc delete mode 100644 utils/unittest/googletest/gtest-filepath.cc delete mode 100644 utils/unittest/googletest/gtest-port.cc delete mode 100644 utils/unittest/googletest/gtest-printers.cc delete mode 100644 utils/unittest/googletest/gtest-test-part.cc delete mode 100644 utils/unittest/googletest/gtest-typed-test.cc delete mode 100644 utils/unittest/googletest/gtest.cc delete mode 100644 utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h create mode 100644 utils/unittest/googletest/src/gtest-all.cc create mode 100644 utils/unittest/googletest/src/gtest-death-test.cc create mode 100644 utils/unittest/googletest/src/gtest-filepath.cc create mode 100644 utils/unittest/googletest/src/gtest-internal-inl.h create mode 100644 utils/unittest/googletest/src/gtest-port.cc create mode 100644 utils/unittest/googletest/src/gtest-printers.cc create mode 100644 utils/unittest/googletest/src/gtest-test-part.cc create mode 100644 utils/unittest/googletest/src/gtest-typed-test.cc create mode 100644 utils/unittest/googletest/src/gtest.cc (limited to 'utils') diff --git a/utils/unittest/CMakeLists.txt b/utils/unittest/CMakeLists.txt index 8bdfee1..fd1a048 100644 --- a/utils/unittest/CMakeLists.txt +++ b/utils/unittest/CMakeLists.txt @@ -14,6 +14,7 @@ # Where gtest's .h files can be found. include_directories( googletest/include + googletest ) if(WIN32) @@ -38,13 +39,7 @@ if(MSVC AND MSVC_VERSION EQUAL 1700) endif () add_llvm_library(gtest - googletest/gtest.cc - googletest/gtest-death-test.cc - googletest/gtest-filepath.cc - googletest/gtest-port.cc - googletest/gtest-printers.cc - googletest/gtest-test-part.cc - googletest/gtest-typed-test.cc + googletest/src/gtest-all.cc ) add_llvm_library(gtest_main diff --git a/utils/unittest/googletest/Makefile b/utils/unittest/googletest/Makefile index bf73670..3d85e7d 100644 --- a/utils/unittest/googletest/Makefile +++ b/utils/unittest/googletest/Makefile @@ -19,6 +19,7 @@ REQUIRES_RTTI = 1 # unittests/Makefile.unittest and ../UnitTestMain/Makefile; ensure that any # changes are made to both. CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest/include +CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest CPP.Flags += $(NO_MISSING_FIELD_INITIALIZERS) $(NO_VARIADIC_MACROS) CPP.Flags += -DGTEST_HAS_RTTI=0 # libstdc++'s TR1 header depends on RTTI and uses C++'0x features not @@ -36,6 +37,6 @@ endif NO_INSTALL = 1 -SOURCES = $(filter-out gtest-all.cc, $(notdir $(wildcard $(PROJ_SRC_DIR)/*.cc))) +SOURCES = src/gtest-all.cc include $(LEVEL)/Makefile.common diff --git a/utils/unittest/googletest/README.LLVM b/utils/unittest/googletest/README.LLVM index 3565a32..1a6f0f5 100644 --- a/utils/unittest/googletest/README.LLVM +++ b/utils/unittest/googletest/README.LLVM @@ -10,23 +10,11 @@ Cleaned up as follows: $ rm -f aclocal* CMakeLists.txt configure* Makefile* CHANGES CONTRIBUTORS README $ rm -rf build-aux cmake codegear fused-src m4 make msvc samples scripts test xcode $ rm -f `find . -name \*\.pump` +$ rm -f src/gtest_main.cc -# Move all the source files to the current directory -$ mv src/* . -$ rmdir src - -# Move extra headers into the already-existing internal headers dir -$ mv *.h include/gtest/internal/ - -# Update paths to the included files -$ perl -pi -e 's|^#include "src/|#include "|' gtest-all.cc -$ perl -pi -e 's|^#include "src/|#include "gtest/internal/|' *.cc - -$ rm -f gtest_main.cc - +# Put the license in the consistent place for LLVM. $ mv COPYING LICENSE.TXT - Modified as follows: * To GTestStreamToHelper in include/gtest/internal/gtest-internal.h, added the ability to stream with raw_os_ostream. diff --git a/utils/unittest/googletest/gtest-all.cc b/utils/unittest/googletest/gtest-all.cc deleted file mode 100644 index 97753e5..0000000 --- a/utils/unittest/googletest/gtest-all.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: mheule@google.com (Markus Heule) -// -// Google C++ Testing Framework (Google Test) -// -// Sometimes it's desirable to build Google Test by compiling a single file. -// This file serves this purpose. - -// This line ensures that gtest.h can be compiled on its own, even -// when it's fused. -#include "gtest/gtest.h" - -// The following lines pull in the real gtest *.cc files. -#include "gtest.cc" -#include "gtest-death-test.cc" -#include "gtest-filepath.cc" -#include "gtest-port.cc" -#include "gtest-printers.cc" -#include "gtest-test-part.cc" -#include "gtest-typed-test.cc" diff --git a/utils/unittest/googletest/gtest-death-test.cc b/utils/unittest/googletest/gtest-death-test.cc deleted file mode 100644 index bf7e32c..0000000 --- a/utils/unittest/googletest/gtest-death-test.cc +++ /dev/null @@ -1,1233 +0,0 @@ -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) -// -// This file implements death tests. - -#include "gtest/gtest-death-test.h" -#include "gtest/internal/gtest-port.h" - -#if GTEST_HAS_DEATH_TEST - -# if GTEST_OS_MAC -# include -# endif // GTEST_OS_MAC - -# include -# include -# include -# include - -# if GTEST_OS_WINDOWS -# include -# else -# include -# include -# endif // GTEST_OS_WINDOWS - -#endif // GTEST_HAS_DEATH_TEST - -#include "gtest/gtest-message.h" -#include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -#include "gtest/internal/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ - -namespace testing { - -// Constants. - -// The default death test style. -static const char kDefaultDeathTestStyle[] = "fast"; - -GTEST_DEFINE_string_( - death_test_style, - internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), - "Indicates how to run a death test in a forked child process: " - "\"threadsafe\" (child process re-executes the test binary " - "from the beginning, running only the specific death test) or " - "\"fast\" (child process runs the death test immediately " - "after forking)."); - -GTEST_DEFINE_bool_( - death_test_use_fork, - internal::BoolFromGTestEnv("death_test_use_fork", false), - "Instructs to use fork()/_exit() instead of clone() in death tests. " - "Ignored and always uses fork() on POSIX systems where clone() is not " - "implemented. Useful when running under valgrind or similar tools if " - "those do not support clone(). Valgrind 3.3.1 will just fail if " - "it sees an unsupported combination of clone() flags. " - "It is not recommended to use this flag w/o valgrind though it will " - "work in 99% of the cases. Once valgrind is fixed, this flag will " - "most likely be removed."); - -namespace internal { -GTEST_DEFINE_string_( - internal_run_death_test, "", - "Indicates the file, line number, temporal index of " - "the single death test to run, and a file descriptor to " - "which a success code may be sent, all separated by " - "colons. This flag is specified if and only if the current " - "process is a sub-process launched for running a thread-safe " - "death test. FOR INTERNAL USE ONLY."); -} // namespace internal - -#if GTEST_HAS_DEATH_TEST - -// ExitedWithCode constructor. -ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { -} - -// ExitedWithCode function-call operator. -bool ExitedWithCode::operator()(int exit_status) const { -# if GTEST_OS_WINDOWS - - return exit_status == exit_code_; - -# else - - return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; - -# endif // GTEST_OS_WINDOWS -} - -# if !GTEST_OS_WINDOWS -// KilledBySignal constructor. -KilledBySignal::KilledBySignal(int signum) : signum_(signum) { -} - -// KilledBySignal function-call operator. -bool KilledBySignal::operator()(int exit_status) const { - return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; -} -# endif // !GTEST_OS_WINDOWS - -namespace internal { - -// Utilities needed for death tests. - -// Generates a textual description of a given exit code, in the format -// specified by wait(2). -static String ExitSummary(int exit_code) { - Message m; - -# if GTEST_OS_WINDOWS - - m << "Exited with exit status " << exit_code; - -# else - - if (WIFEXITED(exit_code)) { - m << "Exited with exit status " << WEXITSTATUS(exit_code); - } else if (WIFSIGNALED(exit_code)) { - m << "Terminated by signal " << WTERMSIG(exit_code); - } -# ifdef WCOREDUMP - if (WCOREDUMP(exit_code)) { - m << " (core dumped)"; - } -# endif -# endif // GTEST_OS_WINDOWS - - return m.GetString(); -} - -// Returns true if exit_status describes a process that was terminated -// by a signal, or exited normally with a nonzero exit code. -bool ExitedUnsuccessfully(int exit_status) { - return !ExitedWithCode(0)(exit_status); -} - -# if !GTEST_OS_WINDOWS -// Generates a textual failure message when a death test finds more than -// one thread running, or cannot determine the number of threads, prior -// to executing the given statement. It is the responsibility of the -// caller not to pass a thread_count of 1. -static String DeathTestThreadWarning(size_t thread_count) { - Message msg; - msg << "Death tests use fork(), which is unsafe particularly" - << " in a threaded context. For this test, " << GTEST_NAME_ << " "; - if (thread_count == 0) - msg << "couldn't detect the number of threads."; - else - msg << "detected " << thread_count << " threads."; - return msg.GetString(); -} -# endif // !GTEST_OS_WINDOWS - -// Flag characters for reporting a death test that did not die. -static const char kDeathTestLived = 'L'; -static const char kDeathTestReturned = 'R'; -static const char kDeathTestThrew = 'T'; -static const char kDeathTestInternalError = 'I'; - -// An enumeration describing all of the possible ways that a death test can -// conclude. DIED means that the process died while executing the test -// code; LIVED means that process lived beyond the end of the test code; -// RETURNED means that the test statement attempted to execute a return -// statement, which is not allowed; THREW means that the test statement -// returned control by throwing an exception. IN_PROGRESS means the test -// has not yet concluded. -// TODO(vladl@google.com): Unify names and possibly values for -// AbortReason, DeathTestOutcome, and flag characters above. -enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; - -// Routine for aborting the program which is safe to call from an -// exec-style death test child process, in which case the error -// message is propagated back to the parent process. Otherwise, the -// message is simply printed to stderr. In either case, the program -// then exits with status 1. -void DeathTestAbort(const String& message) { - // On a POSIX system, this function may be called from a threadsafe-style - // death test child process, which operates on a very small stack. Use - // the heap for any additional non-minuscule memory requirements. - const InternalRunDeathTestFlag* const flag = - GetUnitTestImpl()->internal_run_death_test_flag(); - if (flag != NULL) { - FILE* parent = posix::FDOpen(flag->write_fd(), "w"); - fputc(kDeathTestInternalError, parent); - fprintf(parent, "%s", message.c_str()); - fflush(parent); - _exit(1); - } else { - fprintf(stderr, "%s", message.c_str()); - fflush(stderr); - posix::Abort(); - } -} - -// A replacement for CHECK that calls DeathTestAbort if the assertion -// fails. -# define GTEST_DEATH_TEST_CHECK_(expression) \ - do { \ - if (!::testing::internal::IsTrue(expression)) { \ - DeathTestAbort(::testing::internal::String::Format( \ - "CHECK failed: File %s, line %d: %s", \ - __FILE__, __LINE__, #expression)); \ - } \ - } while (::testing::internal::AlwaysFalse()) - -// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for -// evaluating any system call that fulfills two conditions: it must return -// -1 on failure, and set errno to EINTR when it is interrupted and -// should be tried again. The macro expands to a loop that repeatedly -// evaluates the expression as long as it evaluates to -1 and sets -// errno to EINTR. If the expression evaluates to -1 but errno is -// something other than EINTR, DeathTestAbort is called. -# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ - do { \ - int gtest_retval; \ - do { \ - gtest_retval = (expression); \ - } while (gtest_retval == -1 && errno == EINTR); \ - if (gtest_retval == -1) { \ - DeathTestAbort(::testing::internal::String::Format( \ - "CHECK failed: File %s, line %d: %s != -1", \ - __FILE__, __LINE__, #expression)); \ - } \ - } while (::testing::internal::AlwaysFalse()) - -// Returns the message describing the last system error in errno. -String GetLastErrnoDescription() { - return String(errno == 0 ? "" : posix::StrError(errno)); -} - -// This is called from a death test parent process to read a failure -// message from the death test child process and log it with the FATAL -// severity. On Windows, the message is read from a pipe handle. On other -// platforms, it is read from a file descriptor. -static void FailFromInternalError(int fd) { - Message error; - char buffer[256]; - int num_read; - - do { - while ((num_read = posix::Read(fd, buffer, 255)) > 0) { - buffer[num_read] = '\0'; - error << buffer; - } - } while (num_read == -1 && errno == EINTR); - - if (num_read == 0) { - GTEST_LOG_(FATAL) << error.GetString(); - } else { - const int last_error = errno; - GTEST_LOG_(FATAL) << "Error while reading death test internal: " - << GetLastErrnoDescription() << " [" << last_error << "]"; - } -} - -// Death test constructor. Increments the running death test count -// for the current test. -DeathTest::DeathTest() { - TestInfo* const info = GetUnitTestImpl()->current_test_info(); - if (info == NULL) { - DeathTestAbort("Cannot run a death test outside of a TEST or " - "TEST_F construct"); - } -} - -// Creates and returns a death test by dispatching to the current -// death test factory. -bool DeathTest::Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) { - return GetUnitTestImpl()->death_test_factory()->Create( - statement, regex, file, line, test); -} - -const char* DeathTest::LastMessage() { - return last_death_test_message_.c_str(); -} - -void DeathTest::set_last_death_test_message(const String& message) { - last_death_test_message_ = message; -} - -String DeathTest::last_death_test_message_; - -// Provides cross platform implementation for some death functionality. -class DeathTestImpl : public DeathTest { - protected: - DeathTestImpl(const char* a_statement, const RE* a_regex) - : statement_(a_statement), - regex_(a_regex), - spawned_(false), - status_(-1), - outcome_(IN_PROGRESS), - read_fd_(-1), - write_fd_(-1) {} - - // read_fd_ is expected to be closed and cleared by a derived class. - ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } - - void Abort(AbortReason reason); - virtual bool Passed(bool status_ok); - - const char* statement() const { return statement_; } - const RE* regex() const { return regex_; } - bool spawned() const { return spawned_; } - void set_spawned(bool is_spawned) { spawned_ = is_spawned; } - int status() const { return status_; } - void set_status(int a_status) { status_ = a_status; } - DeathTestOutcome outcome() const { return outcome_; } - void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } - int read_fd() const { return read_fd_; } - void set_read_fd(int fd) { read_fd_ = fd; } - int write_fd() const { return write_fd_; } - void set_write_fd(int fd) { write_fd_ = fd; } - - // Called in the parent process only. Reads the result code of the death - // test child process via a pipe, interprets it to set the outcome_ - // member, and closes read_fd_. Outputs diagnostics and terminates in - // case of unexpected codes. - void ReadAndInterpretStatusByte(); - - private: - // The textual content of the code this object is testing. This class - // doesn't own this string and should not attempt to delete it. - const char* const statement_; - // The regular expression which test output must match. DeathTestImpl - // doesn't own this object and should not attempt to delete it. - const RE* const regex_; - // True if the death test child process has been successfully spawned. - bool spawned_; - // The exit status of the child process. - int status_; - // How the death test concluded. - DeathTestOutcome outcome_; - // Descriptor to the read end of the pipe to the child process. It is - // always -1 in the child process. The child keeps its write end of the - // pipe in write_fd_. - int read_fd_; - // Descriptor to the child's write end of the pipe to the parent process. - // It is always -1 in the parent process. The parent keeps its end of the - // pipe in read_fd_. - int write_fd_; -}; - -// Called in the parent process only. Reads the result code of the death -// test child process via a pipe, interprets it to set the outcome_ -// member, and closes read_fd_. Outputs diagnostics and terminates in -// case of unexpected codes. -void DeathTestImpl::ReadAndInterpretStatusByte() { - char flag; - int bytes_read; - - // The read() here blocks until data is available (signifying the - // failure of the death test) or until the pipe is closed (signifying - // its success), so it's okay to call this in the parent before - // the child process has exited. - do { - bytes_read = posix::Read(read_fd(), &flag, 1); - } while (bytes_read == -1 && errno == EINTR); - - if (bytes_read == 0) { - set_outcome(DIED); - } else if (bytes_read == 1) { - switch (flag) { - case kDeathTestReturned: - set_outcome(RETURNED); - break; - case kDeathTestThrew: - set_outcome(THREW); - break; - case kDeathTestLived: - set_outcome(LIVED); - break; - case kDeathTestInternalError: - FailFromInternalError(read_fd()); // Does not return. - break; - default: - GTEST_LOG_(FATAL) << "Death test child process reported " - << "unexpected status byte (" - << static_cast(flag) << ")"; - } - } else { - GTEST_LOG_(FATAL) << "Read from death test child process failed: " - << GetLastErrnoDescription(); - } - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); - set_read_fd(-1); -} - -// Signals that the death test code which should have exited, didn't. -// Should be called only in a death test child process. -// Writes a status byte to the child's status file descriptor, then -// calls _exit(1). -void DeathTestImpl::Abort(AbortReason reason) { - // The parent process considers the death test to be a failure if - // it finds any data in our pipe. So, here we write a single flag byte - // to the pipe, then exit. - const char status_ch = - reason == TEST_DID_NOT_DIE ? kDeathTestLived : - reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; - - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); - // We are leaking the descriptor here because on some platforms (i.e., - // when built as Windows DLL), destructors of global objects will still - // run after calling _exit(). On such systems, write_fd_ will be - // indirectly closed from the destructor of UnitTestImpl, causing double - // close if it is also closed here. On debug configurations, double close - // may assert. As there are no in-process buffers to flush here, we are - // relying on the OS to close the descriptor after the process terminates - // when the destructors are not run. - _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) -} - -// Returns an indented copy of stderr output for a death test. -// This makes distinguishing death test output lines from regular log lines -// much easier. -static ::std::string FormatDeathTestOutput(const ::std::string& output) { - ::std::string ret; - for (size_t at = 0; ; ) { - const size_t line_end = output.find('\n', at); - ret += "[ DEATH ] "; - if (line_end == ::std::string::npos) { - ret += output.substr(at); - break; - } - ret += output.substr(at, line_end + 1 - at); - at = line_end + 1; - } - return ret; -} - -// Assesses the success or failure of a death test, using both private -// members which have previously been set, and one argument: -// -// Private data members: -// outcome: An enumeration describing how the death test -// concluded: DIED, LIVED, THREW, or RETURNED. The death test -// fails in the latter three cases. -// status: The exit status of the child process. On *nix, it is in the -// in the format specified by wait(2). On Windows, this is the -// value supplied to the ExitProcess() API or a numeric code -// of the exception that terminated the program. -// regex: A regular expression object to be applied to -// the test's captured standard error output; the death test -// fails if it does not match. -// -// Argument: -// status_ok: true if exit_status is acceptable in the context of -// this particular death test, which fails if it is false -// -// Returns true iff all of the above conditions are met. Otherwise, the -// first failing condition, in the order given above, is the one that is -// reported. Also sets the last death test message string. -bool DeathTestImpl::Passed(bool status_ok) { - if (!spawned()) - return false; - - const String error_message = GetCapturedStderr(); - - bool success = false; - Message buffer; - - buffer << "Death test: " << statement() << "\n"; - switch (outcome()) { - case LIVED: - buffer << " Result: failed to die.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); - break; - case THREW: - buffer << " Result: threw an exception.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); - break; - case RETURNED: - buffer << " Result: illegal return in test statement.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); - break; - case DIED: - if (status_ok) { - const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); - if (matched) { - success = true; - } else { - buffer << " Result: died but not with expected error.\n" - << " Expected: " << regex()->pattern() << "\n" - << "Actual msg:\n" << FormatDeathTestOutput(error_message); - } - } else { - buffer << " Result: died but not with expected exit code:\n" - << " " << ExitSummary(status()) << "\n" - << "Actual msg:\n" << FormatDeathTestOutput(error_message); - } - break; - case IN_PROGRESS: - GTEST_LOG_(FATAL) - << "DeathTest::Passed somehow called before conclusion of test"; - } - - DeathTest::set_last_death_test_message(buffer.GetString()); - return success; -} - -# if GTEST_OS_WINDOWS -// WindowsDeathTest implements death tests on Windows. Due to the -// specifics of starting new processes on Windows, death tests there are -// always threadsafe, and Google Test considers the -// --gtest_death_test_style=fast setting to be equivalent to -// --gtest_death_test_style=threadsafe there. -// -// A few implementation notes: Like the Linux version, the Windows -// implementation uses pipes for child-to-parent communication. But due to -// the specifics of pipes on Windows, some extra steps are required: -// -// 1. The parent creates a communication pipe and stores handles to both -// ends of it. -// 2. The parent starts the child and provides it with the information -// necessary to acquire the handle to the write end of the pipe. -// 3. The child acquires the write end of the pipe and signals the parent -// using a Windows event. -// 4. Now the parent can release the write end of the pipe on its side. If -// this is done before step 3, the object's reference count goes down to -// 0 and it is destroyed, preventing the child from acquiring it. The -// parent now has to release it, or read operations on the read end of -// the pipe will not return when the child terminates. -// 5. The parent reads child's output through the pipe (outcome code and -// any possible error messages) from the pipe, and its stderr and then -// determines whether to fail the test. -// -// Note: to distinguish Win32 API calls from the local method and function -// calls, the former are explicitly resolved in the global namespace. -// -class WindowsDeathTest : public DeathTestImpl { - public: - WindowsDeathTest(const char* a_statement, - const RE* a_regex, - const char* file, - int line) - : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} - - // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); - virtual TestRole AssumeRole(); - - private: - // The name of the file in which the death test is located. - const char* const file_; - // The line number on which the death test is located. - const int line_; - // Handle to the write end of the pipe to the child process. - AutoHandle write_handle_; - // Child process handle. - AutoHandle child_handle_; - // Event the child process uses to signal the parent that it has - // acquired the handle to the write end of the pipe. After seeing this - // event the parent can release its own handles to make sure its - // ReadFile() calls return when the child terminates. - AutoHandle event_handle_; -}; - -// Waits for the child in a death test to exit, returning its exit -// status, or 0 if no child process exists. As a side effect, sets the -// outcome data member. -int WindowsDeathTest::Wait() { - if (!spawned()) - return 0; - - // Wait until the child either signals that it has acquired the write end - // of the pipe or it dies. - const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; - switch (::WaitForMultipleObjects(2, - wait_handles, - FALSE, // Waits for any of the handles. - INFINITE)) { - case WAIT_OBJECT_0: - case WAIT_OBJECT_0 + 1: - break; - default: - GTEST_DEATH_TEST_CHECK_(false); // Should not get here. - } - - // The child has acquired the write end of the pipe or exited. - // We release the handle on our side and continue. - write_handle_.Reset(); - event_handle_.Reset(); - - ReadAndInterpretStatusByte(); - - // Waits for the child process to exit if it haven't already. This - // returns immediately if the child has already exited, regardless of - // whether previous calls to WaitForMultipleObjects synchronized on this - // handle or not. - GTEST_DEATH_TEST_CHECK_( - WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), - INFINITE)); - DWORD status_code; - GTEST_DEATH_TEST_CHECK_( - ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); - child_handle_.Reset(); - set_status(static_cast(status_code)); - return status(); -} - -// The AssumeRole process for a Windows death test. It creates a child -// process with the same executable as the current process to run the -// death test. The child process is given the --gtest_filter and -// --gtest_internal_run_death_test flags such that it knows to run the -// current death test only. -DeathTest::TestRole WindowsDeathTest::AssumeRole() { - const UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const TestInfo* const info = impl->current_test_info(); - const int death_test_index = info->result()->death_test_count(); - - if (flag != NULL) { - // ParseInternalRunDeathTestFlag() has performed all the necessary - // processing. - set_write_fd(flag->write_fd()); - return EXECUTE_TEST; - } - - // WindowsDeathTest uses an anonymous pipe to communicate results of - // a death test. - SECURITY_ATTRIBUTES handles_are_inheritable = { - sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; - HANDLE read_handle, write_handle; - GTEST_DEATH_TEST_CHECK_( - ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, - 0) // Default buffer size. - != FALSE); - set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), - O_RDONLY)); - write_handle_.Reset(write_handle); - event_handle_.Reset(::CreateEvent( - &handles_are_inheritable, - TRUE, // The event will automatically reset to non-signaled state. - FALSE, // The initial state is non-signalled. - NULL)); // The even is unnamed. - GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); - const String filter_flag = String::Format("--%s%s=%s.%s", - GTEST_FLAG_PREFIX_, kFilterFlag, - info->test_case_name(), - info->name()); - const String internal_flag = String::Format( - "--%s%s=%s|%d|%d|%u|%Iu|%Iu", - GTEST_FLAG_PREFIX_, - kInternalRunDeathTestFlag, - file_, line_, - death_test_index, - static_cast(::GetCurrentProcessId()), - // size_t has the same with as pointers on both 32-bit and 64-bit - // Windows platforms. - // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. - reinterpret_cast(write_handle), - reinterpret_cast(event_handle_.Get())); - - char executable_path[_MAX_PATH + 1]; // NOLINT - GTEST_DEATH_TEST_CHECK_( - _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, - executable_path, - _MAX_PATH)); - - String command_line = String::Format("%s %s \"%s\"", - ::GetCommandLineA(), - filter_flag.c_str(), - internal_flag.c_str()); - - DeathTest::set_last_death_test_message(""); - - CaptureStderr(); - // Flush the log buffers since the log streams are shared with the child. - FlushInfoLog(); - - // The child process will share the standard handles with the parent. - STARTUPINFOA startup_info; - memset(&startup_info, 0, sizeof(STARTUPINFO)); - startup_info.dwFlags = STARTF_USESTDHANDLES; - startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); - startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); - startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); - - PROCESS_INFORMATION process_info; - GTEST_DEATH_TEST_CHECK_(::CreateProcessA( - executable_path, - const_cast(command_line.c_str()), - NULL, // Retuned process handle is not inheritable. - NULL, // Retuned thread handle is not inheritable. - TRUE, // Child inherits all inheritable handles (for write_handle_). - 0x0, // Default creation flags. - NULL, // Inherit the parent's environment. - UnitTest::GetInstance()->original_working_dir(), - &startup_info, - &process_info) != FALSE); - child_handle_.Reset(process_info.hProcess); - ::CloseHandle(process_info.hThread); - set_spawned(true); - return OVERSEE_TEST; -} -# else // We are not on Windows. - -// ForkingDeathTest provides implementations for most of the abstract -// methods of the DeathTest interface. Only the AssumeRole method is -// left undefined. -class ForkingDeathTest : public DeathTestImpl { - public: - ForkingDeathTest(const char* statement, const RE* regex); - - // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); - - protected: - void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } - - private: - // PID of child process during death test; 0 in the child process itself. - pid_t child_pid_; -}; - -// Constructs a ForkingDeathTest. -ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) - : DeathTestImpl(a_statement, a_regex), - child_pid_(-1) {} - -// Waits for the child in a death test to exit, returning its exit -// status, or 0 if no child process exists. As a side effect, sets the -// outcome data member. -int ForkingDeathTest::Wait() { - if (!spawned()) - return 0; - - ReadAndInterpretStatusByte(); - - int status_value; - GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); - set_status(status_value); - return status_value; -} - -// A concrete death test class that forks, then immediately runs the test -// in the child process. -class NoExecDeathTest : public ForkingDeathTest { - public: - NoExecDeathTest(const char* a_statement, const RE* a_regex) : - ForkingDeathTest(a_statement, a_regex) { } - virtual TestRole AssumeRole(); -}; - -// The AssumeRole process for a fork-and-run death test. It implements a -// straightforward fork, with a simple pipe to transmit the status byte. -DeathTest::TestRole NoExecDeathTest::AssumeRole() { - const size_t thread_count = GetThreadCount(); - if (thread_count != 1) { - GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); - } - - int pipe_fd[2]; - GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); - - DeathTest::set_last_death_test_message(""); - CaptureStderr(); - // When we fork the process below, the log file buffers are copied, but the - // file descriptors are shared. We flush all log files here so that closing - // the file descriptors in the child process doesn't throw off the - // synchronization between descriptors and buffers in the parent process. - // This is as close to the fork as possible to avoid a race condition in case - // there are multiple threads running before the death test, and another - // thread writes to the log file. - FlushInfoLog(); - - const pid_t child_pid = fork(); - GTEST_DEATH_TEST_CHECK_(child_pid != -1); - set_child_pid(child_pid); - if (child_pid == 0) { - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); - set_write_fd(pipe_fd[1]); - // Redirects all logging to stderr in the child process to prevent - // concurrent writes to the log files. We capture stderr in the parent - // process and append the child process' output to a log. - LogToStderr(); - // Event forwarding to the listeners of event listener API mush be shut - // down in death test subprocesses. - GetUnitTestImpl()->listeners()->SuppressEventForwarding(); - return EXECUTE_TEST; - } else { - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); - set_read_fd(pipe_fd[0]); - set_spawned(true); - return OVERSEE_TEST; - } -} - -// A concrete death test class that forks and re-executes the main -// program from the beginning, with command-line flags set that cause -// only this specific death test to be run. -class ExecDeathTest : public ForkingDeathTest { - public: - ExecDeathTest(const char* a_statement, const RE* a_regex, - const char* file, int line) : - ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } - virtual TestRole AssumeRole(); - private: - // The name of the file in which the death test is located. - const char* const file_; - // The line number on which the death test is located. - const int line_; -}; - -// Utility class for accumulating command-line arguments. -class Arguments { - public: - Arguments() { - args_.push_back(NULL); - } - - ~Arguments() { - for (std::vector::iterator i = args_.begin(); i != args_.end(); - ++i) { - free(*i); - } - } - void AddArgument(const char* argument) { - args_.insert(args_.end() - 1, posix::StrDup(argument)); - } - - template - void AddArguments(const ::std::vector& arguments) { - for (typename ::std::vector::const_iterator i = arguments.begin(); - i != arguments.end(); - ++i) { - args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); - } - } - char* const* Argv() { - return &args_[0]; - } - private: - std::vector args_; -}; - -// A struct that encompasses the arguments to the child process of a -// threadsafe-style death test process. -struct ExecDeathTestArgs { - char* const* argv; // Command-line arguments for the child's call to exec - int close_fd; // File descriptor to close; the read end of a pipe -}; - -# if GTEST_OS_MAC -inline char** GetEnviron() { - // When Google Test is built as a framework on MacOS X, the environ variable - // is unavailable. Apple's documentation (man environ) recommends using - // _NSGetEnviron() instead. - return *_NSGetEnviron(); -} -# else -// Some POSIX platforms expect you to declare environ. extern "C" makes -// it reside in the global namespace. -extern "C" char** environ; -inline char** GetEnviron() { return environ; } -# endif // GTEST_OS_MAC - -// The main function for a threadsafe-style death test child process. -// This function is called in a clone()-ed process and thus must avoid -// any potentially unsafe operations like malloc or libc functions. -static int ExecDeathTestChildMain(void* child_arg) { - ExecDeathTestArgs* const args = static_cast(child_arg); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); - - // We need to execute the test program in the same environment where - // it was originally invoked. Therefore we change to the original - // working directory first. - const char* const original_dir = - UnitTest::GetInstance()->original_working_dir(); - // We can safely call chdir() as it's a direct system call. - if (chdir(original_dir) != 0) { - DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", - original_dir, - GetLastErrnoDescription().c_str())); - return EXIT_FAILURE; - } - - // We can safely call execve() as it's a direct system call. We - // cannot use execvp() as it's a libc function and thus potentially - // unsafe. Since execve() doesn't search the PATH, the user must - // invoke the test program via a valid path that contains at least - // one path separator. - execve(args->argv[0], args->argv, GetEnviron()); - DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", - args->argv[0], - original_dir, - GetLastErrnoDescription().c_str())); - return EXIT_FAILURE; -} - -// Two utility routines that together determine the direction the stack -// grows. -// This could be accomplished more elegantly by a single recursive -// function, but we want to guard against the unlikely possibility of -// a smart compiler optimizing the recursion away. -// -// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining -// StackLowerThanAddress into StackGrowsDown, which then doesn't give -// correct answer. -bool StackLowerThanAddress(const void* ptr) GTEST_NO_INLINE_; -bool StackLowerThanAddress(const void* ptr) { - int dummy; - return &dummy < ptr; -} - -bool StackGrowsDown() { - int dummy; - return StackLowerThanAddress(&dummy); -} - -// A threadsafe implementation of fork(2) for threadsafe-style death tests -// that uses clone(2). It dies with an error message if anything goes -// wrong. -static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { - ExecDeathTestArgs args = { argv, close_fd }; - pid_t child_pid = -1; - -# if GTEST_HAS_CLONE - const bool use_fork = GTEST_FLAG(death_test_use_fork); - - if (!use_fork) { - static const bool stack_grows_down = StackGrowsDown(); - const size_t stack_size = getpagesize(); - // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. - void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); - GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); - void* const stack_top = - static_cast(stack) + (stack_grows_down ? stack_size : 0); - - child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); - - GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); - } -# else - const bool use_fork = true; -# endif // GTEST_HAS_CLONE - - if (use_fork && (child_pid = fork()) == 0) { - ExecDeathTestChildMain(&args); - _exit(0); - } - - GTEST_DEATH_TEST_CHECK_(child_pid != -1); - return child_pid; -} - -// The AssumeRole process for a fork-and-exec death test. It re-executes the -// main program from the beginning, setting the --gtest_filter -// and --gtest_internal_run_death_test flags to cause only the current -// death test to be re-run. -DeathTest::TestRole ExecDeathTest::AssumeRole() { - const UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const TestInfo* const info = impl->current_test_info(); - const int death_test_index = info->result()->death_test_count(); - - if (flag != NULL) { - set_write_fd(flag->write_fd()); - return EXECUTE_TEST; - } - - int pipe_fd[2]; - GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); - // Clear the close-on-exec flag on the write end of the pipe, lest - // it be closed when the child process does an exec: - GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); - - const String filter_flag = - String::Format("--%s%s=%s.%s", - GTEST_FLAG_PREFIX_, kFilterFlag, - info->test_case_name(), info->name()); - const String internal_flag = - String::Format("--%s%s=%s|%d|%d|%d", - GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, - file_, line_, death_test_index, pipe_fd[1]); - Arguments args; - args.AddArguments(GetArgvs()); - args.AddArgument(filter_flag.c_str()); - args.AddArgument(internal_flag.c_str()); - - DeathTest::set_last_death_test_message(""); - - CaptureStderr(); - // See the comment in NoExecDeathTest::AssumeRole for why the next line - // is necessary. - FlushInfoLog(); - - const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); - set_child_pid(child_pid); - set_read_fd(pipe_fd[0]); - set_spawned(true); - return OVERSEE_TEST; -} - -# endif // !GTEST_OS_WINDOWS - -// Creates a concrete DeathTest-derived class that depends on the -// --gtest_death_test_style flag, and sets the pointer pointed to -// by the "test" argument to its address. If the test should be -// skipped, sets that pointer to NULL. Returns true, unless the -// flag is set to an invalid value. -bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, - const char* file, int line, - DeathTest** test) { - UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const int death_test_index = impl->current_test_info() - ->increment_death_test_count(); - - if (flag != NULL) { - if (death_test_index > flag->index()) { - DeathTest::set_last_death_test_message(String::Format( - "Death test count (%d) somehow exceeded expected maximum (%d)", - death_test_index, flag->index())); - return false; - } - - if (!(flag->file() == file && flag->line() == line && - flag->index() == death_test_index)) { - *test = NULL; - return true; - } - } - -# if GTEST_OS_WINDOWS - - if (GTEST_FLAG(death_test_style) == "threadsafe" || - GTEST_FLAG(death_test_style) == "fast") { - *test = new WindowsDeathTest(statement, regex, file, line); - } - -# else - - if (GTEST_FLAG(death_test_style) == "threadsafe") { - *test = new ExecDeathTest(statement, regex, file, line); - } else if (GTEST_FLAG(death_test_style) == "fast") { - *test = new NoExecDeathTest(statement, regex); - } - -# endif // GTEST_OS_WINDOWS - - else { // NOLINT - this is more readable than unbalanced brackets inside #if. - DeathTest::set_last_death_test_message(String::Format( - "Unknown death test style \"%s\" encountered", - GTEST_FLAG(death_test_style).c_str())); - return false; - } - - return true; -} - -// Splits a given string on a given delimiter, populating a given -// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have -// ::std::string, so we can use it here. -static void SplitString(const ::std::string& str, char delimiter, - ::std::vector< ::std::string>* dest) { - ::std::vector< ::std::string> parsed; - ::std::string::size_type pos = 0; - while (::testing::internal::AlwaysTrue()) { - const ::std::string::size_type colon = str.find(delimiter, pos); - if (colon == ::std::string::npos) { - parsed.push_back(str.substr(pos)); - break; - } else { - parsed.push_back(str.substr(pos, colon - pos)); - pos = colon + 1; - } - } - dest->swap(parsed); -} - -# if GTEST_OS_WINDOWS -// Recreates the pipe and event handles from the provided parameters, -// signals the event, and returns a file descriptor wrapped around the pipe -// handle. This function is called in the child process only. -int GetStatusFileDescriptor(unsigned int parent_process_id, - size_t write_handle_as_size_t, - size_t event_handle_as_size_t) { - AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, - FALSE, // Non-inheritable. - parent_process_id)); - if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { - DeathTestAbort(String::Format("Unable to open parent process %u", - parent_process_id)); - } - - // TODO(vladl@google.com): Replace the following check with a - // compile-time assertion when available. - GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); - - const HANDLE write_handle = - reinterpret_cast(write_handle_as_size_t); - HANDLE dup_write_handle; - - // The newly initialized handle is accessible only in in the parent - // process. To obtain one accessible within the child, we need to use - // DuplicateHandle. - if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, - ::GetCurrentProcess(), &dup_write_handle, - 0x0, // Requested privileges ignored since - // DUPLICATE_SAME_ACCESS is used. - FALSE, // Request non-inheritable handler. - DUPLICATE_SAME_ACCESS)) { - DeathTestAbort(String::Format( - "Unable to duplicate the pipe handle %Iu from the parent process %u", - write_handle_as_size_t, parent_process_id)); - } - - const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); - HANDLE dup_event_handle; - - if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, - ::GetCurrentProcess(), &dup_event_handle, - 0x0, - FALSE, - DUPLICATE_SAME_ACCESS)) { - DeathTestAbort(String::Format( - "Unable to duplicate the event handle %Iu from the parent process %u", - event_handle_as_size_t, parent_process_id)); - } - - const int write_fd = - ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); - if (write_fd == -1) { - DeathTestAbort(String::Format( - "Unable to convert pipe handle %Iu to a file descriptor", - write_handle_as_size_t)); - } - - // Signals the parent that the write end of the pipe has been acquired - // so the parent can release its own write end. - ::SetEvent(dup_event_handle); - - return write_fd; -} -# endif // GTEST_OS_WINDOWS - -// Returns a newly created InternalRunDeathTestFlag object with fields -// initialized from the GTEST_FLAG(internal_run_death_test) flag if -// the flag is specified; otherwise returns NULL. -InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { - if (GTEST_FLAG(internal_run_death_test) == "") return NULL; - - // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we - // can use it here. - int line = -1; - int index = -1; - ::std::vector< ::std::string> fields; - SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); - int write_fd = -1; - -# if GTEST_OS_WINDOWS - - unsigned int parent_process_id = 0; - size_t write_handle_as_size_t = 0; - size_t event_handle_as_size_t = 0; - - if (fields.size() != 6 - || !ParseNaturalNumber(fields[1], &line) - || !ParseNaturalNumber(fields[2], &index) - || !ParseNaturalNumber(fields[3], &parent_process_id) - || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) - || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { - DeathTestAbort(String::Format( - "Bad --gtest_internal_run_death_test flag: %s", - GTEST_FLAG(internal_run_death_test).c_str())); - } - write_fd = GetStatusFileDescriptor(parent_process_id, - write_handle_as_size_t, - event_handle_as_size_t); -# else - - if (fields.size() != 4 - || !ParseNaturalNumber(fields[1], &line) - || !ParseNaturalNumber(fields[2], &index) - || !ParseNaturalNumber(fields[3], &write_fd)) { - DeathTestAbort(String::Format( - "Bad --gtest_internal_run_death_test flag: %s", - GTEST_FLAG(internal_run_death_test).c_str())); - } - -# endif // GTEST_OS_WINDOWS - - return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); -} - -} // namespace internal - -#endif // GTEST_HAS_DEATH_TEST - -} // namespace testing diff --git a/utils/unittest/googletest/gtest-filepath.cc b/utils/unittest/googletest/gtest-filepath.cc deleted file mode 100644 index ad1bab8..0000000 --- a/utils/unittest/googletest/gtest-filepath.cc +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: keith.ray@gmail.com (Keith Ray) - -#include "gtest/internal/gtest-filepath.h" -#include "gtest/internal/gtest-port.h" - -#include - -#if GTEST_OS_WINDOWS_MOBILE -# include -#elif GTEST_OS_WINDOWS -# include -# include -#elif GTEST_OS_SYMBIAN || GTEST_OS_NACL -// Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h -# include -#else -# include -# include // Some Linux distributions define PATH_MAX here. -#endif // GTEST_OS_WINDOWS_MOBILE - -#if GTEST_OS_WINDOWS -# define GTEST_PATH_MAX_ _MAX_PATH -#elif defined(PATH_MAX) -# define GTEST_PATH_MAX_ PATH_MAX -#elif defined(_XOPEN_PATH_MAX) -# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX -#else -# define GTEST_PATH_MAX_ _POSIX_PATH_MAX -#endif // GTEST_OS_WINDOWS - -#include "gtest/internal/gtest-string.h" - -namespace testing { -namespace internal { - -#if GTEST_OS_WINDOWS -// On Windows, '\\' is the standard path separator, but many tools and the -// Windows API also accept '/' as an alternate path separator. Unless otherwise -// noted, a file path can contain either kind of path separators, or a mixture -// of them. -const char kPathSeparator = '\\'; -const char kAlternatePathSeparator = '/'; -const char kAlternatePathSeparatorString[] = "/"; -# if GTEST_OS_WINDOWS_MOBILE -// Windows CE doesn't have a current directory. You should not use -// the current directory in tests on Windows CE, but this at least -// provides a reasonable fallback. -const char kCurrentDirectoryString[] = "\\"; -// Windows CE doesn't define INVALID_FILE_ATTRIBUTES -const DWORD kInvalidFileAttributes = 0xffffffff; -# else -const char kCurrentDirectoryString[] = ".\\"; -# endif // GTEST_OS_WINDOWS_MOBILE -#else -const char kPathSeparator = '/'; -const char kCurrentDirectoryString[] = "./"; -#endif // GTEST_OS_WINDOWS - -// Returns whether the given character is a valid path separator. -static bool IsPathSeparator(char c) { -#if GTEST_HAS_ALT_PATH_SEP_ - return (c == kPathSeparator) || (c == kAlternatePathSeparator); -#else - return c == kPathSeparator; -#endif -} - -// Returns the current working directory, or "" if unsuccessful. -FilePath FilePath::GetCurrentDir() { -#if GTEST_OS_WINDOWS_MOBILE - // Windows CE doesn't have a current directory, so we just return - // something reasonable. - return FilePath(kCurrentDirectoryString); -#elif GTEST_OS_WINDOWS - char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); -#else - char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); -#endif // GTEST_OS_WINDOWS_MOBILE -} - -// Returns a copy of the FilePath with the case-insensitive extension removed. -// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns -// FilePath("dir/file"). If a case-insensitive extension is not -// found, returns a copy of the original FilePath. -FilePath FilePath::RemoveExtension(const char* extension) const { - String dot_extension(String::Format(".%s", extension)); - if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { - return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); - } - return *this; -} - -// Returns a pointer to the last occurrence of a valid path separator in -// the FilePath. On Windows, for example, both '/' and '\' are valid path -// separators. Returns NULL if no path separator was found. -const char* FilePath::FindLastPathSeparator() const { - const char* const last_sep = strrchr(c_str(), kPathSeparator); -#if GTEST_HAS_ALT_PATH_SEP_ - const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); - // Comparing two pointers of which only one is NULL is undefined. - if (last_alt_sep != NULL && - (last_sep == NULL || last_alt_sep > last_sep)) { - return last_alt_sep; - } -#endif - return last_sep; -} - -// Returns a copy of the FilePath with the directory part removed. -// Example: FilePath("path/to/file").RemoveDirectoryName() returns -// FilePath("file"). If there is no directory part ("just_a_file"), it returns -// the FilePath unmodified. If there is no file part ("just_a_dir/") it -// returns an empty FilePath (""). -// On Windows platform, '\' is the path separator, otherwise it is '/'. -FilePath FilePath::RemoveDirectoryName() const { - const char* const last_sep = FindLastPathSeparator(); - return last_sep ? FilePath(String(last_sep + 1)) : *this; -} - -// RemoveFileName returns the directory path with the filename removed. -// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". -// If the FilePath is "a_file" or "/a_file", RemoveFileName returns -// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does -// not have a file, like "just/a/dir/", it returns the FilePath unmodified. -// On Windows platform, '\' is the path separator, otherwise it is '/'. -FilePath FilePath::RemoveFileName() const { - const char* const last_sep = FindLastPathSeparator(); - String dir; - if (last_sep) { - dir = String(c_str(), last_sep + 1 - c_str()); - } else { - dir = kCurrentDirectoryString; - } - return FilePath(dir); -} - -// Helper functions for naming files in a directory for xml output. - -// Given directory = "dir", base_name = "test", number = 0, -// extension = "xml", returns "dir/test.xml". If number is greater -// than zero (e.g., 12), returns "dir/test_12.xml". -// On Windows platform, uses \ as the separator rather than /. -FilePath FilePath::MakeFileName(const FilePath& directory, - const FilePath& base_name, - int number, - const char* extension) { - String file; - if (number == 0) { - file = String::Format("%s.%s", base_name.c_str(), extension); - } else { - file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); - } - return ConcatPaths(directory, FilePath(file)); -} - -// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". -// On Windows, uses \ as the separator rather than /. -FilePath FilePath::ConcatPaths(const FilePath& directory, - const FilePath& relative_path) { - if (directory.IsEmpty()) - return relative_path; - const FilePath dir(directory.RemoveTrailingPathSeparator()); - return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, - relative_path.c_str())); -} - -// Returns true if pathname describes something findable in the file-system, -// either a file, directory, or whatever. -bool FilePath::FileOrDirectoryExists() const { -#if GTEST_OS_WINDOWS_MOBILE - LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); - const DWORD attributes = GetFileAttributes(unicode); - delete [] unicode; - return attributes != kInvalidFileAttributes; -#else - posix::StatStruct file_stat; - return posix::Stat(pathname_.c_str(), &file_stat) == 0; -#endif // GTEST_OS_WINDOWS_MOBILE -} - -// Returns true if pathname describes a directory in the file-system -// that exists. -bool FilePath::DirectoryExists() const { - bool result = false; -#if GTEST_OS_WINDOWS - // Don't strip off trailing separator if path is a root directory on - // Windows (like "C:\\"). - const FilePath& path(IsRootDirectory() ? *this : - RemoveTrailingPathSeparator()); -#else - const FilePath& path(*this); -#endif - -#if GTEST_OS_WINDOWS_MOBILE - LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); - const DWORD attributes = GetFileAttributes(unicode); - delete [] unicode; - if ((attributes != kInvalidFileAttributes) && - (attributes & FILE_ATTRIBUTE_DIRECTORY)) { - result = true; - } -#else - posix::StatStruct file_stat; - result = posix::Stat(path.c_str(), &file_stat) == 0 && - posix::IsDir(file_stat); -#endif // GTEST_OS_WINDOWS_MOBILE - - return result; -} - -// Returns true if pathname describes a root directory. (Windows has one -// root directory per disk drive.) -bool FilePath::IsRootDirectory() const { -#if GTEST_OS_WINDOWS - // TODO(wan@google.com): on Windows a network share like - // \\server\share can be a root directory, although it cannot be the - // current directory. Handle this properly. - return pathname_.length() == 3 && IsAbsolutePath(); -#else - return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); -#endif -} - -// Returns true if pathname describes an absolute path. -bool FilePath::IsAbsolutePath() const { - const char* const name = pathname_.c_str(); -#if GTEST_OS_WINDOWS - return pathname_.length() >= 3 && - ((name[0] >= 'a' && name[0] <= 'z') || - (name[0] >= 'A' && name[0] <= 'Z')) && - name[1] == ':' && - IsPathSeparator(name[2]); -#else - return IsPathSeparator(name[0]); -#endif -} - -// Returns a pathname for a file that does not currently exist. The pathname -// will be directory/base_name.extension or -// directory/base_name_.extension if directory/base_name.extension -// already exists. The number will be incremented until a pathname is found -// that does not already exist. -// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. -// There could be a race condition if two or more processes are calling this -// function at the same time -- they could both pick the same filename. -FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, - const FilePath& base_name, - const char* extension) { - FilePath full_pathname; - int number = 0; - do { - full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); - } while (full_pathname.FileOrDirectoryExists()); - return full_pathname; -} - -// Returns true if FilePath ends with a path separator, which indicates that -// it is intended to represent a directory. Returns false otherwise. -// This does NOT check that a directory (or file) actually exists. -bool FilePath::IsDirectory() const { - return !pathname_.empty() && - IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); -} - -// Create directories so that path exists. Returns true if successful or if -// the directories already exist; returns false if unable to create directories -// for any reason. -bool FilePath::CreateDirectoriesRecursively() const { - if (!this->IsDirectory()) { - return false; - } - - if (pathname_.length() == 0 || this->DirectoryExists()) { - return true; - } - - const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); - return parent.CreateDirectoriesRecursively() && this->CreateFolder(); -} - -// Create the directory so that path exists. Returns true if successful or -// if the directory already exists; returns false if unable to create the -// directory for any reason, including if the parent directory does not -// exist. Not named "CreateDirectory" because that's a macro on Windows. -bool FilePath::CreateFolder() const { -#if GTEST_OS_WINDOWS_MOBILE - FilePath removed_sep(this->RemoveTrailingPathSeparator()); - LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); - int result = CreateDirectory(unicode, NULL) ? 0 : -1; - delete [] unicode; -#elif GTEST_OS_WINDOWS - int result = _mkdir(pathname_.c_str()); -#else - int result = mkdir(pathname_.c_str(), 0777); -#endif // GTEST_OS_WINDOWS_MOBILE - - if (result == -1) { - return this->DirectoryExists(); // An error is OK if the directory exists. - } - return true; // No error. -} - -// If input name has a trailing separator character, remove it and return the -// name, otherwise return the name string unmodified. -// On Windows platform, uses \ as the separator, other platforms use /. -FilePath FilePath::RemoveTrailingPathSeparator() const { - return IsDirectory() - ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) - : *this; -} - -// Removes any redundant separators that might be in the pathname. -// For example, "bar///foo" becomes "bar/foo". Does not eliminate other -// redundancies that might be in a pathname involving "." or "..". -// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). -void FilePath::Normalize() { - if (pathname_.c_str() == NULL) { - pathname_ = ""; - return; - } - const char* src = pathname_.c_str(); - char* const dest = new char[pathname_.length() + 1]; - char* dest_ptr = dest; - memset(dest_ptr, 0, pathname_.length() + 1); - - while (*src != '\0') { - *dest_ptr = *src; - if (!IsPathSeparator(*src)) { - src++; - } else { -#if GTEST_HAS_ALT_PATH_SEP_ - if (*dest_ptr == kAlternatePathSeparator) { - *dest_ptr = kPathSeparator; - } -#endif - while (IsPathSeparator(*src)) - src++; - } - dest_ptr++; - } - *dest_ptr = '\0'; - pathname_ = dest; - delete[] dest; -} - -} // namespace internal -} // namespace testing diff --git a/utils/unittest/googletest/gtest-port.cc b/utils/unittest/googletest/gtest-port.cc deleted file mode 100644 index 3c32ff1..0000000 --- a/utils/unittest/googletest/gtest-port.cc +++ /dev/null @@ -1,750 +0,0 @@ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) - -#include "gtest/internal/gtest-port.h" - -#include -#include -#include -#include - -#if GTEST_OS_WINDOWS_MOBILE -# include // For TerminateProcess() -#elif GTEST_OS_WINDOWS -# include -# include -#else -# include -#endif // GTEST_OS_WINDOWS_MOBILE - -#if GTEST_OS_MAC -# include -# include -# include -#endif // GTEST_OS_MAC - -#include "gtest/gtest-spi.h" -#include "gtest/gtest-message.h" -#include "gtest/internal/gtest-internal.h" -#include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -#include "gtest/internal/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ - -namespace testing { -namespace internal { - -#if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC and C++Builder do not provide a definition of STDERR_FILENO. -const int kStdOutFileno = 1; -const int kStdErrFileno = 2; -#else -const int kStdOutFileno = STDOUT_FILENO; -const int kStdErrFileno = STDERR_FILENO; -#endif // _MSC_VER - -#if GTEST_OS_MAC - -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. -size_t GetThreadCount() { - const task_t task = mach_task_self(); - mach_msg_type_number_t thread_count; - thread_act_array_t thread_list; - const kern_return_t status = task_threads(task, &thread_list, &thread_count); - if (status == KERN_SUCCESS) { - // task_threads allocates resources in thread_list and we need to free them - // to avoid leaks. - vm_deallocate(task, - reinterpret_cast(thread_list), - sizeof(thread_t) * thread_count); - return static_cast(thread_count); - } else { - return 0; - } -} - -#else - -size_t GetThreadCount() { - // There's no portable way to detect the number of threads, so we just - // return 0 to indicate that we cannot detect it. - return 0; -} - -#endif // GTEST_OS_MAC - -#if GTEST_USES_POSIX_RE - -// Implements RE. Currently only needed for death tests. - -RE::~RE() { - if (is_valid_) { - // regfree'ing an invalid regex might crash because the content - // of the regex is undefined. Since the regex's are essentially - // the same, one cannot be valid (or invalid) without the other - // being so too. - regfree(&partial_regex_); - regfree(&full_regex_); - } - free(const_cast(pattern_)); -} - -// Returns true iff regular expression re matches the entire str. -bool RE::FullMatch(const char* str, const RE& re) { - if (!re.is_valid_) return false; - - regmatch_t match; - return regexec(&re.full_regex_, str, 1, &match, 0) == 0; -} - -// Returns true iff regular expression re matches a substring of str -// (including str itself). -bool RE::PartialMatch(const char* str, const RE& re) { - if (!re.is_valid_) return false; - - regmatch_t match; - return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; -} - -// Initializes an RE from its string representation. -void RE::Init(const char* regex) { - pattern_ = posix::StrDup(regex); - - // Reserves enough bytes to hold the regular expression used for a - // full match. - const size_t full_regex_len = strlen(regex) + 10; - char* const full_pattern = new char[full_regex_len]; - - snprintf(full_pattern, full_regex_len, "^(%s)$", regex); - is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; - // We want to call regcomp(&partial_regex_, ...) even if the - // previous expression returns false. Otherwise partial_regex_ may - // not be properly initialized can may cause trouble when it's - // freed. - // - // Some implementation of POSIX regex (e.g. on at least some - // versions of Cygwin) doesn't accept the empty string as a valid - // regex. We change it to an equivalent form "()" to be safe. - if (is_valid_) { - const char* const partial_regex = (*regex == '\0') ? "()" : regex; - is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; - } - EXPECT_TRUE(is_valid_) - << "Regular expression \"" << regex - << "\" is not a valid POSIX Extended regular expression."; - - delete[] full_pattern; -} - -#elif GTEST_USES_SIMPLE_RE - -// Returns true iff ch appears anywhere in str (excluding the -// terminating '\0' character). -bool IsInSet(char ch, const char* str) { - return ch != '\0' && strchr(str, ch) != NULL; -} - -// Returns true iff ch belongs to the given classification. Unlike -// similar functions in , these aren't affected by the -// current locale. -bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } -bool IsAsciiPunct(char ch) { - return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); -} -bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } -bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } -bool IsAsciiWordChar(char ch) { - return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || - ('0' <= ch && ch <= '9') || ch == '_'; -} - -// Returns true iff "\\c" is a supported escape sequence. -bool IsValidEscape(char c) { - return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); -} - -// Returns true iff the given atom (specified by escaped and pattern) -// matches ch. The result is undefined if the atom is invalid. -bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { - if (escaped) { // "\\p" where p is pattern_char. - switch (pattern_char) { - case 'd': return IsAsciiDigit(ch); - case 'D': return !IsAsciiDigit(ch); - case 'f': return ch == '\f'; - case 'n': return ch == '\n'; - case 'r': return ch == '\r'; - case 's': return IsAsciiWhiteSpace(ch); - case 'S': return !IsAsciiWhiteSpace(ch); - case 't': return ch == '\t'; - case 'v': return ch == '\v'; - case 'w': return IsAsciiWordChar(ch); - case 'W': return !IsAsciiWordChar(ch); - } - return IsAsciiPunct(pattern_char) && pattern_char == ch; - } - - return (pattern_char == '.' && ch != '\n') || pattern_char == ch; -} - -// Helper function used by ValidateRegex() to format error messages. -String FormatRegexSyntaxError(const char* regex, int index) { - return (Message() << "Syntax error at index " << index - << " in simple regular expression \"" << regex << "\": ").GetString(); -} - -// Generates non-fatal failures and returns false if regex is invalid; -// otherwise returns true. -bool ValidateRegex(const char* regex) { - if (regex == NULL) { - // TODO(wan@google.com): fix the source file location in the - // assertion failures to match where the regex is used in user - // code. - ADD_FAILURE() << "NULL is not a valid simple regular expression."; - return false; - } - - bool is_valid = true; - - // True iff ?, *, or + can follow the previous atom. - bool prev_repeatable = false; - for (int i = 0; regex[i]; i++) { - if (regex[i] == '\\') { // An escape sequence - i++; - if (regex[i] == '\0') { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) - << "'\\' cannot appear at the end."; - return false; - } - - if (!IsValidEscape(regex[i])) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) - << "invalid escape sequence \"\\" << regex[i] << "\"."; - is_valid = false; - } - prev_repeatable = true; - } else { // Not an escape sequence. - const char ch = regex[i]; - - if (ch == '^' && i > 0) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'^' can only appear at the beginning."; - is_valid = false; - } else if (ch == '$' && regex[i + 1] != '\0') { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'$' can only appear at the end."; - is_valid = false; - } else if (IsInSet(ch, "()[]{}|")) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'" << ch << "' is unsupported."; - is_valid = false; - } else if (IsRepeat(ch) && !prev_repeatable) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'" << ch << "' can only follow a repeatable token."; - is_valid = false; - } - - prev_repeatable = !IsInSet(ch, "^$?*+"); - } - } - - return is_valid; -} - -// Matches a repeated regex atom followed by a valid simple regular -// expression. The regex atom is defined as c if escaped is false, -// or \c otherwise. repeat is the repetition meta character (?, *, -// or +). The behavior is undefined if str contains too many -// characters to be indexable by size_t, in which case the test will -// probably time out anyway. We are fine with this limitation as -// std::string has it too. -bool MatchRepetitionAndRegexAtHead( - bool escaped, char c, char repeat, const char* regex, - const char* str) { - const size_t min_count = (repeat == '+') ? 1 : 0; - const size_t max_count = (repeat == '?') ? 1 : - static_cast(-1) - 1; - // We cannot call numeric_limits::max() as it conflicts with the - // max() macro on Windows. - - for (size_t i = 0; i <= max_count; ++i) { - // We know that the atom matches each of the first i characters in str. - if (i >= min_count && MatchRegexAtHead(regex, str + i)) { - // We have enough matches at the head, and the tail matches too. - // Since we only care about *whether* the pattern matches str - // (as opposed to *how* it matches), there is no need to find a - // greedy match. - return true; - } - if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) - return false; - } - return false; -} - -// Returns true iff regex matches a prefix of str. regex must be a -// valid simple regular expression and not start with "^", or the -// result is undefined. -bool MatchRegexAtHead(const char* regex, const char* str) { - if (*regex == '\0') // An empty regex matches a prefix of anything. - return true; - - // "$" only matches the end of a string. Note that regex being - // valid guarantees that there's nothing after "$" in it. - if (*regex == '$') - return *str == '\0'; - - // Is the first thing in regex an escape sequence? - const bool escaped = *regex == '\\'; - if (escaped) - ++regex; - if (IsRepeat(regex[1])) { - // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so - // here's an indirect recursion. It terminates as the regex gets - // shorter in each recursion. - return MatchRepetitionAndRegexAtHead( - escaped, regex[0], regex[1], regex + 2, str); - } else { - // regex isn't empty, isn't "$", and doesn't start with a - // repetition. We match the first atom of regex with the first - // character of str and recurse. - return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && - MatchRegexAtHead(regex + 1, str + 1); - } -} - -// Returns true iff regex matches any substring of str. regex must be -// a valid simple regular expression, or the result is undefined. -// -// The algorithm is recursive, but the recursion depth doesn't exceed -// the regex length, so we won't need to worry about running out of -// stack space normally. In rare cases the time complexity can be -// exponential with respect to the regex length + the string length, -// but usually it's must faster (often close to linear). -bool MatchRegexAnywhere(const char* regex, const char* str) { - if (regex == NULL || str == NULL) - return false; - - if (*regex == '^') - return MatchRegexAtHead(regex + 1, str); - - // A successful match can be anywhere in str. - do { - if (MatchRegexAtHead(regex, str)) - return true; - } while (*str++ != '\0'); - return false; -} - -// Implements the RE class. - -RE::~RE() { - free(const_cast(pattern_)); - free(const_cast(full_pattern_)); -} - -// Returns true iff regular expression re matches the entire str. -bool RE::FullMatch(const char* str, const RE& re) { - return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); -} - -// Returns true iff regular expression re matches a substring of str -// (including str itself). -bool RE::PartialMatch(const char* str, const RE& re) { - return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); -} - -// Initializes an RE from its string representation. -void RE::Init(const char* regex) { - pattern_ = full_pattern_ = NULL; - if (regex != NULL) { - pattern_ = posix::StrDup(regex); - } - - is_valid_ = ValidateRegex(regex); - if (!is_valid_) { - // No need to calculate the full pattern when the regex is invalid. - return; - } - - const size_t len = strlen(regex); - // Reserves enough bytes to hold the regular expression used for a - // full match: we need space to prepend a '^', append a '$', and - // terminate the string with '\0'. - char* buffer = static_cast(malloc(len + 3)); - full_pattern_ = buffer; - - if (*regex != '^') - *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. - - // We don't use snprintf or strncpy, as they trigger a warning when - // compiled with VC++ 8.0. - memcpy(buffer, regex, len); - buffer += len; - - if (len == 0 || regex[len - 1] != '$') - *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. - - *buffer = '\0'; -} - -#endif // GTEST_USES_POSIX_RE - -const char kUnknownFile[] = "unknown file"; - -// Formats a source file path and a line number as they would appear -// in an error message from the compiler used to compile this code. -GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { - const char* const file_name = file == NULL ? kUnknownFile : file; - - if (line < 0) { - return String::Format("%s:", file_name).c_str(); - } -#ifdef _MSC_VER - return String::Format("%s(%d):", file_name, line).c_str(); -#else - return String::Format("%s:%d:", file_name, line).c_str(); -#endif // _MSC_VER -} - -// Formats a file location for compiler-independent XML output. -// Although this function is not platform dependent, we put it next to -// FormatFileLocation in order to contrast the two functions. -// Note that FormatCompilerIndependentFileLocation() does NOT append colon -// to the file location it produces, unlike FormatFileLocation(). -GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( - const char* file, int line) { - const char* const file_name = file == NULL ? kUnknownFile : file; - - if (line < 0) - return file_name; - else - return String::Format("%s:%d", file_name, line).c_str(); -} - - -GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) - : severity_(severity) { - const char* const marker = - severity == GTEST_INFO ? "[ INFO ]" : - severity == GTEST_WARNING ? "[WARNING]" : - severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; - GetStream() << ::std::endl << marker << " " - << FormatFileLocation(file, line).c_str() << ": "; -} - -// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. -GTestLog::~GTestLog() { - GetStream() << ::std::endl; - if (severity_ == GTEST_FATAL) { - fflush(stderr); - posix::Abort(); - } -} -// Disable Microsoft deprecation warnings for POSIX functions called from -// this class (creat, dup, dup2, and close) -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4996) -#endif // _MSC_VER - -#if GTEST_HAS_STREAM_REDIRECTION - -// Object that captures an output stream (stdout/stderr). -class CapturedStream { - public: - // The ctor redirects the stream to a temporary file. - CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { - -# if GTEST_OS_WINDOWS - char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT - char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT - - ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); - const UINT success = ::GetTempFileNameA(temp_dir_path, - "gtest_redir", - 0, // Generate unique file name. - temp_file_path); - GTEST_CHECK_(success != 0) - << "Unable to create a temporary file in " << temp_dir_path; - const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); - GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " - << temp_file_path; - filename_ = temp_file_path; -#elif GTEST_OS_LINUX_ANDROID - char name_template[] = "/sdcard/captured_stderr.XXXXXX"; - const int captured_fd = mkstemp(name_template); - filename_ = name_template; -# else - // There's no guarantee that a test has write access to the - // current directory, so we create the temporary file in the /tmp - // directory instead. - char name_template[] = "/tmp/captured_stream.XXXXXX"; - const int captured_fd = mkstemp(name_template); - filename_ = name_template; -# endif // GTEST_OS_WINDOWS - fflush(NULL); - dup2(captured_fd, fd_); - close(captured_fd); - } - - ~CapturedStream() { - remove(filename_.c_str()); - } - - String GetCapturedString() { - if (uncaptured_fd_ != -1) { - // Restores the original stream. - fflush(NULL); - dup2(uncaptured_fd_, fd_); - close(uncaptured_fd_); - uncaptured_fd_ = -1; - } - - FILE* const file = posix::FOpen(filename_.c_str(), "r"); - const String content = ReadEntireFile(file); - posix::FClose(file); - return content; - } - - private: - // Reads the entire content of a file as a String. - static String ReadEntireFile(FILE* file); - - // Returns the size (in bytes) of a file. - static size_t GetFileSize(FILE* file); - - const int fd_; // A stream to capture. - int uncaptured_fd_; - // Name of the temporary file holding the stderr output. - ::std::string filename_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); -}; - -// Returns the size (in bytes) of a file. -size_t CapturedStream::GetFileSize(FILE* file) { - fseek(file, 0, SEEK_END); - return static_cast(ftell(file)); -} - -// Reads the entire content of a file as a string. -String CapturedStream::ReadEntireFile(FILE* file) { - const size_t file_size = GetFileSize(file); - char* const buffer = new char[file_size]; - - size_t bytes_last_read = 0; // # of bytes read in the last fread() - size_t bytes_read = 0; // # of bytes read so far - - fseek(file, 0, SEEK_SET); - - // Keeps reading the file until we cannot read further or the - // pre-determined file size is reached. - do { - bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); - bytes_read += bytes_last_read; - } while (bytes_last_read > 0 && bytes_read < file_size); - - const String content(buffer, bytes_read); - delete[] buffer; - - return content; -} - -# ifdef _MSC_VER -# pragma warning(pop) -# endif // _MSC_VER - -static CapturedStream* g_captured_stderr = NULL; -static CapturedStream* g_captured_stdout = NULL; - -// Starts capturing an output stream (stdout/stderr). -void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { - if (*stream != NULL) { - GTEST_LOG_(FATAL) << "Only one " << stream_name - << " capturer can exist at a time."; - } - *stream = new CapturedStream(fd); -} - -// Stops capturing the output stream and returns the captured string. -String GetCapturedStream(CapturedStream** captured_stream) { - const String content = (*captured_stream)->GetCapturedString(); - - delete *captured_stream; - *captured_stream = NULL; - - return content; -} - -// Starts capturing stdout. -void CaptureStdout() { - CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); -} - -// Starts capturing stderr. -void CaptureStderr() { - CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); -} - -// Stops capturing stdout and returns the captured string. -String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } - -// Stops capturing stderr and returns the captured string. -String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } - -#endif // GTEST_HAS_STREAM_REDIRECTION - -#if GTEST_HAS_DEATH_TEST - -// A copy of all command line arguments. Set by InitGoogleTest(). -::std::vector g_argvs; - -// Returns the command line as a vector of strings. -const ::std::vector& GetArgvs() { return g_argvs; } - -#endif // GTEST_HAS_DEATH_TEST - -#if GTEST_OS_WINDOWS_MOBILE -namespace posix { -void Abort() { - DebugBreak(); - TerminateProcess(GetCurrentProcess(), 1); -} -} // namespace posix -#endif // GTEST_OS_WINDOWS_MOBILE - -// Returns the name of the environment variable corresponding to the -// given flag. For example, FlagToEnvVar("foo") will return -// "GTEST_FOO" in the open-source version. -static String FlagToEnvVar(const char* flag) { - const String full_flag = - (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); - - Message env_var; - for (size_t i = 0; i != full_flag.length(); i++) { - env_var << ToUpper(full_flag.c_str()[i]); - } - - return env_var.GetString(); -} - -// Parses 'str' for a 32-bit signed integer. If successful, writes -// the result to *value and returns true; otherwise leaves *value -// unchanged and returns false. -bool ParseInt32(const Message& src_text, const char* str, Int32* value) { - // Parses the environment variable as a decimal integer. - char* end = NULL; - const long long_value = strtol(str, &end, 10); // NOLINT - - // Has strtol() consumed all characters in the string? - if (*end != '\0') { - // No - an invalid character was encountered. - Message msg; - msg << "WARNING: " << src_text - << " is expected to be a 32-bit integer, but actually" - << " has value \"" << str << "\".\n"; - printf("%s", msg.GetString().c_str()); - fflush(stdout); - return false; - } - - // Is the parsed value in the range of an Int32? - const Int32 result = static_cast(long_value); - if (long_value == LONG_MAX || long_value == LONG_MIN || - // The parsed value overflows as a long. (strtol() returns - // LONG_MAX or LONG_MIN when the input overflows.) - result != long_value - // The parsed value overflows as an Int32. - ) { - Message msg; - msg << "WARNING: " << src_text - << " is expected to be a 32-bit integer, but actually" - << " has value " << str << ", which overflows.\n"; - printf("%s", msg.GetString().c_str()); - fflush(stdout); - return false; - } - - *value = result; - return true; -} - -// Reads and returns the Boolean environment variable corresponding to -// the given flag; if it's not set, returns default_value. -// -// The value is considered true iff it's not "0". -bool BoolFromGTestEnv(const char* flag, bool default_value) { - const String env_var = FlagToEnvVar(flag); - const char* const string_value = posix::GetEnv(env_var.c_str()); - return string_value == NULL ? - default_value : strcmp(string_value, "0") != 0; -} - -// Reads and returns a 32-bit integer stored in the environment -// variable corresponding to the given flag; if it isn't set or -// doesn't represent a valid 32-bit integer, returns default_value. -Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { - const String env_var = FlagToEnvVar(flag); - const char* const string_value = posix::GetEnv(env_var.c_str()); - if (string_value == NULL) { - // The environment variable is not set. - return default_value; - } - - Int32 result = default_value; - if (!ParseInt32(Message() << "Environment variable " << env_var, - string_value, &result)) { - printf("The default value %s is used.\n", - (Message() << default_value).GetString().c_str()); - fflush(stdout); - return default_value; - } - - return result; -} - -// Reads and returns the string environment variable corresponding to -// the given flag; if it's not set, returns default_value. -const char* StringFromGTestEnv(const char* flag, const char* default_value) { - const String env_var = FlagToEnvVar(flag); - const char* const value = posix::GetEnv(env_var.c_str()); - return value == NULL ? default_value : value; -} - -} // namespace internal -} // namespace testing diff --git a/utils/unittest/googletest/gtest-printers.cc b/utils/unittest/googletest/gtest-printers.cc deleted file mode 100644 index 205a394..0000000 --- a/utils/unittest/googletest/gtest-printers.cc +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) - -// Google Test - The Google C++ Testing Framework -// -// This file implements a universal value printer that can print a -// value of any type T: -// -// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); -// -// It uses the << operator when possible, and prints the bytes in the -// object otherwise. A user can override its behavior for a class -// type Foo by defining either operator<<(::std::ostream&, const Foo&) -// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that -// defines Foo. - -#include "gtest/gtest-printers.h" -#include -#include -#include // NOLINT -#include -#include "gtest/internal/gtest-port.h" - -namespace testing { - -namespace { - -using ::std::ostream; - -#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s. -# define snprintf _snprintf -#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. -# define snprintf _snprintf_s -#elif _MSC_VER -# define snprintf _snprintf -#endif // GTEST_OS_WINDOWS_MOBILE - -// Prints a segment of bytes in the given object. -void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, - size_t count, ostream* os) { - char text[5] = ""; - for (size_t i = 0; i != count; i++) { - const size_t j = start + i; - if (i != 0) { - // Organizes the bytes into groups of 2 for easy parsing by - // human. - if ((j % 2) == 0) - *os << ' '; - else - *os << '-'; - } - snprintf(text, sizeof(text), "%02X", obj_bytes[j]); - *os << text; - } -} - -// Prints the bytes in the given value to the given ostream. -void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, - ostream* os) { - // Tells the user how big the object is. - *os << count << "-byte object <"; - - const size_t kThreshold = 132; - const size_t kChunkSize = 64; - // If the object size is bigger than kThreshold, we'll have to omit - // some details by printing only the first and the last kChunkSize - // bytes. - // TODO(wan): let the user control the threshold using a flag. - if (count < kThreshold) { - PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); - } else { - PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); - *os << " ... "; - // Rounds up to 2-byte boundary. - const size_t resume_pos = (count - kChunkSize + 1)/2*2; - PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); - } - *os << ">"; -} - -} // namespace - -namespace internal2 { - -// Delegates to PrintBytesInObjectToImpl() to print the bytes in the -// given object. The delegation simplifies the implementation, which -// uses the << operator and thus is easier done outside of the -// ::testing::internal namespace, which contains a << operator that -// sometimes conflicts with the one in STL. -void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, - ostream* os) { - PrintBytesInObjectToImpl(obj_bytes, count, os); -} - -} // namespace internal2 - -namespace internal { - -// Depending on the value of a char (or wchar_t), we print it in one -// of three formats: -// - as is if it's a printable ASCII (e.g. 'a', '2', ' '), -// - as a hexadecimal escape sequence (e.g. '\x7F'), or -// - as a special escape sequence (e.g. '\r', '\n'). -enum CharFormat { - kAsIs, - kHexEscape, - kSpecialEscape -}; - -// Returns true if c is a printable ASCII character. We test the -// value of c directly instead of calling isprint(), which is buggy on -// Windows Mobile. -inline bool IsPrintableAscii(wchar_t c) { - return 0x20 <= c && c <= 0x7E; -} - -// Prints a wide or narrow char c as a character literal without the -// quotes, escaping it when necessary; returns how c was formatted. -// The template argument UnsignedChar is the unsigned version of Char, -// which is the type of c. -template -static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { - switch (static_cast(c)) { - case L'\0': - *os << "\\0"; - break; - case L'\'': - *os << "\\'"; - break; - case L'\\': - *os << "\\\\"; - break; - case L'\a': - *os << "\\a"; - break; - case L'\b': - *os << "\\b"; - break; - case L'\f': - *os << "\\f"; - break; - case L'\n': - *os << "\\n"; - break; - case L'\r': - *os << "\\r"; - break; - case L'\t': - *os << "\\t"; - break; - case L'\v': - *os << "\\v"; - break; - default: - if (IsPrintableAscii(c)) { - *os << static_cast(c); - return kAsIs; - } else { - *os << String::Format("\\x%X", static_cast(c)); - return kHexEscape; - } - } - return kSpecialEscape; -} - -// Prints a char c as if it's part of a string literal, escaping it when -// necessary; returns how c was formatted. -static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { - switch (c) { - case L'\'': - *os << "'"; - return kAsIs; - case L'"': - *os << "\\\""; - return kSpecialEscape; - default: - return PrintAsCharLiteralTo(c, os); - } -} - -// Prints a char c as if it's part of a string literal, escaping it when -// necessary; returns how c was formatted. -static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) { - return PrintAsWideStringLiteralTo(static_cast(c), os); -} - -// Prints a wide or narrow character c and its code. '\0' is printed -// as "'\\0'", other unprintable characters are also properly escaped -// using the standard C++ escape sequence. The template argument -// UnsignedChar is the unsigned version of Char, which is the type of c. -template -void PrintCharAndCodeTo(Char c, ostream* os) { - // First, print c as a literal in the most readable form we can find. - *os << ((sizeof(c) > 1) ? "L'" : "'"); - const CharFormat format = PrintAsCharLiteralTo(c, os); - *os << "'"; - - // To aid user debugging, we also print c's code in decimal, unless - // it's 0 (in which case c was printed as '\\0', making the code - // obvious). - if (c == 0) - return; - *os << " (" << String::Format("%d", c).c_str(); - - // For more convenience, we print c's code again in hexadecimal, - // unless c was already printed in the form '\x##' or the code is in - // [1, 9]. - if (format == kHexEscape || (1 <= c && c <= 9)) { - // Do nothing. - } else { - *os << String::Format(", 0x%X", - static_cast(c)).c_str(); - } - *os << ")"; -} - -void PrintTo(unsigned char c, ::std::ostream* os) { - PrintCharAndCodeTo(c, os); -} -void PrintTo(signed char c, ::std::ostream* os) { - PrintCharAndCodeTo(c, os); -} - -// Prints a wchar_t as a symbol if it is printable or as its internal -// code otherwise and also as its code. L'\0' is printed as "L'\\0'". -void PrintTo(wchar_t wc, ostream* os) { - PrintCharAndCodeTo(wc, os); -} - -// Prints the given array of characters to the ostream. -// The array starts at *begin, the length is len, it may include '\0' characters -// and may not be null-terminated. -static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { - *os << "\""; - bool is_previous_hex = false; - for (size_t index = 0; index < len; ++index) { - const char cur = begin[index]; - if (is_previous_hex && IsXDigit(cur)) { - // Previous character is of '\x..' form and this character can be - // interpreted as another hexadecimal digit in its number. Break string to - // disambiguate. - *os << "\" \""; - } - is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape; - } - *os << "\""; -} - -// Prints a (const) char array of 'len' elements, starting at address 'begin'. -void UniversalPrintArray(const char* begin, size_t len, ostream* os) { - PrintCharsAsStringTo(begin, len, os); -} - -// Prints the given array of wide characters to the ostream. -// The array starts at *begin, the length is len, it may include L'\0' -// characters and may not be null-terminated. -static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, - ostream* os) { - *os << "L\""; - bool is_previous_hex = false; - for (size_t index = 0; index < len; ++index) { - const wchar_t cur = begin[index]; - if (is_previous_hex && isascii(cur) && IsXDigit(static_cast(cur))) { - // Previous character is of '\x..' form and this character can be - // interpreted as another hexadecimal digit in its number. Break string to - // disambiguate. - *os << "\" L\""; - } - is_previous_hex = PrintAsWideStringLiteralTo(cur, os) == kHexEscape; - } - *os << "\""; -} - -// Prints the given C string to the ostream. -void PrintTo(const char* s, ostream* os) { - if (s == NULL) { - *os << "NULL"; - } else { - *os << ImplicitCast_(s) << " pointing to "; - PrintCharsAsStringTo(s, strlen(s), os); - } -} - -// MSVC compiler can be configured to define whar_t as a typedef -// of unsigned short. Defining an overload for const wchar_t* in that case -// would cause pointers to unsigned shorts be printed as wide strings, -// possibly accessing more memory than intended and causing invalid -// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when -// wchar_t is implemented as a native type. -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -// Prints the given wide C string to the ostream. -void PrintTo(const wchar_t* s, ostream* os) { - if (s == NULL) { - *os << "NULL"; - } else { - *os << ImplicitCast_(s) << " pointing to "; - PrintWideCharsAsStringTo(s, wcslen(s), os); - } -} -#endif // wchar_t is native - -// Prints a ::string object. -#if GTEST_HAS_GLOBAL_STRING -void PrintStringTo(const ::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_GLOBAL_STRING - -void PrintStringTo(const ::std::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} - -// Prints a ::wstring object. -#if GTEST_HAS_GLOBAL_WSTRING -void PrintWideStringTo(const ::wstring& s, ostream* os) { - PrintWideCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -#if GTEST_HAS_STD_WSTRING -void PrintWideStringTo(const ::std::wstring& s, ostream* os) { - PrintWideCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_STD_WSTRING - -} // namespace internal - -} // namespace testing diff --git a/utils/unittest/googletest/gtest-test-part.cc b/utils/unittest/googletest/gtest-test-part.cc deleted file mode 100644 index 1612780..0000000 --- a/utils/unittest/googletest/gtest-test-part.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: mheule@google.com (Markus Heule) -// -// The Google C++ Testing Framework (Google Test) - -#include "gtest/gtest-test-part.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -#include "gtest/internal/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ - -namespace testing { - -using internal::GetUnitTestImpl; - -// Gets the summary of the failure message by omitting the stack trace -// in it. -internal::String TestPartResult::ExtractSummary(const char* message) { - const char* const stack_trace = strstr(message, internal::kStackTraceMarker); - return stack_trace == NULL ? internal::String(message) : - internal::String(message, stack_trace - message); -} - -// Prints a TestPartResult object. -std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { - return os - << result.file_name() << ":" << result.line_number() << ": " - << (result.type() == TestPartResult::kSuccess ? "Success" : - result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : - "Non-fatal failure") << ":\n" - << result.message() << std::endl; -} - -// Appends a TestPartResult to the array. -void TestPartResultArray::Append(const TestPartResult& result) { - array_.push_back(result); -} - -// Returns the TestPartResult at the given index (0-based). -const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { - if (index < 0 || index >= size()) { - printf("\nInvalid index (%d) into TestPartResultArray.\n", index); - internal::posix::Abort(); - } - - return array_[index]; -} - -// Returns the number of TestPartResult objects in the array. -int TestPartResultArray::size() const { - return static_cast(array_.size()); -} - -namespace internal { - -HasNewFatalFailureHelper::HasNewFatalFailureHelper() - : has_new_fatal_failure_(false), - original_reporter_(GetUnitTestImpl()-> - GetTestPartResultReporterForCurrentThread()) { - GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); -} - -HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { - GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( - original_reporter_); -} - -void HasNewFatalFailureHelper::ReportTestPartResult( - const TestPartResult& result) { - if (result.fatally_failed()) - has_new_fatal_failure_ = true; - original_reporter_->ReportTestPartResult(result); -} - -} // namespace internal - -} // namespace testing diff --git a/utils/unittest/googletest/gtest-typed-test.cc b/utils/unittest/googletest/gtest-typed-test.cc deleted file mode 100644 index a5cc88f..0000000 --- a/utils/unittest/googletest/gtest-typed-test.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) - -#include "gtest/gtest-typed-test.h" -#include "gtest/gtest.h" - -namespace testing { -namespace internal { - -#if GTEST_HAS_TYPED_TEST_P - -// Skips to the first non-space char in str. Returns an empty string if str -// contains only whitespace characters. -static const char* SkipSpaces(const char* str) { - while (IsSpace(*str)) - str++; - return str; -} - -// Verifies that registered_tests match the test names in -// defined_test_names_; returns registered_tests if successful, or -// aborts the program otherwise. -const char* TypedTestCasePState::VerifyRegisteredTestNames( - const char* file, int line, const char* registered_tests) { - typedef ::std::set::const_iterator DefinedTestIter; - registered_ = true; - - // Skip initial whitespace in registered_tests since some - // preprocessors prefix stringizied literals with whitespace. - registered_tests = SkipSpaces(registered_tests); - - Message errors; - ::std::set tests; - for (const char* names = registered_tests; names != NULL; - names = SkipComma(names)) { - const String name = GetPrefixUntilComma(names); - if (tests.count(name) != 0) { - errors << "Test " << name << " is listed more than once.\n"; - continue; - } - - bool found = false; - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); - ++it) { - if (name == *it) { - found = true; - break; - } - } - - if (found) { - tests.insert(name); - } else { - errors << "No test named " << name - << " can be found in this test case.\n"; - } - } - - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); - ++it) { - if (tests.count(*it) == 0) { - errors << "You forgot to list test " << *it << ".\n"; - } - } - - const String& errors_str = errors.GetString(); - if (errors_str != "") { - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), - errors_str.c_str()); - fflush(stderr); - posix::Abort(); - } - - return registered_tests; -} - -#endif // GTEST_HAS_TYPED_TEST_P - -} // namespace internal -} // namespace testing diff --git a/utils/unittest/googletest/gtest.cc b/utils/unittest/googletest/gtest.cc deleted file mode 100644 index eb5c68c..0000000 --- a/utils/unittest/googletest/gtest.cc +++ /dev/null @@ -1,4866 +0,0 @@ -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) - -#include "gtest/gtest.h" -#include "gtest/gtest-spi.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include // NOLINT -#include -#include - -#if GTEST_OS_LINUX - -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 - -# include // NOLINT -# include // NOLINT -# include // NOLINT -// Declares vsnprintf(). This header is not available on Windows. -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include - -#elif GTEST_OS_SYMBIAN -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT - -#elif GTEST_OS_ZOS -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT - -// On z/OS we additionally need strings.h for strcasecmp. -# include // NOLINT - -#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. - -# include // NOLINT - -#elif GTEST_OS_WINDOWS // We are on Windows proper. - -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include // NOLINT - -# if GTEST_OS_WINDOWS_MINGW -// MinGW has gettimeofday() but not _ftime64(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -// TODO(kenton@google.com): There are other ways to get the time on -// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW -// supports these. consider using them instead. -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT -# endif // GTEST_OS_WINDOWS_MINGW - -// cpplint thinks that the header is already included, so we want to -// silence it. -# include // NOLINT - -#else - -// Assume other platforms have gettimeofday(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 - -// cpplint thinks that the header is already included, so we want to -// silence it. -# include // NOLINT -# include // NOLINT - -#endif // GTEST_OS_LINUX - -#if GTEST_HAS_EXCEPTIONS -# include -#endif - -#if GTEST_CAN_STREAM_RESULTS_ -# include // NOLINT -# include // NOLINT -#endif - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -#include "gtest/internal/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ - -#if GTEST_OS_WINDOWS -# define vsnprintf _vsnprintf -#endif // GTEST_OS_WINDOWS - -namespace testing { - -using internal::CountIf; -using internal::ForEach; -using internal::GetElementOr; -using internal::Shuffle; - -// Constants. - -// A test whose test case name or test name matches this filter is -// disabled and not run. -static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; - -// A test case whose name matches this filter is considered a death -// test case and will be run before test cases whose name doesn't -// match this filter. -static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; - -// A test filter that matches everything. -static const char kUniversalFilter[] = "*"; - -// The default output file for XML output. -static const char kDefaultOutputFile[] = "test_detail.xml"; - -// The environment variable name for the test shard index. -static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; -// The environment variable name for the total number of test shards. -static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; -// The environment variable name for the test shard status file. -static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; - -namespace internal { - -// The text used in failure messages to indicate the start of the -// stack trace. -const char kStackTraceMarker[] = "\nStack trace:\n"; - -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. -bool g_help_flag = false; - -} // namespace internal - -GTEST_DEFINE_bool_( - also_run_disabled_tests, - internal::BoolFromGTestEnv("also_run_disabled_tests", false), - "Run disabled tests too, in addition to the tests normally being run."); - -GTEST_DEFINE_bool_( - break_on_failure, - internal::BoolFromGTestEnv("break_on_failure", false), - "True iff a failed assertion should be a debugger break-point."); - -GTEST_DEFINE_bool_( - catch_exceptions, - internal::BoolFromGTestEnv("catch_exceptions", true), - "True iff " GTEST_NAME_ - " should catch exceptions and treat them as test failures."); - -GTEST_DEFINE_string_( - color, - internal::StringFromGTestEnv("color", "auto"), - "Whether to use colors in the output. Valid values: yes, no, " - "and auto. 'auto' means to use colors if the output is " - "being sent to a terminal and the TERM environment variable " - "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); - -GTEST_DEFINE_string_( - filter, - internal::StringFromGTestEnv("filter", kUniversalFilter), - "A colon-separated list of glob (not regex) patterns " - "for filtering the tests to run, optionally followed by a " - "'-' and a : separated list of negative patterns (tests to " - "exclude). A test is run if it matches one of the positive " - "patterns and does not match any of the negative patterns."); - -GTEST_DEFINE_bool_(list_tests, false, - "List all tests without running them."); - -GTEST_DEFINE_string_( - output, - internal::StringFromGTestEnv("output", ""), - "A format (currently must be \"xml\"), optionally followed " - "by a colon and an output file name or directory. A directory " - "is indicated by a trailing pathname separator. " - "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " - "If a directory is specified, output files will be created " - "within that directory, with file-names based on the test " - "executable's name and, if necessary, made unique by adding " - "digits."); - -GTEST_DEFINE_bool_( - print_time, - internal::BoolFromGTestEnv("print_time", true), - "True iff " GTEST_NAME_ - " should display elapsed time in text output."); - -GTEST_DEFINE_int32_( - random_seed, - internal::Int32FromGTestEnv("random_seed", 0), - "Random number seed to use when shuffling test orders. Must be in range " - "[1, 99999], or 0 to use a seed based on the current time."); - -GTEST_DEFINE_int32_( - repeat, - internal::Int32FromGTestEnv("repeat", 1), - "How many times to repeat each test. Specify a negative number " - "for repeating forever. Useful for shaking out flaky tests."); - -GTEST_DEFINE_bool_( - show_internal_stack_frames, false, - "True iff " GTEST_NAME_ " should include internal stack frames when " - "printing test failure stack traces."); - -GTEST_DEFINE_bool_( - shuffle, - internal::BoolFromGTestEnv("shuffle", false), - "True iff " GTEST_NAME_ - " should randomize tests' order on every run."); - -GTEST_DEFINE_int32_( - stack_trace_depth, - internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), - "The maximum number of stack frames to print when an " - "assertion fails. The valid range is 0 through 100, inclusive."); - -GTEST_DEFINE_string_( - stream_result_to, - internal::StringFromGTestEnv("stream_result_to", ""), - "This flag specifies the host name and the port number on which to stream " - "test results. Example: \"localhost:555\". The flag is effective only on " - "Linux."); - -GTEST_DEFINE_bool_( - throw_on_failure, - internal::BoolFromGTestEnv("throw_on_failure", false), - "When this flag is specified, a failed assertion will throw an exception " - "if exceptions are enabled or exit the program with a non-zero code " - "otherwise."); - -namespace internal { - -// Generates a random number from [0, range), using a Linear -// Congruential Generator (LCG). Crashes if 'range' is 0 or greater -// than kMaxRange. -UInt32 Random::Generate(UInt32 range) { - // These constants are the same as are used in glibc's rand(3). - state_ = (1103515245U*state_ + 12345U) % kMaxRange; - - GTEST_CHECK_(range > 0) - << "Cannot generate a number in the range [0, 0)."; - GTEST_CHECK_(range <= kMaxRange) - << "Generation of a number in [0, " << range << ") was requested, " - << "but this can only generate numbers in [0, " << kMaxRange << ")."; - - // Converting via modulus introduces a bit of downward bias, but - // it's simple, and a linear congruential generator isn't too good - // to begin with. - return state_ % range; -} - -// GTestIsInitialized() returns true iff the user has initialized -// Google Test. Useful for catching the user mistake of not initializing -// Google Test before calling RUN_ALL_TESTS(). -// -// A user must call testing::InitGoogleTest() to initialize Google -// Test. g_init_gtest_count is set to the number of times -// InitGoogleTest() has been called. We don't protect this variable -// under a mutex as it is only accessed in the main thread. -int g_init_gtest_count = 0; -static bool GTestIsInitialized() { return g_init_gtest_count != 0; } - -// Iterates over a vector of TestCases, keeping a running sum of the -// results of calling a given int-returning method on each. -// Returns the sum. -static int SumOverTestCaseList(const std::vector& case_list, - int (TestCase::*method)() const) { - int sum = 0; - for (size_t i = 0; i < case_list.size(); i++) { - sum += (case_list[i]->*method)(); - } - return sum; -} - -// Returns true iff the test case passed. -static bool TestCasePassed(const TestCase* test_case) { - return test_case->should_run() && test_case->Passed(); -} - -// Returns true iff the test case failed. -static bool TestCaseFailed(const TestCase* test_case) { - return test_case->should_run() && test_case->Failed(); -} - -// Returns true iff test_case contains at least one test that should -// run. -static bool ShouldRunTestCase(const TestCase* test_case) { - return test_case->should_run(); -} - -// AssertHelper constructor. -AssertHelper::AssertHelper(TestPartResult::Type type, - const char* file, - int line, - const char* message) - : data_(new AssertHelperData(type, file, line, message)) { -} - -AssertHelper::~AssertHelper() { - delete data_; -} - -// Message assignment, for assertion streaming support. -void AssertHelper::operator=(const Message& message) const { - UnitTest::GetInstance()-> - AddTestPartResult(data_->type, data_->file, data_->line, - AppendUserMessage(data_->message, message), - UnitTest::GetInstance()->impl() - ->CurrentOsStackTraceExceptTop(1) - // Skips the stack frame for this function itself. - ); // NOLINT -} - -// Mutex for linked pointers. -GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); - -// Application pathname gotten in InitGoogleTest. -String g_executable_path; - -// Returns the current application's name, removing directory path if that -// is present. -FilePath GetCurrentExecutableName() { - FilePath result; - -#if GTEST_OS_WINDOWS - result.Set(FilePath(g_executable_path).RemoveExtension("exe")); -#else - result.Set(FilePath(g_executable_path)); -#endif // GTEST_OS_WINDOWS - - return result.RemoveDirectoryName(); -} - -// Functions for processing the gtest_output flag. - -// Returns the output format, or "" for normal printed output. -String UnitTestOptions::GetOutputFormat() { - const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) return String(""); - - const char* const colon = strchr(gtest_output_flag, ':'); - return (colon == NULL) ? - String(gtest_output_flag) : - String(gtest_output_flag, colon - gtest_output_flag); -} - -// Returns the name of the requested output file, or the default if none -// was explicitly specified. -String UnitTestOptions::GetAbsolutePathToOutputFile() { - const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) - return String(""); - - const char* const colon = strchr(gtest_output_flag, ':'); - if (colon == NULL) - return String(internal::FilePath::ConcatPaths( - internal::FilePath( - UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(kDefaultOutputFile)).ToString() ); - - internal::FilePath output_name(colon + 1); - if (!output_name.IsAbsolutePath()) - // TODO(wan@google.com): on Windows \some\path is not an absolute - // path (as its meaning depends on the current drive), yet the - // following logic for turning it into an absolute path is wrong. - // Fix it. - output_name = internal::FilePath::ConcatPaths( - internal::FilePath(UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(colon + 1)); - - if (!output_name.IsDirectory()) - return output_name.ToString(); - - internal::FilePath result(internal::FilePath::GenerateUniqueFileName( - output_name, internal::GetCurrentExecutableName(), - GetOutputFormat().c_str())); - return result.ToString(); -} - -// Returns true iff the wildcard pattern matches the string. The -// first ':' or '\0' character in pattern marks the end of it. -// -// This recursive algorithm isn't very efficient, but is clear and -// works well enough for matching test names, which are short. -bool UnitTestOptions::PatternMatchesString(const char *pattern, - const char *str) { - switch (*pattern) { - case '\0': - case ':': // Either ':' or '\0' marks the end of the pattern. - return *str == '\0'; - case '?': // Matches any single character. - return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); - case '*': // Matches any string (possibly empty) of characters. - return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || - PatternMatchesString(pattern + 1, str); - default: // Non-special character. Matches itself. - return *pattern == *str && - PatternMatchesString(pattern + 1, str + 1); - } -} - -bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { - const char *cur_pattern = filter; - for (;;) { - if (PatternMatchesString(cur_pattern, name.c_str())) { - return true; - } - - // Finds the next pattern in the filter. - cur_pattern = strchr(cur_pattern, ':'); - - // Returns if no more pattern can be found. - if (cur_pattern == NULL) { - return false; - } - - // Skips the pattern separater (the ':' character). - cur_pattern++; - } -} - -// TODO(keithray): move String function implementations to gtest-string.cc. - -// Returns true iff the user-specified filter matches the test case -// name and the test name. -bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, - const String &test_name) { - const String& full_name = String::Format("%s.%s", - test_case_name.c_str(), - test_name.c_str()); - - // Split --gtest_filter at '-', if there is one, to separate into - // positive filter and negative filter portions - const char* const p = GTEST_FLAG(filter).c_str(); - const char* const dash = strchr(p, '-'); - String positive; - String negative; - if (dash == NULL) { - positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter - negative = String(""); - } else { - positive = String(p, dash - p); // Everything up to the dash - negative = String(dash+1); // Everything after the dash - if (positive.empty()) { - // Treat '-test1' as the same as '*-test1' - positive = kUniversalFilter; - } - } - - // A filter is a colon-separated list of patterns. It matches a - // test if any pattern in it matches the test. - return (MatchesFilter(full_name, positive.c_str()) && - !MatchesFilter(full_name, negative.c_str())); -} - -#if GTEST_HAS_SEH -// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the -// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. -// This function is useful as an __except condition. -int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { - // Google Test should handle a SEH exception if: - // 1. the user wants it to, AND - // 2. this is not a breakpoint exception, AND - // 3. this is not a C++ exception (VC++ implements them via SEH, - // apparently). - // - // SEH exception code for C++ exceptions. - // (see http://support.microsoft.com/kb/185294 for more information). - const DWORD kCxxExceptionCode = 0xe06d7363; - - bool should_handle = true; - - if (!GTEST_FLAG(catch_exceptions)) - should_handle = false; - else if (exception_code == EXCEPTION_BREAKPOINT) - should_handle = false; - else if (exception_code == kCxxExceptionCode) - should_handle = false; - - return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; -} -#endif // GTEST_HAS_SEH - -} // namespace internal - -// The c'tor sets this object as the test part result reporter used by -// Google Test. The 'result' parameter specifies where to report the -// results. Intercepts only failures from the current thread. -ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( - TestPartResultArray* result) - : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), - result_(result) { - Init(); -} - -// The c'tor sets this object as the test part result reporter used by -// Google Test. The 'result' parameter specifies where to report the -// results. -ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( - InterceptMode intercept_mode, TestPartResultArray* result) - : intercept_mode_(intercept_mode), - result_(result) { - Init(); -} - -void ScopedFakeTestPartResultReporter::Init() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - if (intercept_mode_ == INTERCEPT_ALL_THREADS) { - old_reporter_ = impl->GetGlobalTestPartResultReporter(); - impl->SetGlobalTestPartResultReporter(this); - } else { - old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); - impl->SetTestPartResultReporterForCurrentThread(this); - } -} - -// The d'tor restores the test part result reporter used by Google Test -// before. -ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - if (intercept_mode_ == INTERCEPT_ALL_THREADS) { - impl->SetGlobalTestPartResultReporter(old_reporter_); - } else { - impl->SetTestPartResultReporterForCurrentThread(old_reporter_); - } -} - -// Increments the test part result count and remembers the result. -// This method is from the TestPartResultReporterInterface interface. -void ScopedFakeTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - result_->Append(result); -} - -namespace internal { - -// Returns the type ID of ::testing::Test. We should always call this -// instead of GetTypeId< ::testing::Test>() to get the type ID of -// testing::Test. This is to work around a suspected linker bug when -// using Google Test as a framework on Mac OS X. The bug causes -// GetTypeId< ::testing::Test>() to return different values depending -// on whether the call is from the Google Test framework itself or -// from user test code. GetTestTypeId() is guaranteed to always -// return the same value, as it always calls GetTypeId<>() from the -// gtest.cc, which is within the Google Test framework. -TypeId GetTestTypeId() { - return GetTypeId(); -} - -// The value of GetTestTypeId() as seen from within the Google Test -// library. This is solely for testing GetTestTypeId(). -const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); - -// This predicate-formatter checks that 'results' contains a test part -// failure of the given type and that the failure message contains the -// given substring. -AssertionResult HasOneFailure(const char* /* results_expr */, - const char* /* type_expr */, - const char* /* substr_expr */, - const TestPartResultArray& results, - TestPartResult::Type type, - const string& substr) { - const String expected(type == TestPartResult::kFatalFailure ? - "1 fatal failure" : - "1 non-fatal failure"); - Message msg; - if (results.size() != 1) { - msg << "Expected: " << expected << "\n" - << " Actual: " << results.size() << " failures"; - for (int i = 0; i < results.size(); i++) { - msg << "\n" << results.GetTestPartResult(i); - } - return AssertionFailure() << msg; - } - - const TestPartResult& r = results.GetTestPartResult(0); - if (r.type() != type) { - return AssertionFailure() << "Expected: " << expected << "\n" - << " Actual:\n" - << r; - } - - if (strstr(r.message(), substr.c_str()) == NULL) { - return AssertionFailure() << "Expected: " << expected << " containing \"" - << substr << "\"\n" - << " Actual:\n" - << r; - } - - return AssertionSuccess(); -} - -// The constructor of SingleFailureChecker remembers where to look up -// test part results, what type of failure we expect, and what -// substring the failure message should contain. -SingleFailureChecker:: SingleFailureChecker( - const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr) - : results_(results), - type_(type), - substr_(substr) {} - -// The destructor of SingleFailureChecker verifies that the given -// TestPartResultArray contains exactly one failure that has the given -// type and contains the given substring. If that's not the case, a -// non-fatal failure will be generated. -SingleFailureChecker::~SingleFailureChecker() { - EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); -} - -DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( - UnitTestImpl* unit_test) : unit_test_(unit_test) {} - -void DefaultGlobalTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - unit_test_->current_test_result()->AddTestPartResult(result); - unit_test_->listeners()->repeater()->OnTestPartResult(result); -} - -DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( - UnitTestImpl* unit_test) : unit_test_(unit_test) {} - -void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); -} - -// Returns the global test part result reporter. -TestPartResultReporterInterface* -UnitTestImpl::GetGlobalTestPartResultReporter() { - internal::MutexLock lock(&global_test_part_result_reporter_mutex_); - return global_test_part_result_repoter_; -} - -// Sets the global test part result reporter. -void UnitTestImpl::SetGlobalTestPartResultReporter( - TestPartResultReporterInterface* reporter) { - internal::MutexLock lock(&global_test_part_result_reporter_mutex_); - global_test_part_result_repoter_ = reporter; -} - -// Returns the test part result reporter for the current thread. -TestPartResultReporterInterface* -UnitTestImpl::GetTestPartResultReporterForCurrentThread() { - return per_thread_test_part_result_reporter_.get(); -} - -// Sets the test part result reporter for the current thread. -void UnitTestImpl::SetTestPartResultReporterForCurrentThread( - TestPartResultReporterInterface* reporter) { - per_thread_test_part_result_reporter_.set(reporter); -} - -// Gets the number of successful test cases. -int UnitTestImpl::successful_test_case_count() const { - return CountIf(test_cases_, TestCasePassed); -} - -// Gets the number of failed test cases. -int UnitTestImpl::failed_test_case_count() const { - return CountIf(test_cases_, TestCaseFailed); -} - -// Gets the number of all test cases. -int UnitTestImpl::total_test_case_count() const { - return static_cast(test_cases_.size()); -} - -// Gets the number of all test cases that contain at least one test -// that should run. -int UnitTestImpl::test_case_to_run_count() const { - return CountIf(test_cases_, ShouldRunTestCase); -} - -// Gets the number of successful tests. -int UnitTestImpl::successful_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); -} - -// Gets the number of failed tests. -int UnitTestImpl::failed_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); -} - -// Gets the number of disabled tests. -int UnitTestImpl::disabled_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); -} - -// Gets the number of all tests. -int UnitTestImpl::total_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); -} - -// Gets the number of tests that should run. -int UnitTestImpl::test_to_run_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); -} - -// Returns the current OS stack trace as a String. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// CurrentOsStackTraceExceptTop(1), Foo() will be included in the -// trace but Bar() and CurrentOsStackTraceExceptTop() won't. -String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { - (void)skip_count; - return String(""); -} - -// Returns the current time in milliseconds. -TimeInMillis GetTimeInMillis() { -#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) - // Difference between 1970-01-01 and 1601-01-01 in milliseconds. - // http://analogous.blogspot.com/2005/04/epoch.html - const TimeInMillis kJavaEpochToWinFileTimeDelta = - static_cast(116444736UL) * 100000UL; - const DWORD kTenthMicrosInMilliSecond = 10000; - - SYSTEMTIME now_systime; - FILETIME now_filetime; - ULARGE_INTEGER now_int64; - // TODO(kenton@google.com): Shouldn't this just use - // GetSystemTimeAsFileTime()? - GetSystemTime(&now_systime); - if (SystemTimeToFileTime(&now_systime, &now_filetime)) { - now_int64.LowPart = now_filetime.dwLowDateTime; - now_int64.HighPart = now_filetime.dwHighDateTime; - now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - - kJavaEpochToWinFileTimeDelta; - return now_int64.QuadPart; - } - return 0; -#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ - __timeb64 now; - -# ifdef _MSC_VER - - // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 - // (deprecated function) there. - // TODO(kenton@google.com): Use GetTickCount()? Or use - // SystemTimeToFileTime() -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996. - _ftime64(&now); -# pragma warning(pop) // Restores the warning state. -# else - - _ftime64(&now); - -# endif // _MSC_VER - - return static_cast(now.time) * 1000 + now.millitm; -#elif GTEST_HAS_GETTIMEOFDAY_ - struct timeval now; - gettimeofday(&now, NULL); - return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; -#else -# error "Don't know how to get the current time on your system." -#endif -} - -// Utilities - -// class String - -// Returns the input enclosed in double quotes if it's not NULL; -// otherwise returns "(null)". For example, "\"Hello\"" is returned -// for input "Hello". -// -// This is useful for printing a C string in the syntax of a literal. -// -// Known issue: escape sequences are not handled yet. -String String::ShowCStringQuoted(const char* c_str) { - return c_str ? String::Format("\"%s\"", c_str) : String("(null)"); -} - -// Copies at most length characters from str into a newly-allocated -// piece of memory of size length+1. The memory is allocated with new[]. -// A terminating null byte is written to the memory, and a pointer to it -// is returned. If str is NULL, NULL is returned. -static char* CloneString(const char* str, size_t length) { - if (str == NULL) { - return NULL; - } else { - char* const clone = new char[length + 1]; - posix::StrNCpy(clone, str, length); - clone[length] = '\0'; - return clone; - } -} - -// Clones a 0-terminated C string, allocating memory using new. The -// caller is responsible for deleting[] the return value. Returns the -// cloned string, or NULL if the input is NULL. -const char * String::CloneCString(const char* c_str) { - return (c_str == NULL) ? - NULL : CloneString(c_str, strlen(c_str)); -} - -#if GTEST_OS_WINDOWS_MOBILE -// Creates a UTF-16 wide string from the given ANSI string, allocating -// memory using new. The caller is responsible for deleting the return -// value using delete[]. Returns the wide string, or NULL if the -// input is NULL. -LPCWSTR String::AnsiToUtf16(const char* ansi) { - if (!ansi) return NULL; - const int length = strlen(ansi); - const int unicode_length = - MultiByteToWideChar(CP_ACP, 0, ansi, length, - NULL, 0); - WCHAR* unicode = new WCHAR[unicode_length + 1]; - MultiByteToWideChar(CP_ACP, 0, ansi, length, - unicode, unicode_length); - unicode[unicode_length] = 0; - return unicode; -} - -// Creates an ANSI string from the given wide string, allocating -// memory using new. The caller is responsible for deleting the return -// value using delete[]. Returns the ANSI string, or NULL if the -// input is NULL. -const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { - if (!utf16_str) return NULL; - const int ansi_length = - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - NULL, 0, NULL, NULL); - char* ansi = new char[ansi_length + 1]; - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - ansi, ansi_length, NULL, NULL); - ansi[ansi_length] = 0; - return ansi; -} - -#endif // GTEST_OS_WINDOWS_MOBILE - -// Compares two C strings. Returns true iff they have the same content. -// -// Unlike strcmp(), this function can handle NULL argument(s). A NULL -// C string is considered different to any non-NULL C string, -// including the empty string. -bool String::CStringEquals(const char * lhs, const char * rhs) { - if ( lhs == NULL ) return rhs == NULL; - - if ( rhs == NULL ) return false; - - return strcmp(lhs, rhs) == 0; -} - -#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING - -// Converts an array of wide chars to a narrow string using the UTF-8 -// encoding, and streams the result to the given Message object. -static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, - Message* msg) { - // TODO(wan): consider allowing a testing::String object to - // contain '\0'. This will make it behave more like std::string, - // and will allow ToUtf8String() to return the correct encoding - // for '\0' s.t. we can get rid of the conditional here (and in - // several other places). - for (size_t i = 0; i != length; ) { // NOLINT - if (wstr[i] != L'\0') { - *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); - while (i != length && wstr[i] != L'\0') - i++; - } else { - *msg << '\0'; - i++; - } - } -} - -#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING - -} // namespace internal - -#if GTEST_HAS_STD_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::std::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_STD_WSTRING - -#if GTEST_HAS_GLOBAL_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -// AssertionResult constructors. -// Used in EXPECT_TRUE/FALSE(assertion_result). -AssertionResult::AssertionResult(const AssertionResult& other) - : success_(other.success_), - message_(other.message_.get() != NULL ? - new ::std::string(*other.message_) : - static_cast< ::std::string*>(NULL)) { -} - -// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. -AssertionResult AssertionResult::operator!() const { - AssertionResult negation(!success_); - if (message_.get() != NULL) - negation << *message_; - return negation; -} - -// Makes a successful assertion result. -AssertionResult AssertionSuccess() { - return AssertionResult(true); -} - -// Makes a failed assertion result. -AssertionResult AssertionFailure() { - return AssertionResult(false); -} - -// Makes a failed assertion result with the given failure message. -// Deprecated; use AssertionFailure() << message. -AssertionResult AssertionFailure(const Message& message) { - return AssertionFailure() << message; -} - -namespace internal { - -// Constructs and returns the message for an equality assertion -// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. -// -// The first four parameters are the expressions used in the assertion -// and their values, as strings. For example, for ASSERT_EQ(foo, bar) -// where foo is 5 and bar is 6, we have: -// -// expected_expression: "foo" -// actual_expression: "bar" -// expected_value: "5" -// actual_value: "6" -// -// The ignoring_case parameter is true iff the assertion is a -// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will -// be inserted into the message. -AssertionResult EqFailure(const char* expected_expression, - const char* actual_expression, - const String& expected_value, - const String& actual_value, - bool ignoring_case) { - Message msg; - msg << "Value of: " << actual_expression; - if (actual_value != actual_expression) { - msg << "\n Actual: " << actual_value; - } - - msg << "\nExpected: " << expected_expression; - if (ignoring_case) { - msg << " (ignoring case)"; - } - if (expected_value != expected_expression) { - msg << "\nWhich is: " << expected_value; - } - - return AssertionFailure() << msg; -} - -// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. -String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, - const char* expression_text, - const char* actual_predicate_value, - const char* expected_predicate_value) { - const char* actual_message = assertion_result.message(); - Message msg; - msg << "Value of: " << expression_text - << "\n Actual: " << actual_predicate_value; - if (actual_message[0] != '\0') - msg << " (" << actual_message << ")"; - msg << "\nExpected: " << expected_predicate_value; - return msg.GetString(); -} - -// Helper function for implementing ASSERT_NEAR. -AssertionResult DoubleNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - double val1, - double val2, - double abs_error) { - const double diff = fabs(val1 - val2); - if (diff <= abs_error) return AssertionSuccess(); - - // TODO(wan): do not print the value of an expression if it's - // already a literal. - return AssertionFailure() - << "The difference between " << expr1 << " and " << expr2 - << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" - << expr1 << " evaluates to " << val1 << ",\n" - << expr2 << " evaluates to " << val2 << ", and\n" - << abs_error_expr << " evaluates to " << abs_error << "."; -} - - -// Helper template for implementing FloatLE() and DoubleLE(). -template -AssertionResult FloatingPointLE(const char* expr1, - const char* expr2, - RawType val1, - RawType val2) { - // Returns success if val1 is less than val2, - if (val1 < val2) { - return AssertionSuccess(); - } - - // or if val1 is almost equal to val2. - const FloatingPoint lhs(val1), rhs(val2); - if (lhs.AlmostEquals(rhs)) { - return AssertionSuccess(); - } - - // Note that the above two checks will both fail if either val1 or - // val2 is NaN, as the IEEE floating-point standard requires that - // any predicate involving a NaN must return false. - - ::std::stringstream val1_ss; - val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << val1; - - ::std::stringstream val2_ss; - val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << val2; - - return AssertionFailure() - << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" - << " Actual: " << StringStreamToString(&val1_ss) << " vs " - << StringStreamToString(&val2_ss); -} - -} // namespace internal - -// Asserts that val1 is less than, or almost equal to, val2. Fails -// otherwise. In particular, it fails if either val1 or val2 is NaN. -AssertionResult FloatLE(const char* expr1, const char* expr2, - float val1, float val2) { - return internal::FloatingPointLE(expr1, expr2, val1, val2); -} - -// Asserts that val1 is less than, or almost equal to, val2. Fails -// otherwise. In particular, it fails if either val1 or val2 is NaN. -AssertionResult DoubleLE(const char* expr1, const char* expr2, - double val1, double val2) { - return internal::FloatingPointLE(expr1, expr2, val1, val2); -} - -namespace internal { - -// The helper function for {ASSERT|EXPECT}_EQ with int or enum -// arguments. -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - if (expected == actual) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), - false); -} - -// A macro for implementing the helper functions needed to implement -// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here -// just to avoid copy-and-paste of similar code. -#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ -AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ - BiggestInt val1, BiggestInt val2) {\ - if (val1 op val2) {\ - return AssertionSuccess();\ - } else {\ - return AssertionFailure() \ - << "Expected: (" << expr1 << ") " #op " (" << expr2\ - << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ - << " vs " << FormatForComparisonFailureMessage(val2, val1);\ - }\ -} - -// Implements the helper function for {ASSERT|EXPECT}_NE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(NE, !=) -// Implements the helper function for {ASSERT|EXPECT}_LE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(LE, <=) -// Implements the helper function for {ASSERT|EXPECT}_LT with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(LT, < ) -// Implements the helper function for {ASSERT|EXPECT}_GE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(GE, >=) -// Implements the helper function for {ASSERT|EXPECT}_GT with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(GT, > ) - -#undef GTEST_IMPL_CMP_HELPER_ - -// The helper function for {ASSERT|EXPECT}_STREQ. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - String::ShowCStringQuoted(expected), - String::ShowCStringQuoted(actual), - false); -} - -// The helper function for {ASSERT|EXPECT}_STRCASEEQ. -AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CaseInsensitiveCStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - String::ShowCStringQuoted(expected), - String::ShowCStringQuoted(actual), - true); -} - -// The helper function for {ASSERT|EXPECT}_STRNE. -AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2) { - if (!String::CStringEquals(s1, s2)) { - return AssertionSuccess(); - } else { - return AssertionFailure() << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; - } -} - -// The helper function for {ASSERT|EXPECT}_STRCASENE. -AssertionResult CmpHelperSTRCASENE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2) { - if (!String::CaseInsensitiveCStringEquals(s1, s2)) { - return AssertionSuccess(); - } else { - return AssertionFailure() - << "Expected: (" << s1_expression << ") != (" - << s2_expression << ") (ignoring case), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; - } -} - -} // namespace internal - -namespace { - -// Helper functions for implementing IsSubString() and IsNotSubstring(). - -// This group of overloaded functions return true iff needle is a -// substring of haystack. NULL is considered a substring of itself -// only. - -bool IsSubstringPred(const char* needle, const char* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; - - return strstr(haystack, needle) != NULL; -} - -bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; - - return wcsstr(haystack, needle) != NULL; -} - -// StringType here can be either ::std::string or ::std::wstring. -template -bool IsSubstringPred(const StringType& needle, - const StringType& haystack) { - return haystack.find(needle) != StringType::npos; -} - -// This function implements either IsSubstring() or IsNotSubstring(), -// depending on the value of the expected_to_be_substring parameter. -// StringType here can be const char*, const wchar_t*, ::std::string, -// or ::std::wstring. -template -AssertionResult IsSubstringImpl( - bool expected_to_be_substring, - const char* needle_expr, const char* haystack_expr, - const StringType& needle, const StringType& haystack) { - if (IsSubstringPred(needle, haystack) == expected_to_be_substring) - return AssertionSuccess(); - - const bool is_wide_string = sizeof(needle[0]) > 1; - const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; - return AssertionFailure() - << "Value of: " << needle_expr << "\n" - << " Actual: " << begin_string_quote << needle << "\"\n" - << "Expected: " << (expected_to_be_substring ? "" : "not ") - << "a substring of " << haystack_expr << "\n" - << "Which is: " << begin_string_quote << haystack << "\""; -} - -} // namespace - -// IsSubstring() and IsNotSubstring() check whether needle is a -// substring of haystack (NULL is considered a substring of itself -// only), and return an appropriate error message when they fail. - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -#if GTEST_HAS_STD_WSTRING -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} -#endif // GTEST_HAS_STD_WSTRING - -namespace internal { - -#if GTEST_OS_WINDOWS - -namespace { - -// Helper function for IsHRESULT{SuccessFailure} predicates -AssertionResult HRESULTFailureHelper(const char* expr, - const char* expected, - long hr) { // NOLINT -# if GTEST_OS_WINDOWS_MOBILE - - // Windows CE doesn't support FormatMessage. - const char error_text[] = ""; - -# else - - // Looks up the human-readable system message for the HRESULT code - // and since we're not passing any params to FormatMessage, we don't - // want inserts expanded. - const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS; - const DWORD kBufSize = 4096; // String::Format can't exceed this length. - // Gets the system's human readable message string for this HRESULT. - char error_text[kBufSize] = { '\0' }; - DWORD message_length = ::FormatMessageA(kFlags, - 0, // no source, we're asking system - hr, // the error - 0, // no line width restrictions - error_text, // output buffer - kBufSize, // buf size - NULL); // no arguments for inserts - // Trims tailing white space (FormatMessage leaves a trailing cr-lf) - for (; message_length && IsSpace(error_text[message_length - 1]); - --message_length) { - error_text[message_length - 1] = '\0'; - } - -# endif // GTEST_OS_WINDOWS_MOBILE - - const String error_hex(String::Format("0x%08X ", hr)); - return ::testing::AssertionFailure() - << "Expected: " << expr << " " << expected << ".\n" - << " Actual: " << error_hex << error_text << "\n"; -} - -} // namespace - -AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT - if (SUCCEEDED(hr)) { - return AssertionSuccess(); - } - return HRESULTFailureHelper(expr, "succeeds", hr); -} - -AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT - if (FAILED(hr)) { - return AssertionSuccess(); - } - return HRESULTFailureHelper(expr, "fails", hr); -} - -#endif // GTEST_OS_WINDOWS - -// Utility functions for encoding Unicode text (wide strings) in -// UTF-8. - -// A Unicode code-point can have up to 21 bits, and is encoded in UTF-8 -// like this: -// -// Code-point length Encoding -// 0 - 7 bits 0xxxxxxx -// 8 - 11 bits 110xxxxx 10xxxxxx -// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx -// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - -// The maximum code-point a one-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; - -// The maximum code-point a two-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; - -// The maximum code-point a three-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; - -// The maximum code-point a four-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; - -// Chops off the n lowest bits from a bit pattern. Returns the n -// lowest bits. As a side effect, the original bit pattern will be -// shifted to the right by n bits. -inline UInt32 ChopLowBits(UInt32* bits, int n) { - const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); - *bits >>= n; - return low_bits; -} - -// Converts a Unicode code point to a narrow string in UTF-8 encoding. -// code_point parameter is of type UInt32 because wchar_t may not be -// wide enough to contain a code point. -// The output buffer str must containt at least 32 characters. -// The function returns the address of the output buffer. -// If the code_point is not a valid Unicode code point -// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. -char* CodePointToUtf8(UInt32 code_point, char* str) { - if (code_point <= kMaxCodePoint1) { - str[1] = '\0'; - str[0] = static_cast(code_point); // 0xxxxxxx - } else if (code_point <= kMaxCodePoint2) { - str[2] = '\0'; - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xC0 | code_point); // 110xxxxx - } else if (code_point <= kMaxCodePoint3) { - str[3] = '\0'; - str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xE0 | code_point); // 1110xxxx - } else if (code_point <= kMaxCodePoint4) { - str[4] = '\0'; - str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xF0 | code_point); // 11110xxx - } else { - // The longest string String::Format can produce when invoked - // with these parameters is 28 character long (not including - // the terminating nul character). We are asking for 32 character - // buffer just in case. This is also enough for strncpy to - // null-terminate the destination string. - posix::StrNCpy( - str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); - str[31] = '\0'; // Makes sure no change in the format to strncpy leaves - // the result unterminated. - } - return str; -} - -// The following two functions only make sense if the system -// uses UTF-16 for wide string encoding. All supported systems -// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. - -// Determines if the arguments constitute UTF-16 surrogate pair -// and thus should be combined into a single Unicode code point -// using CreateCodePointFromUtf16SurrogatePair. -inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { - return sizeof(wchar_t) == 2 && - (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; -} - -// Creates a Unicode code point from UTF16 surrogate pair. -inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, - wchar_t second) { - const UInt32 mask = (1 << 10) - 1; - return (sizeof(wchar_t) == 2) ? - (((first & mask) << 10) | (second & mask)) + 0x10000 : - // This function should not be called when the condition is - // false, but we provide a sensible default in case it is. - static_cast(first); -} - -// Converts a wide string to a narrow string in UTF-8 encoding. -// The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) -// UTF-32 if sizeof(wchar_t) == 4 (on Linux) -// Parameter str points to a null-terminated wide string. -// Parameter num_chars may additionally limit the number -// of wchar_t characters processed. -1 is used when the entire string -// should be processed. -// If the string contains code points that are not valid Unicode code points -// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding -// and contains invalid UTF-16 surrogate pairs, values in those pairs -// will be encoded as individual Unicode characters from Basic Normal Plane. -String WideStringToUtf8(const wchar_t* str, int num_chars) { - if (num_chars == -1) - num_chars = static_cast(wcslen(str)); - - ::std::stringstream stream; - for (int i = 0; i < num_chars; ++i) { - UInt32 unicode_code_point; - - if (str[i] == L'\0') { - break; - } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { - unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], - str[i + 1]); - i++; - } else { - unicode_code_point = static_cast(str[i]); - } - - char buffer[32]; // CodePointToUtf8 requires a buffer this big. - stream << CodePointToUtf8(unicode_code_point, buffer); - } - return StringStreamToString(&stream); -} - -// Converts a wide C string to a String using the UTF-8 encoding. -// NULL will be converted to "(null)". -String String::ShowWideCString(const wchar_t * wide_c_str) { - if (wide_c_str == NULL) return String("(null)"); - - return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); -} - -// Similar to ShowWideCString(), except that this function encloses -// the converted string in double quotes. -String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) { - if (wide_c_str == NULL) return String("(null)"); - - return String::Format("L\"%s\"", - String::ShowWideCString(wide_c_str).c_str()); -} - -// Compares two wide C strings. Returns true iff they have the same -// content. -// -// Unlike wcscmp(), this function can handle NULL argument(s). A NULL -// C string is considered different to any non-NULL C string, -// including the empty string. -bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { - if (lhs == NULL) return rhs == NULL; - - if (rhs == NULL) return false; - - return wcscmp(lhs, rhs) == 0; -} - -// Helper function for *_STREQ on wide strings. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual) { - if (String::WideCStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - String::ShowWideCStringQuoted(expected), - String::ShowWideCStringQuoted(actual), - false); -} - -// Helper function for *_STRNE on wide strings. -AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const wchar_t* s1, - const wchar_t* s2) { - if (!String::WideCStringEquals(s1, s2)) { - return AssertionSuccess(); - } - - return AssertionFailure() << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: " - << String::ShowWideCStringQuoted(s1) - << " vs " << String::ShowWideCStringQuoted(s2); -} - -// Compares two C strings, ignoring case. Returns true iff they have -// the same content. -// -// Unlike strcasecmp(), this function can handle NULL argument(s). A -// NULL C string is considered different to any non-NULL C string, -// including the empty string. -bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { - if (lhs == NULL) - return rhs == NULL; - if (rhs == NULL) - return false; - return posix::StrCaseCmp(lhs, rhs) == 0; -} - - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike wcscasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL wide C string, - // including the empty string. - // NB: The implementations on different platforms slightly differ. - // On windows, this method uses _wcsicmp which compares according to LC_CTYPE - // environment variable. On GNU platform this method uses wcscasecmp - // which compares according to LC_CTYPE category of the current locale. - // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the - // current locale. -bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, - const wchar_t* rhs) { - if (lhs == NULL) return rhs == NULL; - - if (rhs == NULL) return false; - -#if GTEST_OS_WINDOWS - return _wcsicmp(lhs, rhs) == 0; -#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID - return wcscasecmp(lhs, rhs) == 0; -#else - // Android, Mac OS X and Cygwin don't define wcscasecmp. - // Other unknown OSes may not define it either. - wint_t left, right; - do { - left = towlower(*lhs++); - right = towlower(*rhs++); - } while (left && left == right); - return left == right; -#endif // OS selector -} - -// Compares this with another String. -// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 -// if this is greater than rhs. -int String::Compare(const String & rhs) const { - const char* const lhs_c_str = c_str(); - const char* const rhs_c_str = rhs.c_str(); - - if (lhs_c_str == NULL) { - return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL - } else if (rhs_c_str == NULL) { - return 1; - } - - const size_t shorter_str_len = - length() <= rhs.length() ? length() : rhs.length(); - for (size_t i = 0; i != shorter_str_len; i++) { - if (lhs_c_str[i] < rhs_c_str[i]) { - return -1; - } else if (lhs_c_str[i] > rhs_c_str[i]) { - return 1; - } - } - return (length() < rhs.length()) ? -1 : - (length() > rhs.length()) ? 1 : 0; -} - -// Returns true iff this String ends with the given suffix. *Any* -// String is considered to end with a NULL or empty suffix. -bool String::EndsWith(const char* suffix) const { - if (suffix == NULL || CStringEquals(suffix, "")) return true; - - if (c_str() == NULL) return false; - - const size_t this_len = strlen(c_str()); - const size_t suffix_len = strlen(suffix); - return (this_len >= suffix_len) && - CStringEquals(c_str() + this_len - suffix_len, suffix); -} - -// Returns true iff this String ends with the given suffix, ignoring case. -// Any String is considered to end with a NULL or empty suffix. -bool String::EndsWithCaseInsensitive(const char* suffix) const { - if (suffix == NULL || CStringEquals(suffix, "")) return true; - - if (c_str() == NULL) return false; - - const size_t this_len = strlen(c_str()); - const size_t suffix_len = strlen(suffix); - return (this_len >= suffix_len) && - CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); -} - -// Formats a list of arguments to a String, using the same format -// spec string as for printf. -// -// We do not use the StringPrintf class as it is not universally -// available. -// -// The result is limited to 4096 characters (including the tailing 0). -// If 4096 characters are not enough to format the input, or if -// there's an error, "" is -// returned. -String String::Format(const char * format, ...) { - va_list args; - va_start(args, format); - - char buffer[4096]; - const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); - - // MSVC 8 deprecates vsnprintf(), so we want to suppress warning - // 4996 (deprecated function) there. -#ifdef _MSC_VER // We are using MSVC. -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996. - - const int size = vsnprintf(buffer, kBufferSize, format, args); - -# pragma warning(pop) // Restores the warning state. -#else // We are not using MSVC. - const int size = vsnprintf(buffer, kBufferSize, format, args); -#endif // _MSC_VER - va_end(args); - - // vsnprintf()'s behavior is not portable. When the buffer is not - // big enough, it returns a negative value in MSVC, and returns the - // needed buffer size on Linux. When there is an output error, it - // always returns a negative value. For simplicity, we lump the two - // error cases together. - if (size < 0 || size >= kBufferSize) { - return String(""); - } else { - return String(buffer, size); - } -} - -// Converts the buffer in a stringstream to a String, converting NUL -// bytes to "\\0" along the way. -String StringStreamToString(::std::stringstream* ss) { - const ::std::string& str = ss->str(); - const char* const start = str.c_str(); - const char* const end = start + str.length(); - - // We need to use a helper stringstream to do this transformation - // because String doesn't support push_back(). - ::std::stringstream helper; - for (const char* ch = start; ch != end; ++ch) { - if (*ch == '\0') { - helper << "\\0"; // Replaces NUL with "\\0"; - } else { - helper.put(*ch); - } - } - - return String(helper.str().c_str()); -} - -// Appends the user-supplied message to the Google-Test-generated message. -String AppendUserMessage(const String& gtest_msg, - const Message& user_msg) { - // Appends the user message if it's non-empty. - const String user_msg_string = user_msg.GetString(); - if (user_msg_string.empty()) { - return gtest_msg; - } - - Message msg; - msg << gtest_msg << "\n" << user_msg_string; - - return msg.GetString(); -} - -} // namespace internal - -// class TestResult - -// Creates an empty TestResult. -TestResult::TestResult() - : death_test_count_(0), - elapsed_time_(0) { -} - -// D'tor. -TestResult::~TestResult() { -} - -// Returns the i-th test part result among all the results. i can -// range from 0 to total_part_count() - 1. If i is not in that range, -// aborts the program. -const TestPartResult& TestResult::GetTestPartResult(int i) const { - if (i < 0 || i >= total_part_count()) - internal::posix::Abort(); - return test_part_results_.at(i); -} - -// Returns the i-th test property. i can range from 0 to -// test_property_count() - 1. If i is not in that range, aborts the -// program. -const TestProperty& TestResult::GetTestProperty(int i) const { - if (i < 0 || i >= test_property_count()) - internal::posix::Abort(); - return test_properties_.at(i); -} - -// Clears the test part results. -void TestResult::ClearTestPartResults() { - test_part_results_.clear(); -} - -// Adds a test part result to the list. -void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { - test_part_results_.push_back(test_part_result); -} - -// Adds a test property to the list. If a property with the same key as the -// supplied property is already represented, the value of this test_property -// replaces the old value for that key. -void TestResult::RecordProperty(const TestProperty& test_property) { - if (!ValidateTestProperty(test_property)) { - return; - } - internal::MutexLock lock(&test_properites_mutex_); - const std::vector::iterator property_with_matching_key = - std::find_if(test_properties_.begin(), test_properties_.end(), - internal::TestPropertyKeyIs(test_property.key())); - if (property_with_matching_key == test_properties_.end()) { - test_properties_.push_back(test_property); - return; - } - property_with_matching_key->SetValue(test_property.value()); -} - -// Adds a failure if the key is a reserved attribute of Google Test -// testcase tags. Returns true if the property is valid. -bool TestResult::ValidateTestProperty(const TestProperty& test_property) { - internal::String key(test_property.key()); - if (key == "name" || key == "status" || key == "time" || key == "classname") { - ADD_FAILURE() - << "Reserved key used in RecordProperty(): " - << key - << " ('name', 'status', 'time', and 'classname' are reserved by " - << GTEST_NAME_ << ")"; - return false; - } - return true; -} - -// Clears the object. -void TestResult::Clear() { - test_part_results_.clear(); - test_properties_.clear(); - death_test_count_ = 0; - elapsed_time_ = 0; -} - -// Returns true iff the test failed. -bool TestResult::Failed() const { - for (int i = 0; i < total_part_count(); ++i) { - if (GetTestPartResult(i).failed()) - return true; - } - return false; -} - -// Returns true iff the test part fatally failed. -static bool TestPartFatallyFailed(const TestPartResult& result) { - return result.fatally_failed(); -} - -// Returns true iff the test fatally failed. -bool TestResult::HasFatalFailure() const { - return CountIf(test_part_results_, TestPartFatallyFailed) > 0; -} - -// Returns true iff the test part non-fatally failed. -static bool TestPartNonfatallyFailed(const TestPartResult& result) { - return result.nonfatally_failed(); -} - -// Returns true iff the test has a non-fatal failure. -bool TestResult::HasNonfatalFailure() const { - return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; -} - -// Gets the number of all test parts. This is the sum of the number -// of successful test parts and the number of failed test parts. -int TestResult::total_part_count() const { - return static_cast(test_part_results_.size()); -} - -// Returns the number of the test properties. -int TestResult::test_property_count() const { - return static_cast(test_properties_.size()); -} - -// class Test - -// Creates a Test object. - -// The c'tor saves the values of all Google Test flags. -Test::Test() - : gtest_flag_saver_(new internal::GTestFlagSaver) { -} - -// The d'tor restores the values of all Google Test flags. -Test::~Test() { - delete gtest_flag_saver_; -} - -// Sets up the test fixture. -// -// A sub-class may override this. -void Test::SetUp() { -} - -// Tears down the test fixture. -// -// A sub-class may override this. -void Test::TearDown() { -} - -// Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const char* key, const char* value) { - UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); -} - -// Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const char* key, int value) { - Message value_message; - value_message << value; - RecordProperty(key, value_message.GetString().c_str()); -} - -namespace internal { - -void ReportFailureInUnknownLocation(TestPartResult::Type result_type, - const String& message) { - // This function is a friend of UnitTest and as such has access to - // AddTestPartResult. - UnitTest::GetInstance()->AddTestPartResult( - result_type, - NULL, // No info about the source file where the exception occurred. - -1, // We have no info on which line caused the exception. - message, - String()); // No stack trace, either. -} - -} // namespace internal - -// Google Test requires all tests in the same test case to use the same test -// fixture class. This function checks if the current test has the -// same fixture class as the first test in the current test case. If -// yes, it returns true; otherwise it generates a Google Test failure and -// returns false. -bool Test::HasSameFixtureClass() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - const TestCase* const test_case = impl->current_test_case(); - - // Info about the first test in the current test case. - const TestInfo* const first_test_info = test_case->test_info_list()[0]; - const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; - const char* const first_test_name = first_test_info->name(); - - // Info about the current test. - const TestInfo* const this_test_info = impl->current_test_info(); - const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; - const char* const this_test_name = this_test_info->name(); - - if (this_fixture_id != first_fixture_id) { - // Is the first test defined using TEST? - const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); - // Is this test defined using TEST? - const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); - - if (first_is_TEST || this_is_TEST) { - // The user mixed TEST and TEST_F in this test case - we'll tell - // him/her how to fix it. - - // Gets the name of the TEST and the name of the TEST_F. Note - // that first_is_TEST and this_is_TEST cannot both be true, as - // the fixture IDs are different for the two tests. - const char* const TEST_name = - first_is_TEST ? first_test_name : this_test_name; - const char* const TEST_F_name = - first_is_TEST ? this_test_name : first_test_name; - - ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class, so mixing TEST_F and TEST in the same test case is\n" - << "illegal. In test case " << this_test_info->test_case_name() - << ",\n" - << "test " << TEST_F_name << " is defined using TEST_F but\n" - << "test " << TEST_name << " is defined using TEST. You probably\n" - << "want to change the TEST to TEST_F or move it to another test\n" - << "case."; - } else { - // The user defined two fixture classes with the same name in - // two namespaces - we'll tell him/her how to fix it. - ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " - << this_test_info->test_case_name() << ",\n" - << "you defined test " << first_test_name - << " and test " << this_test_name << "\n" - << "using two different test fixture classes. This can happen if\n" - << "the two classes are from different namespaces or translation\n" - << "units and have the same name. You should probably rename one\n" - << "of the classes to put the tests into different test cases."; - } - return false; - } - - return true; -} - -#if GTEST_HAS_SEH - -// Adds an "exception thrown" fatal failure to the current test. This -// function returns its result via an output parameter pointer because VC++ -// prohibits creation of objects with destructors on stack in functions -// using __try (see error C2712). -static internal::String* FormatSehExceptionMessage(DWORD exception_code, - const char* location) { - Message message; - message << "SEH exception with code 0x" << std::setbase(16) << - exception_code << std::setbase(10) << " thrown in " << location << "."; - - return new internal::String(message.GetString()); -} - -#endif // GTEST_HAS_SEH - -#if GTEST_HAS_EXCEPTIONS - -// Adds an "exception thrown" fatal failure to the current test. -static internal::String FormatCxxExceptionMessage(const char* description, - const char* location) { - Message message; - if (description != NULL) { - message << "C++ exception with description \"" << description << "\""; - } else { - message << "Unknown C++ exception"; - } - message << " thrown in " << location << "."; - - return message.GetString(); -} - -static internal::String PrintTestPartResultToString( - const TestPartResult& test_part_result); - -// A failed Google Test assertion will throw an exception of this type when -// GTEST_FLAG(throw_on_failure) is true (if exceptions are enabled). We -// derive it from std::runtime_error, which is for errors presumably -// detectable only at run time. Since std::runtime_error inherits from -// std::exception, many testing frameworks know how to extract and print the -// message inside it. -class GoogleTestFailureException : public ::std::runtime_error { - public: - explicit GoogleTestFailureException(const TestPartResult& failure) - : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} -}; -#endif // GTEST_HAS_EXCEPTIONS - -namespace internal { -// We put these helper functions in the internal namespace as IBM's xlC -// compiler rejects the code if they were declared static. - -// Runs the given method and handles SEH exceptions it throws, when -// SEH is supported; returns the 0-value for type Result in case of an -// SEH exception. (Microsoft compilers cannot handle SEH and C++ -// exceptions in the same function. Therefore, we provide a separate -// wrapper function for handling SEH exceptions.) -template -Result HandleSehExceptionsInMethodIfSupported( - T* object, Result (T::*method)(), const char* location) { -#if GTEST_HAS_SEH - __try { - return (object->*method)(); - } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT - GetExceptionCode())) { - // We create the exception message on the heap because VC++ prohibits - // creation of objects with destructors on stack in functions using __try - // (see error C2712). - internal::String* exception_message = FormatSehExceptionMessage( - GetExceptionCode(), location); - internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, - *exception_message); - delete exception_message; - return static_cast(0); - } -#else - (void)location; - return (object->*method)(); -#endif // GTEST_HAS_SEH -} - -// Runs the given method and catches and reports C++ and/or SEH-style -// exceptions, if they are supported; returns the 0-value for type -// Result in case of an SEH exception. -template -Result HandleExceptionsInMethodIfSupported( - T* object, Result (T::*method)(), const char* location) { - // NOTE: The user code can affect the way in which Google Test handles - // exceptions by setting GTEST_FLAG(catch_exceptions), but only before - // RUN_ALL_TESTS() starts. It is technically possible to check the flag - // after the exception is caught and either report or re-throw the - // exception based on the flag's value: - // - // try { - // // Perform the test method. - // } catch (...) { - // if (GTEST_FLAG(catch_exceptions)) - // // Report the exception as failure. - // else - // throw; // Re-throws the original exception. - // } - // - // However, the purpose of this flag is to allow the program to drop into - // the debugger when the exception is thrown. On most platforms, once the - // control enters the catch block, the exception origin information is - // lost and the debugger will stop the program at the point of the - // re-throw in this function -- instead of at the point of the original - // throw statement in the code under test. For this reason, we perform - // the check early, sacrificing the ability to affect Google Test's - // exception handling in the method where the exception is thrown. - if (internal::GetUnitTestImpl()->catch_exceptions()) { -#if GTEST_HAS_EXCEPTIONS - try { - return HandleSehExceptionsInMethodIfSupported(object, method, location); - } catch (const GoogleTestFailureException&) { // NOLINT - // This exception doesn't originate in code under test. It makes no - // sense to report it as a test failure. - throw; - } catch (const std::exception& e) { // NOLINT - internal::ReportFailureInUnknownLocation( - TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(e.what(), location)); - } catch (...) { // NOLINT - internal::ReportFailureInUnknownLocation( - TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(NULL, location)); - } - return static_cast(0); -#else - return HandleSehExceptionsInMethodIfSupported(object, method, location); -#endif // GTEST_HAS_EXCEPTIONS - } else { - return (object->*method)(); - } -} - -} // namespace internal - -// Runs the test and updates the test result. -void Test::Run() { - if (!HasSameFixtureClass()) return; - - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); - // We will run the test only if SetUp() was successful. - if (!HasFatalFailure()) { - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &Test::TestBody, "the test body"); - } - - // However, we want to clean up as much as possible. Hence we will - // always call TearDown(), even if SetUp() or the test body has - // failed. - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &Test::TearDown, "TearDown()"); -} - -// Returns true iff the current test has a fatal failure. -bool Test::HasFatalFailure() { - return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); -} - -// Returns true iff the current test has a non-fatal failure. -bool Test::HasNonfatalFailure() { - return internal::GetUnitTestImpl()->current_test_result()-> - HasNonfatalFailure(); -} - -// class TestInfo - -// Constructs a TestInfo object. It assumes ownership of the test factory -// object. -// TODO(vladl@google.com): Make a_test_case_name and a_name const string&'s -// to signify they cannot be NULLs. -TestInfo::TestInfo(const char* a_test_case_name, - const char* a_name, - const char* a_type_param, - const char* a_value_param, - internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory) - : test_case_name_(a_test_case_name), - name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), - value_param_(a_value_param ? new std::string(a_value_param) : NULL), - fixture_class_id_(fixture_class_id), - should_run_(false), - is_disabled_(false), - matches_filter_(false), - factory_(factory), - result_() {} - -// Destructs a TestInfo object. -TestInfo::~TestInfo() { delete factory_; } - -namespace internal { - -// Creates a new TestInfo object and registers it with Google Test; -// returns the created object. -// -// Arguments: -// -// test_case_name: name of the test case -// name: name of the test -// type_param: the name of the test's type parameter, or NULL if -// this is not a typed or a type-parameterized test. -// value_param: text representation of the test's value parameter, -// or NULL if this is not a value-parameterized test. -// fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -// factory: pointer to the factory that creates a test object. -// The newly created TestInfo instance will assume -// ownership of the factory object. -TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, const char* name, - const char* type_param, - const char* value_param, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory) { - TestInfo* const test_info = - new TestInfo(test_case_name, name, type_param, value_param, - fixture_class_id, factory); - GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); - return test_info; -} - -#if GTEST_HAS_PARAM_TEST -void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line) { - Message errors; - errors - << "Attempted redefinition of test case " << test_case_name << ".\n" - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " << test_case_name << ", you tried\n" - << "to define a test using a fixture class different from the one\n" - << "used earlier. This can happen if the two fixture classes are\n" - << "from different namespaces and have the same name. You should\n" - << "probably rename one of the classes to put the tests into different\n" - << "test cases."; - - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), - errors.GetString().c_str()); -} -#endif // GTEST_HAS_PARAM_TEST - -} // namespace internal - -namespace internal { - -// This method expands all parameterized tests registered with macros TEST_P -// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. -// This will be done just once during the program runtime. -void UnitTestImpl::RegisterParameterizedTests() { -#if GTEST_HAS_PARAM_TEST - if (!parameterized_tests_registered_) { - parameterized_test_registry_.RegisterTests(); - parameterized_tests_registered_ = true; - } -#endif -} - -} // namespace internal - -// Creates the test object, runs it, records its result, and then -// deletes it. -void TestInfo::Run() { - if (!should_run_) return; - - // Tells UnitTest where to store test result. - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_info(this); - - TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); - - // Notifies the unit test event listeners that a test is about to start. - repeater->OnTestStart(*this); - - const TimeInMillis start = internal::GetTimeInMillis(); - - impl->os_stack_trace_getter()->UponLeavingGTest(); - - // Creates the test object. - Test* const test = internal::HandleExceptionsInMethodIfSupported( - factory_, &internal::TestFactoryBase::CreateTest, - "the test fixture's constructor"); - - // Runs the test only if the test object was created and its - // constructor didn't generate a fatal failure. - if ((test != NULL) && !Test::HasFatalFailure()) { - // This doesn't throw as all user code that can throw are wrapped into - // exception handling code. - test->Run(); - } - - // Deletes the test object. - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - test, &Test::DeleteSelf_, "the test fixture's destructor"); - - result_.set_elapsed_time(internal::GetTimeInMillis() - start); - - // Notifies the unit test event listener that a test has just finished. - repeater->OnTestEnd(*this); - - // Tells UnitTest to stop associating assertion results to this - // test. - impl->set_current_test_info(NULL); -} - -// class TestCase - -// Gets the number of successful tests in this test case. -int TestCase::successful_test_count() const { - return CountIf(test_info_list_, TestPassed); -} - -// Gets the number of failed tests in this test case. -int TestCase::failed_test_count() const { - return CountIf(test_info_list_, TestFailed); -} - -int TestCase::disabled_test_count() const { - return CountIf(test_info_list_, TestDisabled); -} - -// Get the number of tests in this test case that should run. -int TestCase::test_to_run_count() const { - return CountIf(test_info_list_, ShouldRunTest); -} - -// Gets the number of all tests. -int TestCase::total_test_count() const { - return static_cast(test_info_list_.size()); -} - -// Creates a TestCase with the given name. -// -// Arguments: -// -// name: name of the test case -// a_type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase::TestCase(const char* a_name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) - : name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), - set_up_tc_(set_up_tc), - tear_down_tc_(tear_down_tc), - should_run_(false), - elapsed_time_(0) { -} - -// Destructor of TestCase. -TestCase::~TestCase() { - // Deletes every Test in the collection. - ForEach(test_info_list_, internal::Delete); -} - -// Returns the i-th test among all the tests. i can range from 0 to -// total_test_count() - 1. If i is not in that range, returns NULL. -const TestInfo* TestCase::GetTestInfo(int i) const { - const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; -} - -// Returns the i-th test among all the tests. i can range from 0 to -// total_test_count() - 1. If i is not in that range, returns NULL. -TestInfo* TestCase::GetMutableTestInfo(int i) { - const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; -} - -// Adds a test to this test case. Will delete the test upon -// destruction of the TestCase object. -void TestCase::AddTestInfo(TestInfo * test_info) { - test_info_list_.push_back(test_info); - test_indices_.push_back(static_cast(test_indices_.size())); -} - -// Runs every test in this TestCase. -void TestCase::Run() { - if (!should_run_) return; - - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_case(this); - - TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); - - repeater->OnTestCaseStart(*this); - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); - - const internal::TimeInMillis start = internal::GetTimeInMillis(); - for (int i = 0; i < total_test_count(); i++) { - GetMutableTestInfo(i)->Run(); - } - elapsed_time_ = internal::GetTimeInMillis() - start; - - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); - - repeater->OnTestCaseEnd(*this); - impl->set_current_test_case(NULL); -} - -// Clears the results of all tests in this test case. -void TestCase::ClearResult() { - ForEach(test_info_list_, TestInfo::ClearTestResult); -} - -// Shuffles the tests in this test case. -void TestCase::ShuffleTests(internal::Random* random) { - Shuffle(random, &test_indices_); -} - -// Restores the test order to before the first shuffle. -void TestCase::UnshuffleTests() { - for (size_t i = 0; i < test_indices_.size(); i++) { - test_indices_[i] = static_cast(i); - } -} - -// Formats a countable noun. Depending on its quantity, either the -// singular form or the plural form is used. e.g. -// -// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". -// FormatCountableNoun(5, "book", "books") returns "5 books". -static internal::String FormatCountableNoun(int count, - const char * singular_form, - const char * plural_form) { - return internal::String::Format("%d %s", count, - count == 1 ? singular_form : plural_form); -} - -// Formats the count of tests. -static internal::String FormatTestCount(int test_count) { - return FormatCountableNoun(test_count, "test", "tests"); -} - -// Formats the count of test cases. -static internal::String FormatTestCaseCount(int test_case_count) { - return FormatCountableNoun(test_case_count, "test case", "test cases"); -} - -// Converts a TestPartResult::Type enum to human-friendly string -// representation. Both kNonFatalFailure and kFatalFailure are translated -// to "Failure", as the user usually doesn't care about the difference -// between the two when viewing the test result. -static const char * TestPartResultTypeToString(TestPartResult::Type type) { - switch (type) { - case TestPartResult::kSuccess: - return "Success"; - - case TestPartResult::kNonFatalFailure: - case TestPartResult::kFatalFailure: -#ifdef _MSC_VER - return "error: "; -#else - return "Failure\n"; -#endif - } - - // All cases return, so this is unreachable but GCC doesn't know it - abort(); -} - -// Prints a TestPartResult to a String. -static internal::String PrintTestPartResultToString( - const TestPartResult& test_part_result) { - return (Message() - << internal::FormatFileLocation(test_part_result.file_name(), - test_part_result.line_number()) - << " " << TestPartResultTypeToString(test_part_result.type()) - << test_part_result.message()).GetString(); -} - -// Prints a TestPartResult. -static void PrintTestPartResult(const TestPartResult& test_part_result) { - const internal::String& result = - PrintTestPartResultToString(test_part_result); - printf("%s\n", result.c_str()); - fflush(stdout); - // If the test program runs in Visual Studio or a debugger, the - // following statements add the test part result message to the Output - // window such that the user can double-click on it to jump to the - // corresponding source code location; otherwise they do nothing. -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - // We don't call OutputDebugString*() on Windows Mobile, as printing - // to stdout is done by OutputDebugString() there already - we don't - // want the same message printed twice. - ::OutputDebugStringA(result.c_str()); - ::OutputDebugStringA("\n"); -#endif -} - -// class PrettyUnitTestResultPrinter - -namespace internal { - -enum GTestColor { - COLOR_DEFAULT, - COLOR_RED, - COLOR_GREEN, - COLOR_YELLOW -}; - -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - -// Returns the character attribute for the given color. -WORD GetColorAttribute(GTestColor color) { - switch (color) { - case COLOR_RED: return FOREGROUND_RED; - case COLOR_GREEN: return FOREGROUND_GREEN; - case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; - default: return 0; - } -} - -#else - -// Returns the ANSI color code for the given color. COLOR_DEFAULT is -// an invalid input. -const char* GetAnsiColorCode(GTestColor color) { - switch (color) { - case COLOR_RED: return "1"; - case COLOR_GREEN: return "2"; - case COLOR_YELLOW: return "3"; - default: return NULL; - }; -} - -#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - -// Returns true iff Google Test should use colors in the output. -bool ShouldUseColor(bool stdout_is_tty) { - const char* const gtest_color = GTEST_FLAG(color).c_str(); - - if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { -#if GTEST_OS_WINDOWS - // On Windows the TERM variable is usually not set, but the - // console there does support colors. - return stdout_is_tty; -#else - // On non-Windows platforms, we rely on the TERM variable. - const char* const term = posix::GetEnv("TERM"); - const bool term_supports_color = - String::CStringEquals(term, "xterm") || - String::CStringEquals(term, "xterm-color") || - String::CStringEquals(term, "xterm-256color") || - String::CStringEquals(term, "screen") || - String::CStringEquals(term, "linux") || - String::CStringEquals(term, "cygwin"); - return stdout_is_tty && term_supports_color; -#endif // GTEST_OS_WINDOWS - } - - return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || - String::CaseInsensitiveCStringEquals(gtest_color, "true") || - String::CaseInsensitiveCStringEquals(gtest_color, "t") || - String::CStringEquals(gtest_color, "1"); - // We take "yes", "true", "t", and "1" as meaning "yes". If the - // value is neither one of these nor "auto", we treat it as "no" to - // be conservative. -} - -// Helpers for printing colored strings to stdout. Note that on Windows, we -// cannot simply emit special characters and have the terminal change colors. -// This routine must actually emit the characters rather than return a string -// that would be colored when printed, as can be done on Linux. -void ColoredPrintf(GTestColor color, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - const bool use_color = false; -#else - static const bool in_color_mode = - ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); - const bool use_color = in_color_mode && (color != COLOR_DEFAULT); -#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - // The '!= 0' comparison is necessary to satisfy MSVC 7.1. - - if (!use_color) { - vprintf(fmt, args); - va_end(args); - return; - } - -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); - - // Gets the current text color. - CONSOLE_SCREEN_BUFFER_INFO buffer_info; - GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); - const WORD old_color_attrs = buffer_info.wAttributes; - - // We need to flush the stream buffers into the console before each - // SetConsoleTextAttribute call lest it affect the text that is already - // printed but has not yet reached the console. - fflush(stdout); - SetConsoleTextAttribute(stdout_handle, - GetColorAttribute(color) | FOREGROUND_INTENSITY); - vprintf(fmt, args); - - fflush(stdout); - // Restores the text color. - SetConsoleTextAttribute(stdout_handle, old_color_attrs); -#else - printf("\033[0;3%sm", GetAnsiColorCode(color)); - vprintf(fmt, args); - printf("\033[m"); // Resets the terminal to default. -#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - va_end(args); -} - -void PrintFullTestCommentIfPresent(const TestInfo& test_info) { - const char* const type_param = test_info.type_param(); - const char* const value_param = test_info.value_param(); - - if (type_param != NULL || value_param != NULL) { - printf(", where "); - if (type_param != NULL) { - printf("TypeParam = %s", type_param); - if (value_param != NULL) - printf(" and "); - } - if (value_param != NULL) { - printf("GetParam() = %s", value_param); - } - } -} - -// This class implements the TestEventListener interface. -// -// Class PrettyUnitTestResultPrinter is copyable. -class PrettyUnitTestResultPrinter : public TestEventListener { - public: - PrettyUnitTestResultPrinter() {} - static void PrintTestName(const char * test_case, const char * test) { - printf("%s.%s", test_case, test); - } - - // The following methods override what's in the TestEventListener class. - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} - - private: - static void PrintFailedTests(const UnitTest& unit_test); - - internal::String test_case_name_; -}; - - // Fired before each iteration of tests starts. -void PrettyUnitTestResultPrinter::OnTestIterationStart( - const UnitTest& unit_test, int iteration) { - if (GTEST_FLAG(repeat) != 1) - printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); - - const char* const filter = GTEST_FLAG(filter).c_str(); - - // Prints the filter if it's not *. This reminds the user that some - // tests may be skipped. - if (!internal::String::CStringEquals(filter, kUniversalFilter)) { - ColoredPrintf(COLOR_YELLOW, - "Note: %s filter = %s\n", GTEST_NAME_, filter); - } - - if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { - const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); - ColoredPrintf(COLOR_YELLOW, - "Note: This is test shard %d of %s.\n", - static_cast(shard_index) + 1, - internal::posix::GetEnv(kTestTotalShards)); - } - - if (GTEST_FLAG(shuffle)) { - ColoredPrintf(COLOR_YELLOW, - "Note: Randomizing tests' orders with a seed of %d .\n", - unit_test.random_seed()); - } - - ColoredPrintf(COLOR_GREEN, "[==========] "); - printf("Running %s from %s.\n", - FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( - const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("Global test environment set-up.\n"); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { - test_case_name_ = test_case.name(); - const internal::String counts = - FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s", counts.c_str(), test_case_name_.c_str()); - if (test_case.type_param() == NULL) { - printf("\n"); - } else { - printf(", where TypeParam = %s\n", test_case.type_param()); - } - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { - ColoredPrintf(COLOR_GREEN, "[ RUN ] "); - PrintTestName(test_case_name_.c_str(), test_info.name()); - printf("\n"); - fflush(stdout); -} - -// Called after an assertion failure. -void PrettyUnitTestResultPrinter::OnTestPartResult( - const TestPartResult& result) { - // If the test part succeeded, we don't need to do anything. - if (result.type() == TestPartResult::kSuccess) - return; - - // Print failure message from the assertion (e.g. expected this and got that). - PrintTestPartResult(result); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { - if (test_info.result()->Passed()) { - ColoredPrintf(COLOR_GREEN, "[ OK ] "); - } else { - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - } - PrintTestName(test_case_name_.c_str(), test_info.name()); - if (test_info.result()->Failed()) - PrintFullTestCommentIfPresent(test_info); - - if (GTEST_FLAG(print_time)) { - printf(" (%s ms)\n", internal::StreamableToString( - test_info.result()->elapsed_time()).c_str()); - } else { - printf("\n"); - } - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { - if (!GTEST_FLAG(print_time)) return; - - test_case_name_ = test_case.name(); - const internal::String counts = - FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s (%s ms total)\n\n", - counts.c_str(), test_case_name_.c_str(), - internal::StreamableToString(test_case.elapsed_time()).c_str()); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( - const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("Global test environment tear-down\n"); - fflush(stdout); -} - -// Internal helper for printing the list of failed tests. -void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { - const int failed_test_count = unit_test.failed_test_count(); - if (failed_test_count == 0) { - return; - } - - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - const TestCase& test_case = *unit_test.GetTestCase(i); - if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { - continue; - } - for (int j = 0; j < test_case.total_test_count(); ++j) { - const TestInfo& test_info = *test_case.GetTestInfo(j); - if (!test_info.should_run() || test_info.result()->Passed()) { - continue; - } - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s.%s", test_case.name(), test_info.name()); - PrintFullTestCommentIfPresent(test_info); - printf("\n"); - } - } -} - -void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { - ColoredPrintf(COLOR_GREEN, "[==========] "); - printf("%s from %s ran.", - FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); - if (GTEST_FLAG(print_time)) { - printf(" (%s ms total)", - internal::StreamableToString(unit_test.elapsed_time()).c_str()); - } - printf("\n"); - ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); - printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); - - int num_failures = unit_test.failed_test_count(); - if (!unit_test.Passed()) { - const int failed_test_count = unit_test.failed_test_count(); - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); - PrintFailedTests(unit_test); - printf("\n%2d FAILED %s\n", num_failures, - num_failures == 1 ? "TEST" : "TESTS"); - } - - int num_disabled = unit_test.disabled_test_count(); - if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { - if (!num_failures) { - printf("\n"); // Add a spacer if no FAILURE banner is displayed. - } - ColoredPrintf(COLOR_YELLOW, - " YOU HAVE %d DISABLED %s\n\n", - num_disabled, - num_disabled == 1 ? "TEST" : "TESTS"); - } - // Ensure that Google Test output is printed before, e.g., heapchecker output. - fflush(stdout); -} - -// End PrettyUnitTestResultPrinter - -// class TestEventRepeater -// -// This class forwards events to other event listeners. -class TestEventRepeater : public TestEventListener { - public: - TestEventRepeater() : forwarding_enabled_(true) {} - virtual ~TestEventRepeater(); - void Append(TestEventListener *listener); - TestEventListener* Release(TestEventListener* listener); - - // Controls whether events will be forwarded to listeners_. Set to false - // in death test child processes. - bool forwarding_enabled() const { return forwarding_enabled_; } - void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } - - virtual void OnTestProgramStart(const UnitTest& unit_test); - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& unit_test); - - private: - // Controls whether events will be forwarded to listeners_. Set to false - // in death test child processes. - bool forwarding_enabled_; - // The list of listeners that receive events. - std::vector listeners_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); -}; - -TestEventRepeater::~TestEventRepeater() { - ForEach(listeners_, Delete); -} - -void TestEventRepeater::Append(TestEventListener *listener) { - listeners_.push_back(listener); -} - -// TODO(vladl@google.com): Factor the search functionality into Vector::Find. -TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { - for (size_t i = 0; i < listeners_.size(); ++i) { - if (listeners_[i] == listener) { - listeners_.erase(listeners_.begin() + i); - return listener; - } - } - - return NULL; -} - -// Since most methods are very similar, use macros to reduce boilerplate. -// This defines a member that forwards the call to all listeners. -#define GTEST_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (size_t i = 0; i < listeners_.size(); i++) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} -// This defines a member that forwards the call to all listeners in reverse -// order. -#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} - -GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) -GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) -GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) -GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) -GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) -GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) -GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) -GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) - -#undef GTEST_REPEATER_METHOD_ -#undef GTEST_REVERSE_REPEATER_METHOD_ - -void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, - int iteration) { - if (forwarding_enabled_) { - for (size_t i = 0; i < listeners_.size(); i++) { - listeners_[i]->OnTestIterationStart(unit_test, iteration); - } - } -} - -void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, - int iteration) { - if (forwarding_enabled_) { - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { - listeners_[i]->OnTestIterationEnd(unit_test, iteration); - } - } -} - -// End TestEventRepeater - -// This class generates an XML output file. -class XmlUnitTestResultPrinter : public EmptyTestEventListener { - public: - explicit XmlUnitTestResultPrinter(const char* output_file); - - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - - private: - // Is c a whitespace character that is normalized to a space character - // when it appears in an XML attribute value? - static bool IsNormalizableWhitespace(char c) { - return c == 0x9 || c == 0xA || c == 0xD; - } - - // May c appear in a well-formed XML document? - static bool IsValidXmlCharacter(char c) { - return IsNormalizableWhitespace(c) || c >= 0x20; - } - - // Returns an XML-escaped copy of the input string str. If - // is_attribute is true, the text is meant to appear as an attribute - // value, and normalizable whitespace is preserved by replacing it - // with character references. - static String EscapeXml(const char* str, bool is_attribute); - - // Returns the given string with all characters invalid in XML removed. - static string RemoveInvalidXmlCharacters(const string& str); - - // Convenience wrapper around EscapeXml when str is an attribute value. - static String EscapeXmlAttribute(const char* str) { - return EscapeXml(str, true); - } - - // Convenience wrapper around EscapeXml when str is not an attribute value. - static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } - - // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. - static void OutputXmlCDataSection(::std::ostream* stream, const char* data); - - // Streams an XML representation of a TestInfo object. - static void OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info); - - // Prints an XML representation of a TestCase object - static void PrintXmlTestCase(FILE* out, const TestCase& test_case); - - // Prints an XML summary of unit_test to output stream out. - static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); - - // Produces a string representing the test properties in a result as space - // delimited XML attributes based on the property key="value" pairs. - // When the String is not empty, it includes a space at the beginning, - // to delimit this attribute from prior attributes. - static String TestPropertiesAsXmlAttributes(const TestResult& result); - - // The output file. - const String output_file_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); -}; - -// Creates a new XmlUnitTestResultPrinter. -XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) - : output_file_(output_file) { - if (output_file_.c_str() == NULL || output_file_.empty()) { - fprintf(stderr, "XML output file may not be null\n"); - fflush(stderr); - exit(EXIT_FAILURE); - } -} - -// Called after the unit test ends. -void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { - FILE* xmlout = NULL; - FilePath output_file(output_file_); - FilePath output_dir(output_file.RemoveFileName()); - - if (output_dir.CreateDirectoriesRecursively()) { - xmlout = posix::FOpen(output_file_.c_str(), "w"); - } - if (xmlout == NULL) { - // TODO(wan): report the reason of the failure. - // - // We don't do it for now as: - // - // 1. There is no urgent need for it. - // 2. It's a bit involved to make the errno variable thread-safe on - // all three operating systems (Linux, Windows, and Mac OS). - // 3. To interpret the meaning of errno in a thread-safe way, - // we need the strerror_r() function, which is not available on - // Windows. - fprintf(stderr, - "Unable to open file \"%s\"\n", - output_file_.c_str()); - fflush(stderr); - exit(EXIT_FAILURE); - } - PrintXmlUnitTest(xmlout, unit_test); - fclose(xmlout); -} - -// Returns an XML-escaped copy of the input string str. If is_attribute -// is true, the text is meant to appear as an attribute value, and -// normalizable whitespace is preserved by replacing it with character -// references. -// -// Invalid XML characters in str, if any, are stripped from the output. -// It is expected that most, if not all, of the text processed by this -// module will consist of ordinary English text. -// If this module is ever modified to produce version 1.1 XML output, -// most invalid characters can be retained using character references. -// TODO(wan): It might be nice to have a minimally invasive, human-readable -// escaping scheme for invalid characters, rather than dropping them. -String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { - Message m; - - if (str != NULL) { - for (const char* src = str; *src; ++src) { - switch (*src) { - case '<': - m << "<"; - break; - case '>': - m << ">"; - break; - case '&': - m << "&"; - break; - case '\'': - if (is_attribute) - m << "'"; - else - m << '\''; - break; - case '"': - if (is_attribute) - m << """; - else - m << '"'; - break; - default: - if (IsValidXmlCharacter(*src)) { - if (is_attribute && IsNormalizableWhitespace(*src)) - m << String::Format("&#x%02X;", unsigned(*src)); - else - m << *src; - } - break; - } - } - } - - return m.GetString(); -} - -// Returns the given string with all characters invalid in XML removed. -// Currently invalid characters are dropped from the string. An -// alternative is to replace them with certain characters such as . or ?. -string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const string& str) { - string output; - output.reserve(str.size()); - for (string::const_iterator it = str.begin(); it != str.end(); ++it) - if (IsValidXmlCharacter(*it)) - output.push_back(*it); - - return output; -} - -// The following routines generate an XML representation of a UnitTest -// object. -// -// This is how Google Test concepts map to the DTD: -// -// <-- corresponds to a UnitTest object -// <-- corresponds to a TestCase object -// <-- corresponds to a TestInfo object -// ... -// ... -// ... -// <-- individual assertion failures -// -// -// - -// Formats the given time in milliseconds as seconds. -std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { - ::std::stringstream ss; - ss << ms/1000.0; - return ss.str(); -} - -// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. -void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, - const char* data) { - const char* segment = data; - *stream << ""); - if (next_segment != NULL) { - stream->write( - segment, static_cast(next_segment - segment)); - *stream << "]]>]]>"); - } else { - *stream << segment; - break; - } - } - *stream << "]]>"; -} - -// Prints an XML representation of a TestInfo object. -// TODO(wan): There is also value in printing properties with the plain printer. -void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info) { - const TestResult& result = *test_info.result(); - *stream << " \n"; - *stream << " "; - const string location = internal::FormatCompilerIndependentFileLocation( - part.file_name(), part.line_number()); - const string message = location + "\n" + part.message(); - OutputXmlCDataSection(stream, - RemoveInvalidXmlCharacters(message).c_str()); - *stream << "\n"; - } - } - - if (failures == 0) - *stream << " />\n"; - else - *stream << " \n"; -} - -// Prints an XML representation of a TestCase object -void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, - const TestCase& test_case) { - fprintf(out, - " \n", - FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); - for (int i = 0; i < test_case.total_test_count(); ++i) { - ::std::stringstream stream; - OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); - fprintf(out, "%s", StringStreamToString(&stream).c_str()); - } - fprintf(out, " \n"); -} - -// Prints an XML summary of unit_test to output stream out. -void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, - const UnitTest& unit_test) { - fprintf(out, "\n"); - fprintf(out, - "\n"); - for (int i = 0; i < unit_test.total_test_case_count(); ++i) - PrintXmlTestCase(out, *unit_test.GetTestCase(i)); - fprintf(out, "\n"); -} - -// Produces a string representing the test properties in a result as space -// delimited XML attributes based on the property key="value" pairs. -String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( - const TestResult& result) { - Message attributes; - for (int i = 0; i < result.test_property_count(); ++i) { - const TestProperty& property = result.GetTestProperty(i); - attributes << " " << property.key() << "=" - << "\"" << EscapeXmlAttribute(property.value()) << "\""; - } - return attributes.GetString(); -} - -// End XmlUnitTestResultPrinter - -#if GTEST_CAN_STREAM_RESULTS_ - -// Streams test results to the given port on the given host machine. -class StreamingListener : public EmptyTestEventListener { - public: - // Escapes '=', '&', '%', and '\n' characters in str as "%xx". - static string UrlEncode(const char* str); - - StreamingListener(const string& host, const string& port) - : sockfd_(-1), host_name_(host), port_num_(port) { - MakeConnection(); - Send("gtest_streaming_protocol_version=1.0\n"); - } - - virtual ~StreamingListener() { - if (sockfd_ != -1) - CloseConnection(); - } - - void OnTestProgramStart(const UnitTest& /* unit_test */) { - Send("event=TestProgramStart\n"); - } - - void OnTestProgramEnd(const UnitTest& unit_test) { - // Note that Google Test current only report elapsed time for each - // test iteration, not for the entire test program. - Send(String::Format("event=TestProgramEnd&passed=%d\n", - unit_test.Passed())); - - // Notify the streaming server to stop. - CloseConnection(); - } - - void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { - Send(String::Format("event=TestIterationStart&iteration=%d\n", - iteration)); - } - - void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { - Send(String::Format("event=TestIterationEnd&passed=%d&elapsed_time=%sms\n", - unit_test.Passed(), - StreamableToString(unit_test.elapsed_time()).c_str())); - } - - void OnTestCaseStart(const TestCase& test_case) { - Send(String::Format("event=TestCaseStart&name=%s\n", test_case.name())); - } - - void OnTestCaseEnd(const TestCase& test_case) { - Send(String::Format("event=TestCaseEnd&passed=%d&elapsed_time=%sms\n", - test_case.Passed(), - StreamableToString(test_case.elapsed_time()).c_str())); - } - - void OnTestStart(const TestInfo& test_info) { - Send(String::Format("event=TestStart&name=%s\n", test_info.name())); - } - - void OnTestEnd(const TestInfo& test_info) { - Send(String::Format( - "event=TestEnd&passed=%d&elapsed_time=%sms\n", - (test_info.result())->Passed(), - StreamableToString((test_info.result())->elapsed_time()).c_str())); - } - - void OnTestPartResult(const TestPartResult& test_part_result) { - const char* file_name = test_part_result.file_name(); - if (file_name == NULL) - file_name = ""; - Send(String::Format("event=TestPartResult&file=%s&line=%d&message=", - UrlEncode(file_name).c_str(), - test_part_result.line_number())); - Send(UrlEncode(test_part_result.message()) + "\n"); - } - - private: - // Creates a client socket and connects to the server. - void MakeConnection(); - - // Closes the socket. - void CloseConnection() { - GTEST_CHECK_(sockfd_ != -1) - << "CloseConnection() can be called only when there is a connection."; - - close(sockfd_); - sockfd_ = -1; - } - - // Sends a string to the socket. - void Send(const string& message) { - GTEST_CHECK_(sockfd_ != -1) - << "Send() can be called only when there is a connection."; - - const int len = static_cast(message.length()); - if (write(sockfd_, message.c_str(), len) != len) { - GTEST_LOG_(WARNING) - << "stream_result_to: failed to stream to " - << host_name_ << ":" << port_num_; - } - } - - int sockfd_; // socket file descriptor - const string host_name_; - const string port_num_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); -}; // class StreamingListener - -// Checks if str contains '=', '&', '%' or '\n' characters. If yes, -// replaces them by "%xx" where xx is their hexadecimal value. For -// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) -// in both time and space -- important as the input str may contain an -// arbitrarily long test failure message and stack trace. -string StreamingListener::UrlEncode(const char* str) { - string result; - result.reserve(strlen(str) + 1); - for (char ch = *str; ch != '\0'; ch = *++str) { - switch (ch) { - case '%': - case '=': - case '&': - case '\n': - result.append(String::Format("%%%02x", static_cast(ch))); - break; - default: - result.push_back(ch); - break; - } - } - return result; -} - -void StreamingListener::MakeConnection() { - GTEST_CHECK_(sockfd_ == -1) - << "MakeConnection() can't be called when there is already a connection."; - - addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. - hints.ai_socktype = SOCK_STREAM; - addrinfo* servinfo = NULL; - - // Use the getaddrinfo() to get a linked list of IP addresses for - // the given host name. - const int error_num = getaddrinfo( - host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); - if (error_num != 0) { - GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " - << gai_strerror(error_num); - } - - // Loop through all the results and connect to the first we can. - for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; - cur_addr = cur_addr->ai_next) { - sockfd_ = socket( - cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); - if (sockfd_ != -1) { - // Connect the client socket to the server socket. - if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { - close(sockfd_); - sockfd_ = -1; - } - } - } - - freeaddrinfo(servinfo); // all done with this structure - - if (sockfd_ == -1) { - GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " - << host_name_ << ":" << port_num_; - } -} - -// End of class Streaming Listener -#endif // GTEST_CAN_STREAM_RESULTS__ - -// Class ScopedTrace - -// Pushes the given source file location and message onto a per-thread -// trace stack maintained by Google Test. -// L < UnitTest::mutex_ -ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { - TraceInfo trace; - trace.file = file; - trace.line = line; - trace.message = message.GetString(); - - UnitTest::GetInstance()->PushGTestTrace(trace); -} - -// Pops the info pushed by the c'tor. -// L < UnitTest::mutex_ -ScopedTrace::~ScopedTrace() { - UnitTest::GetInstance()->PopGTestTrace(); -} - - -// class OsStackTraceGetter - -// Returns the current OS stack trace as a String. Parameters: -// -// max_depth - the maximum number of stack frames to be included -// in the trace. -// skip_count - the number of top frames to be skipped; doesn't count -// against max_depth. -// -// L < mutex_ -// We use "L < mutex_" to denote that the function may acquire mutex_. -String OsStackTraceGetter::CurrentStackTrace(int, int) { - return String(""); -} - -// L < mutex_ -void OsStackTraceGetter::UponLeavingGTest() { -} - -const char* const -OsStackTraceGetter::kElidedFramesMarker = - "... " GTEST_NAME_ " internal frames ..."; - -} // namespace internal - -// class TestEventListeners - -TestEventListeners::TestEventListeners() - : repeater_(new internal::TestEventRepeater()), - default_result_printer_(NULL), - default_xml_generator_(NULL) { -} - -TestEventListeners::~TestEventListeners() { delete repeater_; } - -// Returns the standard listener responsible for the default console -// output. Can be removed from the listeners list to shut down default -// console output. Note that removing this object from the listener list -// with Release transfers its ownership to the user. -void TestEventListeners::Append(TestEventListener* listener) { - repeater_->Append(listener); -} - -// Removes the given event listener from the list and returns it. It then -// becomes the caller's responsibility to delete the listener. Returns -// NULL if the listener is not found in the list. -TestEventListener* TestEventListeners::Release(TestEventListener* listener) { - if (listener == default_result_printer_) - default_result_printer_ = NULL; - else if (listener == default_xml_generator_) - default_xml_generator_ = NULL; - return repeater_->Release(listener); -} - -// Returns repeater that broadcasts the TestEventListener events to all -// subscribers. -TestEventListener* TestEventListeners::repeater() { return repeater_; } - -// Sets the default_result_printer attribute to the provided listener. -// The listener is also added to the listener list and previous -// default_result_printer is removed from it and deleted. The listener can -// also be NULL in which case it will not be added to the list. Does -// nothing if the previous and the current listener objects are the same. -void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { - if (default_result_printer_ != listener) { - // It is an error to pass this method a listener that is already in the - // list. - delete Release(default_result_printer_); - default_result_printer_ = listener; - if (listener != NULL) - Append(listener); - } -} - -// Sets the default_xml_generator attribute to the provided listener. The -// listener is also added to the listener list and previous -// default_xml_generator is removed from it and deleted. The listener can -// also be NULL in which case it will not be added to the list. Does -// nothing if the previous and the current listener objects are the same. -void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { - if (default_xml_generator_ != listener) { - // It is an error to pass this method a listener that is already in the - // list. - delete Release(default_xml_generator_); - default_xml_generator_ = listener; - if (listener != NULL) - Append(listener); - } -} - -// Controls whether events will be forwarded by the repeater to the -// listeners in the list. -bool TestEventListeners::EventForwardingEnabled() const { - return repeater_->forwarding_enabled(); -} - -void TestEventListeners::SuppressEventForwarding() { - repeater_->set_forwarding_enabled(false); -} - -// class UnitTest - -// Gets the singleton UnitTest object. The first time this method is -// called, a UnitTest object is constructed and returned. Consecutive -// calls will return the same object. -// -// We don't protect this under mutex_ as a user is not supposed to -// call this before main() starts, from which point on the return -// value will never change. -UnitTest * UnitTest::GetInstance() { - // When compiled with MSVC 7.1 in optimized mode, destroying the - // UnitTest object upon exiting the program messes up the exit code, - // causing successful tests to appear failed. We have to use a - // different implementation in this case to bypass the compiler bug. - // This implementation makes the compiler happy, at the cost of - // leaking the UnitTest object. - - // CodeGear C++Builder insists on a public destructor for the - // default implementation. Use this implementation to keep good OO - // design with private destructor. - -#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) - static UnitTest* const instance = new UnitTest; - return instance; -#else - static UnitTest instance; - return &instance; -#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) -} - -// Gets the number of successful test cases. -int UnitTest::successful_test_case_count() const { - return impl()->successful_test_case_count(); -} - -// Gets the number of failed test cases. -int UnitTest::failed_test_case_count() const { - return impl()->failed_test_case_count(); -} - -// Gets the number of all test cases. -int UnitTest::total_test_case_count() const { - return impl()->total_test_case_count(); -} - -// Gets the number of all test cases that contain at least one test -// that should run. -int UnitTest::test_case_to_run_count() const { - return impl()->test_case_to_run_count(); -} - -// Gets the number of successful tests. -int UnitTest::successful_test_count() const { - return impl()->successful_test_count(); -} - -// Gets the number of failed tests. -int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } - -// Gets the number of disabled tests. -int UnitTest::disabled_test_count() const { - return impl()->disabled_test_count(); -} - -// Gets the number of all tests. -int UnitTest::total_test_count() const { return impl()->total_test_count(); } - -// Gets the number of tests that should run. -int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } - -// Gets the elapsed time, in milliseconds. -internal::TimeInMillis UnitTest::elapsed_time() const { - return impl()->elapsed_time(); -} - -// Returns true iff the unit test passed (i.e. all test cases passed). -bool UnitTest::Passed() const { return impl()->Passed(); } - -// Returns true iff the unit test failed (i.e. some test case failed -// or something outside of all tests failed). -bool UnitTest::Failed() const { return impl()->Failed(); } - -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -const TestCase* UnitTest::GetTestCase(int i) const { - return impl()->GetTestCase(i); -} - -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -TestCase* UnitTest::GetMutableTestCase(int i) { - return impl()->GetMutableTestCase(i); -} - -// Returns the list of event listeners that can be used to track events -// inside Google Test. -TestEventListeners& UnitTest::listeners() { - return *impl()->listeners(); -} - -// Registers and returns a global test environment. When a test -// program is run, all global test environments will be set-up in the -// order they were registered. After all tests in the program have -// finished, all global test environments will be torn-down in the -// *reverse* order they were registered. -// -// The UnitTest object takes ownership of the given environment. -// -// We don't protect this under mutex_, as we only support calling it -// from the main thread. -Environment* UnitTest::AddEnvironment(Environment* env) { - if (env == NULL) { - return NULL; - } - - impl_->environments().push_back(env); - return env; -} - -// Adds a TestPartResult to the current TestResult object. All Google Test -// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call -// this to report their results. The user code should use the -// assertion macros instead of calling this directly. -// L < mutex_ -void UnitTest::AddTestPartResult(TestPartResult::Type result_type, - const char* file_name, - int line_number, - const internal::String& message, - const internal::String& os_stack_trace) { - Message msg; - msg << message; - - internal::MutexLock lock(&mutex_); - if (impl_->gtest_trace_stack().size() > 0) { - msg << "\n" << GTEST_NAME_ << " trace:"; - - for (int i = static_cast(impl_->gtest_trace_stack().size()); - i > 0; --i) { - const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; - msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) - << " " << trace.message; - } - } - - if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { - msg << internal::kStackTraceMarker << os_stack_trace; - } - - const TestPartResult result = - TestPartResult(result_type, file_name, line_number, - msg.GetString().c_str()); - impl_->GetTestPartResultReporterForCurrentThread()-> - ReportTestPartResult(result); - - if (result_type != TestPartResult::kSuccess) { - // gtest_break_on_failure takes precedence over - // gtest_throw_on_failure. This allows a user to set the latter - // in the code (perhaps in order to use Google Test assertions - // with another testing framework) and specify the former on the - // command line for debugging. - if (GTEST_FLAG(break_on_failure)) { -#if GTEST_OS_WINDOWS - // Using DebugBreak on Windows allows gtest to still break into a debugger - // when a failure happens and both the --gtest_break_on_failure and - // the --gtest_catch_exceptions flags are specified. - DebugBreak(); -#else - abort(); -#endif // GTEST_OS_WINDOWS - } else if (GTEST_FLAG(throw_on_failure)) { -#if GTEST_HAS_EXCEPTIONS - throw GoogleTestFailureException(result); -#else - // We cannot call abort() as it generates a pop-up in debug mode - // that cannot be suppressed in VC 7.1 or below. - exit(1); -#endif - } - } -} - -// Creates and adds a property to the current TestResult. If a property matching -// the supplied value already exists, updates its value instead. -void UnitTest::RecordPropertyForCurrentTest(const char* key, - const char* value) { - const TestProperty test_property(key, value); - impl_->current_test_result()->RecordProperty(test_property); -} - -// Runs all tests in this UnitTest object and prints the result. -// Returns 0 if successful, or 1 otherwise. -// -// We don't protect this under mutex_, as we only support calling it -// from the main thread. -int UnitTest::Run() { - // Captures the value of GTEST_FLAG(catch_exceptions). This value will be - // used for the duration of the program. - impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); - -#if GTEST_HAS_SEH - const bool in_death_test_child_process = - internal::GTEST_FLAG(internal_run_death_test).length() > 0; - - // Either the user wants Google Test to catch exceptions thrown by the - // tests or this is executing in the context of death test child - // process. In either case the user does not want to see pop-up dialogs - // about crashes - they are expected. - if (impl()->catch_exceptions() || in_death_test_child_process) { - -# if !GTEST_OS_WINDOWS_MOBILE - // SetErrorMode doesn't exist on CE. - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | - SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); -# endif // !GTEST_OS_WINDOWS_MOBILE - -# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE - // Death test children can be terminated with _abort(). On Windows, - // _abort() can show a dialog with a warning message. This forces the - // abort message to go to stderr instead. - _set_error_mode(_OUT_TO_STDERR); -# endif - -# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE - // In the debug version, Visual Studio pops up a separate dialog - // offering a choice to debug the aborted program. We need to suppress - // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement - // executed. Google Test will notify the user of any unexpected - // failure via stderr. - // - // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. - // Users of prior VC versions shall suffer the agony and pain of - // clicking through the countless debug dialogs. - // TODO(vladl@google.com): find a way to suppress the abort dialog() in the - // debug mode when compiled with VC 7.1 or lower. - if (!GTEST_FLAG(break_on_failure)) - _set_abort_behavior( - 0x0, // Clear the following flags: - _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. -# endif - - } -#endif // GTEST_HAS_SEH - - return internal::HandleExceptionsInMethodIfSupported( - impl(), - &internal::UnitTestImpl::RunAllTests, - "auxiliary test code (environments or event listeners)") ? 0 : 1; -} - -// Returns the working directory when the first TEST() or TEST_F() was -// executed. -const char* UnitTest::original_working_dir() const { - return impl_->original_working_dir_.c_str(); -} - -// Returns the TestCase object for the test that's currently running, -// or NULL if no test is running. -// L < mutex_ -const TestCase* UnitTest::current_test_case() const { - internal::MutexLock lock(&mutex_); - return impl_->current_test_case(); -} - -// Returns the TestInfo object for the test that's currently running, -// or NULL if no test is running. -// L < mutex_ -const TestInfo* UnitTest::current_test_info() const { - internal::MutexLock lock(&mutex_); - return impl_->current_test_info(); -} - -// Returns the random seed used at the start of the current test run. -int UnitTest::random_seed() const { return impl_->random_seed(); } - -#if GTEST_HAS_PARAM_TEST -// Returns ParameterizedTestCaseRegistry object used to keep track of -// value-parameterized tests and instantiate and register them. -// L < mutex_ -internal::ParameterizedTestCaseRegistry& - UnitTest::parameterized_test_registry() { - return impl_->parameterized_test_registry(); -} -#endif // GTEST_HAS_PARAM_TEST - -// Creates an empty UnitTest. -UnitTest::UnitTest() { - impl_ = new internal::UnitTestImpl(this); -} - -// Destructor of UnitTest. -UnitTest::~UnitTest() { - delete impl_; -} - -// Pushes a trace defined by SCOPED_TRACE() on to the per-thread -// Google Test trace stack. -// L < mutex_ -void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { - internal::MutexLock lock(&mutex_); - impl_->gtest_trace_stack().push_back(trace); -} - -// Pops a trace from the per-thread Google Test trace stack. -// L < mutex_ -void UnitTest::PopGTestTrace() { - internal::MutexLock lock(&mutex_); - impl_->gtest_trace_stack().pop_back(); -} - -namespace internal { - -UnitTestImpl::UnitTestImpl(UnitTest* parent) - : parent_(parent), -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4355) // Temporarily disables warning 4355 - // (using this in initializer). - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), -# pragma warning(pop) // Restores the warning state again. -#else - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), -#endif // _MSC_VER - global_test_part_result_repoter_( - &default_global_test_part_result_reporter_), - per_thread_test_part_result_reporter_( - &default_per_thread_test_part_result_reporter_), -#if GTEST_HAS_PARAM_TEST - parameterized_test_registry_(), - parameterized_tests_registered_(false), -#endif // GTEST_HAS_PARAM_TEST - last_death_test_case_(-1), - current_test_case_(NULL), - current_test_info_(NULL), - ad_hoc_test_result_(), - os_stack_trace_getter_(NULL), - post_flag_parse_init_performed_(false), - random_seed_(0), // Will be overridden by the flag before first use. - random_(0), // Will be reseeded before first use. - elapsed_time_(0), -#if GTEST_HAS_DEATH_TEST - internal_run_death_test_flag_(NULL), - death_test_factory_(new DefaultDeathTestFactory), -#endif - // Will be overridden by the flag before first use. - catch_exceptions_(false) { - listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); -} - -UnitTestImpl::~UnitTestImpl() { - // Deletes every TestCase. - ForEach(test_cases_, internal::Delete); - - // Deletes every Environment. - ForEach(environments_, internal::Delete); - - delete os_stack_trace_getter_; -} - -#if GTEST_HAS_DEATH_TEST -// Disables event forwarding if the control is currently in a death test -// subprocess. Must not be called before InitGoogleTest. -void UnitTestImpl::SuppressTestEventsIfInSubprocess() { - if (internal_run_death_test_flag_.get() != NULL) - listeners()->SuppressEventForwarding(); -} -#endif // GTEST_HAS_DEATH_TEST - -// Initializes event listeners performing XML output as specified by -// UnitTestOptions. Must not be called before InitGoogleTest. -void UnitTestImpl::ConfigureXmlOutput() { - const String& output_format = UnitTestOptions::GetOutputFormat(); - if (output_format == "xml") { - listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( - UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); - } else if (output_format != "") { - printf("WARNING: unrecognized output format \"%s\" ignored.\n", - output_format.c_str()); - fflush(stdout); - } -} - -#if GTEST_CAN_STREAM_RESULTS_ -// Initializes event listeners for streaming test results in String form. -// Must not be called before InitGoogleTest. -void UnitTestImpl::ConfigureStreamingOutput() { - const string& target = GTEST_FLAG(stream_result_to); - if (!target.empty()) { - const size_t pos = target.find(':'); - if (pos != string::npos) { - listeners()->Append(new StreamingListener(target.substr(0, pos), - target.substr(pos+1))); - } else { - printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", - target.c_str()); - fflush(stdout); - } - } -} -#endif // GTEST_CAN_STREAM_RESULTS_ - -// Performs initialization dependent upon flag values obtained in -// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to -// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest -// this function is also called from RunAllTests. Since this function can be -// called more than once, it has to be idempotent. -void UnitTestImpl::PostFlagParsingInit() { - // Ensures that this function does not execute more than once. - if (!post_flag_parse_init_performed_) { - post_flag_parse_init_performed_ = true; - -#if GTEST_HAS_DEATH_TEST - InitDeathTestSubprocessControlInfo(); - SuppressTestEventsIfInSubprocess(); -#endif // GTEST_HAS_DEATH_TEST - - // Registers parameterized tests. This makes parameterized tests - // available to the UnitTest reflection API without running - // RUN_ALL_TESTS. - RegisterParameterizedTests(); - - // Configures listeners for XML output. This makes it possible for users - // to shut down the default XML output before invoking RUN_ALL_TESTS. - ConfigureXmlOutput(); - -#if GTEST_CAN_STREAM_RESULTS_ - // Configures listeners for streaming test results to the specified server. - ConfigureStreamingOutput(); -#endif // GTEST_CAN_STREAM_RESULTS_ - } -} - -// A predicate that checks the name of a TestCase against a known -// value. -// -// This is used for implementation of the UnitTest class only. We put -// it in the anonymous namespace to prevent polluting the outer -// namespace. -// -// TestCaseNameIs is copyable. -class TestCaseNameIs { - public: - // Constructor. - explicit TestCaseNameIs(const String& name) - : name_(name) {} - - // Returns true iff the name of test_case matches name_. - bool operator()(const TestCase* test_case) const { - return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; - } - - private: - String name_; -}; - -// Finds and returns a TestCase with the given name. If one doesn't -// exist, creates one and returns it. It's the CALLER'S -// RESPONSIBILITY to ensure that this function is only called WHEN THE -// TESTS ARE NOT SHUFFLED. -// -// Arguments: -// -// test_case_name: name of the test case -// type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) { - // Can we find a TestCase with the given name? - const std::vector::const_iterator test_case = - std::find_if(test_cases_.begin(), test_cases_.end(), - TestCaseNameIs(test_case_name)); - - if (test_case != test_cases_.end()) - return *test_case; - - // No. Let's create one. - TestCase* const new_test_case = - new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); - - // Is this a death test case? - if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), - kDeathTestCaseFilter)) { - // Yes. Inserts the test case after the last death test case - // defined so far. This only works when the test cases haven't - // been shuffled. Otherwise we may end up running a death test - // after a non-death test. - ++last_death_test_case_; - test_cases_.insert(test_cases_.begin() + last_death_test_case_, - new_test_case); - } else { - // No. Appends to the end of the list. - test_cases_.push_back(new_test_case); - } - - test_case_indices_.push_back(static_cast(test_case_indices_.size())); - return new_test_case; -} - -// Helpers for setting up / tearing down the given environment. They -// are for use in the ForEach() function. -static void SetUpEnvironment(Environment* env) { env->SetUp(); } -static void TearDownEnvironment(Environment* env) { env->TearDown(); } - -// Runs all tests in this UnitTest object, prints the result, and -// returns true if all tests are successful. If any exception is -// thrown during a test, the test is considered to be failed, but the -// rest of the tests will still be run. -// -// When parameterized tests are enabled, it expands and registers -// parameterized tests first in RegisterParameterizedTests(). -// All other functions called from RunAllTests() may safely assume that -// parameterized tests are ready to be counted and run. -bool UnitTestImpl::RunAllTests() { - // Makes sure InitGoogleTest() was called. - if (!GTestIsInitialized()) { - printf("%s", - "\nThis test program did NOT call ::testing::InitGoogleTest " - "before calling RUN_ALL_TESTS(). Please fix it.\n"); - return false; - } - - // Do not run any test if the --help flag was specified. - if (g_help_flag) - return true; - - // Repeats the call to the post-flag parsing initialization in case the - // user didn't call InitGoogleTest. - PostFlagParsingInit(); - - // Even if sharding is not on, test runners may want to use the - // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding - // protocol. - internal::WriteToShardStatusFileIfNeeded(); - - // True iff we are in a subprocess for running a thread-safe-style - // death test. - bool in_subprocess_for_death_test = false; - -#if GTEST_HAS_DEATH_TEST - in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); -#endif // GTEST_HAS_DEATH_TEST - - const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, - in_subprocess_for_death_test); - - // Compares the full test names with the filter to decide which - // tests to run. - const bool has_tests_to_run = FilterTests(should_shard - ? HONOR_SHARDING_PROTOCOL - : IGNORE_SHARDING_PROTOCOL) > 0; - - // Lists the tests and exits if the --gtest_list_tests flag was specified. - if (GTEST_FLAG(list_tests)) { - // This must be called *after* FilterTests() has been called. - ListTestsMatchingFilter(); - return true; - } - - random_seed_ = GTEST_FLAG(shuffle) ? - GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; - - // True iff at least one test has failed. - bool failed = false; - - TestEventListener* repeater = listeners()->repeater(); - - repeater->OnTestProgramStart(*parent_); - - // How many times to repeat the tests? We don't want to repeat them - // when we are inside the subprocess of a death test. - const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); - // Repeats forever if the repeat count is negative. - const bool forever = repeat < 0; - for (int i = 0; forever || i != repeat; i++) { - // We want to preserve failures generated by ad-hoc test - // assertions executed before RUN_ALL_TESTS(). - ClearNonAdHocTestResult(); - - const TimeInMillis start = GetTimeInMillis(); - - // Shuffles test cases and tests if requested. - if (has_tests_to_run && GTEST_FLAG(shuffle)) { - random()->Reseed(random_seed_); - // This should be done before calling OnTestIterationStart(), - // such that a test event listener can see the actual test order - // in the event. - ShuffleTests(); - } - - // Tells the unit test event listeners that the tests are about to start. - repeater->OnTestIterationStart(*parent_, i); - - // Runs each test case if there is at least one test to run. - if (has_tests_to_run) { - // Sets up all environments beforehand. - repeater->OnEnvironmentsSetUpStart(*parent_); - ForEach(environments_, SetUpEnvironment); - repeater->OnEnvironmentsSetUpEnd(*parent_); - - // Runs the tests only if there was no fatal failure during global - // set-up. - if (!Test::HasFatalFailure()) { - for (int test_index = 0; test_index < total_test_case_count(); - test_index++) { - GetMutableTestCase(test_index)->Run(); - } - } - - // Tears down all environments in reverse order afterwards. - repeater->OnEnvironmentsTearDownStart(*parent_); - std::for_each(environments_.rbegin(), environments_.rend(), - TearDownEnvironment); - repeater->OnEnvironmentsTearDownEnd(*parent_); - } - - elapsed_time_ = GetTimeInMillis() - start; - - // Tells the unit test event listener that the tests have just finished. - repeater->OnTestIterationEnd(*parent_, i); - - // Gets the result and clears it. - if (!Passed()) { - failed = true; - } - - // Restores the original test order after the iteration. This - // allows the user to quickly repro a failure that happens in the - // N-th iteration without repeating the first (N - 1) iterations. - // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in - // case the user somehow changes the value of the flag somewhere - // (it's always safe to unshuffle the tests). - UnshuffleTests(); - - if (GTEST_FLAG(shuffle)) { - // Picks a new random seed for each iteration. - random_seed_ = GetNextRandomSeed(random_seed_); - } - } - - repeater->OnTestProgramEnd(*parent_); - - return !failed; -} - -// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file -// if the variable is present. If a file already exists at this location, this -// function will write over it. If the variable is present, but the file cannot -// be created, prints an error and exits. -void WriteToShardStatusFileIfNeeded() { - const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); - if (test_shard_file != NULL) { - FILE* const file = posix::FOpen(test_shard_file, "w"); - if (file == NULL) { - ColoredPrintf(COLOR_RED, - "Could not write to the test shard status file \"%s\" " - "specified by the %s environment variable.\n", - test_shard_file, kTestShardStatusFile); - fflush(stdout); - exit(EXIT_FAILURE); - } - fclose(file); - } -} - -// Checks whether sharding is enabled by examining the relevant -// environment variable values. If the variables are present, -// but inconsistent (i.e., shard_index >= total_shards), prints -// an error and exits. If in_subprocess_for_death_test, sharding is -// disabled because it must only be applied to the original test -// process. Otherwise, we could filter out death tests we intended to execute. -bool ShouldShard(const char* total_shards_env, - const char* shard_index_env, - bool in_subprocess_for_death_test) { - if (in_subprocess_for_death_test) { - return false; - } - - const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); - const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); - - if (total_shards == -1 && shard_index == -1) { - return false; - } else if (total_shards == -1 && shard_index != -1) { - const Message msg = Message() - << "Invalid environment variables: you have " - << kTestShardIndex << " = " << shard_index - << ", but have left " << kTestTotalShards << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } else if (total_shards != -1 && shard_index == -1) { - const Message msg = Message() - << "Invalid environment variables: you have " - << kTestTotalShards << " = " << total_shards - << ", but have left " << kTestShardIndex << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } else if (shard_index < 0 || shard_index >= total_shards) { - const Message msg = Message() - << "Invalid environment variables: we require 0 <= " - << kTestShardIndex << " < " << kTestTotalShards - << ", but you have " << kTestShardIndex << "=" << shard_index - << ", " << kTestTotalShards << "=" << total_shards << ".\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } - - return total_shards > 1; -} - -// Parses the environment variable var as an Int32. If it is unset, -// returns default_val. If it is not an Int32, prints an error -// and aborts. -Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { - const char* str_val = posix::GetEnv(var); - if (str_val == NULL) { - return default_val; - } - - Int32 result; - if (!ParseInt32(Message() << "The value of environment variable " << var, - str_val, &result)) { - exit(EXIT_FAILURE); - } - return result; -} - -// Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test -// method. Assumes that 0 <= shard_index < total_shards. -bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { - return (test_id % total_shards) == shard_index; -} - -// Compares the name of each test with the user-specified filter to -// decide whether the test should be run, then records the result in -// each TestCase and TestInfo object. -// If shard_tests == true, further filters tests based on sharding -// variables in the environment - see -// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. -// Returns the number of tests that should run. -int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { - const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestTotalShards, -1) : -1; - const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestShardIndex, -1) : -1; - - // num_runnable_tests are the number of tests that will - // run across all shards (i.e., match filter and are not disabled). - // num_selected_tests are the number of tests to be run on - // this shard. - int num_runnable_tests = 0; - int num_selected_tests = 0; - for (size_t i = 0; i < test_cases_.size(); i++) { - TestCase* const test_case = test_cases_[i]; - const String &test_case_name = test_case->name(); - test_case->set_should_run(false); - - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - TestInfo* const test_info = test_case->test_info_list()[j]; - const String test_name(test_info->name()); - // A test is disabled if test case name or test name matches - // kDisableTestFilter. - const bool is_disabled = - internal::UnitTestOptions::MatchesFilter(test_case_name, - kDisableTestFilter) || - internal::UnitTestOptions::MatchesFilter(test_name, - kDisableTestFilter); - test_info->is_disabled_ = is_disabled; - - const bool matches_filter = - internal::UnitTestOptions::FilterMatchesTest(test_case_name, - test_name); - test_info->matches_filter_ = matches_filter; - - const bool is_runnable = - (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && - matches_filter; - - const bool is_selected = is_runnable && - (shard_tests == IGNORE_SHARDING_PROTOCOL || - ShouldRunTestOnShard(total_shards, shard_index, - num_runnable_tests)); - - num_runnable_tests += is_runnable; - num_selected_tests += is_selected; - - test_info->should_run_ = is_selected; - test_case->set_should_run(test_case->should_run() || is_selected); - } - } - return num_selected_tests; -} - -// Prints the names of the tests matching the user-specified filter flag. -void UnitTestImpl::ListTestsMatchingFilter() { - for (size_t i = 0; i < test_cases_.size(); i++) { - const TestCase* const test_case = test_cases_[i]; - bool printed_test_case_name = false; - - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - const TestInfo* const test_info = - test_case->test_info_list()[j]; - if (test_info->matches_filter_) { - if (!printed_test_case_name) { - printed_test_case_name = true; - printf("%s.\n", test_case->name()); - } - printf(" %s\n", test_info->name()); - } - } - } - fflush(stdout); -} - -// Sets the OS stack trace getter. -// -// Does nothing if the input and the current OS stack trace getter are -// the same; otherwise, deletes the old getter and makes the input the -// current getter. -void UnitTestImpl::set_os_stack_trace_getter( - OsStackTraceGetterInterface* getter) { - if (os_stack_trace_getter_ != getter) { - delete os_stack_trace_getter_; - os_stack_trace_getter_ = getter; - } -} - -// Returns the current OS stack trace getter if it is not NULL; -// otherwise, creates an OsStackTraceGetter, makes it the current -// getter, and returns it. -OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { - if (os_stack_trace_getter_ == NULL) { - os_stack_trace_getter_ = new OsStackTraceGetter; - } - - return os_stack_trace_getter_; -} - -// Returns the TestResult for the test that's currently running, or -// the TestResult for the ad hoc test if no test is running. -TestResult* UnitTestImpl::current_test_result() { - return current_test_info_ ? - &(current_test_info_->result_) : &ad_hoc_test_result_; -} - -// Shuffles all test cases, and the tests within each test case, -// making sure that death tests are still run first. -void UnitTestImpl::ShuffleTests() { - // Shuffles the death test cases. - ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); - - // Shuffles the non-death test cases. - ShuffleRange(random(), last_death_test_case_ + 1, - static_cast(test_cases_.size()), &test_case_indices_); - - // Shuffles the tests inside each test case. - for (size_t i = 0; i < test_cases_.size(); i++) { - test_cases_[i]->ShuffleTests(random()); - } -} - -// Restores the test cases and tests to their order before the first shuffle. -void UnitTestImpl::UnshuffleTests() { - for (size_t i = 0; i < test_cases_.size(); i++) { - // Unshuffles the tests in each test case. - test_cases_[i]->UnshuffleTests(); - // Resets the index of each test case. - test_case_indices_[i] = static_cast(i); - } -} - -// Returns the current OS stack trace as a String. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in -// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, - int skip_count) { - // We pass skip_count + 1 to skip this wrapper function in addition - // to what the user really wants to skip. - return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); -} - -// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to -// suppress unreachable code warnings. -namespace { -class ClassUniqueToAlwaysTrue {}; -} - -bool IsTrue(bool condition) { return condition; } - -bool AlwaysTrue() { -#if GTEST_HAS_EXCEPTIONS - // This condition is always false so AlwaysTrue() never actually throws, - // but it makes the compiler think that it may throw. - if (IsTrue(false)) - throw ClassUniqueToAlwaysTrue(); -#endif // GTEST_HAS_EXCEPTIONS - return true; -} - -// If *pstr starts with the given prefix, modifies *pstr to be right -// past the prefix and returns true; otherwise leaves *pstr unchanged -// and returns false. None of pstr, *pstr, and prefix can be NULL. -bool SkipPrefix(const char* prefix, const char** pstr) { - const size_t prefix_len = strlen(prefix); - if (strncmp(*pstr, prefix, prefix_len) == 0) { - *pstr += prefix_len; - return true; - } - return false; -} - -// Parses a string as a command line flag. The string should have -// the format "--flag=value". When def_optional is true, the "=value" -// part can be omitted. -// -// Returns the value of the flag, or NULL if the parsing failed. -const char* ParseFlagValue(const char* str, - const char* flag, - bool def_optional) { - // str and flag must not be NULL. - if (str == NULL || flag == NULL) return NULL; - - // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. - const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); - const size_t flag_len = flag_str.length(); - if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; - - // Skips the flag name. - const char* flag_end = str + flag_len; - - // When def_optional is true, it's OK to not have a "=value" part. - if (def_optional && (flag_end[0] == '\0')) { - return flag_end; - } - - // If def_optional is true and there are more characters after the - // flag name, or if def_optional is false, there must be a '=' after - // the flag name. - if (flag_end[0] != '=') return NULL; - - // Returns the string after "=". - return flag_end + 1; -} - -// Parses a string for a bool flag, in the form of either -// "--flag=value" or "--flag". -// -// In the former case, the value is taken as true as long as it does -// not start with '0', 'f', or 'F'. -// -// In the latter case, the value is taken as true. -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseBoolFlag(const char* str, const char* flag, bool* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, true); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Converts the string value to a bool. - *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); - return true; -} - -// Parses a string for an Int32 flag, in the form of -// "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, false); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Sets *value to the value of the flag. - return ParseInt32(Message() << "The value of flag --" << flag, - value_str, value); -} - -// Parses a string for a string flag, in the form of -// "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseStringFlag(const char* str, const char* flag, String* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, false); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Sets *value to the value of the flag. - *value = value_str; - return true; -} - -// Determines whether a string has a prefix that Google Test uses for its -// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. -// If Google Test detects that a command line flag has its prefix but is not -// recognized, it will print its help message. Flags starting with -// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test -// internal flags and do not trigger the help message. -static bool HasGoogleTestFlagPrefix(const char* str) { - return (SkipPrefix("--", &str) || - SkipPrefix("-", &str) || - SkipPrefix("/", &str)) && - !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && - (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || - SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); -} - -// Prints a string containing code-encoded text. The following escape -// sequences can be used in the string to control the text color: -// -// @@ prints a single '@' character. -// @R changes the color to red. -// @G changes the color to green. -// @Y changes the color to yellow. -// @D changes to the default terminal text color. -// -// TODO(wan@google.com): Write tests for this once we add stdout -// capturing to Google Test. -static void PrintColorEncoded(const char* str) { - GTestColor color = COLOR_DEFAULT; // The current color. - - // Conceptually, we split the string into segments divided by escape - // sequences. Then we print one segment at a time. At the end of - // each iteration, the str pointer advances to the beginning of the - // next segment. - for (;;) { - const char* p = strchr(str, '@'); - if (p == NULL) { - ColoredPrintf(color, "%s", str); - return; - } - - ColoredPrintf(color, "%s", String(str, p - str).c_str()); - - const char ch = p[1]; - str = p + 2; - if (ch == '@') { - ColoredPrintf(color, "@"); - } else if (ch == 'D') { - color = COLOR_DEFAULT; - } else if (ch == 'R') { - color = COLOR_RED; - } else if (ch == 'G') { - color = COLOR_GREEN; - } else if (ch == 'Y') { - color = COLOR_YELLOW; - } else { - --str; - } - } -} - -static const char kColorEncodedHelpMessage[] = -"This program contains tests written using " GTEST_NAME_ ". You can use the\n" -"following command line flags to control its behavior:\n" -"\n" -"Test Selection:\n" -" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" -" List the names of all tests instead of running them. The name of\n" -" TEST(Foo, Bar) is \"Foo.Bar\".\n" -" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" - "[@G-@YNEGATIVE_PATTERNS]@D\n" -" Run only the tests whose name matches one of the positive patterns but\n" -" none of the negative patterns. '?' matches any single character; '*'\n" -" matches any substring; ':' separates two patterns.\n" -" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" -" Run all disabled tests too.\n" -"\n" -"Test Execution:\n" -" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" -" Run the tests repeatedly; use a negative count to repeat forever.\n" -" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" -" Randomize tests' orders on every iteration.\n" -" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" -" Random number seed to use for shuffling test orders (between 1 and\n" -" 99999, or 0 to use a seed based on the current time).\n" -"\n" -"Test Output:\n" -" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" -" Enable/disable colored output. The default is @Gauto@D.\n" -" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" -" Don't print the elapsed time of each test.\n" -" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" - GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" -" Generate an XML report in the given directory or with the given file\n" -" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" -#if GTEST_CAN_STREAM_RESULTS_ -" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" -" Stream test results to the given server.\n" -#endif // GTEST_CAN_STREAM_RESULTS_ -"\n" -"Assertion Behavior:\n" -#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" -" Set the default death test style.\n" -#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" -" Turn assertion failures into debugger break-points.\n" -" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -" Turn assertion failures into C++ exceptions.\n" -" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" -" Do not report exceptions as test failures. Instead, allow them\n" -" to crash the program or throw a pop-up (on Windows).\n" -"\n" -"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " - "the corresponding\n" -"environment variable of a flag (all letters in upper-case). For example, to\n" -"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ - "color=no@D or set\n" -"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" -"\n" -"For more information, please read the " GTEST_NAME_ " documentation at\n" -"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" -"(not one in your own code or tests), please report it to\n" -"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. The type parameter CharType can be -// instantiated to either char or wchar_t. -template -void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { - for (int i = 1; i < *argc; i++) { - const String arg_string = StreamableToString(argv[i]); - const char* const arg = arg_string.c_str(); - - using internal::ParseBoolFlag; - using internal::ParseInt32Flag; - using internal::ParseStringFlag; - - // Do we see a Google Test flag? - if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, - >EST_FLAG(also_run_disabled_tests)) || - ParseBoolFlag(arg, kBreakOnFailureFlag, - >EST_FLAG(break_on_failure)) || - ParseBoolFlag(arg, kCatchExceptionsFlag, - >EST_FLAG(catch_exceptions)) || - ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || - ParseStringFlag(arg, kDeathTestStyleFlag, - >EST_FLAG(death_test_style)) || - ParseBoolFlag(arg, kDeathTestUseFork, - >EST_FLAG(death_test_use_fork)) || - ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || - ParseStringFlag(arg, kInternalRunDeathTestFlag, - >EST_FLAG(internal_run_death_test)) || - ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || - ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || - ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || - ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || - ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || - ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || - ParseInt32Flag(arg, kStackTraceDepthFlag, - >EST_FLAG(stack_trace_depth)) || - ParseStringFlag(arg, kStreamResultToFlag, - >EST_FLAG(stream_result_to)) || - ParseBoolFlag(arg, kThrowOnFailureFlag, - >EST_FLAG(throw_on_failure)) - ) { - // Yes. Shift the remainder of the argv list left by one. Note - // that argv has (*argc + 1) elements, the last one always being - // NULL. The following loop moves the trailing NULL element as - // well. - for (int j = i; j != *argc; j++) { - argv[j] = argv[j + 1]; - } - - // Decrements the argument count. - (*argc)--; - - // We also need to decrement the iterator as we just removed - // an element. - i--; - } else if (arg_string == "--help" || arg_string == "-h" || - arg_string == "-?" || arg_string == "/?" || - HasGoogleTestFlagPrefix(arg)) { - // Both help flag and unrecognized Google Test flags (excluding - // internal ones) trigger help display. - g_help_flag = true; - } - } - - if (g_help_flag) { - // We print the help here instead of in RUN_ALL_TESTS(), as the - // latter may not be called at all if the user is using Google - // Test with another testing framework. - PrintColorEncoded(kColorEncodedHelpMessage); - } -} - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. -void ParseGoogleTestFlagsOnly(int* argc, char** argv) { - ParseGoogleTestFlagsOnlyImpl(argc, argv); -} -void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { - ParseGoogleTestFlagsOnlyImpl(argc, argv); -} - -// The internal implementation of InitGoogleTest(). -// -// The type parameter CharType can be instantiated to either char or -// wchar_t. -template -void InitGoogleTestImpl(int* argc, CharType** argv) { - g_init_gtest_count++; - - // We don't want to run the initialization code twice. - if (g_init_gtest_count != 1) return; - - if (*argc <= 0) return; - - internal::g_executable_path = internal::StreamableToString(argv[0]); - -#if GTEST_HAS_DEATH_TEST - - g_argvs.clear(); - for (int i = 0; i != *argc; i++) { - g_argvs.push_back(StreamableToString(argv[i])); - } - -#endif // GTEST_HAS_DEATH_TEST - - ParseGoogleTestFlagsOnly(argc, argv); - GetUnitTestImpl()->PostFlagParsingInit(); -} - -} // namespace internal - -// Initializes Google Test. This must be called before calling -// RUN_ALL_TESTS(). In particular, it parses a command line for the -// flags that Google Test recognizes. Whenever a Google Test flag is -// seen, it is removed from argv, and *argc is decremented. -// -// No value is returned. Instead, the Google Test flag variables are -// updated. -// -// Calling the function for the second time has no user-visible effect. -void InitGoogleTest(int* argc, char** argv) { - internal::InitGoogleTestImpl(argc, argv); -} - -// This overloaded version can be used in Windows programs compiled in -// UNICODE mode. -void InitGoogleTest(int* argc, wchar_t** argv) { - internal::InitGoogleTestImpl(argc, argv); -} - -} // namespace testing diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h b/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h deleted file mode 100644 index 6554cfc..0000000 --- a/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h +++ /dev/null @@ -1,1037 +0,0 @@ -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Utility functions and classes used by the Google C++ testing framework. -// -// Author: wan@google.com (Zhanyong Wan) -// -// This file contains purely Google Test's internal implementation. Please -// DO NOT #INCLUDE IT IN A USER PROGRAM. - -#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ -#define GTEST_SRC_GTEST_INTERNAL_INL_H_ - -// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is -// part of Google Test's implementation; otherwise it's undefined. -#if !GTEST_IMPLEMENTATION_ -// A user is trying to include this from his code - just say no. -# error "gtest-internal-inl.h is part of Google Test's internal implementation." -# error "It must not be included except by Google Test itself." -#endif // GTEST_IMPLEMENTATION_ - -#ifndef _WIN32_WCE -# include -#endif // !_WIN32_WCE -#include -#include // For strtoll/_strtoul64/malloc/free. -#include // For memmove. - -#include -#include -#include - -#include "gtest/internal/gtest-port.h" - -#if GTEST_OS_WINDOWS -# include // NOLINT -#endif // GTEST_OS_WINDOWS - -#include "gtest/gtest.h" // NOLINT -#include "gtest/gtest-spi.h" - -namespace testing { - -// Declares the flags. -// -// We don't want the users to modify this flag in the code, but want -// Google Test's own unit tests to be able to access it. Therefore we -// declare it here as opposed to in gtest.h. -GTEST_DECLARE_bool_(death_test_use_fork); - -namespace internal { - -// The value of GetTestTypeId() as seen from within the Google Test -// library. This is solely for testing GetTestTypeId(). -GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; - -// Names of the flags (needed for parsing Google Test flags). -const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; -const char kBreakOnFailureFlag[] = "break_on_failure"; -const char kCatchExceptionsFlag[] = "catch_exceptions"; -const char kColorFlag[] = "color"; -const char kFilterFlag[] = "filter"; -const char kListTestsFlag[] = "list_tests"; -const char kOutputFlag[] = "output"; -const char kPrintTimeFlag[] = "print_time"; -const char kRandomSeedFlag[] = "random_seed"; -const char kRepeatFlag[] = "repeat"; -const char kShuffleFlag[] = "shuffle"; -const char kStackTraceDepthFlag[] = "stack_trace_depth"; -const char kStreamResultToFlag[] = "stream_result_to"; -const char kThrowOnFailureFlag[] = "throw_on_failure"; - -// A valid random seed must be in [1, kMaxRandomSeed]. -const int kMaxRandomSeed = 99999; - -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. -GTEST_API_ extern bool g_help_flag; - -// Returns the current time in milliseconds. -GTEST_API_ TimeInMillis GetTimeInMillis(); - -// Returns true iff Google Test should use colors in the output. -GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); - -// Formats the given time in milliseconds as seconds. -GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); - -// Parses a string for an Int32 flag, in the form of "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -GTEST_API_ bool ParseInt32Flag( - const char* str, const char* flag, Int32* value); - -// Returns a random seed in range [1, kMaxRandomSeed] based on the -// given --gtest_random_seed flag value. -inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { - const unsigned int raw_seed = (random_seed_flag == 0) ? - static_cast(GetTimeInMillis()) : - static_cast(random_seed_flag); - - // Normalizes the actual seed to range [1, kMaxRandomSeed] such that - // it's easy to type. - const int normalized_seed = - static_cast((raw_seed - 1U) % - static_cast(kMaxRandomSeed)) + 1; - return normalized_seed; -} - -// Returns the first valid random seed after 'seed'. The behavior is -// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is -// considered to be 1. -inline int GetNextRandomSeed(int seed) { - GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) - << "Invalid random seed " << seed << " - must be in [1, " - << kMaxRandomSeed << "]."; - const int next_seed = seed + 1; - return (next_seed > kMaxRandomSeed) ? 1 : next_seed; -} - -// This class saves the values of all Google Test flags in its c'tor, and -// restores them in its d'tor. -class GTestFlagSaver { - public: - // The c'tor. - GTestFlagSaver() { - also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); - break_on_failure_ = GTEST_FLAG(break_on_failure); - catch_exceptions_ = GTEST_FLAG(catch_exceptions); - color_ = GTEST_FLAG(color); - death_test_style_ = GTEST_FLAG(death_test_style); - death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); - filter_ = GTEST_FLAG(filter); - internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); - list_tests_ = GTEST_FLAG(list_tests); - output_ = GTEST_FLAG(output); - print_time_ = GTEST_FLAG(print_time); - random_seed_ = GTEST_FLAG(random_seed); - repeat_ = GTEST_FLAG(repeat); - shuffle_ = GTEST_FLAG(shuffle); - stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); - stream_result_to_ = GTEST_FLAG(stream_result_to); - throw_on_failure_ = GTEST_FLAG(throw_on_failure); - } - - // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. - ~GTestFlagSaver() { - GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; - GTEST_FLAG(break_on_failure) = break_on_failure_; - GTEST_FLAG(catch_exceptions) = catch_exceptions_; - GTEST_FLAG(color) = color_; - GTEST_FLAG(death_test_style) = death_test_style_; - GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; - GTEST_FLAG(filter) = filter_; - GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; - GTEST_FLAG(list_tests) = list_tests_; - GTEST_FLAG(output) = output_; - GTEST_FLAG(print_time) = print_time_; - GTEST_FLAG(random_seed) = random_seed_; - GTEST_FLAG(repeat) = repeat_; - GTEST_FLAG(shuffle) = shuffle_; - GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; - GTEST_FLAG(stream_result_to) = stream_result_to_; - GTEST_FLAG(throw_on_failure) = throw_on_failure_; - } - private: - // Fields for saving the original values of flags. - bool also_run_disabled_tests_; - bool break_on_failure_; - bool catch_exceptions_; - String color_; - String death_test_style_; - bool death_test_use_fork_; - String filter_; - String internal_run_death_test_; - bool list_tests_; - String output_; - bool print_time_; - internal::Int32 random_seed_; - internal::Int32 repeat_; - bool shuffle_; - internal::Int32 stack_trace_depth_; - String stream_result_to_; - bool throw_on_failure_; -} GTEST_ATTRIBUTE_UNUSED_; - -// Converts a Unicode code point to a narrow string in UTF-8 encoding. -// code_point parameter is of type UInt32 because wchar_t may not be -// wide enough to contain a code point. -// The output buffer str must containt at least 32 characters. -// The function returns the address of the output buffer. -// If the code_point is not a valid Unicode code point -// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. -GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); - -// Converts a wide string to a narrow string in UTF-8 encoding. -// The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) -// UTF-32 if sizeof(wchar_t) == 4 (on Linux) -// Parameter str points to a null-terminated wide string. -// Parameter num_chars may additionally limit the number -// of wchar_t characters processed. -1 is used when the entire string -// should be processed. -// If the string contains code points that are not valid Unicode code points -// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding -// and contains invalid UTF-16 surrogate pairs, values in those pairs -// will be encoded as individual Unicode characters from Basic Normal Plane. -GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); - -// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file -// if the variable is present. If a file already exists at this location, this -// function will write over it. If the variable is present, but the file cannot -// be created, prints an error and exits. -void WriteToShardStatusFileIfNeeded(); - -// Checks whether sharding is enabled by examining the relevant -// environment variable values. If the variables are present, -// but inconsistent (e.g., shard_index >= total_shards), prints -// an error and exits. If in_subprocess_for_death_test, sharding is -// disabled because it must only be applied to the original test -// process. Otherwise, we could filter out death tests we intended to execute. -GTEST_API_ bool ShouldShard(const char* total_shards_str, - const char* shard_index_str, - bool in_subprocess_for_death_test); - -// Parses the environment variable var as an Int32. If it is unset, -// returns default_val. If it is not an Int32, prints an error and -// and aborts. -GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); - -// Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test -// method. Assumes that 0 <= shard_index < total_shards. -GTEST_API_ bool ShouldRunTestOnShard( - int total_shards, int shard_index, int test_id); - -// STL container utilities. - -// Returns the number of elements in the given container that satisfy -// the given predicate. -template -inline int CountIf(const Container& c, Predicate predicate) { - // Implemented as an explicit loop since std::count_if() in libCstd on - // Solaris has a non-standard signature. - int count = 0; - for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { - if (predicate(*it)) - ++count; - } - return count; -} - -// Applies a function/functor to each element in the container. -template -void ForEach(const Container& c, Functor functor) { - std::for_each(c.begin(), c.end(), functor); -} - -// Returns the i-th element of the vector, or default_value if i is not -// in range [0, v.size()). -template -inline E GetElementOr(const std::vector& v, int i, E default_value) { - return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; -} - -// Performs an in-place shuffle of a range of the vector's elements. -// 'begin' and 'end' are element indices as an STL-style range; -// i.e. [begin, end) are shuffled, where 'end' == size() means to -// shuffle to the end of the vector. -template -void ShuffleRange(internal::Random* random, int begin, int end, - std::vector* v) { - const int size = static_cast(v->size()); - GTEST_CHECK_(0 <= begin && begin <= size) - << "Invalid shuffle range start " << begin << ": must be in range [0, " - << size << "]."; - GTEST_CHECK_(begin <= end && end <= size) - << "Invalid shuffle range finish " << end << ": must be in range [" - << begin << ", " << size << "]."; - - // Fisher-Yates shuffle, from - // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle - for (int range_width = end - begin; range_width >= 2; range_width--) { - const int last_in_range = begin + range_width - 1; - const int selected = begin + random->Generate(range_width); - std::swap((*v)[selected], (*v)[last_in_range]); - } -} - -// Performs an in-place shuffle of the vector's elements. -template -inline void Shuffle(internal::Random* random, std::vector* v) { - ShuffleRange(random, 0, static_cast(v->size()), v); -} - -// A function for deleting an object. Handy for being used as a -// functor. -template -static void Delete(T* x) { - delete x; -} - -// A predicate that checks the key of a TestProperty against a known key. -// -// TestPropertyKeyIs is copyable. -class TestPropertyKeyIs { - public: - // Constructor. - // - // TestPropertyKeyIs has NO default constructor. - explicit TestPropertyKeyIs(const char* key) - : key_(key) {} - - // Returns true iff the test name of test property matches on key_. - bool operator()(const TestProperty& test_property) const { - return String(test_property.key()).Compare(key_) == 0; - } - - private: - String key_; -}; - -// Class UnitTestOptions. -// -// This class contains functions for processing options the user -// specifies when running the tests. It has only static members. -// -// In most cases, the user can specify an option using either an -// environment variable or a command line flag. E.g. you can set the -// test filter using either GTEST_FILTER or --gtest_filter. If both -// the variable and the flag are present, the latter overrides the -// former. -class GTEST_API_ UnitTestOptions { - public: - // Functions for processing the gtest_output flag. - - // Returns the output format, or "" for normal printed output. - static String GetOutputFormat(); - - // Returns the absolute path of the requested output file, or the - // default (test_detail.xml in the original working directory) if - // none was explicitly specified. - static String GetAbsolutePathToOutputFile(); - - // Functions for processing the gtest_filter flag. - - // Returns true iff the wildcard pattern matches the string. The - // first ':' or '\0' character in pattern marks the end of it. - // - // This recursive algorithm isn't very efficient, but is clear and - // works well enough for matching test names, which are short. - static bool PatternMatchesString(const char *pattern, const char *str); - - // Returns true iff the user-specified filter matches the test case - // name and the test name. - static bool FilterMatchesTest(const String &test_case_name, - const String &test_name); - -#if GTEST_OS_WINDOWS - // Function for supporting the gtest_catch_exception flag. - - // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the - // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. - // This function is useful as an __except condition. - static int GTestShouldProcessSEH(DWORD exception_code); -#endif // GTEST_OS_WINDOWS - - // Returns true if "name" matches the ':' separated list of glob-style - // filters in "filter". - static bool MatchesFilter(const String& name, const char* filter); -}; - -// Returns the current application's name, removing directory path if that -// is present. Used by UnitTestOptions::GetOutputFile. -GTEST_API_ FilePath GetCurrentExecutableName(); - -// The role interface for getting the OS stack trace as a string. -class OsStackTraceGetterInterface { - public: - OsStackTraceGetterInterface() {} - virtual ~OsStackTraceGetterInterface() {} - - // Returns the current OS stack trace as a String. Parameters: - // - // max_depth - the maximum number of stack frames to be included - // in the trace. - // skip_count - the number of top frames to be skipped; doesn't count - // against max_depth. - virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; - - // UponLeavingGTest() should be called immediately before Google Test calls - // user code. It saves some information about the current stack that - // CurrentStackTrace() will use to find and hide Google Test stack frames. - virtual void UponLeavingGTest() = 0; - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); -}; - -// A working implementation of the OsStackTraceGetterInterface interface. -class OsStackTraceGetter : public OsStackTraceGetterInterface { - public: - OsStackTraceGetter() : caller_frame_(NULL) {} - virtual String CurrentStackTrace(int max_depth, int skip_count); - virtual void UponLeavingGTest(); - - // This string is inserted in place of stack frames that are part of - // Google Test's implementation. - static const char* const kElidedFramesMarker; - - private: - Mutex mutex_; // protects all internal state - - // We save the stack frame below the frame that calls user code. - // We do this because the address of the frame immediately below - // the user code changes between the call to UponLeavingGTest() - // and any calls to CurrentStackTrace() from within the user code. - void* caller_frame_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); -}; - -// Information about a Google Test trace point. -struct TraceInfo { - const char* file; - int line; - String message; -}; - -// This is the default global test part result reporter used in UnitTestImpl. -// This class should only be used by UnitTestImpl. -class DefaultGlobalTestPartResultReporter - : public TestPartResultReporterInterface { - public: - explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); - // Implements the TestPartResultReporterInterface. Reports the test part - // result in the current test. - virtual void ReportTestPartResult(const TestPartResult& result); - - private: - UnitTestImpl* const unit_test_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); -}; - -// This is the default per thread test part result reporter used in -// UnitTestImpl. This class should only be used by UnitTestImpl. -class DefaultPerThreadTestPartResultReporter - : public TestPartResultReporterInterface { - public: - explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); - // Implements the TestPartResultReporterInterface. The implementation just - // delegates to the current global test part result reporter of *unit_test_. - virtual void ReportTestPartResult(const TestPartResult& result); - - private: - UnitTestImpl* const unit_test_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); -}; - -// The private implementation of the UnitTest class. We don't protect -// the methods under a mutex, as this class is not accessible by a -// user and the UnitTest class that delegates work to this class does -// proper locking. -class GTEST_API_ UnitTestImpl { - public: - explicit UnitTestImpl(UnitTest* parent); - virtual ~UnitTestImpl(); - - // There are two different ways to register your own TestPartResultReporter. - // You can register your own repoter to listen either only for test results - // from the current thread or for results from all threads. - // By default, each per-thread test result repoter just passes a new - // TestPartResult to the global test result reporter, which registers the - // test part result for the currently running test. - - // Returns the global test part result reporter. - TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); - - // Sets the global test part result reporter. - void SetGlobalTestPartResultReporter( - TestPartResultReporterInterface* reporter); - - // Returns the test part result reporter for the current thread. - TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); - - // Sets the test part result reporter for the current thread. - void SetTestPartResultReporterForCurrentThread( - TestPartResultReporterInterface* reporter); - - // Gets the number of successful test cases. - int successful_test_case_count() const; - - // Gets the number of failed test cases. - int failed_test_case_count() const; - - // Gets the number of all test cases. - int total_test_case_count() const; - - // Gets the number of all test cases that contain at least one test - // that should run. - int test_case_to_run_count() const; - - // Gets the number of successful tests. - int successful_test_count() const; - - // Gets the number of failed tests. - int failed_test_count() const; - - // Gets the number of disabled tests. - int disabled_test_count() const; - - // Gets the number of all tests. - int total_test_count() const; - - // Gets the number of tests that should run. - int test_to_run_count() const; - - // Gets the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Returns true iff the unit test passed (i.e. all test cases passed). - bool Passed() const { return !Failed(); } - - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). - bool Failed() const { - return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); - } - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[i]; - } - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i) { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[index]; - } - - // Provides access to the event listener list. - TestEventListeners* listeners() { return &listeners_; } - - // Returns the TestResult for the test that's currently running, or - // the TestResult for the ad hoc test if no test is running. - TestResult* current_test_result(); - - // Returns the TestResult for the ad hoc test. - const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } - - // Sets the OS stack trace getter. - // - // Does nothing if the input and the current OS stack trace getter - // are the same; otherwise, deletes the old getter and makes the - // input the current getter. - void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); - - // Returns the current OS stack trace getter if it is not NULL; - // otherwise, creates an OsStackTraceGetter, makes it the current - // getter, and returns it. - OsStackTraceGetterInterface* os_stack_trace_getter(); - - // Returns the current OS stack trace as a String. - // - // The maximum number of stack frames to be included is specified by - // the gtest_stack_trace_depth flag. The skip_count parameter - // specifies the number of top frames to be skipped, which doesn't - // count against the number of frames to be included. - // - // For example, if Foo() calls Bar(), which in turn calls - // CurrentOsStackTraceExceptTop(1), Foo() will be included in the - // trace but Bar() and CurrentOsStackTraceExceptTop() won't. - String CurrentOsStackTraceExceptTop(int skip_count); - - // Finds and returns a TestCase with the given name. If one doesn't - // exist, creates one and returns it. - // - // Arguments: - // - // test_case_name: name of the test case - // type_param: the name of the test's type parameter, or NULL if - // this is not a typed or a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase* GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); - - // Adds a TestInfo to the unit test. - // - // Arguments: - // - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - // test_info: the TestInfo object - void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, - TestInfo* test_info) { - // In order to support thread-safe death tests, we need to - // remember the original working directory when the test program - // was first invoked. We cannot do this in RUN_ALL_TESTS(), as - // the user may have changed the current directory before calling - // RUN_ALL_TESTS(). Therefore we capture the current directory in - // AddTestInfo(), which is called to register a TEST or TEST_F - // before main() is reached. - if (original_working_dir_.IsEmpty()) { - original_working_dir_.Set(FilePath::GetCurrentDir()); - GTEST_CHECK_(!original_working_dir_.IsEmpty()) - << "Failed to get the current working directory."; - } - - GetTestCase(test_info->test_case_name(), - test_info->type_param(), - set_up_tc, - tear_down_tc)->AddTestInfo(test_info); - } - -#if GTEST_HAS_PARAM_TEST - // Returns ParameterizedTestCaseRegistry object used to keep track of - // value-parameterized tests and instantiate and register them. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { - return parameterized_test_registry_; - } -#endif // GTEST_HAS_PARAM_TEST - - // Sets the TestCase object for the test that's currently running. - void set_current_test_case(TestCase* a_current_test_case) { - current_test_case_ = a_current_test_case; - } - - // Sets the TestInfo object for the test that's currently running. If - // current_test_info is NULL, the assertion results will be stored in - // ad_hoc_test_result_. - void set_current_test_info(TestInfo* a_current_test_info) { - current_test_info_ = a_current_test_info; - } - - // Registers all parameterized tests defined using TEST_P and - // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter - // combination. This method can be called more then once; it has guards - // protecting from registering the tests more then once. If - // value-parameterized tests are disabled, RegisterParameterizedTests is - // present but does nothing. - void RegisterParameterizedTests(); - - // Runs all tests in this UnitTest object, prints the result, and - // returns true if all tests are successful. If any exception is - // thrown during a test, this test is considered to be failed, but - // the rest of the tests will still be run. - bool RunAllTests(); - - // Clears the results of all tests, except the ad hoc tests. - void ClearNonAdHocTestResult() { - ForEach(test_cases_, TestCase::ClearTestCaseResult); - } - - // Clears the results of ad-hoc test assertions. - void ClearAdHocTestResult() { - ad_hoc_test_result_.Clear(); - } - - enum ReactionToSharding { - HONOR_SHARDING_PROTOCOL, - IGNORE_SHARDING_PROTOCOL - }; - - // Matches the full name of each test against the user-specified - // filter to decide whether the test should run, then records the - // result in each TestCase and TestInfo object. - // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests - // based on sharding variables in the environment. - // Returns the number of tests that should run. - int FilterTests(ReactionToSharding shard_tests); - - // Prints the names of the tests matching the user-specified filter flag. - void ListTestsMatchingFilter(); - - const TestCase* current_test_case() const { return current_test_case_; } - TestInfo* current_test_info() { return current_test_info_; } - const TestInfo* current_test_info() const { return current_test_info_; } - - // Returns the vector of environments that need to be set-up/torn-down - // before/after the tests are run. - std::vector& environments() { return environments_; } - - // Getters for the per-thread Google Test trace stack. - std::vector& gtest_trace_stack() { - return *(gtest_trace_stack_.pointer()); - } - const std::vector& gtest_trace_stack() const { - return gtest_trace_stack_.get(); - } - -#if GTEST_HAS_DEATH_TEST - void InitDeathTestSubprocessControlInfo() { - internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); - } - // Returns a pointer to the parsed --gtest_internal_run_death_test - // flag, or NULL if that flag was not specified. - // This information is useful only in a death test child process. - // Must not be called before a call to InitGoogleTest. - const InternalRunDeathTestFlag* internal_run_death_test_flag() const { - return internal_run_death_test_flag_.get(); - } - - // Returns a pointer to the current death test factory. - internal::DeathTestFactory* death_test_factory() { - return death_test_factory_.get(); - } - - void SuppressTestEventsIfInSubprocess(); - - friend class ReplaceDeathTestFactory; -#endif // GTEST_HAS_DEATH_TEST - - // Initializes the event listener performing XML output as specified by - // UnitTestOptions. Must not be called before InitGoogleTest. - void ConfigureXmlOutput(); - -#if GTEST_CAN_STREAM_RESULTS_ - // Initializes the event listener for streaming test results to a socket. - // Must not be called before InitGoogleTest. - void ConfigureStreamingOutput(); -#endif - - // Performs initialization dependent upon flag values obtained in - // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to - // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest - // this function is also called from RunAllTests. Since this function can be - // called more than once, it has to be idempotent. - void PostFlagParsingInit(); - - // Gets the random seed used at the start of the current test iteration. - int random_seed() const { return random_seed_; } - - // Gets the random number generator. - internal::Random* random() { return &random_; } - - // Shuffles all test cases, and the tests within each test case, - // making sure that death tests are still run first. - void ShuffleTests(); - - // Restores the test cases and tests to their order before the first shuffle. - void UnshuffleTests(); - - // Returns the value of GTEST_FLAG(catch_exceptions) at the moment - // UnitTest::Run() starts. - bool catch_exceptions() const { return catch_exceptions_; } - - private: - friend class ::testing::UnitTest; - - // Used by UnitTest::Run() to capture the state of - // GTEST_FLAG(catch_exceptions) at the moment it starts. - void set_catch_exceptions(bool value) { catch_exceptions_ = value; } - - // The UnitTest object that owns this implementation object. - UnitTest* const parent_; - - // The working directory when the first TEST() or TEST_F() was - // executed. - internal::FilePath original_working_dir_; - - // The default test part result reporters. - DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; - DefaultPerThreadTestPartResultReporter - default_per_thread_test_part_result_reporter_; - - // Points to (but doesn't own) the global test part result reporter. - TestPartResultReporterInterface* global_test_part_result_repoter_; - - // Protects read and write access to global_test_part_result_reporter_. - internal::Mutex global_test_part_result_reporter_mutex_; - - // Points to (but doesn't own) the per-thread test part result reporter. - internal::ThreadLocal - per_thread_test_part_result_reporter_; - - // The vector of environments that need to be set-up/torn-down - // before/after the tests are run. - std::vector environments_; - - // The vector of TestCases in their original order. It owns the - // elements in the vector. - std::vector test_cases_; - - // Provides a level of indirection for the test case list to allow - // easy shuffling and restoring the test case order. The i-th - // element of this vector is the index of the i-th test case in the - // shuffled order. - std::vector test_case_indices_; - -#if GTEST_HAS_PARAM_TEST - // ParameterizedTestRegistry object used to register value-parameterized - // tests. - internal::ParameterizedTestCaseRegistry parameterized_test_registry_; - - // Indicates whether RegisterParameterizedTests() has been called already. - bool parameterized_tests_registered_; -#endif // GTEST_HAS_PARAM_TEST - - // Index of the last death test case registered. Initially -1. - int last_death_test_case_; - - // This points to the TestCase for the currently running test. It - // changes as Google Test goes through one test case after another. - // When no test is running, this is set to NULL and Google Test - // stores assertion results in ad_hoc_test_result_. Initially NULL. - TestCase* current_test_case_; - - // This points to the TestInfo for the currently running test. It - // changes as Google Test goes through one test after another. When - // no test is running, this is set to NULL and Google Test stores - // assertion results in ad_hoc_test_result_. Initially NULL. - TestInfo* current_test_info_; - - // Normally, a user only writes assertions inside a TEST or TEST_F, - // or inside a function called by a TEST or TEST_F. Since Google - // Test keeps track of which test is current running, it can - // associate such an assertion with the test it belongs to. - // - // If an assertion is encountered when no TEST or TEST_F is running, - // Google Test attributes the assertion result to an imaginary "ad hoc" - // test, and records the result in ad_hoc_test_result_. - TestResult ad_hoc_test_result_; - - // The list of event listeners that can be used to track events inside - // Google Test. - TestEventListeners listeners_; - - // The OS stack trace getter. Will be deleted when the UnitTest - // object is destructed. By default, an OsStackTraceGetter is used, - // but the user can set this field to use a custom getter if that is - // desired. - OsStackTraceGetterInterface* os_stack_trace_getter_; - - // True iff PostFlagParsingInit() has been called. - bool post_flag_parse_init_performed_; - - // The random number seed used at the beginning of the test run. - int random_seed_; - - // Our random number generator. - internal::Random random_; - - // How long the test took to run, in milliseconds. - TimeInMillis elapsed_time_; - -#if GTEST_HAS_DEATH_TEST - // The decomposed components of the gtest_internal_run_death_test flag, - // parsed when RUN_ALL_TESTS is called. - internal::scoped_ptr internal_run_death_test_flag_; - internal::scoped_ptr death_test_factory_; -#endif // GTEST_HAS_DEATH_TEST - - // A per-thread stack of traces created by the SCOPED_TRACE() macro. - internal::ThreadLocal > gtest_trace_stack_; - - // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() - // starts. - bool catch_exceptions_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); -}; // class UnitTestImpl - -// Convenience function for accessing the global UnitTest -// implementation object. -inline UnitTestImpl* GetUnitTestImpl() { - return UnitTest::GetInstance()->impl(); -} - -#if GTEST_USES_SIMPLE_RE - -// Internal helper functions for implementing the simple regular -// expression matcher. -GTEST_API_ bool IsInSet(char ch, const char* str); -GTEST_API_ bool IsAsciiDigit(char ch); -GTEST_API_ bool IsAsciiPunct(char ch); -GTEST_API_ bool IsRepeat(char ch); -GTEST_API_ bool IsAsciiWhiteSpace(char ch); -GTEST_API_ bool IsAsciiWordChar(char ch); -GTEST_API_ bool IsValidEscape(char ch); -GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); -GTEST_API_ bool ValidateRegex(const char* regex); -GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); -GTEST_API_ bool MatchRepetitionAndRegexAtHead( - bool escaped, char ch, char repeat, const char* regex, const char* str); -GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); - -#endif // GTEST_USES_SIMPLE_RE - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. -GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); -GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); - -#if GTEST_HAS_DEATH_TEST - -// Returns the message describing the last system error, regardless of the -// platform. -GTEST_API_ String GetLastErrnoDescription(); - -# if GTEST_OS_WINDOWS -// Provides leak-safe Windows kernel handle ownership. -class AutoHandle { - public: - AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} - explicit AutoHandle(HANDLE handle) : handle_(handle) {} - - ~AutoHandle() { Reset(); } - - HANDLE Get() const { return handle_; } - void Reset() { Reset(INVALID_HANDLE_VALUE); } - void Reset(HANDLE handle) { - if (handle != handle_) { - if (handle_ != INVALID_HANDLE_VALUE) - ::CloseHandle(handle_); - handle_ = handle; - } - } - - private: - HANDLE handle_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); -}; -# endif // GTEST_OS_WINDOWS - -// Attempts to parse a string into a positive integer pointed to by the -// number parameter. Returns true if that is possible. -// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use -// it here. -template -bool ParseNaturalNumber(const ::std::string& str, Integer* number) { - // Fail fast if the given string does not begin with a digit; - // this bypasses strtoXXX's "optional leading whitespace and plus - // or minus sign" semantics, which are undesirable here. - if (str.empty() || !IsDigit(str[0])) { - return false; - } - errno = 0; - - char* end; - // BiggestConvertible is the largest integer type that system-provided - // string-to-number conversion routines can return. - -# if GTEST_OS_WINDOWS && !defined(__GNUC__) - - // MSVC and C++ Builder define __int64 instead of the standard long long. - typedef unsigned __int64 BiggestConvertible; - const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); - -# else - - typedef unsigned long long BiggestConvertible; // NOLINT - const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); - -# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) - - const bool parse_success = *end == '\0' && errno == 0; - - // TODO(vladl@google.com): Convert this to compile time assertion when it is - // available. - GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); - - const Integer result = static_cast(parsed); - if (parse_success && static_cast(result) == parsed) { - *number = result; - return true; - } - return false; -} -#endif // GTEST_HAS_DEATH_TEST - -// TestResult contains some private methods that should be hidden from -// Google Test user but are required for testing. This class allow our tests -// to access them. -// -// This class is supplied only for the purpose of testing Google Test's own -// constructs. Do not use it in user tests, either directly or indirectly. -class TestResultAccessor { - public: - static void RecordProperty(TestResult* test_result, - const TestProperty& property) { - test_result->RecordProperty(property); - } - - static void ClearTestPartResults(TestResult* test_result) { - test_result->ClearTestPartResults(); - } - - static const std::vector& test_part_results( - const TestResult& test_result) { - return test_result.test_part_results(); - } -}; - -} // namespace internal -} // namespace testing - -#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ diff --git a/utils/unittest/googletest/src/gtest-all.cc b/utils/unittest/googletest/src/gtest-all.cc new file mode 100644 index 0000000..0a9cee5 --- /dev/null +++ b/utils/unittest/googletest/src/gtest-all.cc @@ -0,0 +1,48 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// Google C++ Testing Framework (Google Test) +// +// Sometimes it's desirable to build Google Test by compiling a single file. +// This file serves this purpose. + +// This line ensures that gtest.h can be compiled on its own, even +// when it's fused. +#include "gtest/gtest.h" + +// The following lines pull in the real gtest *.cc files. +#include "src/gtest.cc" +#include "src/gtest-death-test.cc" +#include "src/gtest-filepath.cc" +#include "src/gtest-port.cc" +#include "src/gtest-printers.cc" +#include "src/gtest-test-part.cc" +#include "src/gtest-typed-test.cc" diff --git a/utils/unittest/googletest/src/gtest-death-test.cc b/utils/unittest/googletest/src/gtest-death-test.cc new file mode 100644 index 0000000..82453f2 --- /dev/null +++ b/utils/unittest/googletest/src/gtest-death-test.cc @@ -0,0 +1,1233 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) +// +// This file implements death tests. + +#include "gtest/gtest-death-test.h" +#include "gtest/internal/gtest-port.h" + +#if GTEST_HAS_DEATH_TEST + +# if GTEST_OS_MAC +# include +# endif // GTEST_OS_MAC + +# include +# include +# include +# include + +# if GTEST_OS_WINDOWS +# include +# else +# include +# include +# endif // GTEST_OS_WINDOWS + +#endif // GTEST_HAS_DEATH_TEST + +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-string.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +// Constants. + +// The default death test style. +static const char kDefaultDeathTestStyle[] = "fast"; + +GTEST_DEFINE_string_( + death_test_style, + internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), + "Indicates how to run a death test in a forked child process: " + "\"threadsafe\" (child process re-executes the test binary " + "from the beginning, running only the specific death test) or " + "\"fast\" (child process runs the death test immediately " + "after forking)."); + +GTEST_DEFINE_bool_( + death_test_use_fork, + internal::BoolFromGTestEnv("death_test_use_fork", false), + "Instructs to use fork()/_exit() instead of clone() in death tests. " + "Ignored and always uses fork() on POSIX systems where clone() is not " + "implemented. Useful when running under valgrind or similar tools if " + "those do not support clone(). Valgrind 3.3.1 will just fail if " + "it sees an unsupported combination of clone() flags. " + "It is not recommended to use this flag w/o valgrind though it will " + "work in 99% of the cases. Once valgrind is fixed, this flag will " + "most likely be removed."); + +namespace internal { +GTEST_DEFINE_string_( + internal_run_death_test, "", + "Indicates the file, line number, temporal index of " + "the single death test to run, and a file descriptor to " + "which a success code may be sent, all separated by " + "colons. This flag is specified if and only if the current " + "process is a sub-process launched for running a thread-safe " + "death test. FOR INTERNAL USE ONLY."); +} // namespace internal + +#if GTEST_HAS_DEATH_TEST + +// ExitedWithCode constructor. +ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { +} + +// ExitedWithCode function-call operator. +bool ExitedWithCode::operator()(int exit_status) const { +# if GTEST_OS_WINDOWS + + return exit_status == exit_code_; + +# else + + return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; + +# endif // GTEST_OS_WINDOWS +} + +# if !GTEST_OS_WINDOWS +// KilledBySignal constructor. +KilledBySignal::KilledBySignal(int signum) : signum_(signum) { +} + +// KilledBySignal function-call operator. +bool KilledBySignal::operator()(int exit_status) const { + return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; +} +# endif // !GTEST_OS_WINDOWS + +namespace internal { + +// Utilities needed for death tests. + +// Generates a textual description of a given exit code, in the format +// specified by wait(2). +static String ExitSummary(int exit_code) { + Message m; + +# if GTEST_OS_WINDOWS + + m << "Exited with exit status " << exit_code; + +# else + + if (WIFEXITED(exit_code)) { + m << "Exited with exit status " << WEXITSTATUS(exit_code); + } else if (WIFSIGNALED(exit_code)) { + m << "Terminated by signal " << WTERMSIG(exit_code); + } +# ifdef WCOREDUMP + if (WCOREDUMP(exit_code)) { + m << " (core dumped)"; + } +# endif +# endif // GTEST_OS_WINDOWS + + return m.GetString(); +} + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +bool ExitedUnsuccessfully(int exit_status) { + return !ExitedWithCode(0)(exit_status); +} + +# if !GTEST_OS_WINDOWS +// Generates a textual failure message when a death test finds more than +// one thread running, or cannot determine the number of threads, prior +// to executing the given statement. It is the responsibility of the +// caller not to pass a thread_count of 1. +static String DeathTestThreadWarning(size_t thread_count) { + Message msg; + msg << "Death tests use fork(), which is unsafe particularly" + << " in a threaded context. For this test, " << GTEST_NAME_ << " "; + if (thread_count == 0) + msg << "couldn't detect the number of threads."; + else + msg << "detected " << thread_count << " threads."; + return msg.GetString(); +} +# endif // !GTEST_OS_WINDOWS + +// Flag characters for reporting a death test that did not die. +static const char kDeathTestLived = 'L'; +static const char kDeathTestReturned = 'R'; +static const char kDeathTestThrew = 'T'; +static const char kDeathTestInternalError = 'I'; + +// An enumeration describing all of the possible ways that a death test can +// conclude. DIED means that the process died while executing the test +// code; LIVED means that process lived beyond the end of the test code; +// RETURNED means that the test statement attempted to execute a return +// statement, which is not allowed; THREW means that the test statement +// returned control by throwing an exception. IN_PROGRESS means the test +// has not yet concluded. +// TODO(vladl@google.com): Unify names and possibly values for +// AbortReason, DeathTestOutcome, and flag characters above. +enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; + +// Routine for aborting the program which is safe to call from an +// exec-style death test child process, in which case the error +// message is propagated back to the parent process. Otherwise, the +// message is simply printed to stderr. In either case, the program +// then exits with status 1. +void DeathTestAbort(const String& message) { + // On a POSIX system, this function may be called from a threadsafe-style + // death test child process, which operates on a very small stack. Use + // the heap for any additional non-minuscule memory requirements. + const InternalRunDeathTestFlag* const flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + if (flag != NULL) { + FILE* parent = posix::FDOpen(flag->write_fd(), "w"); + fputc(kDeathTestInternalError, parent); + fprintf(parent, "%s", message.c_str()); + fflush(parent); + _exit(1); + } else { + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); + posix::Abort(); + } +} + +// A replacement for CHECK that calls DeathTestAbort if the assertion +// fails. +# define GTEST_DEATH_TEST_CHECK_(expression) \ + do { \ + if (!::testing::internal::IsTrue(expression)) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for +// evaluating any system call that fulfills two conditions: it must return +// -1 on failure, and set errno to EINTR when it is interrupted and +// should be tried again. The macro expands to a loop that repeatedly +// evaluates the expression as long as it evaluates to -1 and sets +// errno to EINTR. If the expression evaluates to -1 but errno is +// something other than EINTR, DeathTestAbort is called. +# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ + do { \ + int gtest_retval; \ + do { \ + gtest_retval = (expression); \ + } while (gtest_retval == -1 && errno == EINTR); \ + if (gtest_retval == -1) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s != -1", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// Returns the message describing the last system error in errno. +String GetLastErrnoDescription() { + return String(errno == 0 ? "" : posix::StrError(errno)); +} + +// This is called from a death test parent process to read a failure +// message from the death test child process and log it with the FATAL +// severity. On Windows, the message is read from a pipe handle. On other +// platforms, it is read from a file descriptor. +static void FailFromInternalError(int fd) { + Message error; + char buffer[256]; + int num_read; + + do { + while ((num_read = posix::Read(fd, buffer, 255)) > 0) { + buffer[num_read] = '\0'; + error << buffer; + } + } while (num_read == -1 && errno == EINTR); + + if (num_read == 0) { + GTEST_LOG_(FATAL) << error.GetString(); + } else { + const int last_error = errno; + GTEST_LOG_(FATAL) << "Error while reading death test internal: " + << GetLastErrnoDescription() << " [" << last_error << "]"; + } +} + +// Death test constructor. Increments the running death test count +// for the current test. +DeathTest::DeathTest() { + TestInfo* const info = GetUnitTestImpl()->current_test_info(); + if (info == NULL) { + DeathTestAbort("Cannot run a death test outside of a TEST or " + "TEST_F construct"); + } +} + +// Creates and returns a death test by dispatching to the current +// death test factory. +bool DeathTest::Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) { + return GetUnitTestImpl()->death_test_factory()->Create( + statement, regex, file, line, test); +} + +const char* DeathTest::LastMessage() { + return last_death_test_message_.c_str(); +} + +void DeathTest::set_last_death_test_message(const String& message) { + last_death_test_message_ = message; +} + +String DeathTest::last_death_test_message_; + +// Provides cross platform implementation for some death functionality. +class DeathTestImpl : public DeathTest { + protected: + DeathTestImpl(const char* a_statement, const RE* a_regex) + : statement_(a_statement), + regex_(a_regex), + spawned_(false), + status_(-1), + outcome_(IN_PROGRESS), + read_fd_(-1), + write_fd_(-1) {} + + // read_fd_ is expected to be closed and cleared by a derived class. + ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + + void Abort(AbortReason reason); + virtual bool Passed(bool status_ok); + + const char* statement() const { return statement_; } + const RE* regex() const { return regex_; } + bool spawned() const { return spawned_; } + void set_spawned(bool is_spawned) { spawned_ = is_spawned; } + int status() const { return status_; } + void set_status(int a_status) { status_ = a_status; } + DeathTestOutcome outcome() const { return outcome_; } + void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } + int read_fd() const { return read_fd_; } + void set_read_fd(int fd) { read_fd_ = fd; } + int write_fd() const { return write_fd_; } + void set_write_fd(int fd) { write_fd_ = fd; } + + // Called in the parent process only. Reads the result code of the death + // test child process via a pipe, interprets it to set the outcome_ + // member, and closes read_fd_. Outputs diagnostics and terminates in + // case of unexpected codes. + void ReadAndInterpretStatusByte(); + + private: + // The textual content of the code this object is testing. This class + // doesn't own this string and should not attempt to delete it. + const char* const statement_; + // The regular expression which test output must match. DeathTestImpl + // doesn't own this object and should not attempt to delete it. + const RE* const regex_; + // True if the death test child process has been successfully spawned. + bool spawned_; + // The exit status of the child process. + int status_; + // How the death test concluded. + DeathTestOutcome outcome_; + // Descriptor to the read end of the pipe to the child process. It is + // always -1 in the child process. The child keeps its write end of the + // pipe in write_fd_. + int read_fd_; + // Descriptor to the child's write end of the pipe to the parent process. + // It is always -1 in the parent process. The parent keeps its end of the + // pipe in read_fd_. + int write_fd_; +}; + +// Called in the parent process only. Reads the result code of the death +// test child process via a pipe, interprets it to set the outcome_ +// member, and closes read_fd_. Outputs diagnostics and terminates in +// case of unexpected codes. +void DeathTestImpl::ReadAndInterpretStatusByte() { + char flag; + int bytes_read; + + // The read() here blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before + // the child process has exited. + do { + bytes_read = posix::Read(read_fd(), &flag, 1); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0) { + set_outcome(DIED); + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + set_outcome(RETURNED); + break; + case kDeathTestThrew: + set_outcome(THREW); + break; + case kDeathTestLived: + set_outcome(LIVED); + break; + case kDeathTestInternalError: + FailFromInternalError(read_fd()); // Does not return. + break; + default: + GTEST_LOG_(FATAL) << "Death test child process reported " + << "unexpected status byte (" + << static_cast(flag) << ")"; + } + } else { + GTEST_LOG_(FATAL) << "Read from death test child process failed: " + << GetLastErrnoDescription(); + } + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); + set_read_fd(-1); +} + +// Signals that the death test code which should have exited, didn't. +// Should be called only in a death test child process. +// Writes a status byte to the child's status file descriptor, then +// calls _exit(1). +void DeathTestImpl::Abort(AbortReason reason) { + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char status_ch = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : + reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; + + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); + // We are leaking the descriptor here because on some platforms (i.e., + // when built as Windows DLL), destructors of global objects will still + // run after calling _exit(). On such systems, write_fd_ will be + // indirectly closed from the destructor of UnitTestImpl, causing double + // close if it is also closed here. On debug configurations, double close + // may assert. As there are no in-process buffers to flush here, we are + // relying on the OS to close the descriptor after the process terminates + // when the destructors are not run. + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// Returns an indented copy of stderr output for a death test. +// This makes distinguishing death test output lines from regular log lines +// much easier. +static ::std::string FormatDeathTestOutput(const ::std::string& output) { + ::std::string ret; + for (size_t at = 0; ; ) { + const size_t line_end = output.find('\n', at); + ret += "[ DEATH ] "; + if (line_end == ::std::string::npos) { + ret += output.substr(at); + break; + } + ret += output.substr(at, line_end + 1 - at); + at = line_end + 1; + } + return ret; +} + +// Assesses the success or failure of a death test, using both private +// members which have previously been set, and one argument: +// +// Private data members: +// outcome: An enumeration describing how the death test +// concluded: DIED, LIVED, THREW, or RETURNED. The death test +// fails in the latter three cases. +// status: The exit status of the child process. On *nix, it is in the +// in the format specified by wait(2). On Windows, this is the +// value supplied to the ExitProcess() API or a numeric code +// of the exception that terminated the program. +// regex: A regular expression object to be applied to +// the test's captured standard error output; the death test +// fails if it does not match. +// +// Argument: +// status_ok: true if exit_status is acceptable in the context of +// this particular death test, which fails if it is false +// +// Returns true iff all of the above conditions are met. Otherwise, the +// first failing condition, in the order given above, is the one that is +// reported. Also sets the last death test message string. +bool DeathTestImpl::Passed(bool status_ok) { + if (!spawned()) + return false; + + const String error_message = GetCapturedStderr(); + + bool success = false; + Message buffer; + + buffer << "Death test: " << statement() << "\n"; + switch (outcome()) { + case LIVED: + buffer << " Result: failed to die.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case THREW: + buffer << " Result: threw an exception.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case RETURNED: + buffer << " Result: illegal return in test statement.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case DIED: + if (status_ok) { + const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); + if (matched) { + success = true; + } else { + buffer << " Result: died but not with expected error.\n" + << " Expected: " << regex()->pattern() << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + } else { + buffer << " Result: died but not with expected exit code:\n" + << " " << ExitSummary(status()) << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + break; + case IN_PROGRESS: + GTEST_LOG_(FATAL) + << "DeathTest::Passed somehow called before conclusion of test"; + } + + DeathTest::set_last_death_test_message(buffer.GetString()); + return success; +} + +# if GTEST_OS_WINDOWS +// WindowsDeathTest implements death tests on Windows. Due to the +// specifics of starting new processes on Windows, death tests there are +// always threadsafe, and Google Test considers the +// --gtest_death_test_style=fast setting to be equivalent to +// --gtest_death_test_style=threadsafe there. +// +// A few implementation notes: Like the Linux version, the Windows +// implementation uses pipes for child-to-parent communication. But due to +// the specifics of pipes on Windows, some extra steps are required: +// +// 1. The parent creates a communication pipe and stores handles to both +// ends of it. +// 2. The parent starts the child and provides it with the information +// necessary to acquire the handle to the write end of the pipe. +// 3. The child acquires the write end of the pipe and signals the parent +// using a Windows event. +// 4. Now the parent can release the write end of the pipe on its side. If +// this is done before step 3, the object's reference count goes down to +// 0 and it is destroyed, preventing the child from acquiring it. The +// parent now has to release it, or read operations on the read end of +// the pipe will not return when the child terminates. +// 5. The parent reads child's output through the pipe (outcome code and +// any possible error messages) from the pipe, and its stderr and then +// determines whether to fail the test. +// +// Note: to distinguish Win32 API calls from the local method and function +// calls, the former are explicitly resolved in the global namespace. +// +class WindowsDeathTest : public DeathTestImpl { + public: + WindowsDeathTest(const char* a_statement, + const RE* a_regex, + const char* file, + int line) + : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // Handle to the write end of the pipe to the child process. + AutoHandle write_handle_; + // Child process handle. + AutoHandle child_handle_; + // Event the child process uses to signal the parent that it has + // acquired the handle to the write end of the pipe. After seeing this + // event the parent can release its own handles to make sure its + // ReadFile() calls return when the child terminates. + AutoHandle event_handle_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int WindowsDeathTest::Wait() { + if (!spawned()) + return 0; + + // Wait until the child either signals that it has acquired the write end + // of the pipe or it dies. + const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; + switch (::WaitForMultipleObjects(2, + wait_handles, + FALSE, // Waits for any of the handles. + INFINITE)) { + case WAIT_OBJECT_0: + case WAIT_OBJECT_0 + 1: + break; + default: + GTEST_DEATH_TEST_CHECK_(false); // Should not get here. + } + + // The child has acquired the write end of the pipe or exited. + // We release the handle on our side and continue. + write_handle_.Reset(); + event_handle_.Reset(); + + ReadAndInterpretStatusByte(); + + // Waits for the child process to exit if it haven't already. This + // returns immediately if the child has already exited, regardless of + // whether previous calls to WaitForMultipleObjects synchronized on this + // handle or not. + GTEST_DEATH_TEST_CHECK_( + WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), + INFINITE)); + DWORD status_code; + GTEST_DEATH_TEST_CHECK_( + ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); + child_handle_.Reset(); + set_status(static_cast(status_code)); + return status(); +} + +// The AssumeRole process for a Windows death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole WindowsDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + // WindowsDeathTest uses an anonymous pipe to communicate results of + // a death test. + SECURITY_ATTRIBUTES handles_are_inheritable = { + sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + HANDLE read_handle, write_handle; + GTEST_DEATH_TEST_CHECK_( + ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, + 0) // Default buffer size. + != FALSE); + set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), + O_RDONLY)); + write_handle_.Reset(write_handle); + event_handle_.Reset(::CreateEvent( + &handles_are_inheritable, + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + NULL)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); + const String filter_flag = String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), + info->name()); + const String internal_flag = String::Format( + "--%s%s=%s|%d|%d|%u|%Iu|%Iu", + GTEST_FLAG_PREFIX_, + kInternalRunDeathTestFlag, + file_, line_, + death_test_index, + static_cast(::GetCurrentProcessId()), + // size_t has the same with as pointers on both 32-bit and 64-bit + // Windows platforms. + // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. + reinterpret_cast(write_handle), + reinterpret_cast(event_handle_.Get())); + + char executable_path[_MAX_PATH + 1]; // NOLINT + GTEST_DEATH_TEST_CHECK_( + _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, + executable_path, + _MAX_PATH)); + + String command_line = String::Format("%s %s \"%s\"", + ::GetCommandLineA(), + filter_flag.c_str(), + internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // The child process will share the standard handles with the parent. + STARTUPINFOA startup_info; + memset(&startup_info, 0, sizeof(STARTUPINFO)); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); + + PROCESS_INFORMATION process_info; + GTEST_DEATH_TEST_CHECK_(::CreateProcessA( + executable_path, + const_cast(command_line.c_str()), + NULL, // Retuned process handle is not inheritable. + NULL, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + NULL, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), + &startup_info, + &process_info) != FALSE); + child_handle_.Reset(process_info.hProcess); + ::CloseHandle(process_info.hThread); + set_spawned(true); + return OVERSEE_TEST; +} +# else // We are not on Windows. + +// ForkingDeathTest provides implementations for most of the abstract +// methods of the DeathTest interface. Only the AssumeRole method is +// left undefined. +class ForkingDeathTest : public DeathTestImpl { + public: + ForkingDeathTest(const char* statement, const RE* regex); + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + + protected: + void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } + + private: + // PID of child process during death test; 0 in the child process itself. + pid_t child_pid_; +}; + +// Constructs a ForkingDeathTest. +ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) + : DeathTestImpl(a_statement, a_regex), + child_pid_(-1) {} + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int ForkingDeathTest::Wait() { + if (!spawned()) + return 0; + + ReadAndInterpretStatusByte(); + + int status_value; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); + set_status(status_value); + return status_value; +} + +// A concrete death test class that forks, then immediately runs the test +// in the child process. +class NoExecDeathTest : public ForkingDeathTest { + public: + NoExecDeathTest(const char* a_statement, const RE* a_regex) : + ForkingDeathTest(a_statement, a_regex) { } + virtual TestRole AssumeRole(); +}; + +// The AssumeRole process for a fork-and-run death test. It implements a +// straightforward fork, with a simple pipe to transmit the status byte. +DeathTest::TestRole NoExecDeathTest::AssumeRole() { + const size_t thread_count = GetThreadCount(); + if (thread_count != 1) { + GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + + DeathTest::set_last_death_test_message(""); + CaptureStderr(); + // When we fork the process below, the log file buffers are copied, but the + // file descriptors are shared. We flush all log files here so that closing + // the file descriptors in the child process doesn't throw off the + // synchronization between descriptors and buffers in the parent process. + // This is as close to the fork as possible to avoid a race condition in case + // there are multiple threads running before the death test, and another + // thread writes to the log file. + FlushInfoLog(); + + const pid_t child_pid = fork(); + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + set_child_pid(child_pid); + if (child_pid == 0) { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); + set_write_fd(pipe_fd[1]); + // Redirects all logging to stderr in the child process to prevent + // concurrent writes to the log files. We capture stderr in the parent + // process and append the child process' output to a log. + LogToStderr(); + // Event forwarding to the listeners of event listener API mush be shut + // down in death test subprocesses. + GetUnitTestImpl()->listeners()->SuppressEventForwarding(); + return EXECUTE_TEST; + } else { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; + } +} + +// A concrete death test class that forks and re-executes the main +// program from the beginning, with command-line flags set that cause +// only this specific death test to be run. +class ExecDeathTest : public ForkingDeathTest { + public: + ExecDeathTest(const char* a_statement, const RE* a_regex, + const char* file, int line) : + ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } + virtual TestRole AssumeRole(); + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + private: + std::vector args_; +}; + +// A struct that encompasses the arguments to the child process of a +// threadsafe-style death test process. +struct ExecDeathTestArgs { + char* const* argv; // Command-line arguments for the child's call to exec + int close_fd; // File descriptor to close; the read end of a pipe +}; + +# if GTEST_OS_MAC +inline char** GetEnviron() { + // When Google Test is built as a framework on MacOS X, the environ variable + // is unavailable. Apple's documentation (man environ) recommends using + // _NSGetEnviron() instead. + return *_NSGetEnviron(); +} +# else +// Some POSIX platforms expect you to declare environ. extern "C" makes +// it reside in the global namespace. +extern "C" char** environ; +inline char** GetEnviron() { return environ; } +# endif // GTEST_OS_MAC + +// The main function for a threadsafe-style death test child process. +// This function is called in a clone()-ed process and thus must avoid +// any potentially unsafe operations like malloc or libc functions. +static int ExecDeathTestChildMain(void* child_arg) { + ExecDeathTestArgs* const args = static_cast(child_arg); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); + + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; + } + + // We can safely call execve() as it's a direct system call. We + // cannot use execvp() as it's a libc function and thus potentially + // unsafe. Since execve() doesn't search the PATH, the user must + // invoke the test program via a valid path that contains at least + // one path separator. + execve(args->argv[0], args->argv, GetEnviron()); + DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", + args->argv[0], + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; +} + +// Two utility routines that together determine the direction the stack +// grows. +// This could be accomplished more elegantly by a single recursive +// function, but we want to guard against the unlikely possibility of +// a smart compiler optimizing the recursion away. +// +// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining +// StackLowerThanAddress into StackGrowsDown, which then doesn't give +// correct answer. +bool StackLowerThanAddress(const void* ptr) GTEST_NO_INLINE_; +bool StackLowerThanAddress(const void* ptr) { + int dummy; + return &dummy < ptr; +} + +bool StackGrowsDown() { + int dummy; + return StackLowerThanAddress(&dummy); +} + +// A threadsafe implementation of fork(2) for threadsafe-style death tests +// that uses clone(2). It dies with an error message if anything goes +// wrong. +static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { + ExecDeathTestArgs args = { argv, close_fd }; + pid_t child_pid = -1; + +# if GTEST_HAS_CLONE + const bool use_fork = GTEST_FLAG(death_test_use_fork); + + if (!use_fork) { + static const bool stack_grows_down = StackGrowsDown(); + const size_t stack_size = getpagesize(); + // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. + void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); + void* const stack_top = + static_cast(stack) + (stack_grows_down ? stack_size : 0); + + child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); + + GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); + } +# else + const bool use_fork = true; +# endif // GTEST_HAS_CLONE + + if (use_fork && (child_pid = fork()) == 0) { + ExecDeathTestChildMain(&args); + _exit(0); + } + + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + return child_pid; +} + +// The AssumeRole process for a fork-and-exec death test. It re-executes the +// main program from the beginning, setting the --gtest_filter +// and --gtest_internal_run_death_test flags to cause only the current +// death test to be re-run. +DeathTest::TestRole ExecDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + // Clear the close-on-exec flag on the write end of the pipe, lest + // it be closed when the child process does an exec: + GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); + + const String filter_flag = + String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), info->name()); + const String internal_flag = + String::Format("--%s%s=%s|%d|%d|%d", + GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, + file_, line_, death_test_index, pipe_fd[1]); + Arguments args; + args.AddArguments(GetArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // See the comment in NoExecDeathTest::AssumeRole for why the next line + // is necessary. + FlushInfoLog(); + + const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_child_pid(child_pid); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; +} + +# endif // !GTEST_OS_WINDOWS + +// Creates a concrete DeathTest-derived class that depends on the +// --gtest_death_test_style flag, and sets the pointer pointed to +// by the "test" argument to its address. If the test should be +// skipped, sets that pointer to NULL. Returns true, unless the +// flag is set to an invalid value. +bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, + const char* file, int line, + DeathTest** test) { + UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const int death_test_index = impl->current_test_info() + ->increment_death_test_count(); + + if (flag != NULL) { + if (death_test_index > flag->index()) { + DeathTest::set_last_death_test_message(String::Format( + "Death test count (%d) somehow exceeded expected maximum (%d)", + death_test_index, flag->index())); + return false; + } + + if (!(flag->file() == file && flag->line() == line && + flag->index() == death_test_index)) { + *test = NULL; + return true; + } + } + +# if GTEST_OS_WINDOWS + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new WindowsDeathTest(statement, regex, file, line); + } + +# else + + if (GTEST_FLAG(death_test_style) == "threadsafe") { + *test = new ExecDeathTest(statement, regex, file, line); + } else if (GTEST_FLAG(death_test_style) == "fast") { + *test = new NoExecDeathTest(statement, regex); + } + +# endif // GTEST_OS_WINDOWS + + else { // NOLINT - this is more readable than unbalanced brackets inside #if. + DeathTest::set_last_death_test_message(String::Format( + "Unknown death test style \"%s\" encountered", + GTEST_FLAG(death_test_style).c_str())); + return false; + } + + return true; +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have +// ::std::string, so we can use it here. +static void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + +# if GTEST_OS_WINDOWS +// Recreates the pipe and event handles from the provided parameters, +// signals the event, and returns a file descriptor wrapped around the pipe +// handle. This function is called in the child process only. +int GetStatusFileDescriptor(unsigned int parent_process_id, + size_t write_handle_as_size_t, + size_t event_handle_as_size_t) { + AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, + FALSE, // Non-inheritable. + parent_process_id)); + if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { + DeathTestAbort(String::Format("Unable to open parent process %u", + parent_process_id)); + } + + // TODO(vladl@google.com): Replace the following check with a + // compile-time assertion when available. + GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); + + const HANDLE write_handle = + reinterpret_cast(write_handle_as_size_t); + HANDLE dup_write_handle; + + // The newly initialized handle is accessible only in in the parent + // process. To obtain one accessible within the child, we need to use + // DuplicateHandle. + if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, + ::GetCurrentProcess(), &dup_write_handle, + 0x0, // Requested privileges ignored since + // DUPLICATE_SAME_ACCESS is used. + FALSE, // Request non-inheritable handler. + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the pipe handle %Iu from the parent process %u", + write_handle_as_size_t, parent_process_id)); + } + + const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); + HANDLE dup_event_handle; + + if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, + ::GetCurrentProcess(), &dup_event_handle, + 0x0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the event handle %Iu from the parent process %u", + event_handle_as_size_t, parent_process_id)); + } + + const int write_fd = + ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); + if (write_fd == -1) { + DeathTestAbort(String::Format( + "Unable to convert pipe handle %Iu to a file descriptor", + write_handle_as_size_t)); + } + + // Signals the parent that the write end of the pipe has been acquired + // so the parent can release its own write end. + ::SetEvent(dup_event_handle); + + return write_fd; +} +# endif // GTEST_OS_WINDOWS + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { + if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + + // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we + // can use it here. + int line = -1; + int index = -1; + ::std::vector< ::std::string> fields; + SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); + int write_fd = -1; + +# if GTEST_OS_WINDOWS + + unsigned int parent_process_id = 0; + size_t write_handle_as_size_t = 0; + size_t event_handle_as_size_t = 0; + + if (fields.size() != 6 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &parent_process_id) + || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) + || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } + write_fd = GetStatusFileDescriptor(parent_process_id, + write_handle_as_size_t, + event_handle_as_size_t); +# else + + if (fields.size() != 4 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &write_fd)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } + +# endif // GTEST_OS_WINDOWS + + return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); +} + +} // namespace internal + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace testing diff --git a/utils/unittest/googletest/src/gtest-filepath.cc b/utils/unittest/googletest/src/gtest-filepath.cc new file mode 100644 index 0000000..ad1bab8 --- /dev/null +++ b/utils/unittest/googletest/src/gtest-filepath.cc @@ -0,0 +1,378 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: keith.ray@gmail.com (Keith Ray) + +#include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-port.h" + +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include +#elif GTEST_OS_WINDOWS +# include +# include +#elif GTEST_OS_SYMBIAN || GTEST_OS_NACL +// Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h +# include +#else +# include +# include // Some Linux distributions define PATH_MAX here. +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_MAX_ _MAX_PATH +#elif defined(PATH_MAX) +# define GTEST_PATH_MAX_ PATH_MAX +#elif defined(_XOPEN_PATH_MAX) +# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +#else +# define GTEST_PATH_MAX_ _POSIX_PATH_MAX +#endif // GTEST_OS_WINDOWS + +#include "gtest/internal/gtest-string.h" + +namespace testing { +namespace internal { + +#if GTEST_OS_WINDOWS +// On Windows, '\\' is the standard path separator, but many tools and the +// Windows API also accept '/' as an alternate path separator. Unless otherwise +// noted, a file path can contain either kind of path separators, or a mixture +// of them. +const char kPathSeparator = '\\'; +const char kAlternatePathSeparator = '/'; +const char kAlternatePathSeparatorString[] = "/"; +# if GTEST_OS_WINDOWS_MOBILE +// Windows CE doesn't have a current directory. You should not use +// the current directory in tests on Windows CE, but this at least +// provides a reasonable fallback. +const char kCurrentDirectoryString[] = "\\"; +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES +const DWORD kInvalidFileAttributes = 0xffffffff; +# else +const char kCurrentDirectoryString[] = ".\\"; +# endif // GTEST_OS_WINDOWS_MOBILE +#else +const char kPathSeparator = '/'; +const char kCurrentDirectoryString[] = "./"; +#endif // GTEST_OS_WINDOWS + +// Returns whether the given character is a valid path separator. +static bool IsPathSeparator(char c) { +#if GTEST_HAS_ALT_PATH_SEP_ + return (c == kPathSeparator) || (c == kAlternatePathSeparator); +#else + return c == kPathSeparator; +#endif +} + +// Returns the current working directory, or "" if unsuccessful. +FilePath FilePath::GetCurrentDir() { +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't have a current directory, so we just return + // something reasonable. + return FilePath(kCurrentDirectoryString); +#elif GTEST_OS_WINDOWS + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#else + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns a copy of the FilePath with the case-insensitive extension removed. +// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns +// FilePath("dir/file"). If a case-insensitive extension is not +// found, returns a copy of the original FilePath. +FilePath FilePath::RemoveExtension(const char* extension) const { + String dot_extension(String::Format(".%s", extension)); + if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { + return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); + } + return *this; +} + +// Returns a pointer to the last occurrence of a valid path separator in +// the FilePath. On Windows, for example, both '/' and '\' are valid path +// separators. Returns NULL if no path separator was found. +const char* FilePath::FindLastPathSeparator() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); +#if GTEST_HAS_ALT_PATH_SEP_ + const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); + // Comparing two pointers of which only one is NULL is undefined. + if (last_alt_sep != NULL && + (last_sep == NULL || last_alt_sep > last_sep)) { + return last_alt_sep; + } +#endif + return last_sep; +} + +// Returns a copy of the FilePath with the directory part removed. +// Example: FilePath("path/to/file").RemoveDirectoryName() returns +// FilePath("file"). If there is no directory part ("just_a_file"), it returns +// the FilePath unmodified. If there is no file part ("just_a_dir/") it +// returns an empty FilePath (""). +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveDirectoryName() const { + const char* const last_sep = FindLastPathSeparator(); + return last_sep ? FilePath(String(last_sep + 1)) : *this; +} + +// RemoveFileName returns the directory path with the filename removed. +// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". +// If the FilePath is "a_file" or "/a_file", RemoveFileName returns +// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does +// not have a file, like "just/a/dir/", it returns the FilePath unmodified. +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveFileName() const { + const char* const last_sep = FindLastPathSeparator(); + String dir; + if (last_sep) { + dir = String(c_str(), last_sep + 1 - c_str()); + } else { + dir = kCurrentDirectoryString; + } + return FilePath(dir); +} + +// Helper functions for naming files in a directory for xml output. + +// Given directory = "dir", base_name = "test", number = 0, +// extension = "xml", returns "dir/test.xml". If number is greater +// than zero (e.g., 12), returns "dir/test_12.xml". +// On Windows platform, uses \ as the separator rather than /. +FilePath FilePath::MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension) { + String file; + if (number == 0) { + file = String::Format("%s.%s", base_name.c_str(), extension); + } else { + file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); + } + return ConcatPaths(directory, FilePath(file)); +} + +// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". +// On Windows, uses \ as the separator rather than /. +FilePath FilePath::ConcatPaths(const FilePath& directory, + const FilePath& relative_path) { + if (directory.IsEmpty()) + return relative_path; + const FilePath dir(directory.RemoveTrailingPathSeparator()); + return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, + relative_path.c_str())); +} + +// Returns true if pathname describes something findable in the file-system, +// either a file, directory, or whatever. +bool FilePath::FileOrDirectoryExists() const { +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + return attributes != kInvalidFileAttributes; +#else + posix::StatStruct file_stat; + return posix::Stat(pathname_.c_str(), &file_stat) == 0; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns true if pathname describes a directory in the file-system +// that exists. +bool FilePath::DirectoryExists() const { + bool result = false; +#if GTEST_OS_WINDOWS + // Don't strip off trailing separator if path is a root directory on + // Windows (like "C:\\"). + const FilePath& path(IsRootDirectory() ? *this : + RemoveTrailingPathSeparator()); +#else + const FilePath& path(*this); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + if ((attributes != kInvalidFileAttributes) && + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = true; + } +#else + posix::StatStruct file_stat; + result = posix::Stat(path.c_str(), &file_stat) == 0 && + posix::IsDir(file_stat); +#endif // GTEST_OS_WINDOWS_MOBILE + + return result; +} + +// Returns true if pathname describes a root directory. (Windows has one +// root directory per disk drive.) +bool FilePath::IsRootDirectory() const { +#if GTEST_OS_WINDOWS + // TODO(wan@google.com): on Windows a network share like + // \\server\share can be a root directory, although it cannot be the + // current directory. Handle this properly. + return pathname_.length() == 3 && IsAbsolutePath(); +#else + return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); +#endif +} + +// Returns true if pathname describes an absolute path. +bool FilePath::IsAbsolutePath() const { + const char* const name = pathname_.c_str(); +#if GTEST_OS_WINDOWS + return pathname_.length() >= 3 && + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && + IsPathSeparator(name[2]); +#else + return IsPathSeparator(name[0]); +#endif +} + +// Returns a pathname for a file that does not currently exist. The pathname +// will be directory/base_name.extension or +// directory/base_name_.extension if directory/base_name.extension +// already exists. The number will be incremented until a pathname is found +// that does not already exist. +// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. +// There could be a race condition if two or more processes are calling this +// function at the same time -- they could both pick the same filename. +FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension) { + FilePath full_pathname; + int number = 0; + do { + full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); + } while (full_pathname.FileOrDirectoryExists()); + return full_pathname; +} + +// Returns true if FilePath ends with a path separator, which indicates that +// it is intended to represent a directory. Returns false otherwise. +// This does NOT check that a directory (or file) actually exists. +bool FilePath::IsDirectory() const { + return !pathname_.empty() && + IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); +} + +// Create directories so that path exists. Returns true if successful or if +// the directories already exist; returns false if unable to create directories +// for any reason. +bool FilePath::CreateDirectoriesRecursively() const { + if (!this->IsDirectory()) { + return false; + } + + if (pathname_.length() == 0 || this->DirectoryExists()) { + return true; + } + + const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); + return parent.CreateDirectoriesRecursively() && this->CreateFolder(); +} + +// Create the directory so that path exists. Returns true if successful or +// if the directory already exists; returns false if unable to create the +// directory for any reason, including if the parent directory does not +// exist. Not named "CreateDirectory" because that's a macro on Windows. +bool FilePath::CreateFolder() const { +#if GTEST_OS_WINDOWS_MOBILE + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + int result = CreateDirectory(unicode, NULL) ? 0 : -1; + delete [] unicode; +#elif GTEST_OS_WINDOWS + int result = _mkdir(pathname_.c_str()); +#else + int result = mkdir(pathname_.c_str(), 0777); +#endif // GTEST_OS_WINDOWS_MOBILE + + if (result == -1) { + return this->DirectoryExists(); // An error is OK if the directory exists. + } + return true; // No error. +} + +// If input name has a trailing separator character, remove it and return the +// name, otherwise return the name string unmodified. +// On Windows platform, uses \ as the separator, other platforms use /. +FilePath FilePath::RemoveTrailingPathSeparator() const { + return IsDirectory() + ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) + : *this; +} + +// Removes any redundant separators that might be in the pathname. +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other +// redundancies that might be in a pathname involving "." or "..". +// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). +void FilePath::Normalize() { + if (pathname_.c_str() == NULL) { + pathname_ = ""; + return; + } + const char* src = pathname_.c_str(); + char* const dest = new char[pathname_.length() + 1]; + char* dest_ptr = dest; + memset(dest_ptr, 0, pathname_.length() + 1); + + while (*src != '\0') { + *dest_ptr = *src; + if (!IsPathSeparator(*src)) { + src++; + } else { +#if GTEST_HAS_ALT_PATH_SEP_ + if (*dest_ptr == kAlternatePathSeparator) { + *dest_ptr = kPathSeparator; + } +#endif + while (IsPathSeparator(*src)) + src++; + } + dest_ptr++; + } + *dest_ptr = '\0'; + pathname_ = dest; + delete[] dest; +} + +} // namespace internal +} // namespace testing diff --git a/utils/unittest/googletest/src/gtest-internal-inl.h b/utils/unittest/googletest/src/gtest-internal-inl.h new file mode 100644 index 0000000..6554cfc --- /dev/null +++ b/utils/unittest/googletest/src/gtest-internal-inl.h @@ -0,0 +1,1037 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility functions and classes used by the Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This file contains purely Google Test's internal implementation. Please +// DO NOT #INCLUDE IT IN A USER PROGRAM. + +#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ +#define GTEST_SRC_GTEST_INTERNAL_INL_H_ + +// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is +// part of Google Test's implementation; otherwise it's undefined. +#if !GTEST_IMPLEMENTATION_ +// A user is trying to include this from his code - just say no. +# error "gtest-internal-inl.h is part of Google Test's internal implementation." +# error "It must not be included except by Google Test itself." +#endif // GTEST_IMPLEMENTATION_ + +#ifndef _WIN32_WCE +# include +#endif // !_WIN32_WCE +#include +#include // For strtoll/_strtoul64/malloc/free. +#include // For memmove. + +#include +#include +#include + +#include "gtest/internal/gtest-port.h" + +#if GTEST_OS_WINDOWS +# include // NOLINT +#endif // GTEST_OS_WINDOWS + +#include "gtest/gtest.h" // NOLINT +#include "gtest/gtest-spi.h" + +namespace testing { + +// Declares the flags. +// +// We don't want the users to modify this flag in the code, but want +// Google Test's own unit tests to be able to access it. Therefore we +// declare it here as opposed to in gtest.h. +GTEST_DECLARE_bool_(death_test_use_fork); + +namespace internal { + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; + +// Names of the flags (needed for parsing Google Test flags). +const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; +const char kBreakOnFailureFlag[] = "break_on_failure"; +const char kCatchExceptionsFlag[] = "catch_exceptions"; +const char kColorFlag[] = "color"; +const char kFilterFlag[] = "filter"; +const char kListTestsFlag[] = "list_tests"; +const char kOutputFlag[] = "output"; +const char kPrintTimeFlag[] = "print_time"; +const char kRandomSeedFlag[] = "random_seed"; +const char kRepeatFlag[] = "repeat"; +const char kShuffleFlag[] = "shuffle"; +const char kStackTraceDepthFlag[] = "stack_trace_depth"; +const char kStreamResultToFlag[] = "stream_result_to"; +const char kThrowOnFailureFlag[] = "throw_on_failure"; + +// A valid random seed must be in [1, kMaxRandomSeed]. +const int kMaxRandomSeed = 99999; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +GTEST_API_ extern bool g_help_flag; + +// Returns the current time in milliseconds. +GTEST_API_ TimeInMillis GetTimeInMillis(); + +// Returns true iff Google Test should use colors in the output. +GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); + +// Formats the given time in milliseconds as seconds. +GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); + +// Parses a string for an Int32 flag, in the form of "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +GTEST_API_ bool ParseInt32Flag( + const char* str, const char* flag, Int32* value); + +// Returns a random seed in range [1, kMaxRandomSeed] based on the +// given --gtest_random_seed flag value. +inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { + const unsigned int raw_seed = (random_seed_flag == 0) ? + static_cast(GetTimeInMillis()) : + static_cast(random_seed_flag); + + // Normalizes the actual seed to range [1, kMaxRandomSeed] such that + // it's easy to type. + const int normalized_seed = + static_cast((raw_seed - 1U) % + static_cast(kMaxRandomSeed)) + 1; + return normalized_seed; +} + +// Returns the first valid random seed after 'seed'. The behavior is +// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is +// considered to be 1. +inline int GetNextRandomSeed(int seed) { + GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) + << "Invalid random seed " << seed << " - must be in [1, " + << kMaxRandomSeed << "]."; + const int next_seed = seed + 1; + return (next_seed > kMaxRandomSeed) ? 1 : next_seed; +} + +// This class saves the values of all Google Test flags in its c'tor, and +// restores them in its d'tor. +class GTestFlagSaver { + public: + // The c'tor. + GTestFlagSaver() { + also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); + break_on_failure_ = GTEST_FLAG(break_on_failure); + catch_exceptions_ = GTEST_FLAG(catch_exceptions); + color_ = GTEST_FLAG(color); + death_test_style_ = GTEST_FLAG(death_test_style); + death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); + filter_ = GTEST_FLAG(filter); + internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); + list_tests_ = GTEST_FLAG(list_tests); + output_ = GTEST_FLAG(output); + print_time_ = GTEST_FLAG(print_time); + random_seed_ = GTEST_FLAG(random_seed); + repeat_ = GTEST_FLAG(repeat); + shuffle_ = GTEST_FLAG(shuffle); + stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); + stream_result_to_ = GTEST_FLAG(stream_result_to); + throw_on_failure_ = GTEST_FLAG(throw_on_failure); + } + + // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. + ~GTestFlagSaver() { + GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; + GTEST_FLAG(break_on_failure) = break_on_failure_; + GTEST_FLAG(catch_exceptions) = catch_exceptions_; + GTEST_FLAG(color) = color_; + GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; + GTEST_FLAG(filter) = filter_; + GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; + GTEST_FLAG(list_tests) = list_tests_; + GTEST_FLAG(output) = output_; + GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(random_seed) = random_seed_; + GTEST_FLAG(repeat) = repeat_; + GTEST_FLAG(shuffle) = shuffle_; + GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; + GTEST_FLAG(stream_result_to) = stream_result_to_; + GTEST_FLAG(throw_on_failure) = throw_on_failure_; + } + private: + // Fields for saving the original values of flags. + bool also_run_disabled_tests_; + bool break_on_failure_; + bool catch_exceptions_; + String color_; + String death_test_style_; + bool death_test_use_fork_; + String filter_; + String internal_run_death_test_; + bool list_tests_; + String output_; + bool print_time_; + internal::Int32 random_seed_; + internal::Int32 repeat_; + bool shuffle_; + internal::Int32 stack_trace_depth_; + String stream_result_to_; + bool throw_on_failure_; +} GTEST_ATTRIBUTE_UNUSED_; + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded(); + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (e.g., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +GTEST_API_ bool ShouldShard(const char* total_shards_str, + const char* shard_index_str, + bool in_subprocess_for_death_test); + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error and +// and aborts. +GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +GTEST_API_ bool ShouldRunTestOnShard( + int total_shards, int shard_index, int test_id); + +// STL container utilities. + +// Returns the number of elements in the given container that satisfy +// the given predicate. +template +inline int CountIf(const Container& c, Predicate predicate) { + // Implemented as an explicit loop since std::count_if() in libCstd on + // Solaris has a non-standard signature. + int count = 0; + for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { + if (predicate(*it)) + ++count; + } + return count; +} + +// Applies a function/functor to each element in the container. +template +void ForEach(const Container& c, Functor functor) { + std::for_each(c.begin(), c.end(), functor); +} + +// Returns the i-th element of the vector, or default_value if i is not +// in range [0, v.size()). +template +inline E GetElementOr(const std::vector& v, int i, E default_value) { + return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; +} + +// Performs an in-place shuffle of a range of the vector's elements. +// 'begin' and 'end' are element indices as an STL-style range; +// i.e. [begin, end) are shuffled, where 'end' == size() means to +// shuffle to the end of the vector. +template +void ShuffleRange(internal::Random* random, int begin, int end, + std::vector* v) { + const int size = static_cast(v->size()); + GTEST_CHECK_(0 <= begin && begin <= size) + << "Invalid shuffle range start " << begin << ": must be in range [0, " + << size << "]."; + GTEST_CHECK_(begin <= end && end <= size) + << "Invalid shuffle range finish " << end << ": must be in range [" + << begin << ", " << size << "]."; + + // Fisher-Yates shuffle, from + // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + for (int range_width = end - begin; range_width >= 2; range_width--) { + const int last_in_range = begin + range_width - 1; + const int selected = begin + random->Generate(range_width); + std::swap((*v)[selected], (*v)[last_in_range]); + } +} + +// Performs an in-place shuffle of the vector's elements. +template +inline void Shuffle(internal::Random* random, std::vector* v) { + ShuffleRange(random, 0, static_cast(v->size()), v); +} + +// A function for deleting an object. Handy for being used as a +// functor. +template +static void Delete(T* x) { + delete x; +} + +// A predicate that checks the key of a TestProperty against a known key. +// +// TestPropertyKeyIs is copyable. +class TestPropertyKeyIs { + public: + // Constructor. + // + // TestPropertyKeyIs has NO default constructor. + explicit TestPropertyKeyIs(const char* key) + : key_(key) {} + + // Returns true iff the test name of test property matches on key_. + bool operator()(const TestProperty& test_property) const { + return String(test_property.key()).Compare(key_) == 0; + } + + private: + String key_; +}; + +// Class UnitTestOptions. +// +// This class contains functions for processing options the user +// specifies when running the tests. It has only static members. +// +// In most cases, the user can specify an option using either an +// environment variable or a command line flag. E.g. you can set the +// test filter using either GTEST_FILTER or --gtest_filter. If both +// the variable and the flag are present, the latter overrides the +// former. +class GTEST_API_ UnitTestOptions { + public: + // Functions for processing the gtest_output flag. + + // Returns the output format, or "" for normal printed output. + static String GetOutputFormat(); + + // Returns the absolute path of the requested output file, or the + // default (test_detail.xml in the original working directory) if + // none was explicitly specified. + static String GetAbsolutePathToOutputFile(); + + // Functions for processing the gtest_filter flag. + + // Returns true iff the wildcard pattern matches the string. The + // first ':' or '\0' character in pattern marks the end of it. + // + // This recursive algorithm isn't very efficient, but is clear and + // works well enough for matching test names, which are short. + static bool PatternMatchesString(const char *pattern, const char *str); + + // Returns true iff the user-specified filter matches the test case + // name and the test name. + static bool FilterMatchesTest(const String &test_case_name, + const String &test_name); + +#if GTEST_OS_WINDOWS + // Function for supporting the gtest_catch_exception flag. + + // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the + // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. + // This function is useful as an __except condition. + static int GTestShouldProcessSEH(DWORD exception_code); +#endif // GTEST_OS_WINDOWS + + // Returns true if "name" matches the ':' separated list of glob-style + // filters in "filter". + static bool MatchesFilter(const String& name, const char* filter); +}; + +// Returns the current application's name, removing directory path if that +// is present. Used by UnitTestOptions::GetOutputFile. +GTEST_API_ FilePath GetCurrentExecutableName(); + +// The role interface for getting the OS stack trace as a string. +class OsStackTraceGetterInterface { + public: + OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface() {} + + // Returns the current OS stack trace as a String. Parameters: + // + // max_depth - the maximum number of stack frames to be included + // in the trace. + // skip_count - the number of top frames to be skipped; doesn't count + // against max_depth. + virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; + + // UponLeavingGTest() should be called immediately before Google Test calls + // user code. It saves some information about the current stack that + // CurrentStackTrace() will use to find and hide Google Test stack frames. + virtual void UponLeavingGTest() = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); +}; + +// A working implementation of the OsStackTraceGetterInterface interface. +class OsStackTraceGetter : public OsStackTraceGetterInterface { + public: + OsStackTraceGetter() : caller_frame_(NULL) {} + virtual String CurrentStackTrace(int max_depth, int skip_count); + virtual void UponLeavingGTest(); + + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + + private: + Mutex mutex_; // protects all internal state + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to CurrentStackTrace() from within the user code. + void* caller_frame_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); +}; + +// Information about a Google Test trace point. +struct TraceInfo { + const char* file; + int line; + String message; +}; + +// This is the default global test part result reporter used in UnitTestImpl. +// This class should only be used by UnitTestImpl. +class DefaultGlobalTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. Reports the test part + // result in the current test. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); +}; + +// This is the default per thread test part result reporter used in +// UnitTestImpl. This class should only be used by UnitTestImpl. +class DefaultPerThreadTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. The implementation just + // delegates to the current global test part result reporter of *unit_test_. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); +}; + +// The private implementation of the UnitTest class. We don't protect +// the methods under a mutex, as this class is not accessible by a +// user and the UnitTest class that delegates work to this class does +// proper locking. +class GTEST_API_ UnitTestImpl { + public: + explicit UnitTestImpl(UnitTest* parent); + virtual ~UnitTestImpl(); + + // There are two different ways to register your own TestPartResultReporter. + // You can register your own repoter to listen either only for test results + // from the current thread or for results from all threads. + // By default, each per-thread test result repoter just passes a new + // TestPartResult to the global test result reporter, which registers the + // test part result for the currently running test. + + // Returns the global test part result reporter. + TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); + + // Sets the global test part result reporter. + void SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter); + + // Returns the test part result reporter for the current thread. + TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); + + // Sets the test part result reporter for the current thread. + void SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter); + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const { return !Failed(); } + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const { + return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[i]; + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i) { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[index]; + } + + // Provides access to the event listener list. + TestEventListeners* listeners() { return &listeners_; } + + // Returns the TestResult for the test that's currently running, or + // the TestResult for the ad hoc test if no test is running. + TestResult* current_test_result(); + + // Returns the TestResult for the ad hoc test. + const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } + + // Sets the OS stack trace getter. + // + // Does nothing if the input and the current OS stack trace getter + // are the same; otherwise, deletes the old getter and makes the + // input the current getter. + void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); + + // Returns the current OS stack trace getter if it is not NULL; + // otherwise, creates an OsStackTraceGetter, makes it the current + // getter, and returns it. + OsStackTraceGetterInterface* os_stack_trace_getter(); + + // Returns the current OS stack trace as a String. + // + // The maximum number of stack frames to be included is specified by + // the gtest_stack_trace_depth flag. The skip_count parameter + // specifies the number of top frames to be skipped, which doesn't + // count against the number of frames to be included. + // + // For example, if Foo() calls Bar(), which in turn calls + // CurrentOsStackTraceExceptTop(1), Foo() will be included in the + // trace but Bar() and CurrentOsStackTraceExceptTop() won't. + String CurrentOsStackTraceExceptTop(int skip_count); + + // Finds and returns a TestCase with the given name. If one doesn't + // exist, creates one and returns it. + // + // Arguments: + // + // test_case_name: name of the test case + // type_param: the name of the test's type parameter, or NULL if + // this is not a typed or a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase* GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Adds a TestInfo to the unit test. + // + // Arguments: + // + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + // test_info: the TestInfo object + void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + TestInfo* test_info) { + // In order to support thread-safe death tests, we need to + // remember the original working directory when the test program + // was first invoked. We cannot do this in RUN_ALL_TESTS(), as + // the user may have changed the current directory before calling + // RUN_ALL_TESTS(). Therefore we capture the current directory in + // AddTestInfo(), which is called to register a TEST or TEST_F + // before main() is reached. + if (original_working_dir_.IsEmpty()) { + original_working_dir_.Set(FilePath::GetCurrentDir()); + GTEST_CHECK_(!original_working_dir_.IsEmpty()) + << "Failed to get the current working directory."; + } + + GetTestCase(test_info->test_case_name(), + test_info->type_param(), + set_up_tc, + tear_down_tc)->AddTestInfo(test_info); + } + +#if GTEST_HAS_PARAM_TEST + // Returns ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + return parameterized_test_registry_; + } +#endif // GTEST_HAS_PARAM_TEST + + // Sets the TestCase object for the test that's currently running. + void set_current_test_case(TestCase* a_current_test_case) { + current_test_case_ = a_current_test_case; + } + + // Sets the TestInfo object for the test that's currently running. If + // current_test_info is NULL, the assertion results will be stored in + // ad_hoc_test_result_. + void set_current_test_info(TestInfo* a_current_test_info) { + current_test_info_ = a_current_test_info; + } + + // Registers all parameterized tests defined using TEST_P and + // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter + // combination. This method can be called more then once; it has guards + // protecting from registering the tests more then once. If + // value-parameterized tests are disabled, RegisterParameterizedTests is + // present but does nothing. + void RegisterParameterizedTests(); + + // Runs all tests in this UnitTest object, prints the result, and + // returns true if all tests are successful. If any exception is + // thrown during a test, this test is considered to be failed, but + // the rest of the tests will still be run. + bool RunAllTests(); + + // Clears the results of all tests, except the ad hoc tests. + void ClearNonAdHocTestResult() { + ForEach(test_cases_, TestCase::ClearTestCaseResult); + } + + // Clears the results of ad-hoc test assertions. + void ClearAdHocTestResult() { + ad_hoc_test_result_.Clear(); + } + + enum ReactionToSharding { + HONOR_SHARDING_PROTOCOL, + IGNORE_SHARDING_PROTOCOL + }; + + // Matches the full name of each test against the user-specified + // filter to decide whether the test should run, then records the + // result in each TestCase and TestInfo object. + // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests + // based on sharding variables in the environment. + // Returns the number of tests that should run. + int FilterTests(ReactionToSharding shard_tests); + + // Prints the names of the tests matching the user-specified filter flag. + void ListTestsMatchingFilter(); + + const TestCase* current_test_case() const { return current_test_case_; } + TestInfo* current_test_info() { return current_test_info_; } + const TestInfo* current_test_info() const { return current_test_info_; } + + // Returns the vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector& environments() { return environments_; } + + // Getters for the per-thread Google Test trace stack. + std::vector& gtest_trace_stack() { + return *(gtest_trace_stack_.pointer()); + } + const std::vector& gtest_trace_stack() const { + return gtest_trace_stack_.get(); + } + +#if GTEST_HAS_DEATH_TEST + void InitDeathTestSubprocessControlInfo() { + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + } + // Returns a pointer to the parsed --gtest_internal_run_death_test + // flag, or NULL if that flag was not specified. + // This information is useful only in a death test child process. + // Must not be called before a call to InitGoogleTest. + const InternalRunDeathTestFlag* internal_run_death_test_flag() const { + return internal_run_death_test_flag_.get(); + } + + // Returns a pointer to the current death test factory. + internal::DeathTestFactory* death_test_factory() { + return death_test_factory_.get(); + } + + void SuppressTestEventsIfInSubprocess(); + + friend class ReplaceDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + + // Initializes the event listener performing XML output as specified by + // UnitTestOptions. Must not be called before InitGoogleTest. + void ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Initializes the event listener for streaming test results to a socket. + // Must not be called before InitGoogleTest. + void ConfigureStreamingOutput(); +#endif + + // Performs initialization dependent upon flag values obtained in + // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to + // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest + // this function is also called from RunAllTests. Since this function can be + // called more than once, it has to be idempotent. + void PostFlagParsingInit(); + + // Gets the random seed used at the start of the current test iteration. + int random_seed() const { return random_seed_; } + + // Gets the random number generator. + internal::Random* random() { return &random_; } + + // Shuffles all test cases, and the tests within each test case, + // making sure that death tests are still run first. + void ShuffleTests(); + + // Restores the test cases and tests to their order before the first shuffle. + void UnshuffleTests(); + + // Returns the value of GTEST_FLAG(catch_exceptions) at the moment + // UnitTest::Run() starts. + bool catch_exceptions() const { return catch_exceptions_; } + + private: + friend class ::testing::UnitTest; + + // Used by UnitTest::Run() to capture the state of + // GTEST_FLAG(catch_exceptions) at the moment it starts. + void set_catch_exceptions(bool value) { catch_exceptions_ = value; } + + // The UnitTest object that owns this implementation object. + UnitTest* const parent_; + + // The working directory when the first TEST() or TEST_F() was + // executed. + internal::FilePath original_working_dir_; + + // The default test part result reporters. + DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; + DefaultPerThreadTestPartResultReporter + default_per_thread_test_part_result_reporter_; + + // Points to (but doesn't own) the global test part result reporter. + TestPartResultReporterInterface* global_test_part_result_repoter_; + + // Protects read and write access to global_test_part_result_reporter_. + internal::Mutex global_test_part_result_reporter_mutex_; + + // Points to (but doesn't own) the per-thread test part result reporter. + internal::ThreadLocal + per_thread_test_part_result_reporter_; + + // The vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector environments_; + + // The vector of TestCases in their original order. It owns the + // elements in the vector. + std::vector test_cases_; + + // Provides a level of indirection for the test case list to allow + // easy shuffling and restoring the test case order. The i-th + // element of this vector is the index of the i-th test case in the + // shuffled order. + std::vector test_case_indices_; + +#if GTEST_HAS_PARAM_TEST + // ParameterizedTestRegistry object used to register value-parameterized + // tests. + internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + + // Indicates whether RegisterParameterizedTests() has been called already. + bool parameterized_tests_registered_; +#endif // GTEST_HAS_PARAM_TEST + + // Index of the last death test case registered. Initially -1. + int last_death_test_case_; + + // This points to the TestCase for the currently running test. It + // changes as Google Test goes through one test case after another. + // When no test is running, this is set to NULL and Google Test + // stores assertion results in ad_hoc_test_result_. Initially NULL. + TestCase* current_test_case_; + + // This points to the TestInfo for the currently running test. It + // changes as Google Test goes through one test after another. When + // no test is running, this is set to NULL and Google Test stores + // assertion results in ad_hoc_test_result_. Initially NULL. + TestInfo* current_test_info_; + + // Normally, a user only writes assertions inside a TEST or TEST_F, + // or inside a function called by a TEST or TEST_F. Since Google + // Test keeps track of which test is current running, it can + // associate such an assertion with the test it belongs to. + // + // If an assertion is encountered when no TEST or TEST_F is running, + // Google Test attributes the assertion result to an imaginary "ad hoc" + // test, and records the result in ad_hoc_test_result_. + TestResult ad_hoc_test_result_; + + // The list of event listeners that can be used to track events inside + // Google Test. + TestEventListeners listeners_; + + // The OS stack trace getter. Will be deleted when the UnitTest + // object is destructed. By default, an OsStackTraceGetter is used, + // but the user can set this field to use a custom getter if that is + // desired. + OsStackTraceGetterInterface* os_stack_trace_getter_; + + // True iff PostFlagParsingInit() has been called. + bool post_flag_parse_init_performed_; + + // The random number seed used at the beginning of the test run. + int random_seed_; + + // Our random number generator. + internal::Random random_; + + // How long the test took to run, in milliseconds. + TimeInMillis elapsed_time_; + +#if GTEST_HAS_DEATH_TEST + // The decomposed components of the gtest_internal_run_death_test flag, + // parsed when RUN_ALL_TESTS is called. + internal::scoped_ptr internal_run_death_test_flag_; + internal::scoped_ptr death_test_factory_; +#endif // GTEST_HAS_DEATH_TEST + + // A per-thread stack of traces created by the SCOPED_TRACE() macro. + internal::ThreadLocal > gtest_trace_stack_; + + // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() + // starts. + bool catch_exceptions_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); +}; // class UnitTestImpl + +// Convenience function for accessing the global UnitTest +// implementation object. +inline UnitTestImpl* GetUnitTestImpl() { + return UnitTest::GetInstance()->impl(); +} + +#if GTEST_USES_SIMPLE_RE + +// Internal helper functions for implementing the simple regular +// expression matcher. +GTEST_API_ bool IsInSet(char ch, const char* str); +GTEST_API_ bool IsAsciiDigit(char ch); +GTEST_API_ bool IsAsciiPunct(char ch); +GTEST_API_ bool IsRepeat(char ch); +GTEST_API_ bool IsAsciiWhiteSpace(char ch); +GTEST_API_ bool IsAsciiWordChar(char ch); +GTEST_API_ bool IsValidEscape(char ch); +GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); +GTEST_API_ bool ValidateRegex(const char* regex); +GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); +GTEST_API_ bool MatchRepetitionAndRegexAtHead( + bool escaped, char ch, char repeat, const char* regex, const char* str); +GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); + +#endif // GTEST_USES_SIMPLE_RE + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); + +#if GTEST_HAS_DEATH_TEST + +// Returns the message describing the last system error, regardless of the +// platform. +GTEST_API_ String GetLastErrnoDescription(); + +# if GTEST_OS_WINDOWS +// Provides leak-safe Windows kernel handle ownership. +class AutoHandle { + public: + AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} + explicit AutoHandle(HANDLE handle) : handle_(handle) {} + + ~AutoHandle() { Reset(); } + + HANDLE Get() const { return handle_; } + void Reset() { Reset(INVALID_HANDLE_VALUE); } + void Reset(HANDLE handle) { + if (handle != handle_) { + if (handle_ != INVALID_HANDLE_VALUE) + ::CloseHandle(handle_); + handle_ = handle; + } + } + + private: + HANDLE handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; +# endif // GTEST_OS_WINDOWS + +// Attempts to parse a string into a positive integer pointed to by the +// number parameter. Returns true if that is possible. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use +// it here. +template +bool ParseNaturalNumber(const ::std::string& str, Integer* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtoXXX's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !IsDigit(str[0])) { + return false; + } + errno = 0; + + char* end; + // BiggestConvertible is the largest integer type that system-provided + // string-to-number conversion routines can return. + +# if GTEST_OS_WINDOWS && !defined(__GNUC__) + + // MSVC and C++ Builder define __int64 instead of the standard long long. + typedef unsigned __int64 BiggestConvertible; + const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); + +# else + + typedef unsigned long long BiggestConvertible; // NOLINT + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); + +# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) + + const bool parse_success = *end == '\0' && errno == 0; + + // TODO(vladl@google.com): Convert this to compile time assertion when it is + // available. + GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); + + const Integer result = static_cast(parsed); + if (parse_success && static_cast(result) == parsed) { + *number = result; + return true; + } + return false; +} +#endif // GTEST_HAS_DEATH_TEST + +// TestResult contains some private methods that should be hidden from +// Google Test user but are required for testing. This class allow our tests +// to access them. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +class TestResultAccessor { + public: + static void RecordProperty(TestResult* test_result, + const TestProperty& property) { + test_result->RecordProperty(property); + } + + static void ClearTestPartResults(TestResult* test_result) { + test_result->ClearTestPartResults(); + } + + static const std::vector& test_part_results( + const TestResult& test_result) { + return test_result.test_part_results(); + } +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ diff --git a/utils/unittest/googletest/src/gtest-port.cc b/utils/unittest/googletest/src/gtest-port.cc new file mode 100644 index 0000000..7459562 --- /dev/null +++ b/utils/unittest/googletest/src/gtest-port.cc @@ -0,0 +1,750 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/internal/gtest-port.h" + +#include +#include +#include +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include // For TerminateProcess() +#elif GTEST_OS_WINDOWS +# include +# include +#else +# include +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_MAC +# include +# include +# include +#endif // GTEST_OS_MAC + +#include "gtest/gtest-spi.h" +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { +namespace internal { + +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC and C++Builder do not provide a definition of STDERR_FILENO. +const int kStdOutFileno = 1; +const int kStdErrFileno = 2; +#else +const int kStdOutFileno = STDOUT_FILENO; +const int kStdErrFileno = STDERR_FILENO; +#endif // _MSC_VER + +#if GTEST_OS_MAC + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const task_t task = mach_task_self(); + mach_msg_type_number_t thread_count; + thread_act_array_t thread_list; + const kern_return_t status = task_threads(task, &thread_list, &thread_count); + if (status == KERN_SUCCESS) { + // task_threads allocates resources in thread_list and we need to free them + // to avoid leaks. + vm_deallocate(task, + reinterpret_cast(thread_list), + sizeof(thread_t) * thread_count); + return static_cast(thread_count); + } else { + return 0; + } +} + +#else + +size_t GetThreadCount() { + // There's no portable way to detect the number of threads, so we just + // return 0 to indicate that we cannot detect it. + return 0; +} + +#endif // GTEST_OS_MAC + +#if GTEST_USES_POSIX_RE + +// Implements RE. Currently only needed for death tests. + +RE::~RE() { + if (is_valid_) { + // regfree'ing an invalid regex might crash because the content + // of the regex is undefined. Since the regex's are essentially + // the same, one cannot be valid (or invalid) without the other + // being so too. + regfree(&partial_regex_); + regfree(&full_regex_); + } + free(const_cast(pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.full_regex_, str, 1, &match, 0) == 0; +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = posix::StrDup(regex); + + // Reserves enough bytes to hold the regular expression used for a + // full match. + const size_t full_regex_len = strlen(regex) + 10; + char* const full_pattern = new char[full_regex_len]; + + snprintf(full_pattern, full_regex_len, "^(%s)$", regex); + is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; + // We want to call regcomp(&partial_regex_, ...) even if the + // previous expression returns false. Otherwise partial_regex_ may + // not be properly initialized can may cause trouble when it's + // freed. + // + // Some implementation of POSIX regex (e.g. on at least some + // versions of Cygwin) doesn't accept the empty string as a valid + // regex. We change it to an equivalent form "()" to be safe. + if (is_valid_) { + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; + } + EXPECT_TRUE(is_valid_) + << "Regular expression \"" << regex + << "\" is not a valid POSIX Extended regular expression."; + + delete[] full_pattern; +} + +#elif GTEST_USES_SIMPLE_RE + +// Returns true iff ch appears anywhere in str (excluding the +// terminating '\0' character). +bool IsInSet(char ch, const char* str) { + return ch != '\0' && strchr(str, ch) != NULL; +} + +// Returns true iff ch belongs to the given classification. Unlike +// similar functions in , these aren't affected by the +// current locale. +bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsAsciiPunct(char ch) { + return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); +} +bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } +bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsAsciiWordChar(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9') || ch == '_'; +} + +// Returns true iff "\\c" is a supported escape sequence. +bool IsValidEscape(char c) { + return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); +} + +// Returns true iff the given atom (specified by escaped and pattern) +// matches ch. The result is undefined if the atom is invalid. +bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { + if (escaped) { // "\\p" where p is pattern_char. + switch (pattern_char) { + case 'd': return IsAsciiDigit(ch); + case 'D': return !IsAsciiDigit(ch); + case 'f': return ch == '\f'; + case 'n': return ch == '\n'; + case 'r': return ch == '\r'; + case 's': return IsAsciiWhiteSpace(ch); + case 'S': return !IsAsciiWhiteSpace(ch); + case 't': return ch == '\t'; + case 'v': return ch == '\v'; + case 'w': return IsAsciiWordChar(ch); + case 'W': return !IsAsciiWordChar(ch); + } + return IsAsciiPunct(pattern_char) && pattern_char == ch; + } + + return (pattern_char == '.' && ch != '\n') || pattern_char == ch; +} + +// Helper function used by ValidateRegex() to format error messages. +String FormatRegexSyntaxError(const char* regex, int index) { + return (Message() << "Syntax error at index " << index + << " in simple regular expression \"" << regex << "\": ").GetString(); +} + +// Generates non-fatal failures and returns false if regex is invalid; +// otherwise returns true. +bool ValidateRegex(const char* regex) { + if (regex == NULL) { + // TODO(wan@google.com): fix the source file location in the + // assertion failures to match where the regex is used in user + // code. + ADD_FAILURE() << "NULL is not a valid simple regular expression."; + return false; + } + + bool is_valid = true; + + // True iff ?, *, or + can follow the previous atom. + bool prev_repeatable = false; + for (int i = 0; regex[i]; i++) { + if (regex[i] == '\\') { // An escape sequence + i++; + if (regex[i] == '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "'\\' cannot appear at the end."; + return false; + } + + if (!IsValidEscape(regex[i])) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "invalid escape sequence \"\\" << regex[i] << "\"."; + is_valid = false; + } + prev_repeatable = true; + } else { // Not an escape sequence. + const char ch = regex[i]; + + if (ch == '^' && i > 0) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'^' can only appear at the beginning."; + is_valid = false; + } else if (ch == '$' && regex[i + 1] != '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'$' can only appear at the end."; + is_valid = false; + } else if (IsInSet(ch, "()[]{}|")) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' is unsupported."; + is_valid = false; + } else if (IsRepeat(ch) && !prev_repeatable) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' can only follow a repeatable token."; + is_valid = false; + } + + prev_repeatable = !IsInSet(ch, "^$?*+"); + } + } + + return is_valid; +} + +// Matches a repeated regex atom followed by a valid simple regular +// expression. The regex atom is defined as c if escaped is false, +// or \c otherwise. repeat is the repetition meta character (?, *, +// or +). The behavior is undefined if str contains too many +// characters to be indexable by size_t, in which case the test will +// probably time out anyway. We are fine with this limitation as +// std::string has it too. +bool MatchRepetitionAndRegexAtHead( + bool escaped, char c, char repeat, const char* regex, + const char* str) { + const size_t min_count = (repeat == '+') ? 1 : 0; + const size_t max_count = (repeat == '?') ? 1 : + static_cast(-1) - 1; + // We cannot call numeric_limits::max() as it conflicts with the + // max() macro on Windows. + + for (size_t i = 0; i <= max_count; ++i) { + // We know that the atom matches each of the first i characters in str. + if (i >= min_count && MatchRegexAtHead(regex, str + i)) { + // We have enough matches at the head, and the tail matches too. + // Since we only care about *whether* the pattern matches str + // (as opposed to *how* it matches), there is no need to find a + // greedy match. + return true; + } + if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) + return false; + } + return false; +} + +// Returns true iff regex matches a prefix of str. regex must be a +// valid simple regular expression and not start with "^", or the +// result is undefined. +bool MatchRegexAtHead(const char* regex, const char* str) { + if (*regex == '\0') // An empty regex matches a prefix of anything. + return true; + + // "$" only matches the end of a string. Note that regex being + // valid guarantees that there's nothing after "$" in it. + if (*regex == '$') + return *str == '\0'; + + // Is the first thing in regex an escape sequence? + const bool escaped = *regex == '\\'; + if (escaped) + ++regex; + if (IsRepeat(regex[1])) { + // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so + // here's an indirect recursion. It terminates as the regex gets + // shorter in each recursion. + return MatchRepetitionAndRegexAtHead( + escaped, regex[0], regex[1], regex + 2, str); + } else { + // regex isn't empty, isn't "$", and doesn't start with a + // repetition. We match the first atom of regex with the first + // character of str and recurse. + return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && + MatchRegexAtHead(regex + 1, str + 1); + } +} + +// Returns true iff regex matches any substring of str. regex must be +// a valid simple regular expression, or the result is undefined. +// +// The algorithm is recursive, but the recursion depth doesn't exceed +// the regex length, so we won't need to worry about running out of +// stack space normally. In rare cases the time complexity can be +// exponential with respect to the regex length + the string length, +// but usually it's must faster (often close to linear). +bool MatchRegexAnywhere(const char* regex, const char* str) { + if (regex == NULL || str == NULL) + return false; + + if (*regex == '^') + return MatchRegexAtHead(regex + 1, str); + + // A successful match can be anywhere in str. + do { + if (MatchRegexAtHead(regex, str)) + return true; + } while (*str++ != '\0'); + return false; +} + +// Implements the RE class. + +RE::~RE() { + free(const_cast(pattern_)); + free(const_cast(full_pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = full_pattern_ = NULL; + if (regex != NULL) { + pattern_ = posix::StrDup(regex); + } + + is_valid_ = ValidateRegex(regex); + if (!is_valid_) { + // No need to calculate the full pattern when the regex is invalid. + return; + } + + const size_t len = strlen(regex); + // Reserves enough bytes to hold the regular expression used for a + // full match: we need space to prepend a '^', append a '$', and + // terminate the string with '\0'. + char* buffer = static_cast(malloc(len + 3)); + full_pattern_ = buffer; + + if (*regex != '^') + *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. + + // We don't use snprintf or strncpy, as they trigger a warning when + // compiled with VC++ 8.0. + memcpy(buffer, regex, len); + buffer += len; + + if (len == 0 || regex[len - 1] != '$') + *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. + + *buffer = '\0'; +} + +#endif // GTEST_USES_POSIX_RE + +const char kUnknownFile[] = "unknown file"; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { + const char* const file_name = file == NULL ? kUnknownFile : file; + + if (line < 0) { + return String::Format("%s:", file_name).c_str(); + } +#ifdef _MSC_VER + return String::Format("%s(%d):", file_name, line).c_str(); +#else + return String::Format("%s:%d:", file_name, line).c_str(); +#endif // _MSC_VER +} + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +// Note that FormatCompilerIndependentFileLocation() does NOT append colon +// to the file location it produces, unlike FormatFileLocation(). +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( + const char* file, int line) { + const char* const file_name = file == NULL ? kUnknownFile : file; + + if (line < 0) + return file_name; + else + return String::Format("%s:%d", file_name, line).c_str(); +} + + +GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) + : severity_(severity) { + const char* const marker = + severity == GTEST_INFO ? "[ INFO ]" : + severity == GTEST_WARNING ? "[WARNING]" : + severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; + GetStream() << ::std::endl << marker << " " + << FormatFileLocation(file, line).c_str() << ": "; +} + +// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. +GTestLog::~GTestLog() { + GetStream() << ::std::endl; + if (severity_ == GTEST_FATAL) { + fflush(stderr); + posix::Abort(); + } +} +// Disable Microsoft deprecation warnings for POSIX functions called from +// this class (creat, dup, dup2, and close) +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4996) +#endif // _MSC_VER + +#if GTEST_HAS_STREAM_REDIRECTION + +// Object that captures an output stream (stdout/stderr). +class CapturedStream { + public: + // The ctor redirects the stream to a temporary file. + CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { + +# if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT + char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT + + ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); + const UINT success = ::GetTempFileNameA(temp_dir_path, + "gtest_redir", + 0, // Generate unique file name. + temp_file_path); + GTEST_CHECK_(success != 0) + << "Unable to create a temporary file in " << temp_dir_path; + const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " + << temp_file_path; + filename_ = temp_file_path; +#elif GTEST_OS_LINUX_ANDROID + char name_template[] = "/sdcard/captured_stderr.XXXXXX"; + const int captured_fd = mkstemp(name_template); + filename_ = name_template; +# else + // There's no guarantee that a test has write access to the + // current directory, so we create the temporary file in the /tmp + // directory instead. + char name_template[] = "/tmp/captured_stream.XXXXXX"; + const int captured_fd = mkstemp(name_template); + filename_ = name_template; +# endif // GTEST_OS_WINDOWS + fflush(NULL); + dup2(captured_fd, fd_); + close(captured_fd); + } + + ~CapturedStream() { + remove(filename_.c_str()); + } + + String GetCapturedString() { + if (uncaptured_fd_ != -1) { + // Restores the original stream. + fflush(NULL); + dup2(uncaptured_fd_, fd_); + close(uncaptured_fd_); + uncaptured_fd_ = -1; + } + + FILE* const file = posix::FOpen(filename_.c_str(), "r"); + const String content = ReadEntireFile(file); + posix::FClose(file); + return content; + } + + private: + // Reads the entire content of a file as a String. + static String ReadEntireFile(FILE* file); + + // Returns the size (in bytes) of a file. + static size_t GetFileSize(FILE* file); + + const int fd_; // A stream to capture. + int uncaptured_fd_; + // Name of the temporary file holding the stderr output. + ::std::string filename_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); +}; + +// Returns the size (in bytes) of a file. +size_t CapturedStream::GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); +} + +// Reads the entire content of a file as a string. +String CapturedStream::ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const String content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +# ifdef _MSC_VER +# pragma warning(pop) +# endif // _MSC_VER + +static CapturedStream* g_captured_stderr = NULL; +static CapturedStream* g_captured_stdout = NULL; + +// Starts capturing an output stream (stdout/stderr). +void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { + if (*stream != NULL) { + GTEST_LOG_(FATAL) << "Only one " << stream_name + << " capturer can exist at a time."; + } + *stream = new CapturedStream(fd); +} + +// Stops capturing the output stream and returns the captured string. +String GetCapturedStream(CapturedStream** captured_stream) { + const String content = (*captured_stream)->GetCapturedString(); + + delete *captured_stream; + *captured_stream = NULL; + + return content; +} + +// Starts capturing stdout. +void CaptureStdout() { + CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); +} + +// Starts capturing stderr. +void CaptureStderr() { + CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); +} + +// Stops capturing stdout and returns the captured string. +String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } + +// Stops capturing stderr and returns the captured string. +String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } + +#endif // GTEST_HAS_STREAM_REDIRECTION + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +::std::vector g_argvs; + +// Returns the command line as a vector of strings. +const ::std::vector& GetArgvs() { return g_argvs; } + +#endif // GTEST_HAS_DEATH_TEST + +#if GTEST_OS_WINDOWS_MOBILE +namespace posix { +void Abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +} // namespace posix +#endif // GTEST_OS_WINDOWS_MOBILE + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GTEST_FOO" in the open-source version. +static String FlagToEnvVar(const char* flag) { + const String full_flag = + (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); + + Message env_var; + for (size_t i = 0; i != full_flag.length(); i++) { + env_var << ToUpper(full_flag.c_str()[i]); + } + + return env_var.GetString(); +} + +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const Message& src_text, const char* str, Int32* value) { + // Parses the environment variable as a decimal integer. + char* end = NULL; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value \"" << str << "\".\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + // Is the parsed value in the range of an Int32? + const Int32 result = static_cast(long_value); + if (long_value == LONG_MAX || long_value == LONG_MIN || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value " << str << ", which overflows.\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + *value = result; + return true; +} + +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true iff it's not "0". +bool BoolFromGTestEnv(const char* flag, bool default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + return string_value == NULL ? + default_value : strcmp(string_value, "0") != 0; +} + +// Reads and returns a 32-bit integer stored in the environment +// variable corresponding to the given flag; if it isn't set or +// doesn't represent a valid 32-bit integer, returns default_value. +Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + if (string_value == NULL) { + // The environment variable is not set. + return default_value; + } + + Int32 result = default_value; + if (!ParseInt32(Message() << "Environment variable " << env_var, + string_value, &result)) { + printf("The default value %s is used.\n", + (Message() << default_value).GetString().c_str()); + fflush(stdout); + return default_value; + } + + return result; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromGTestEnv(const char* flag, const char* default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const value = posix::GetEnv(env_var.c_str()); + return value == NULL ? default_value : value; +} + +} // namespace internal +} // namespace testing diff --git a/utils/unittest/googletest/src/gtest-printers.cc b/utils/unittest/googletest/src/gtest-printers.cc new file mode 100644 index 0000000..205a394 --- /dev/null +++ b/utils/unittest/googletest/src/gtest-printers.cc @@ -0,0 +1,356 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// It uses the << operator when possible, and prints the bytes in the +// object otherwise. A user can override its behavior for a class +// type Foo by defining either operator<<(::std::ostream&, const Foo&) +// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that +// defines Foo. + +#include "gtest/gtest-printers.h" +#include +#include +#include // NOLINT +#include +#include "gtest/internal/gtest-port.h" + +namespace testing { + +namespace { + +using ::std::ostream; + +#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s. +# define snprintf _snprintf +#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. +# define snprintf _snprintf_s +#elif _MSC_VER +# define snprintf _snprintf +#endif // GTEST_OS_WINDOWS_MOBILE + +// Prints a segment of bytes in the given object. +void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, + size_t count, ostream* os) { + char text[5] = ""; + for (size_t i = 0; i != count; i++) { + const size_t j = start + i; + if (i != 0) { + // Organizes the bytes into groups of 2 for easy parsing by + // human. + if ((j % 2) == 0) + *os << ' '; + else + *os << '-'; + } + snprintf(text, sizeof(text), "%02X", obj_bytes[j]); + *os << text; + } +} + +// Prints the bytes in the given value to the given ostream. +void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, + ostream* os) { + // Tells the user how big the object is. + *os << count << "-byte object <"; + + const size_t kThreshold = 132; + const size_t kChunkSize = 64; + // If the object size is bigger than kThreshold, we'll have to omit + // some details by printing only the first and the last kChunkSize + // bytes. + // TODO(wan): let the user control the threshold using a flag. + if (count < kThreshold) { + PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); + } else { + PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); + *os << " ... "; + // Rounds up to 2-byte boundary. + const size_t resume_pos = (count - kChunkSize + 1)/2*2; + PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); + } + *os << ">"; +} + +} // namespace + +namespace internal2 { + +// Delegates to PrintBytesInObjectToImpl() to print the bytes in the +// given object. The delegation simplifies the implementation, which +// uses the << operator and thus is easier done outside of the +// ::testing::internal namespace, which contains a << operator that +// sometimes conflicts with the one in STL. +void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, + ostream* os) { + PrintBytesInObjectToImpl(obj_bytes, count, os); +} + +} // namespace internal2 + +namespace internal { + +// Depending on the value of a char (or wchar_t), we print it in one +// of three formats: +// - as is if it's a printable ASCII (e.g. 'a', '2', ' '), +// - as a hexadecimal escape sequence (e.g. '\x7F'), or +// - as a special escape sequence (e.g. '\r', '\n'). +enum CharFormat { + kAsIs, + kHexEscape, + kSpecialEscape +}; + +// Returns true if c is a printable ASCII character. We test the +// value of c directly instead of calling isprint(), which is buggy on +// Windows Mobile. +inline bool IsPrintableAscii(wchar_t c) { + return 0x20 <= c && c <= 0x7E; +} + +// Prints a wide or narrow char c as a character literal without the +// quotes, escaping it when necessary; returns how c was formatted. +// The template argument UnsignedChar is the unsigned version of Char, +// which is the type of c. +template +static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { + switch (static_cast(c)) { + case L'\0': + *os << "\\0"; + break; + case L'\'': + *os << "\\'"; + break; + case L'\\': + *os << "\\\\"; + break; + case L'\a': + *os << "\\a"; + break; + case L'\b': + *os << "\\b"; + break; + case L'\f': + *os << "\\f"; + break; + case L'\n': + *os << "\\n"; + break; + case L'\r': + *os << "\\r"; + break; + case L'\t': + *os << "\\t"; + break; + case L'\v': + *os << "\\v"; + break; + default: + if (IsPrintableAscii(c)) { + *os << static_cast(c); + return kAsIs; + } else { + *os << String::Format("\\x%X", static_cast(c)); + return kHexEscape; + } + } + return kSpecialEscape; +} + +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\'': + *os << "'"; + return kAsIs; + case L'"': + *os << "\\\""; + return kSpecialEscape; + default: + return PrintAsCharLiteralTo(c, os); + } +} + +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) { + return PrintAsWideStringLiteralTo(static_cast(c), os); +} + +// Prints a wide or narrow character c and its code. '\0' is printed +// as "'\\0'", other unprintable characters are also properly escaped +// using the standard C++ escape sequence. The template argument +// UnsignedChar is the unsigned version of Char, which is the type of c. +template +void PrintCharAndCodeTo(Char c, ostream* os) { + // First, print c as a literal in the most readable form we can find. + *os << ((sizeof(c) > 1) ? "L'" : "'"); + const CharFormat format = PrintAsCharLiteralTo(c, os); + *os << "'"; + + // To aid user debugging, we also print c's code in decimal, unless + // it's 0 (in which case c was printed as '\\0', making the code + // obvious). + if (c == 0) + return; + *os << " (" << String::Format("%d", c).c_str(); + + // For more convenience, we print c's code again in hexadecimal, + // unless c was already printed in the form '\x##' or the code is in + // [1, 9]. + if (format == kHexEscape || (1 <= c && c <= 9)) { + // Do nothing. + } else { + *os << String::Format(", 0x%X", + static_cast(c)).c_str(); + } + *os << ")"; +} + +void PrintTo(unsigned char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} +void PrintTo(signed char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} + +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its code. L'\0' is printed as "L'\\0'". +void PrintTo(wchar_t wc, ostream* os) { + PrintCharAndCodeTo(wc, os); +} + +// Prints the given array of characters to the ostream. +// The array starts at *begin, the length is len, it may include '\0' characters +// and may not be null-terminated. +static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { + *os << "\""; + bool is_previous_hex = false; + for (size_t index = 0; index < len; ++index) { + const char cur = begin[index]; + if (is_previous_hex && IsXDigit(cur)) { + // Previous character is of '\x..' form and this character can be + // interpreted as another hexadecimal digit in its number. Break string to + // disambiguate. + *os << "\" \""; + } + is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape; + } + *os << "\""; +} + +// Prints a (const) char array of 'len' elements, starting at address 'begin'. +void UniversalPrintArray(const char* begin, size_t len, ostream* os) { + PrintCharsAsStringTo(begin, len, os); +} + +// Prints the given array of wide characters to the ostream. +// The array starts at *begin, the length is len, it may include L'\0' +// characters and may not be null-terminated. +static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, + ostream* os) { + *os << "L\""; + bool is_previous_hex = false; + for (size_t index = 0; index < len; ++index) { + const wchar_t cur = begin[index]; + if (is_previous_hex && isascii(cur) && IsXDigit(static_cast(cur))) { + // Previous character is of '\x..' form and this character can be + // interpreted as another hexadecimal digit in its number. Break string to + // disambiguate. + *os << "\" L\""; + } + is_previous_hex = PrintAsWideStringLiteralTo(cur, os) == kHexEscape; + } + *os << "\""; +} + +// Prints the given C string to the ostream. +void PrintTo(const char* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintCharsAsStringTo(s, strlen(s), os); + } +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Prints the given wide C string to the ostream. +void PrintTo(const wchar_t* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintWideCharsAsStringTo(s, wcslen(s), os); + } +} +#endif // wchar_t is native + +// Prints a ::string object. +#if GTEST_HAS_GLOBAL_STRING +void PrintStringTo(const ::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +void PrintStringTo(const ::std::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} + +// Prints a ::wstring object. +#if GTEST_HAS_GLOBAL_WSTRING +void PrintWideStringTo(const ::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +void PrintWideStringTo(const ::std::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_STD_WSTRING + +} // namespace internal + +} // namespace testing diff --git a/utils/unittest/googletest/src/gtest-test-part.cc b/utils/unittest/googletest/src/gtest-test-part.cc new file mode 100644 index 0000000..5ddc67c --- /dev/null +++ b/utils/unittest/googletest/src/gtest-test-part.cc @@ -0,0 +1,110 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// The Google C++ Testing Framework (Google Test) + +#include "gtest/gtest-test-part.h" + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +using internal::GetUnitTestImpl; + +// Gets the summary of the failure message by omitting the stack trace +// in it. +internal::String TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, internal::kStackTraceMarker); + return stack_trace == NULL ? internal::String(message) : + internal::String(message, stack_trace - message); +} + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { + return os + << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess ? "Success" : + result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : + "Non-fatal failure") << ":\n" + << result.message() << std::endl; +} + +// Appends a TestPartResult to the array. +void TestPartResultArray::Append(const TestPartResult& result) { + array_.push_back(result); +} + +// Returns the TestPartResult at the given index (0-based). +const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { + if (index < 0 || index >= size()) { + printf("\nInvalid index (%d) into TestPartResultArray.\n", index); + internal::posix::Abort(); + } + + return array_[index]; +} + +// Returns the number of TestPartResult objects in the array. +int TestPartResultArray::size() const { + return static_cast(array_.size()); +} + +namespace internal { + +HasNewFatalFailureHelper::HasNewFatalFailureHelper() + : has_new_fatal_failure_(false), + original_reporter_(GetUnitTestImpl()-> + GetTestPartResultReporterForCurrentThread()) { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); +} + +HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( + original_reporter_); +} + +void HasNewFatalFailureHelper::ReportTestPartResult( + const TestPartResult& result) { + if (result.fatally_failed()) + has_new_fatal_failure_ = true; + original_reporter_->ReportTestPartResult(result); +} + +} // namespace internal + +} // namespace testing diff --git a/utils/unittest/googletest/src/gtest-typed-test.cc b/utils/unittest/googletest/src/gtest-typed-test.cc new file mode 100644 index 0000000..a5cc88f --- /dev/null +++ b/utils/unittest/googletest/src/gtest-typed-test.cc @@ -0,0 +1,110 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#include "gtest/gtest-typed-test.h" +#include "gtest/gtest.h" + +namespace testing { +namespace internal { + +#if GTEST_HAS_TYPED_TEST_P + +// Skips to the first non-space char in str. Returns an empty string if str +// contains only whitespace characters. +static const char* SkipSpaces(const char* str) { + while (IsSpace(*str)) + str++; + return str; +} + +// Verifies that registered_tests match the test names in +// defined_test_names_; returns registered_tests if successful, or +// aborts the program otherwise. +const char* TypedTestCasePState::VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests) { + typedef ::std::set::const_iterator DefinedTestIter; + registered_ = true; + + // Skip initial whitespace in registered_tests since some + // preprocessors prefix stringizied literals with whitespace. + registered_tests = SkipSpaces(registered_tests); + + Message errors; + ::std::set tests; + for (const char* names = registered_tests; names != NULL; + names = SkipComma(names)) { + const String name = GetPrefixUntilComma(names); + if (tests.count(name) != 0) { + errors << "Test " << name << " is listed more than once.\n"; + continue; + } + + bool found = false; + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (name == *it) { + found = true; + break; + } + } + + if (found) { + tests.insert(name); + } else { + errors << "No test named " << name + << " can be found in this test case.\n"; + } + } + + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (tests.count(*it) == 0) { + errors << "You forgot to list test " << *it << ".\n"; + } + } + + const String& errors_str = errors.GetString(); + if (errors_str != "") { + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors_str.c_str()); + fflush(stderr); + posix::Abort(); + } + + return registered_tests; +} + +#endif // GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing diff --git a/utils/unittest/googletest/src/gtest.cc b/utils/unittest/googletest/src/gtest.cc new file mode 100644 index 0000000..9891928 --- /dev/null +++ b/utils/unittest/googletest/src/gtest.cc @@ -0,0 +1,4866 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) + +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include // NOLINT +#include +#include + +#if GTEST_OS_LINUX + +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +# include // NOLINT +# include // NOLINT +# include // NOLINT +// Declares vsnprintf(). This header is not available on Windows. +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include + +#elif GTEST_OS_SYMBIAN +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +#elif GTEST_OS_ZOS +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +// On z/OS we additionally need strings.h for strcasecmp. +# include // NOLINT + +#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. + +# include // NOLINT + +#elif GTEST_OS_WINDOWS // We are on Windows proper. + +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT + +# if GTEST_OS_WINDOWS_MINGW +// MinGW has gettimeofday() but not _ftime64(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +// TODO(kenton@google.com): There are other ways to get the time on +// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW +// supports these. consider using them instead. +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT +# endif // GTEST_OS_WINDOWS_MINGW + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT + +#else + +// Assume other platforms have gettimeofday(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT +# include // NOLINT + +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +# include +#endif + +#if GTEST_CAN_STREAM_RESULTS_ +# include // NOLINT +# include // NOLINT +#endif + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#include "src/gtest-internal-inl.h" +#undef GTEST_IMPLEMENTATION_ + +#if GTEST_OS_WINDOWS +# define vsnprintf _vsnprintf +#endif // GTEST_OS_WINDOWS + +namespace testing { + +using internal::CountIf; +using internal::ForEach; +using internal::GetElementOr; +using internal::Shuffle; + +// Constants. + +// A test whose test case name or test name matches this filter is +// disabled and not run. +static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; + +// A test case whose name matches this filter is considered a death +// test case and will be run before test cases whose name doesn't +// match this filter. +static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; + +// A test filter that matches everything. +static const char kUniversalFilter[] = "*"; + +// The default output file for XML output. +static const char kDefaultOutputFile[] = "test_detail.xml"; + +// The environment variable name for the test shard index. +static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; +// The environment variable name for the total number of test shards. +static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; +// The environment variable name for the test shard status file. +static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; + +namespace internal { + +// The text used in failure messages to indicate the start of the +// stack trace. +const char kStackTraceMarker[] = "\nStack trace:\n"; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +bool g_help_flag = false; + +} // namespace internal + +GTEST_DEFINE_bool_( + also_run_disabled_tests, + internal::BoolFromGTestEnv("also_run_disabled_tests", false), + "Run disabled tests too, in addition to the tests normally being run."); + +GTEST_DEFINE_bool_( + break_on_failure, + internal::BoolFromGTestEnv("break_on_failure", false), + "True iff a failed assertion should be a debugger break-point."); + +GTEST_DEFINE_bool_( + catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", true), + "True iff " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); + +GTEST_DEFINE_string_( + color, + internal::StringFromGTestEnv("color", "auto"), + "Whether to use colors in the output. Valid values: yes, no, " + "and auto. 'auto' means to use colors if the output is " + "being sent to a terminal and the TERM environment variable " + "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); + +GTEST_DEFINE_string_( + filter, + internal::StringFromGTestEnv("filter", kUniversalFilter), + "A colon-separated list of glob (not regex) patterns " + "for filtering the tests to run, optionally followed by a " + "'-' and a : separated list of negative patterns (tests to " + "exclude). A test is run if it matches one of the positive " + "patterns and does not match any of the negative patterns."); + +GTEST_DEFINE_bool_(list_tests, false, + "List all tests without running them."); + +GTEST_DEFINE_string_( + output, + internal::StringFromGTestEnv("output", ""), + "A format (currently must be \"xml\"), optionally followed " + "by a colon and an output file name or directory. A directory " + "is indicated by a trailing pathname separator. " + "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " + "If a directory is specified, output files will be created " + "within that directory, with file-names based on the test " + "executable's name and, if necessary, made unique by adding " + "digits."); + +GTEST_DEFINE_bool_( + print_time, + internal::BoolFromGTestEnv("print_time", true), + "True iff " GTEST_NAME_ + " should display elapsed time in text output."); + +GTEST_DEFINE_int32_( + random_seed, + internal::Int32FromGTestEnv("random_seed", 0), + "Random number seed to use when shuffling test orders. Must be in range " + "[1, 99999], or 0 to use a seed based on the current time."); + +GTEST_DEFINE_int32_( + repeat, + internal::Int32FromGTestEnv("repeat", 1), + "How many times to repeat each test. Specify a negative number " + "for repeating forever. Useful for shaking out flaky tests."); + +GTEST_DEFINE_bool_( + show_internal_stack_frames, false, + "True iff " GTEST_NAME_ " should include internal stack frames when " + "printing test failure stack traces."); + +GTEST_DEFINE_bool_( + shuffle, + internal::BoolFromGTestEnv("shuffle", false), + "True iff " GTEST_NAME_ + " should randomize tests' order on every run."); + +GTEST_DEFINE_int32_( + stack_trace_depth, + internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), + "The maximum number of stack frames to print when an " + "assertion fails. The valid range is 0 through 100, inclusive."); + +GTEST_DEFINE_string_( + stream_result_to, + internal::StringFromGTestEnv("stream_result_to", ""), + "This flag specifies the host name and the port number on which to stream " + "test results. Example: \"localhost:555\". The flag is effective only on " + "Linux."); + +GTEST_DEFINE_bool_( + throw_on_failure, + internal::BoolFromGTestEnv("throw_on_failure", false), + "When this flag is specified, a failed assertion will throw an exception " + "if exceptions are enabled or exit the program with a non-zero code " + "otherwise."); + +namespace internal { + +// Generates a random number from [0, range), using a Linear +// Congruential Generator (LCG). Crashes if 'range' is 0 or greater +// than kMaxRange. +UInt32 Random::Generate(UInt32 range) { + // These constants are the same as are used in glibc's rand(3). + state_ = (1103515245U*state_ + 12345U) % kMaxRange; + + GTEST_CHECK_(range > 0) + << "Cannot generate a number in the range [0, 0)."; + GTEST_CHECK_(range <= kMaxRange) + << "Generation of a number in [0, " << range << ") was requested, " + << "but this can only generate numbers in [0, " << kMaxRange << ")."; + + // Converting via modulus introduces a bit of downward bias, but + // it's simple, and a linear congruential generator isn't too good + // to begin with. + return state_ % range; +} + +// GTestIsInitialized() returns true iff the user has initialized +// Google Test. Useful for catching the user mistake of not initializing +// Google Test before calling RUN_ALL_TESTS(). +// +// A user must call testing::InitGoogleTest() to initialize Google +// Test. g_init_gtest_count is set to the number of times +// InitGoogleTest() has been called. We don't protect this variable +// under a mutex as it is only accessed in the main thread. +int g_init_gtest_count = 0; +static bool GTestIsInitialized() { return g_init_gtest_count != 0; } + +// Iterates over a vector of TestCases, keeping a running sum of the +// results of calling a given int-returning method on each. +// Returns the sum. +static int SumOverTestCaseList(const std::vector& case_list, + int (TestCase::*method)() const) { + int sum = 0; + for (size_t i = 0; i < case_list.size(); i++) { + sum += (case_list[i]->*method)(); + } + return sum; +} + +// Returns true iff the test case passed. +static bool TestCasePassed(const TestCase* test_case) { + return test_case->should_run() && test_case->Passed(); +} + +// Returns true iff the test case failed. +static bool TestCaseFailed(const TestCase* test_case) { + return test_case->should_run() && test_case->Failed(); +} + +// Returns true iff test_case contains at least one test that should +// run. +static bool ShouldRunTestCase(const TestCase* test_case) { + return test_case->should_run(); +} + +// AssertHelper constructor. +AssertHelper::AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message) + : data_(new AssertHelperData(type, file, line, message)) { +} + +AssertHelper::~AssertHelper() { + delete data_; +} + +// Message assignment, for assertion streaming support. +void AssertHelper::operator=(const Message& message) const { + UnitTest::GetInstance()-> + AddTestPartResult(data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), + UnitTest::GetInstance()->impl() + ->CurrentOsStackTraceExceptTop(1) + // Skips the stack frame for this function itself. + ); // NOLINT +} + +// Mutex for linked pointers. +GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// Application pathname gotten in InitGoogleTest. +String g_executable_path; + +// Returns the current application's name, removing directory path if that +// is present. +FilePath GetCurrentExecutableName() { + FilePath result; + +#if GTEST_OS_WINDOWS + result.Set(FilePath(g_executable_path).RemoveExtension("exe")); +#else + result.Set(FilePath(g_executable_path)); +#endif // GTEST_OS_WINDOWS + + return result.RemoveDirectoryName(); +} + +// Functions for processing the gtest_output flag. + +// Returns the output format, or "" for normal printed output. +String UnitTestOptions::GetOutputFormat() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + return (colon == NULL) ? + String(gtest_output_flag) : + String(gtest_output_flag, colon - gtest_output_flag); +} + +// Returns the name of the requested output file, or the default if none +// was explicitly specified. +String UnitTestOptions::GetAbsolutePathToOutputFile() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) + return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + if (colon == NULL) + return String(internal::FilePath::ConcatPaths( + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(kDefaultOutputFile)).ToString() ); + + internal::FilePath output_name(colon + 1); + if (!output_name.IsAbsolutePath()) + // TODO(wan@google.com): on Windows \some\path is not an absolute + // path (as its meaning depends on the current drive), yet the + // following logic for turning it into an absolute path is wrong. + // Fix it. + output_name = internal::FilePath::ConcatPaths( + internal::FilePath(UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(colon + 1)); + + if (!output_name.IsDirectory()) + return output_name.ToString(); + + internal::FilePath result(internal::FilePath::GenerateUniqueFileName( + output_name, internal::GetCurrentExecutableName(), + GetOutputFormat().c_str())); + return result.ToString(); +} + +// Returns true iff the wildcard pattern matches the string. The +// first ':' or '\0' character in pattern marks the end of it. +// +// This recursive algorithm isn't very efficient, but is clear and +// works well enough for matching test names, which are short. +bool UnitTestOptions::PatternMatchesString(const char *pattern, + const char *str) { + switch (*pattern) { + case '\0': + case ':': // Either ':' or '\0' marks the end of the pattern. + return *str == '\0'; + case '?': // Matches any single character. + return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); + case '*': // Matches any string (possibly empty) of characters. + return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || + PatternMatchesString(pattern + 1, str); + default: // Non-special character. Matches itself. + return *pattern == *str && + PatternMatchesString(pattern + 1, str + 1); + } +} + +bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { + const char *cur_pattern = filter; + for (;;) { + if (PatternMatchesString(cur_pattern, name.c_str())) { + return true; + } + + // Finds the next pattern in the filter. + cur_pattern = strchr(cur_pattern, ':'); + + // Returns if no more pattern can be found. + if (cur_pattern == NULL) { + return false; + } + + // Skips the pattern separater (the ':' character). + cur_pattern++; + } +} + +// TODO(keithray): move String function implementations to gtest-string.cc. + +// Returns true iff the user-specified filter matches the test case +// name and the test name. +bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, + const String &test_name) { + const String& full_name = String::Format("%s.%s", + test_case_name.c_str(), + test_name.c_str()); + + // Split --gtest_filter at '-', if there is one, to separate into + // positive filter and negative filter portions + const char* const p = GTEST_FLAG(filter).c_str(); + const char* const dash = strchr(p, '-'); + String positive; + String negative; + if (dash == NULL) { + positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter + negative = String(""); + } else { + positive = String(p, dash - p); // Everything up to the dash + negative = String(dash+1); // Everything after the dash + if (positive.empty()) { + // Treat '-test1' as the same as '*-test1' + positive = kUniversalFilter; + } + } + + // A filter is a colon-separated list of patterns. It matches a + // test if any pattern in it matches the test. + return (MatchesFilter(full_name, positive.c_str()) && + !MatchesFilter(full_name, negative.c_str())); +} + +#if GTEST_HAS_SEH +// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the +// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. +// This function is useful as an __except condition. +int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { + // Google Test should handle a SEH exception if: + // 1. the user wants it to, AND + // 2. this is not a breakpoint exception, AND + // 3. this is not a C++ exception (VC++ implements them via SEH, + // apparently). + // + // SEH exception code for C++ exceptions. + // (see http://support.microsoft.com/kb/185294 for more information). + const DWORD kCxxExceptionCode = 0xe06d7363; + + bool should_handle = true; + + if (!GTEST_FLAG(catch_exceptions)) + should_handle = false; + else if (exception_code == EXCEPTION_BREAKPOINT) + should_handle = false; + else if (exception_code == kCxxExceptionCode) + should_handle = false; + + return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} +#endif // GTEST_HAS_SEH + +} // namespace internal + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. Intercepts only failures from the current thread. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + TestPartResultArray* result) + : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), + result_(result) { + Init(); +} + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + InterceptMode intercept_mode, TestPartResultArray* result) + : intercept_mode_(intercept_mode), + result_(result) { + Init(); +} + +void ScopedFakeTestPartResultReporter::Init() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + old_reporter_ = impl->GetGlobalTestPartResultReporter(); + impl->SetGlobalTestPartResultReporter(this); + } else { + old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); + impl->SetTestPartResultReporterForCurrentThread(this); + } +} + +// The d'tor restores the test part result reporter used by Google Test +// before. +ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + impl->SetGlobalTestPartResultReporter(old_reporter_); + } else { + impl->SetTestPartResultReporterForCurrentThread(old_reporter_); + } +} + +// Increments the test part result count and remembers the result. +// This method is from the TestPartResultReporterInterface interface. +void ScopedFakeTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + result_->Append(result); +} + +namespace internal { + +// Returns the type ID of ::testing::Test. We should always call this +// instead of GetTypeId< ::testing::Test>() to get the type ID of +// testing::Test. This is to work around a suspected linker bug when +// using Google Test as a framework on Mac OS X. The bug causes +// GetTypeId< ::testing::Test>() to return different values depending +// on whether the call is from the Google Test framework itself or +// from user test code. GetTestTypeId() is guaranteed to always +// return the same value, as it always calls GetTypeId<>() from the +// gtest.cc, which is within the Google Test framework. +TypeId GetTestTypeId() { + return GetTypeId(); +} + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); + +// This predicate-formatter checks that 'results' contains a test part +// failure of the given type and that the failure message contains the +// given substring. +AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const string& substr) { + const String expected(type == TestPartResult::kFatalFailure ? + "1 fatal failure" : + "1 non-fatal failure"); + Message msg; + if (results.size() != 1) { + msg << "Expected: " << expected << "\n" + << " Actual: " << results.size() << " failures"; + for (int i = 0; i < results.size(); i++) { + msg << "\n" << results.GetTestPartResult(i); + } + return AssertionFailure() << msg; + } + + const TestPartResult& r = results.GetTestPartResult(0); + if (r.type() != type) { + return AssertionFailure() << "Expected: " << expected << "\n" + << " Actual:\n" + << r; + } + + if (strstr(r.message(), substr.c_str()) == NULL) { + return AssertionFailure() << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; + } + + return AssertionSuccess(); +} + +// The constructor of SingleFailureChecker remembers where to look up +// test part results, what type of failure we expect, and what +// substring the failure message should contain. +SingleFailureChecker:: SingleFailureChecker( + const TestPartResultArray* results, + TestPartResult::Type type, + const string& substr) + : results_(results), + type_(type), + substr_(substr) {} + +// The destructor of SingleFailureChecker verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +SingleFailureChecker::~SingleFailureChecker() { + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); +} + +DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultGlobalTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->current_test_result()->AddTestPartResult(result); + unit_test_->listeners()->repeater()->OnTestPartResult(result); +} + +DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); +} + +// Returns the global test part result reporter. +TestPartResultReporterInterface* +UnitTestImpl::GetGlobalTestPartResultReporter() { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + return global_test_part_result_repoter_; +} + +// Sets the global test part result reporter. +void UnitTestImpl::SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter) { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + global_test_part_result_repoter_ = reporter; +} + +// Returns the test part result reporter for the current thread. +TestPartResultReporterInterface* +UnitTestImpl::GetTestPartResultReporterForCurrentThread() { + return per_thread_test_part_result_reporter_.get(); +} + +// Sets the test part result reporter for the current thread. +void UnitTestImpl::SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter) { + per_thread_test_part_result_reporter_.set(reporter); +} + +// Gets the number of successful test cases. +int UnitTestImpl::successful_test_case_count() const { + return CountIf(test_cases_, TestCasePassed); +} + +// Gets the number of failed test cases. +int UnitTestImpl::failed_test_case_count() const { + return CountIf(test_cases_, TestCaseFailed); +} + +// Gets the number of all test cases. +int UnitTestImpl::total_test_case_count() const { + return static_cast(test_cases_.size()); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTestImpl::test_case_to_run_count() const { + return CountIf(test_cases_, ShouldRunTestCase); +} + +// Gets the number of successful tests. +int UnitTestImpl::successful_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); +} + +// Gets the number of failed tests. +int UnitTestImpl::failed_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); +} + +// Gets the number of disabled tests. +int UnitTestImpl::disabled_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); +} + +// Gets the number of all tests. +int UnitTestImpl::total_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); +} + +// Gets the number of tests that should run. +int UnitTestImpl::test_to_run_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// CurrentOsStackTraceExceptTop(1), Foo() will be included in the +// trace but Bar() and CurrentOsStackTraceExceptTop() won't. +String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { + (void)skip_count; + return String(""); +} + +// Returns the current time in milliseconds. +TimeInMillis GetTimeInMillis() { +#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) + // Difference between 1970-01-01 and 1601-01-01 in milliseconds. + // http://analogous.blogspot.com/2005/04/epoch.html + const TimeInMillis kJavaEpochToWinFileTimeDelta = + static_cast(116444736UL) * 100000UL; + const DWORD kTenthMicrosInMilliSecond = 10000; + + SYSTEMTIME now_systime; + FILETIME now_filetime; + ULARGE_INTEGER now_int64; + // TODO(kenton@google.com): Shouldn't this just use + // GetSystemTimeAsFileTime()? + GetSystemTime(&now_systime); + if (SystemTimeToFileTime(&now_systime, &now_filetime)) { + now_int64.LowPart = now_filetime.dwLowDateTime; + now_int64.HighPart = now_filetime.dwHighDateTime; + now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - + kJavaEpochToWinFileTimeDelta; + return now_int64.QuadPart; + } + return 0; +#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ + __timeb64 now; + +# ifdef _MSC_VER + + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 + // (deprecated function) there. + // TODO(kenton@google.com): Use GetTickCount()? Or use + // SystemTimeToFileTime() +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + _ftime64(&now); +# pragma warning(pop) // Restores the warning state. +# else + + _ftime64(&now); + +# endif // _MSC_VER + + return static_cast(now.time) * 1000 + now.millitm; +#elif GTEST_HAS_GETTIMEOFDAY_ + struct timeval now; + gettimeofday(&now, NULL); + return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; +#else +# error "Don't know how to get the current time on your system." +#endif +} + +// Utilities + +// class String + +// Returns the input enclosed in double quotes if it's not NULL; +// otherwise returns "(null)". For example, "\"Hello\"" is returned +// for input "Hello". +// +// This is useful for printing a C string in the syntax of a literal. +// +// Known issue: escape sequences are not handled yet. +String String::ShowCStringQuoted(const char* c_str) { + return c_str ? String::Format("\"%s\"", c_str) : String("(null)"); +} + +// Copies at most length characters from str into a newly-allocated +// piece of memory of size length+1. The memory is allocated with new[]. +// A terminating null byte is written to the memory, and a pointer to it +// is returned. If str is NULL, NULL is returned. +static char* CloneString(const char* str, size_t length) { + if (str == NULL) { + return NULL; + } else { + char* const clone = new char[length + 1]; + posix::StrNCpy(clone, str, length); + clone[length] = '\0'; + return clone; + } +} + +// Clones a 0-terminated C string, allocating memory using new. The +// caller is responsible for deleting[] the return value. Returns the +// cloned string, or NULL if the input is NULL. +const char * String::CloneCString(const char* c_str) { + return (c_str == NULL) ? + NULL : CloneString(c_str, strlen(c_str)); +} + +#if GTEST_OS_WINDOWS_MOBILE +// Creates a UTF-16 wide string from the given ANSI string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the wide string, or NULL if the +// input is NULL. +LPCWSTR String::AnsiToUtf16(const char* ansi) { + if (!ansi) return NULL; + const int length = strlen(ansi); + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi, length, + NULL, 0); + WCHAR* unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, + unicode, unicode_length); + unicode[unicode_length] = 0; + return unicode; +} + +// Creates an ANSI string from the given wide string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the ANSI string, or NULL if the +// input is NULL. +const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return NULL; + const int ansi_length = + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + NULL, 0, NULL, NULL); + char* ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + ansi, ansi_length, NULL, NULL); + ansi[ansi_length] = 0; + return ansi; +} + +#endif // GTEST_OS_WINDOWS_MOBILE + +// Compares two C strings. Returns true iff they have the same content. +// +// Unlike strcmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CStringEquals(const char * lhs, const char * rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + + return strcmp(lhs, rhs) == 0; +} + +#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +// Converts an array of wide chars to a narrow string using the UTF-8 +// encoding, and streams the result to the given Message object. +static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, + Message* msg) { + // TODO(wan): consider allowing a testing::String object to + // contain '\0'. This will make it behave more like std::string, + // and will allow ToUtf8String() to return the correct encoding + // for '\0' s.t. we can get rid of the conditional here (and in + // several other places). + for (size_t i = 0; i != length; ) { // NOLINT + if (wstr[i] != L'\0') { + *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); + while (i != length && wstr[i] != L'\0') + i++; + } else { + *msg << '\0'; + i++; + } + } +} + +#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +} // namespace internal + +#if GTEST_HAS_STD_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::std::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +// AssertionResult constructors. +// Used in EXPECT_TRUE/FALSE(assertion_result). +AssertionResult::AssertionResult(const AssertionResult& other) + : success_(other.success_), + message_(other.message_.get() != NULL ? + new ::std::string(*other.message_) : + static_cast< ::std::string*>(NULL)) { +} + +// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. +AssertionResult AssertionResult::operator!() const { + AssertionResult negation(!success_); + if (message_.get() != NULL) + negation << *message_; + return negation; +} + +// Makes a successful assertion result. +AssertionResult AssertionSuccess() { + return AssertionResult(true); +} + +// Makes a failed assertion result. +AssertionResult AssertionFailure() { + return AssertionResult(false); +} + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << message. +AssertionResult AssertionFailure(const Message& message) { + return AssertionFailure() << message; +} + +namespace internal { + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case) { + Message msg; + msg << "Value of: " << actual_expression; + if (actual_value != actual_expression) { + msg << "\n Actual: " << actual_value; + } + + msg << "\nExpected: " << expected_expression; + if (ignoring_case) { + msg << " (ignoring case)"; + } + if (expected_value != expected_expression) { + msg << "\nWhich is: " << expected_value; + } + + return AssertionFailure() << msg; +} + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value) { + const char* actual_message = assertion_result.message(); + Message msg; + msg << "Value of: " << expression_text + << "\n Actual: " << actual_predicate_value; + if (actual_message[0] != '\0') + msg << " (" << actual_message << ")"; + msg << "\nExpected: " << expected_predicate_value; + return msg.GetString(); +} + +// Helper function for implementing ASSERT_NEAR. +AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error) { + const double diff = fabs(val1 - val2); + if (diff <= abs_error) return AssertionSuccess(); + + // TODO(wan): do not print the value of an expression if it's + // already a literal. + return AssertionFailure() + << "The difference between " << expr1 << " and " << expr2 + << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; +} + + +// Helper template for implementing FloatLE() and DoubleLE(). +template +AssertionResult FloatingPointLE(const char* expr1, + const char* expr2, + RawType val1, + RawType val2) { + // Returns success if val1 is less than val2, + if (val1 < val2) { + return AssertionSuccess(); + } + + // or if val1 is almost equal to val2. + const FloatingPoint lhs(val1), rhs(val2); + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + // Note that the above two checks will both fail if either val1 or + // val2 is NaN, as the IEEE floating-point standard requires that + // any predicate involving a NaN must return false. + + ::std::stringstream val1_ss; + val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val1; + + ::std::stringstream val2_ss; + val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val2; + + return AssertionFailure() + << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StringStreamToString(&val1_ss) << " vs " + << StringStreamToString(&val2_ss); +} + +} // namespace internal + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +namespace internal { + +// The helper function for {ASSERT|EXPECT}_EQ with int or enum +// arguments. +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + if (expected == actual) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here +// just to avoid copy-and-paste of similar code. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + BiggestInt val1, BiggestInt val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +} + +// Implements the helper function for {ASSERT|EXPECT}_NE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(NE, !=) +// Implements the helper function for {ASSERT|EXPECT}_LE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LE, <=) +// Implements the helper function for {ASSERT|EXPECT}_LT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LT, < ) +// Implements the helper function for {ASSERT|EXPECT}_GE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GE, >=) +// Implements the helper function for {ASSERT|EXPECT}_GT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GT, > ) + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + false); +} + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CaseInsensitiveCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + true); +} + +// The helper function for {ASSERT|EXPECT}_STRNE. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CaseInsensitiveCStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() + << "Expected: (" << s1_expression << ") != (" + << s2_expression << ") (ignoring case), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +} // namespace internal + +namespace { + +// Helper functions for implementing IsSubString() and IsNotSubstring(). + +// This group of overloaded functions return true iff needle is a +// substring of haystack. NULL is considered a substring of itself +// only. + +bool IsSubstringPred(const char* needle, const char* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return strstr(haystack, needle) != NULL; +} + +bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return wcsstr(haystack, needle) != NULL; +} + +// StringType here can be either ::std::string or ::std::wstring. +template +bool IsSubstringPred(const StringType& needle, + const StringType& haystack) { + return haystack.find(needle) != StringType::npos; +} + +// This function implements either IsSubstring() or IsNotSubstring(), +// depending on the value of the expected_to_be_substring parameter. +// StringType here can be const char*, const wchar_t*, ::std::string, +// or ::std::wstring. +template +AssertionResult IsSubstringImpl( + bool expected_to_be_substring, + const char* needle_expr, const char* haystack_expr, + const StringType& needle, const StringType& haystack) { + if (IsSubstringPred(needle, haystack) == expected_to_be_substring) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(needle[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure() + << "Value of: " << needle_expr << "\n" + << " Actual: " << begin_string_quote << needle << "\"\n" + << "Expected: " << (expected_to_be_substring ? "" : "not ") + << "a substring of " << haystack_expr << "\n" + << "Which is: " << begin_string_quote << haystack << "\""; +} + +} // namespace + +// IsSubstring() and IsNotSubstring() check whether needle is a +// substring of haystack (NULL is considered a substring of itself +// only), and return an appropriate error message when they fail. + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +#if GTEST_HAS_STD_WSTRING +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +#if GTEST_OS_WINDOWS + +namespace { + +// Helper function for IsHRESULT{SuccessFailure} predicates +AssertionResult HRESULTFailureHelper(const char* expr, + const char* expected, + long hr) { // NOLINT +# if GTEST_OS_WINDOWS_MOBILE + + // Windows CE doesn't support FormatMessage. + const char error_text[] = ""; + +# else + + // Looks up the human-readable system message for the HRESULT code + // and since we're not passing any params to FormatMessage, we don't + // want inserts expanded. + const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS; + const DWORD kBufSize = 4096; // String::Format can't exceed this length. + // Gets the system's human readable message string for this HRESULT. + char error_text[kBufSize] = { '\0' }; + DWORD message_length = ::FormatMessageA(kFlags, + 0, // no source, we're asking system + hr, // the error + 0, // no line width restrictions + error_text, // output buffer + kBufSize, // buf size + NULL); // no arguments for inserts + // Trims tailing white space (FormatMessage leaves a trailing cr-lf) + for (; message_length && IsSpace(error_text[message_length - 1]); + --message_length) { + error_text[message_length - 1] = '\0'; + } + +# endif // GTEST_OS_WINDOWS_MOBILE + + const String error_hex(String::Format("0x%08X ", hr)); + return ::testing::AssertionFailure() + << "Expected: " << expr << " " << expected << ".\n" + << " Actual: " << error_hex << error_text << "\n"; +} + +} // namespace + +AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT + if (SUCCEEDED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "succeeds", hr); +} + +AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT + if (FAILED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "fails", hr); +} + +#endif // GTEST_OS_WINDOWS + +// Utility functions for encoding Unicode text (wide strings) in +// UTF-8. + +// A Unicode code-point can have up to 21 bits, and is encoded in UTF-8 +// like this: +// +// Code-point length Encoding +// 0 - 7 bits 0xxxxxxx +// 8 - 11 bits 110xxxxx 10xxxxxx +// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx +// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +// The maximum code-point a one-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; + +// The maximum code-point a two-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; + +// The maximum code-point a three-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; + +// The maximum code-point a four-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; + +// Chops off the n lowest bits from a bit pattern. Returns the n +// lowest bits. As a side effect, the original bit pattern will be +// shifted to the right by n bits. +inline UInt32 ChopLowBits(UInt32* bits, int n) { + const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); + *bits >>= n; + return low_bits; +} + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +char* CodePointToUtf8(UInt32 code_point, char* str) { + if (code_point <= kMaxCodePoint1) { + str[1] = '\0'; + str[0] = static_cast(code_point); // 0xxxxxxx + } else if (code_point <= kMaxCodePoint2) { + str[2] = '\0'; + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xC0 | code_point); // 110xxxxx + } else if (code_point <= kMaxCodePoint3) { + str[3] = '\0'; + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xE0 | code_point); // 1110xxxx + } else if (code_point <= kMaxCodePoint4) { + str[4] = '\0'; + str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xF0 | code_point); // 11110xxx + } else { + // The longest string String::Format can produce when invoked + // with these parameters is 28 character long (not including + // the terminating nul character). We are asking for 32 character + // buffer just in case. This is also enough for strncpy to + // null-terminate the destination string. + posix::StrNCpy( + str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); + str[31] = '\0'; // Makes sure no change in the format to strncpy leaves + // the result unterminated. + } + return str; +} + +// The following two functions only make sense if the system +// uses UTF-16 for wide string encoding. All supported systems +// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. + +// Determines if the arguments constitute UTF-16 surrogate pair +// and thus should be combined into a single Unicode code point +// using CreateCodePointFromUtf16SurrogatePair. +inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { + return sizeof(wchar_t) == 2 && + (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; +} + +// Creates a Unicode code point from UTF16 surrogate pair. +inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + const UInt32 mask = (1 << 10) - 1; + return (sizeof(wchar_t) == 2) ? + (((first & mask) << 10) | (second & mask)) + 0x10000 : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + static_cast(first); +} + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +String WideStringToUtf8(const wchar_t* str, int num_chars) { + if (num_chars == -1) + num_chars = static_cast(wcslen(str)); + + ::std::stringstream stream; + for (int i = 0; i < num_chars; ++i) { + UInt32 unicode_code_point; + + if (str[i] == L'\0') { + break; + } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { + unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], + str[i + 1]); + i++; + } else { + unicode_code_point = static_cast(str[i]); + } + + char buffer[32]; // CodePointToUtf8 requires a buffer this big. + stream << CodePointToUtf8(unicode_code_point, buffer); + } + return StringStreamToString(&stream); +} + +// Converts a wide C string to a String using the UTF-8 encoding. +// NULL will be converted to "(null)". +String String::ShowWideCString(const wchar_t * wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); +} + +// Similar to ShowWideCString(), except that this function encloses +// the converted string in double quotes. +String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String::Format("L\"%s\"", + String::ShowWideCString(wide_c_str).c_str()); +} + +// Compares two wide C strings. Returns true iff they have the same +// content. +// +// Unlike wcscmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + + return wcscmp(lhs, rhs) == 0; +} + +// Helper function for *_STREQ on wide strings. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual) { + if (String::WideCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowWideCStringQuoted(expected), + String::ShowWideCStringQuoted(actual), + false); +} + +// Helper function for *_STRNE on wide strings. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2) { + if (!String::WideCStringEquals(s1, s2)) { + return AssertionSuccess(); + } + + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << String::ShowWideCStringQuoted(s1) + << " vs " << String::ShowWideCStringQuoted(s2); +} + +// Compares two C strings, ignoring case. Returns true iff they have +// the same content. +// +// Unlike strcasecmp(), this function can handle NULL argument(s). A +// NULL C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { + if (lhs == NULL) + return rhs == NULL; + if (rhs == NULL) + return false; + return posix::StrCaseCmp(lhs, rhs) == 0; +} + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + +#if GTEST_OS_WINDOWS + return _wcsicmp(lhs, rhs) == 0; +#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID + return wcscasecmp(lhs, rhs) == 0; +#else + // Android, Mac OS X and Cygwin don't define wcscasecmp. + // Other unknown OSes may not define it either. + wint_t left, right; + do { + left = towlower(*lhs++); + right = towlower(*rhs++); + } while (left && left == right); + return left == right; +#endif // OS selector +} + +// Compares this with another String. +// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 +// if this is greater than rhs. +int String::Compare(const String & rhs) const { + const char* const lhs_c_str = c_str(); + const char* const rhs_c_str = rhs.c_str(); + + if (lhs_c_str == NULL) { + return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL + } else if (rhs_c_str == NULL) { + return 1; + } + + const size_t shorter_str_len = + length() <= rhs.length() ? length() : rhs.length(); + for (size_t i = 0; i != shorter_str_len; i++) { + if (lhs_c_str[i] < rhs_c_str[i]) { + return -1; + } else if (lhs_c_str[i] > rhs_c_str[i]) { + return 1; + } + } + return (length() < rhs.length()) ? -1 : + (length() > rhs.length()) ? 1 : 0; +} + +// Returns true iff this String ends with the given suffix. *Any* +// String is considered to end with a NULL or empty suffix. +bool String::EndsWith(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Returns true iff this String ends with the given suffix, ignoring case. +// Any String is considered to end with a NULL or empty suffix. +bool String::EndsWithCaseInsensitive(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Formats a list of arguments to a String, using the same format +// spec string as for printf. +// +// We do not use the StringPrintf class as it is not universally +// available. +// +// The result is limited to 4096 characters (including the tailing 0). +// If 4096 characters are not enough to format the input, or if +// there's an error, "" is +// returned. +String String::Format(const char * format, ...) { + va_list args; + va_start(args, format); + + char buffer[4096]; + const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); + + // MSVC 8 deprecates vsnprintf(), so we want to suppress warning + // 4996 (deprecated function) there. +#ifdef _MSC_VER // We are using MSVC. +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + + const int size = vsnprintf(buffer, kBufferSize, format, args); + +# pragma warning(pop) // Restores the warning state. +#else // We are not using MSVC. + const int size = vsnprintf(buffer, kBufferSize, format, args); +#endif // _MSC_VER + va_end(args); + + // vsnprintf()'s behavior is not portable. When the buffer is not + // big enough, it returns a negative value in MSVC, and returns the + // needed buffer size on Linux. When there is an output error, it + // always returns a negative value. For simplicity, we lump the two + // error cases together. + if (size < 0 || size >= kBufferSize) { + return String(""); + } else { + return String(buffer, size); + } +} + +// Converts the buffer in a stringstream to a String, converting NUL +// bytes to "\\0" along the way. +String StringStreamToString(::std::stringstream* ss) { + const ::std::string& str = ss->str(); + const char* const start = str.c_str(); + const char* const end = start + str.length(); + + // We need to use a helper stringstream to do this transformation + // because String doesn't support push_back(). + ::std::stringstream helper; + for (const char* ch = start; ch != end; ++ch) { + if (*ch == '\0') { + helper << "\\0"; // Replaces NUL with "\\0"; + } else { + helper.put(*ch); + } + } + + return String(helper.str().c_str()); +} + +// Appends the user-supplied message to the Google-Test-generated message. +String AppendUserMessage(const String& gtest_msg, + const Message& user_msg) { + // Appends the user message if it's non-empty. + const String user_msg_string = user_msg.GetString(); + if (user_msg_string.empty()) { + return gtest_msg; + } + + Message msg; + msg << gtest_msg << "\n" << user_msg_string; + + return msg.GetString(); +} + +} // namespace internal + +// class TestResult + +// Creates an empty TestResult. +TestResult::TestResult() + : death_test_count_(0), + elapsed_time_(0) { +} + +// D'tor. +TestResult::~TestResult() { +} + +// Returns the i-th test part result among all the results. i can +// range from 0 to total_part_count() - 1. If i is not in that range, +// aborts the program. +const TestPartResult& TestResult::GetTestPartResult(int i) const { + if (i < 0 || i >= total_part_count()) + internal::posix::Abort(); + return test_part_results_.at(i); +} + +// Returns the i-th test property. i can range from 0 to +// test_property_count() - 1. If i is not in that range, aborts the +// program. +const TestProperty& TestResult::GetTestProperty(int i) const { + if (i < 0 || i >= test_property_count()) + internal::posix::Abort(); + return test_properties_.at(i); +} + +// Clears the test part results. +void TestResult::ClearTestPartResults() { + test_part_results_.clear(); +} + +// Adds a test part result to the list. +void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { + test_part_results_.push_back(test_part_result); +} + +// Adds a test property to the list. If a property with the same key as the +// supplied property is already represented, the value of this test_property +// replaces the old value for that key. +void TestResult::RecordProperty(const TestProperty& test_property) { + if (!ValidateTestProperty(test_property)) { + return; + } + internal::MutexLock lock(&test_properites_mutex_); + const std::vector::iterator property_with_matching_key = + std::find_if(test_properties_.begin(), test_properties_.end(), + internal::TestPropertyKeyIs(test_property.key())); + if (property_with_matching_key == test_properties_.end()) { + test_properties_.push_back(test_property); + return; + } + property_with_matching_key->SetValue(test_property.value()); +} + +// Adds a failure if the key is a reserved attribute of Google Test +// testcase tags. Returns true if the property is valid. +bool TestResult::ValidateTestProperty(const TestProperty& test_property) { + internal::String key(test_property.key()); + if (key == "name" || key == "status" || key == "time" || key == "classname") { + ADD_FAILURE() + << "Reserved key used in RecordProperty(): " + << key + << " ('name', 'status', 'time', and 'classname' are reserved by " + << GTEST_NAME_ << ")"; + return false; + } + return true; +} + +// Clears the object. +void TestResult::Clear() { + test_part_results_.clear(); + test_properties_.clear(); + death_test_count_ = 0; + elapsed_time_ = 0; +} + +// Returns true iff the test failed. +bool TestResult::Failed() const { + for (int i = 0; i < total_part_count(); ++i) { + if (GetTestPartResult(i).failed()) + return true; + } + return false; +} + +// Returns true iff the test part fatally failed. +static bool TestPartFatallyFailed(const TestPartResult& result) { + return result.fatally_failed(); +} + +// Returns true iff the test fatally failed. +bool TestResult::HasFatalFailure() const { + return CountIf(test_part_results_, TestPartFatallyFailed) > 0; +} + +// Returns true iff the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult& result) { + return result.nonfatally_failed(); +} + +// Returns true iff the test has a non-fatal failure. +bool TestResult::HasNonfatalFailure() const { + return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; +} + +// Gets the number of all test parts. This is the sum of the number +// of successful test parts and the number of failed test parts. +int TestResult::total_part_count() const { + return static_cast(test_part_results_.size()); +} + +// Returns the number of the test properties. +int TestResult::test_property_count() const { + return static_cast(test_properties_.size()); +} + +// class Test + +// Creates a Test object. + +// The c'tor saves the values of all Google Test flags. +Test::Test() + : gtest_flag_saver_(new internal::GTestFlagSaver) { +} + +// The d'tor restores the values of all Google Test flags. +Test::~Test() { + delete gtest_flag_saver_; +} + +// Sets up the test fixture. +// +// A sub-class may override this. +void Test::SetUp() { +} + +// Tears down the test fixture. +// +// A sub-class may override this. +void Test::TearDown() { +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, const char* value) { + UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, int value) { + Message value_message; + value_message << value; + RecordProperty(key, value_message.GetString().c_str()); +} + +namespace internal { + +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const String& message) { + // This function is a friend of UnitTest and as such has access to + // AddTestPartResult. + UnitTest::GetInstance()->AddTestPartResult( + result_type, + NULL, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. + message, + String()); // No stack trace, either. +} + +} // namespace internal + +// Google Test requires all tests in the same test case to use the same test +// fixture class. This function checks if the current test has the +// same fixture class as the first test in the current test case. If +// yes, it returns true; otherwise it generates a Google Test failure and +// returns false. +bool Test::HasSameFixtureClass() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + const TestCase* const test_case = impl->current_test_case(); + + // Info about the first test in the current test case. + const TestInfo* const first_test_info = test_case->test_info_list()[0]; + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; + const char* const first_test_name = first_test_info->name(); + + // Info about the current test. + const TestInfo* const this_test_info = impl->current_test_info(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; + const char* const this_test_name = this_test_info->name(); + + if (this_fixture_id != first_fixture_id) { + // Is the first test defined using TEST? + const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); + // Is this test defined using TEST? + const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); + + if (first_is_TEST || this_is_TEST) { + // The user mixed TEST and TEST_F in this test case - we'll tell + // him/her how to fix it. + + // Gets the name of the TEST and the name of the TEST_F. Note + // that first_is_TEST and this_is_TEST cannot both be true, as + // the fixture IDs are different for the two tests. + const char* const TEST_name = + first_is_TEST ? first_test_name : this_test_name; + const char* const TEST_F_name = + first_is_TEST ? this_test_name : first_test_name; + + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test case is\n" + << "illegal. In test case " << this_test_info->test_case_name() + << ",\n" + << "test " << TEST_F_name << " is defined using TEST_F but\n" + << "test " << TEST_name << " is defined using TEST. You probably\n" + << "want to change the TEST to TEST_F or move it to another test\n" + << "case."; + } else { + // The user defined two fixture classes with the same name in + // two namespaces - we'll tell him/her how to fix it. + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " + << this_test_info->test_case_name() << ",\n" + << "you defined test " << first_test_name + << " and test " << this_test_name << "\n" + << "using two different test fixture classes. This can happen if\n" + << "the two classes are from different namespaces or translation\n" + << "units and have the same name. You should probably rename one\n" + << "of the classes to put the tests into different test cases."; + } + return false; + } + + return true; +} + +#if GTEST_HAS_SEH + +// Adds an "exception thrown" fatal failure to the current test. This +// function returns its result via an output parameter pointer because VC++ +// prohibits creation of objects with destructors on stack in functions +// using __try (see error C2712). +static internal::String* FormatSehExceptionMessage(DWORD exception_code, + const char* location) { + Message message; + message << "SEH exception with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " thrown in " << location << "."; + + return new internal::String(message.GetString()); +} + +#endif // GTEST_HAS_SEH + +#if GTEST_HAS_EXCEPTIONS + +// Adds an "exception thrown" fatal failure to the current test. +static internal::String FormatCxxExceptionMessage(const char* description, + const char* location) { + Message message; + if (description != NULL) { + message << "C++ exception with description \"" << description << "\""; + } else { + message << "Unknown C++ exception"; + } + message << " thrown in " << location << "."; + + return message.GetString(); +} + +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result); + +// A failed Google Test assertion will throw an exception of this type when +// GTEST_FLAG(throw_on_failure) is true (if exceptions are enabled). We +// derive it from std::runtime_error, which is for errors presumably +// detectable only at run time. Since std::runtime_error inherits from +// std::exception, many testing frameworks know how to extract and print the +// message inside it. +class GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} +}; +#endif // GTEST_HAS_EXCEPTIONS + +namespace internal { +// We put these helper functions in the internal namespace as IBM's xlC +// compiler rejects the code if they were declared static. + +// Runs the given method and handles SEH exceptions it throws, when +// SEH is supported; returns the 0-value for type Result in case of an +// SEH exception. (Microsoft compilers cannot handle SEH and C++ +// exceptions in the same function. Therefore, we provide a separate +// wrapper function for handling SEH exceptions.) +template +Result HandleSehExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { +#if GTEST_HAS_SEH + __try { + return (object->*method)(); + } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT + GetExceptionCode())) { + // We create the exception message on the heap because VC++ prohibits + // creation of objects with destructors on stack in functions using __try + // (see error C2712). + internal::String* exception_message = FormatSehExceptionMessage( + GetExceptionCode(), location); + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, + *exception_message); + delete exception_message; + return static_cast(0); + } +#else + (void)location; + return (object->*method)(); +#endif // GTEST_HAS_SEH +} + +// Runs the given method and catches and reports C++ and/or SEH-style +// exceptions, if they are supported; returns the 0-value for type +// Result in case of an SEH exception. +template +Result HandleExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { + // NOTE: The user code can affect the way in which Google Test handles + // exceptions by setting GTEST_FLAG(catch_exceptions), but only before + // RUN_ALL_TESTS() starts. It is technically possible to check the flag + // after the exception is caught and either report or re-throw the + // exception based on the flag's value: + // + // try { + // // Perform the test method. + // } catch (...) { + // if (GTEST_FLAG(catch_exceptions)) + // // Report the exception as failure. + // else + // throw; // Re-throws the original exception. + // } + // + // However, the purpose of this flag is to allow the program to drop into + // the debugger when the exception is thrown. On most platforms, once the + // control enters the catch block, the exception origin information is + // lost and the debugger will stop the program at the point of the + // re-throw in this function -- instead of at the point of the original + // throw statement in the code under test. For this reason, we perform + // the check early, sacrificing the ability to affect Google Test's + // exception handling in the method where the exception is thrown. + if (internal::GetUnitTestImpl()->catch_exceptions()) { +#if GTEST_HAS_EXCEPTIONS + try { + return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const GoogleTestFailureException&) { // NOLINT + // This exception doesn't originate in code under test. It makes no + // sense to report it as a test failure. + throw; + } catch (const std::exception& e) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(e.what(), location)); + } catch (...) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(NULL, location)); + } + return static_cast(0); +#else + return HandleSehExceptionsInMethodIfSupported(object, method, location); +#endif // GTEST_HAS_EXCEPTIONS + } else { + return (object->*method)(); + } +} + +} // namespace internal + +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); + // We will run the test only if SetUp() was successful. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TestBody, "the test body"); + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TearDown, "TearDown()"); +} + +// Returns true iff the current test has a fatal failure. +bool Test::HasFatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); +} + +// Returns true iff the current test has a non-fatal failure. +bool Test::HasNonfatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()-> + HasNonfatalFailure(); +} + +// class TestInfo + +// Constructs a TestInfo object. It assumes ownership of the test factory +// object. +// TODO(vladl@google.com): Make a_test_case_name and a_name const string&'s +// to signify they cannot be NULLs. +TestInfo::TestInfo(const char* a_test_case_name, + const char* a_name, + const char* a_type_param, + const char* a_value_param, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory) + : test_case_name_(a_test_case_name), + name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + value_param_(a_value_param ? new std::string(a_value_param) : NULL), + fixture_class_id_(fixture_class_id), + should_run_(false), + is_disabled_(false), + matches_filter_(false), + factory_(factory), + result_() {} + +// Destructs a TestInfo object. +TestInfo::~TestInfo() { delete factory_; } + +namespace internal { + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// type_param: the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param: text representation of the test's value parameter, +// or NULL if this is not a value-parameterized test. +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* type_param, + const char* value_param, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory) { + TestInfo* const test_info = + new TestInfo(test_case_name, name, type_param, value_param, + fixture_class_id, factory); + GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + return test_info; +} + +#if GTEST_HAS_PARAM_TEST +void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line) { + Message errors; + errors + << "Attempted redefinition of test case " << test_case_name << ".\n" + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " << test_case_name << ", you tried\n" + << "to define a test using a fixture class different from the one\n" + << "used earlier. This can happen if the two fixture classes are\n" + << "from different namespaces and have the same name. You should\n" + << "probably rename one of the classes to put the tests into different\n" + << "test cases."; + + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors.GetString().c_str()); +} +#endif // GTEST_HAS_PARAM_TEST + +} // namespace internal + +namespace internal { + +// This method expands all parameterized tests registered with macros TEST_P +// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// This will be done just once during the program runtime. +void UnitTestImpl::RegisterParameterizedTests() { +#if GTEST_HAS_PARAM_TEST + if (!parameterized_tests_registered_) { + parameterized_test_registry_.RegisterTests(); + parameterized_tests_registered_ = true; + } +#endif +} + +} // namespace internal + +// Creates the test object, runs it, records its result, and then +// deletes it. +void TestInfo::Run() { + if (!should_run_) return; + + // Tells UnitTest where to store test result. + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*this); + + const TimeInMillis start = internal::GetTimeInMillis(); + + impl->os_stack_trace_getter()->UponLeavingGTest(); + + // Creates the test object. + Test* const test = internal::HandleExceptionsInMethodIfSupported( + factory_, &internal::TestFactoryBase::CreateTest, + "the test fixture's constructor"); + + // Runs the test only if the test object was created and its + // constructor didn't generate a fatal failure. + if ((test != NULL) && !Test::HasFatalFailure()) { + // This doesn't throw as all user code that can throw are wrapped into + // exception handling code. + test->Run(); + } + + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); + + result_.set_elapsed_time(internal::GetTimeInMillis() - start); + + // Notifies the unit test event listener that a test has just finished. + repeater->OnTestEnd(*this); + + // Tells UnitTest to stop associating assertion results to this + // test. + impl->set_current_test_info(NULL); +} + +// class TestCase + +// Gets the number of successful tests in this test case. +int TestCase::successful_test_count() const { + return CountIf(test_info_list_, TestPassed); +} + +// Gets the number of failed tests in this test case. +int TestCase::failed_test_count() const { + return CountIf(test_info_list_, TestFailed); +} + +int TestCase::disabled_test_count() const { + return CountIf(test_info_list_, TestDisabled); +} + +// Get the number of tests in this test case that should run. +int TestCase::test_to_run_count() const { + return CountIf(test_info_list_, ShouldRunTest); +} + +// Gets the number of all tests. +int TestCase::total_test_count() const { + return static_cast(test_info_list_.size()); +} + +// Creates a TestCase with the given name. +// +// Arguments: +// +// name: name of the test case +// a_type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase::TestCase(const char* a_name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) + : name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + set_up_tc_(set_up_tc), + tear_down_tc_(tear_down_tc), + should_run_(false), + elapsed_time_(0) { +} + +// Destructor of TestCase. +TestCase::~TestCase() { + // Deletes every Test in the collection. + ForEach(test_info_list_, internal::Delete); +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +const TestInfo* TestCase::GetTestInfo(int i) const { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +TestInfo* TestCase::GetMutableTestInfo(int i) { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Adds a test to this test case. Will delete the test upon +// destruction of the TestCase object. +void TestCase::AddTestInfo(TestInfo * test_info) { + test_info_list_.push_back(test_info); + test_indices_.push_back(static_cast(test_indices_.size())); +} + +// Runs every test in this TestCase. +void TestCase::Run() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_case(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + repeater->OnTestCaseStart(*this); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); + + const internal::TimeInMillis start = internal::GetTimeInMillis(); + for (int i = 0; i < total_test_count(); i++) { + GetMutableTestInfo(i)->Run(); + } + elapsed_time_ = internal::GetTimeInMillis() - start; + + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); + + repeater->OnTestCaseEnd(*this); + impl->set_current_test_case(NULL); +} + +// Clears the results of all tests in this test case. +void TestCase::ClearResult() { + ForEach(test_info_list_, TestInfo::ClearTestResult); +} + +// Shuffles the tests in this test case. +void TestCase::ShuffleTests(internal::Random* random) { + Shuffle(random, &test_indices_); +} + +// Restores the test order to before the first shuffle. +void TestCase::UnshuffleTests() { + for (size_t i = 0; i < test_indices_.size(); i++) { + test_indices_[i] = static_cast(i); + } +} + +// Formats a countable noun. Depending on its quantity, either the +// singular form or the plural form is used. e.g. +// +// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". +// FormatCountableNoun(5, "book", "books") returns "5 books". +static internal::String FormatCountableNoun(int count, + const char * singular_form, + const char * plural_form) { + return internal::String::Format("%d %s", count, + count == 1 ? singular_form : plural_form); +} + +// Formats the count of tests. +static internal::String FormatTestCount(int test_count) { + return FormatCountableNoun(test_count, "test", "tests"); +} + +// Formats the count of test cases. +static internal::String FormatTestCaseCount(int test_case_count) { + return FormatCountableNoun(test_case_count, "test case", "test cases"); +} + +// Converts a TestPartResult::Type enum to human-friendly string +// representation. Both kNonFatalFailure and kFatalFailure are translated +// to "Failure", as the user usually doesn't care about the difference +// between the two when viewing the test result. +static const char * TestPartResultTypeToString(TestPartResult::Type type) { + switch (type) { + case TestPartResult::kSuccess: + return "Success"; + + case TestPartResult::kNonFatalFailure: + case TestPartResult::kFatalFailure: +#ifdef _MSC_VER + return "error: "; +#else + return "Failure\n"; +#endif + } + + // All cases return, so this is unreachable but GCC doesn't know it + abort(); +} + +// Prints a TestPartResult to a String. +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result) { + return (Message() + << internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()) + << " " << TestPartResultTypeToString(test_part_result.type()) + << test_part_result.message()).GetString(); +} + +// Prints a TestPartResult. +static void PrintTestPartResult(const TestPartResult& test_part_result) { + const internal::String& result = + PrintTestPartResultToString(test_part_result); + printf("%s\n", result.c_str()); + fflush(stdout); + // If the test program runs in Visual Studio or a debugger, the + // following statements add the test part result message to the Output + // window such that the user can double-click on it to jump to the + // corresponding source code location; otherwise they do nothing. +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + // We don't call OutputDebugString*() on Windows Mobile, as printing + // to stdout is done by OutputDebugString() there already - we don't + // want the same message printed twice. + ::OutputDebugStringA(result.c_str()); + ::OutputDebugStringA("\n"); +#endif +} + +// class PrettyUnitTestResultPrinter + +namespace internal { + +enum GTestColor { + COLOR_DEFAULT, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW +}; + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns the character attribute for the given color. +WORD GetColorAttribute(GTestColor color) { + switch (color) { + case COLOR_RED: return FOREGROUND_RED; + case COLOR_GREEN: return FOREGROUND_GREEN; + case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + default: return 0; + } +} + +#else + +// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// an invalid input. +const char* GetAnsiColorCode(GTestColor color) { + switch (color) { + case COLOR_RED: return "1"; + case COLOR_GREEN: return "2"; + case COLOR_YELLOW: return "3"; + default: return NULL; + }; +} + +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns true iff Google Test should use colors in the output. +bool ShouldUseColor(bool stdout_is_tty) { + const char* const gtest_color = GTEST_FLAG(color).c_str(); + + if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { +#if GTEST_OS_WINDOWS + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return stdout_is_tty; +#else + // On non-Windows platforms, we rely on the TERM variable. + const char* const term = posix::GetEnv("TERM"); + const bool term_supports_color = + String::CStringEquals(term, "xterm") || + String::CStringEquals(term, "xterm-color") || + String::CStringEquals(term, "xterm-256color") || + String::CStringEquals(term, "screen") || + String::CStringEquals(term, "linux") || + String::CStringEquals(term, "cygwin"); + return stdout_is_tty && term_supports_color; +#endif // GTEST_OS_WINDOWS + } + + return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || + String::CaseInsensitiveCStringEquals(gtest_color, "true") || + String::CaseInsensitiveCStringEquals(gtest_color, "t") || + String::CStringEquals(gtest_color, "1"); + // We take "yes", "true", "t", and "1" as meaning "yes". If the + // value is neither one of these nor "auto", we treat it as "no" to + // be conservative. +} + +// Helpers for printing colored strings to stdout. Note that on Windows, we +// cannot simply emit special characters and have the terminal change colors. +// This routine must actually emit the characters rather than return a string +// that would be colored when printed, as can be done on Linux. +void ColoredPrintf(GTestColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + const bool use_color = false; +#else + static const bool in_color_mode = + ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); + const bool use_color = in_color_mode && (color != COLOR_DEFAULT); +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + // The '!= 0' comparison is necessary to satisfy MSVC 7.1. + + if (!use_color) { + vprintf(fmt, args); + va_end(args); + return; + } + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); + SetConsoleTextAttribute(stdout_handle, + GetColorAttribute(color) | FOREGROUND_INTENSITY); + vprintf(fmt, args); + + fflush(stdout); + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + printf("\033[0;3%sm", GetAnsiColorCode(color)); + vprintf(fmt, args); + printf("\033[m"); // Resets the terminal to default. +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + va_end(args); +} + +void PrintFullTestCommentIfPresent(const TestInfo& test_info) { + const char* const type_param = test_info.type_param(); + const char* const value_param = test_info.value_param(); + + if (type_param != NULL || value_param != NULL) { + printf(", where "); + if (type_param != NULL) { + printf("TypeParam = %s", type_param); + if (value_param != NULL) + printf(" and "); + } + if (value_param != NULL) { + printf("GetParam() = %s", value_param); + } + } +} + +// This class implements the TestEventListener interface. +// +// Class PrettyUnitTestResultPrinter is copyable. +class PrettyUnitTestResultPrinter : public TestEventListener { + public: + PrettyUnitTestResultPrinter() {} + static void PrintTestName(const char * test_case, const char * test) { + printf("%s.%s", test_case, test); + } + + // The following methods override what's in the TestEventListener class. + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + + private: + static void PrintFailedTests(const UnitTest& unit_test); + + internal::String test_case_name_; +}; + + // Fired before each iteration of tests starts. +void PrettyUnitTestResultPrinter::OnTestIterationStart( + const UnitTest& unit_test, int iteration) { + if (GTEST_FLAG(repeat) != 1) + printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); + + const char* const filter = GTEST_FLAG(filter).c_str(); + + // Prints the filter if it's not *. This reminds the user that some + // tests may be skipped. + if (!internal::String::CStringEquals(filter, kUniversalFilter)) { + ColoredPrintf(COLOR_YELLOW, + "Note: %s filter = %s\n", GTEST_NAME_, filter); + } + + if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { + const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); + ColoredPrintf(COLOR_YELLOW, + "Note: This is test shard %d of %s.\n", + static_cast(shard_index) + 1, + internal::posix::GetEnv(kTestTotalShards)); + } + + if (GTEST_FLAG(shuffle)) { + ColoredPrintf(COLOR_YELLOW, + "Note: Randomizing tests' orders with a seed of %d .\n", + unit_test.random_seed()); + } + + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("Running %s from %s.\n", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment set-up.\n"); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_case_name_.c_str()); + if (test_case.type_param() == NULL) { + printf("\n"); + } else { + printf(", where TypeParam = %s\n", test_case.type_param()); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { + ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + PrintTestName(test_case_name_.c_str(), test_info.name()); + printf("\n"); + fflush(stdout); +} + +// Called after an assertion failure. +void PrettyUnitTestResultPrinter::OnTestPartResult( + const TestPartResult& result) { + // If the test part succeeded, we don't need to do anything. + if (result.type() == TestPartResult::kSuccess) + return; + + // Print failure message from the assertion (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { + ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else { + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + } + PrintTestName(test_case_name_.c_str(), test_info.name()); + if (test_info.result()->Failed()) + PrintFullTestCommentIfPresent(test_info); + + if (GTEST_FLAG(print_time)) { + printf(" (%s ms)\n", internal::StreamableToString( + test_info.result()->elapsed_time()).c_str()); + } else { + printf("\n"); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { + if (!GTEST_FLAG(print_time)) return; + + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", + counts.c_str(), test_case_name_.c_str(), + internal::StreamableToString(test_case.elapsed_time()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment tear-down\n"); + fflush(stdout); +} + +// Internal helper for printing the list of failed tests. +void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { + const int failed_test_count = unit_test.failed_test_count(); + if (failed_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase& test_case = *unit_test.GetTestCase(i); + if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_case.total_test_count(); ++j) { + const TestInfo& test_info = *test_case.GetTestInfo(j); + if (!test_info.should_run() || test_info.result()->Passed()) { + continue; + } + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s.%s", test_case.name(), test_info.name()); + PrintFullTestCommentIfPresent(test_info); + printf("\n"); + } + } +} + +void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("%s from %s ran.", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms total)", + internal::StreamableToString(unit_test.elapsed_time()).c_str()); + } + printf("\n"); + ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + + int num_failures = unit_test.failed_test_count(); + if (!unit_test.Passed()) { + const int failed_test_count = unit_test.failed_test_count(); + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); + PrintFailedTests(unit_test); + printf("\n%2d FAILED %s\n", num_failures, + num_failures == 1 ? "TEST" : "TESTS"); + } + + int num_disabled = unit_test.disabled_test_count(); + if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { + if (!num_failures) { + printf("\n"); // Add a spacer if no FAILURE banner is displayed. + } + ColoredPrintf(COLOR_YELLOW, + " YOU HAVE %d DISABLED %s\n\n", + num_disabled, + num_disabled == 1 ? "TEST" : "TESTS"); + } + // Ensure that Google Test output is printed before, e.g., heapchecker output. + fflush(stdout); +} + +// End PrettyUnitTestResultPrinter + +// class TestEventRepeater +// +// This class forwards events to other event listeners. +class TestEventRepeater : public TestEventListener { + public: + TestEventRepeater() : forwarding_enabled_(true) {} + virtual ~TestEventRepeater(); + void Append(TestEventListener *listener); + TestEventListener* Release(TestEventListener* listener); + + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled() const { return forwarding_enabled_; } + void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } + + virtual void OnTestProgramStart(const UnitTest& unit_test); + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& unit_test); + + private: + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled_; + // The list of listeners that receive events. + std::vector listeners_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); +}; + +TestEventRepeater::~TestEventRepeater() { + ForEach(listeners_, Delete); +} + +void TestEventRepeater::Append(TestEventListener *listener) { + listeners_.push_back(listener); +} + +// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { + for (size_t i = 0; i < listeners_.size(); ++i) { + if (listeners_[i] == listener) { + listeners_.erase(listeners_.begin() + i); + return listener; + } + } + + return NULL; +} + +// Since most methods are very similar, use macros to reduce boilerplate. +// This defines a member that forwards the call to all listeners. +#define GTEST_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = 0; i < listeners_.size(); i++) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} +// This defines a member that forwards the call to all listeners in reverse +// order. +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} + +GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) +GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) +GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) + +#undef GTEST_REPEATER_METHOD_ +#undef GTEST_REVERSE_REPEATER_METHOD_ + +void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (size_t i = 0; i < listeners_.size(); i++) { + listeners_[i]->OnTestIterationStart(unit_test, iteration); + } + } +} + +void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { + listeners_[i]->OnTestIterationEnd(unit_test, iteration); + } + } +} + +// End TestEventRepeater + +// This class generates an XML output file. +class XmlUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit XmlUnitTestResultPrinter(const char* output_file); + + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + + private: + // Is c a whitespace character that is normalized to a space character + // when it appears in an XML attribute value? + static bool IsNormalizableWhitespace(char c) { + return c == 0x9 || c == 0xA || c == 0xD; + } + + // May c appear in a well-formed XML document? + static bool IsValidXmlCharacter(char c) { + return IsNormalizableWhitespace(c) || c >= 0x20; + } + + // Returns an XML-escaped copy of the input string str. If + // is_attribute is true, the text is meant to appear as an attribute + // value, and normalizable whitespace is preserved by replacing it + // with character references. + static String EscapeXml(const char* str, bool is_attribute); + + // Returns the given string with all characters invalid in XML removed. + static string RemoveInvalidXmlCharacters(const string& str); + + // Convenience wrapper around EscapeXml when str is an attribute value. + static String EscapeXmlAttribute(const char* str) { + return EscapeXml(str, true); + } + + // Convenience wrapper around EscapeXml when str is not an attribute value. + static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } + + // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. + static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + + // Streams an XML representation of a TestInfo object. + static void OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + + // Prints an XML representation of a TestCase object + static void PrintXmlTestCase(FILE* out, const TestCase& test_case); + + // Prints an XML summary of unit_test to output stream out. + static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as space + // delimited XML attributes based on the property key="value" pairs. + // When the String is not empty, it includes a space at the beginning, + // to delimit this attribute from prior attributes. + static String TestPropertiesAsXmlAttributes(const TestResult& result); + + // The output file. + const String output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); +}; + +// Creates a new XmlUnitTestResultPrinter. +XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.c_str() == NULL || output_file_.empty()) { + fprintf(stderr, "XML output file may not be null\n"); + fflush(stderr); + exit(EXIT_FAILURE); + } +} + +// Called after the unit test ends. +void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* xmlout = NULL; + FilePath output_file(output_file_); + FilePath output_dir(output_file.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + xmlout = posix::FOpen(output_file_.c_str(), "w"); + } + if (xmlout == NULL) { + // TODO(wan): report the reason of the failure. + // + // We don't do it for now as: + // + // 1. There is no urgent need for it. + // 2. It's a bit involved to make the errno variable thread-safe on + // all three operating systems (Linux, Windows, and Mac OS). + // 3. To interpret the meaning of errno in a thread-safe way, + // we need the strerror_r() function, which is not available on + // Windows. + fprintf(stderr, + "Unable to open file \"%s\"\n", + output_file_.c_str()); + fflush(stderr); + exit(EXIT_FAILURE); + } + PrintXmlUnitTest(xmlout, unit_test); + fclose(xmlout); +} + +// Returns an XML-escaped copy of the input string str. If is_attribute +// is true, the text is meant to appear as an attribute value, and +// normalizable whitespace is preserved by replacing it with character +// references. +// +// Invalid XML characters in str, if any, are stripped from the output. +// It is expected that most, if not all, of the text processed by this +// module will consist of ordinary English text. +// If this module is ever modified to produce version 1.1 XML output, +// most invalid characters can be retained using character references. +// TODO(wan): It might be nice to have a minimally invasive, human-readable +// escaping scheme for invalid characters, rather than dropping them. +String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { + Message m; + + if (str != NULL) { + for (const char* src = str; *src; ++src) { + switch (*src) { + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: + if (IsValidXmlCharacter(*src)) { + if (is_attribute && IsNormalizableWhitespace(*src)) + m << String::Format("&#x%02X;", unsigned(*src)); + else + m << *src; + } + break; + } + } + } + + return m.GetString(); +} + +// Returns the given string with all characters invalid in XML removed. +// Currently invalid characters are dropped from the string. An +// alternative is to replace them with certain characters such as . or ?. +string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const string& str) { + string output; + output.reserve(str.size()); + for (string::const_iterator it = str.begin(); it != str.end(); ++it) + if (IsValidXmlCharacter(*it)) + output.push_back(*it); + + return output; +} + +// The following routines generate an XML representation of a UnitTest +// object. +// +// This is how Google Test concepts map to the DTD: +// +// <-- corresponds to a UnitTest object +// <-- corresponds to a TestCase object +// <-- corresponds to a TestInfo object +// ... +// ... +// ... +// <-- individual assertion failures +// +// +// + +// Formats the given time in milliseconds as seconds. +std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { + ::std::stringstream ss; + ss << ms/1000.0; + return ss.str(); +} + +// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. +void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, + const char* data) { + const char* segment = data; + *stream << ""); + if (next_segment != NULL) { + stream->write( + segment, static_cast(next_segment - segment)); + *stream << "]]>]]>"); + } else { + *stream << segment; + break; + } + } + *stream << "]]>"; +} + +// Prints an XML representation of a TestInfo object. +// TODO(wan): There is also value in printing properties with the plain printer. +void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + *stream << " \n"; + *stream << " "; + const string location = internal::FormatCompilerIndependentFileLocation( + part.file_name(), part.line_number()); + const string message = location + "\n" + part.message(); + OutputXmlCDataSection(stream, + RemoveInvalidXmlCharacters(message).c_str()); + *stream << "\n"; + } + } + + if (failures == 0) + *stream << " />\n"; + else + *stream << " \n"; +} + +// Prints an XML representation of a TestCase object +void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, + const TestCase& test_case) { + fprintf(out, + " \n", + FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); + for (int i = 0; i < test_case.total_test_count(); ++i) { + ::std::stringstream stream; + OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); + fprintf(out, "%s", StringStreamToString(&stream).c_str()); + } + fprintf(out, " \n"); +} + +// Prints an XML summary of unit_test to output stream out. +void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, + const UnitTest& unit_test) { + fprintf(out, "\n"); + fprintf(out, + "\n"); + for (int i = 0; i < unit_test.total_test_case_count(); ++i) + PrintXmlTestCase(out, *unit_test.GetTestCase(i)); + fprintf(out, "\n"); +} + +// Produces a string representing the test properties in a result as space +// delimited XML attributes based on the property key="value" pairs. +String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( + const TestResult& result) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << " " << property.key() << "=" + << "\"" << EscapeXmlAttribute(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End XmlUnitTestResultPrinter + +#if GTEST_CAN_STREAM_RESULTS_ + +// Streams test results to the given port on the given host machine. +class StreamingListener : public EmptyTestEventListener { + public: + // Escapes '=', '&', '%', and '\n' characters in str as "%xx". + static string UrlEncode(const char* str); + + StreamingListener(const string& host, const string& port) + : sockfd_(-1), host_name_(host), port_num_(port) { + MakeConnection(); + Send("gtest_streaming_protocol_version=1.0\n"); + } + + virtual ~StreamingListener() { + if (sockfd_ != -1) + CloseConnection(); + } + + void OnTestProgramStart(const UnitTest& /* unit_test */) { + Send("event=TestProgramStart\n"); + } + + void OnTestProgramEnd(const UnitTest& unit_test) { + // Note that Google Test current only report elapsed time for each + // test iteration, not for the entire test program. + Send(String::Format("event=TestProgramEnd&passed=%d\n", + unit_test.Passed())); + + // Notify the streaming server to stop. + CloseConnection(); + } + + void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + Send(String::Format("event=TestIterationStart&iteration=%d\n", + iteration)); + } + + void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + Send(String::Format("event=TestIterationEnd&passed=%d&elapsed_time=%sms\n", + unit_test.Passed(), + StreamableToString(unit_test.elapsed_time()).c_str())); + } + + void OnTestCaseStart(const TestCase& test_case) { + Send(String::Format("event=TestCaseStart&name=%s\n", test_case.name())); + } + + void OnTestCaseEnd(const TestCase& test_case) { + Send(String::Format("event=TestCaseEnd&passed=%d&elapsed_time=%sms\n", + test_case.Passed(), + StreamableToString(test_case.elapsed_time()).c_str())); + } + + void OnTestStart(const TestInfo& test_info) { + Send(String::Format("event=TestStart&name=%s\n", test_info.name())); + } + + void OnTestEnd(const TestInfo& test_info) { + Send(String::Format( + "event=TestEnd&passed=%d&elapsed_time=%sms\n", + (test_info.result())->Passed(), + StreamableToString((test_info.result())->elapsed_time()).c_str())); + } + + void OnTestPartResult(const TestPartResult& test_part_result) { + const char* file_name = test_part_result.file_name(); + if (file_name == NULL) + file_name = ""; + Send(String::Format("event=TestPartResult&file=%s&line=%d&message=", + UrlEncode(file_name).c_str(), + test_part_result.line_number())); + Send(UrlEncode(test_part_result.message()) + "\n"); + } + + private: + // Creates a client socket and connects to the server. + void MakeConnection(); + + // Closes the socket. + void CloseConnection() { + GTEST_CHECK_(sockfd_ != -1) + << "CloseConnection() can be called only when there is a connection."; + + close(sockfd_); + sockfd_ = -1; + } + + // Sends a string to the socket. + void Send(const string& message) { + GTEST_CHECK_(sockfd_ != -1) + << "Send() can be called only when there is a connection."; + + const int len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != len) { + GTEST_LOG_(WARNING) + << "stream_result_to: failed to stream to " + << host_name_ << ":" << port_num_; + } + } + + int sockfd_; // socket file descriptor + const string host_name_; + const string port_num_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); +}; // class StreamingListener + +// Checks if str contains '=', '&', '%' or '\n' characters. If yes, +// replaces them by "%xx" where xx is their hexadecimal value. For +// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) +// in both time and space -- important as the input str may contain an +// arbitrarily long test failure message and stack trace. +string StreamingListener::UrlEncode(const char* str) { + string result; + result.reserve(strlen(str) + 1); + for (char ch = *str; ch != '\0'; ch = *++str) { + switch (ch) { + case '%': + case '=': + case '&': + case '\n': + result.append(String::Format("%%%02x", static_cast(ch))); + break; + default: + result.push_back(ch); + break; + } + } + return result; +} + +void StreamingListener::MakeConnection() { + GTEST_CHECK_(sockfd_ == -1) + << "MakeConnection() can't be called when there is already a connection."; + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. + hints.ai_socktype = SOCK_STREAM; + addrinfo* servinfo = NULL; + + // Use the getaddrinfo() to get a linked list of IP addresses for + // the given host name. + const int error_num = getaddrinfo( + host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); + if (error_num != 0) { + GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " + << gai_strerror(error_num); + } + + // Loop through all the results and connect to the first we can. + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + cur_addr = cur_addr->ai_next) { + sockfd_ = socket( + cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); + if (sockfd_ != -1) { + // Connect the client socket to the server socket. + if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { + close(sockfd_); + sockfd_ = -1; + } + } + } + + freeaddrinfo(servinfo); // all done with this structure + + if (sockfd_ == -1) { + GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " + << host_name_ << ":" << port_num_; + } +} + +// End of class Streaming Listener +#endif // GTEST_CAN_STREAM_RESULTS__ + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +// L < UnitTest::mutex_ +ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { + TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message = message.GetString(); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +// L < UnitTest::mutex_ +ScopedTrace::~ScopedTrace() { + UnitTest::GetInstance()->PopGTestTrace(); +} + + +// class OsStackTraceGetter + +// Returns the current OS stack trace as a String. Parameters: +// +// max_depth - the maximum number of stack frames to be included +// in the trace. +// skip_count - the number of top frames to be skipped; doesn't count +// against max_depth. +// +// L < mutex_ +// We use "L < mutex_" to denote that the function may acquire mutex_. +String OsStackTraceGetter::CurrentStackTrace(int, int) { + return String(""); +} + +// L < mutex_ +void OsStackTraceGetter::UponLeavingGTest() { +} + +const char* const +OsStackTraceGetter::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; + +} // namespace internal + +// class TestEventListeners + +TestEventListeners::TestEventListeners() + : repeater_(new internal::TestEventRepeater()), + default_result_printer_(NULL), + default_xml_generator_(NULL) { +} + +TestEventListeners::~TestEventListeners() { delete repeater_; } + +// Returns the standard listener responsible for the default console +// output. Can be removed from the listeners list to shut down default +// console output. Note that removing this object from the listener list +// with Release transfers its ownership to the user. +void TestEventListeners::Append(TestEventListener* listener) { + repeater_->Append(listener); +} + +// Removes the given event listener from the list and returns it. It then +// becomes the caller's responsibility to delete the listener. Returns +// NULL if the listener is not found in the list. +TestEventListener* TestEventListeners::Release(TestEventListener* listener) { + if (listener == default_result_printer_) + default_result_printer_ = NULL; + else if (listener == default_xml_generator_) + default_xml_generator_ = NULL; + return repeater_->Release(listener); +} + +// Returns repeater that broadcasts the TestEventListener events to all +// subscribers. +TestEventListener* TestEventListeners::repeater() { return repeater_; } + +// Sets the default_result_printer attribute to the provided listener. +// The listener is also added to the listener list and previous +// default_result_printer is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { + if (default_result_printer_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_result_printer_); + default_result_printer_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Sets the default_xml_generator attribute to the provided listener. The +// listener is also added to the listener list and previous +// default_xml_generator is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { + if (default_xml_generator_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_xml_generator_); + default_xml_generator_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Controls whether events will be forwarded by the repeater to the +// listeners in the list. +bool TestEventListeners::EventForwardingEnabled() const { + return repeater_->forwarding_enabled(); +} + +void TestEventListeners::SuppressEventForwarding() { + repeater_->set_forwarding_enabled(false); +} + +// class UnitTest + +// Gets the singleton UnitTest object. The first time this method is +// called, a UnitTest object is constructed and returned. Consecutive +// calls will return the same object. +// +// We don't protect this under mutex_ as a user is not supposed to +// call this before main() starts, from which point on the return +// value will never change. +UnitTest * UnitTest::GetInstance() { + // When compiled with MSVC 7.1 in optimized mode, destroying the + // UnitTest object upon exiting the program messes up the exit code, + // causing successful tests to appear failed. We have to use a + // different implementation in this case to bypass the compiler bug. + // This implementation makes the compiler happy, at the cost of + // leaking the UnitTest object. + + // CodeGear C++Builder insists on a public destructor for the + // default implementation. Use this implementation to keep good OO + // design with private destructor. + +#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) + static UnitTest* const instance = new UnitTest; + return instance; +#else + static UnitTest instance; + return &instance; +#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +} + +// Gets the number of successful test cases. +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_case_count(); +} + +// Gets the number of failed test cases. +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_case_count(); +} + +// Gets the number of all test cases. +int UnitTest::total_test_case_count() const { + return impl()->total_test_case_count(); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTest::test_case_to_run_count() const { + return impl()->test_case_to_run_count(); +} + +// Gets the number of successful tests. +int UnitTest::successful_test_count() const { + return impl()->successful_test_count(); +} + +// Gets the number of failed tests. +int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } + +// Gets the number of disabled tests. +int UnitTest::disabled_test_count() const { + return impl()->disabled_test_count(); +} + +// Gets the number of all tests. +int UnitTest::total_test_count() const { return impl()->total_test_count(); } + +// Gets the number of tests that should run. +int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } + +// Gets the elapsed time, in milliseconds. +internal::TimeInMillis UnitTest::elapsed_time() const { + return impl()->elapsed_time(); +} + +// Returns true iff the unit test passed (i.e. all test cases passed). +bool UnitTest::Passed() const { return impl()->Passed(); } + +// Returns true iff the unit test failed (i.e. some test case failed +// or something outside of all tests failed). +bool UnitTest::Failed() const { return impl()->Failed(); } + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +const TestCase* UnitTest::GetTestCase(int i) const { + return impl()->GetTestCase(i); +} + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +TestCase* UnitTest::GetMutableTestCase(int i) { + return impl()->GetMutableTestCase(i); +} + +// Returns the list of event listeners that can be used to track events +// inside Google Test. +TestEventListeners& UnitTest::listeners() { + return *impl()->listeners(); +} + +// Registers and returns a global test environment. When a test +// program is run, all global test environments will be set-up in the +// order they were registered. After all tests in the program have +// finished, all global test environments will be torn-down in the +// *reverse* order they were registered. +// +// The UnitTest object takes ownership of the given environment. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +Environment* UnitTest::AddEnvironment(Environment* env) { + if (env == NULL) { + return NULL; + } + + impl_->environments().push_back(env); + return env; +} + +// Adds a TestPartResult to the current TestResult object. All Google Test +// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call +// this to report their results. The user code should use the +// assertion macros instead of calling this directly. +// L < mutex_ +void UnitTest::AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace) { + Message msg; + msg << message; + + internal::MutexLock lock(&mutex_); + if (impl_->gtest_trace_stack().size() > 0) { + msg << "\n" << GTEST_NAME_ << " trace:"; + + for (int i = static_cast(impl_->gtest_trace_stack().size()); + i > 0; --i) { + const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; + msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) + << " " << trace.message; + } + } + + if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + msg << internal::kStackTraceMarker << os_stack_trace; + } + + const TestPartResult result = + TestPartResult(result_type, file_name, line_number, + msg.GetString().c_str()); + impl_->GetTestPartResultReporterForCurrentThread()-> + ReportTestPartResult(result); + + if (result_type != TestPartResult::kSuccess) { + // gtest_break_on_failure takes precedence over + // gtest_throw_on_failure. This allows a user to set the latter + // in the code (perhaps in order to use Google Test assertions + // with another testing framework) and specify the former on the + // command line for debugging. + if (GTEST_FLAG(break_on_failure)) { +#if GTEST_OS_WINDOWS + // Using DebugBreak on Windows allows gtest to still break into a debugger + // when a failure happens and both the --gtest_break_on_failure and + // the --gtest_catch_exceptions flags are specified. + DebugBreak(); +#else + abort(); +#endif // GTEST_OS_WINDOWS + } else if (GTEST_FLAG(throw_on_failure)) { +#if GTEST_HAS_EXCEPTIONS + throw GoogleTestFailureException(result); +#else + // We cannot call abort() as it generates a pop-up in debug mode + // that cannot be suppressed in VC 7.1 or below. + exit(1); +#endif + } + } +} + +// Creates and adds a property to the current TestResult. If a property matching +// the supplied value already exists, updates its value instead. +void UnitTest::RecordPropertyForCurrentTest(const char* key, + const char* value) { + const TestProperty test_property(key, value); + impl_->current_test_result()->RecordProperty(test_property); +} + +// Runs all tests in this UnitTest object and prints the result. +// Returns 0 if successful, or 1 otherwise. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +int UnitTest::Run() { + // Captures the value of GTEST_FLAG(catch_exceptions). This value will be + // used for the duration of the program. + impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); + +#if GTEST_HAS_SEH + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).length() > 0; + + // Either the user wants Google Test to catch exceptions thrown by the + // tests or this is executing in the context of death test child + // process. In either case the user does not want to see pop-up dialogs + // about crashes - they are expected. + if (impl()->catch_exceptions() || in_death_test_child_process) { + +# if !GTEST_OS_WINDOWS_MOBILE + // SetErrorMode doesn't exist on CE. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); +# endif // !GTEST_OS_WINDOWS_MOBILE + +# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE + // Death test children can be terminated with _abort(). On Windows, + // _abort() can show a dialog with a warning message. This forces the + // abort message to go to stderr instead. + _set_error_mode(_OUT_TO_STDERR); +# endif + +# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program. We need to suppress + // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement + // executed. Google Test will notify the user of any unexpected + // failure via stderr. + // + // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. + // Users of prior VC versions shall suffer the agony and pain of + // clicking through the countless debug dialogs. + // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // debug mode when compiled with VC 7.1 or lower. + if (!GTEST_FLAG(break_on_failure)) + _set_abort_behavior( + 0x0, // Clear the following flags: + _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. +# endif + + } +#endif // GTEST_HAS_SEH + + return internal::HandleExceptionsInMethodIfSupported( + impl(), + &internal::UnitTestImpl::RunAllTests, + "auxiliary test code (environments or event listeners)") ? 0 : 1; +} + +// Returns the working directory when the first TEST() or TEST_F() was +// executed. +const char* UnitTest::original_working_dir() const { + return impl_->original_working_dir_.c_str(); +} + +// Returns the TestCase object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestCase* UnitTest::current_test_case() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_case(); +} + +// Returns the TestInfo object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestInfo* UnitTest::current_test_info() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_info(); +} + +// Returns the random seed used at the start of the current test run. +int UnitTest::random_seed() const { return impl_->random_seed(); } + +#if GTEST_HAS_PARAM_TEST +// Returns ParameterizedTestCaseRegistry object used to keep track of +// value-parameterized tests and instantiate and register them. +// L < mutex_ +internal::ParameterizedTestCaseRegistry& + UnitTest::parameterized_test_registry() { + return impl_->parameterized_test_registry(); +} +#endif // GTEST_HAS_PARAM_TEST + +// Creates an empty UnitTest. +UnitTest::UnitTest() { + impl_ = new internal::UnitTestImpl(this); +} + +// Destructor of UnitTest. +UnitTest::~UnitTest() { + delete impl_; +} + +// Pushes a trace defined by SCOPED_TRACE() on to the per-thread +// Google Test trace stack. +// L < mutex_ +void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().push_back(trace); +} + +// Pops a trace from the per-thread Google Test trace stack. +// L < mutex_ +void UnitTest::PopGTestTrace() { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().pop_back(); +} + +namespace internal { + +UnitTestImpl::UnitTestImpl(UnitTest* parent) + : parent_(parent), +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4355) // Temporarily disables warning 4355 + // (using this in initializer). + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +# pragma warning(pop) // Restores the warning state again. +#else + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#endif // _MSC_VER + global_test_part_result_repoter_( + &default_global_test_part_result_reporter_), + per_thread_test_part_result_reporter_( + &default_per_thread_test_part_result_reporter_), +#if GTEST_HAS_PARAM_TEST + parameterized_test_registry_(), + parameterized_tests_registered_(false), +#endif // GTEST_HAS_PARAM_TEST + last_death_test_case_(-1), + current_test_case_(NULL), + current_test_info_(NULL), + ad_hoc_test_result_(), + os_stack_trace_getter_(NULL), + post_flag_parse_init_performed_(false), + random_seed_(0), // Will be overridden by the flag before first use. + random_(0), // Will be reseeded before first use. + elapsed_time_(0), +#if GTEST_HAS_DEATH_TEST + internal_run_death_test_flag_(NULL), + death_test_factory_(new DefaultDeathTestFactory), +#endif + // Will be overridden by the flag before first use. + catch_exceptions_(false) { + listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); +} + +UnitTestImpl::~UnitTestImpl() { + // Deletes every TestCase. + ForEach(test_cases_, internal::Delete); + + // Deletes every Environment. + ForEach(environments_, internal::Delete); + + delete os_stack_trace_getter_; +} + +#if GTEST_HAS_DEATH_TEST +// Disables event forwarding if the control is currently in a death test +// subprocess. Must not be called before InitGoogleTest. +void UnitTestImpl::SuppressTestEventsIfInSubprocess() { + if (internal_run_death_test_flag_.get() != NULL) + listeners()->SuppressEventForwarding(); +} +#endif // GTEST_HAS_DEATH_TEST + +// Initializes event listeners performing XML output as specified by +// UnitTestOptions. Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureXmlOutput() { + const String& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format != "") { + printf("WARNING: unrecognized output format \"%s\" ignored.\n", + output_format.c_str()); + fflush(stdout); + } +} + +#if GTEST_CAN_STREAM_RESULTS_ +// Initializes event listeners for streaming test results in String form. +// Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureStreamingOutput() { + const string& target = GTEST_FLAG(stream_result_to); + if (!target.empty()) { + const size_t pos = target.find(':'); + if (pos != string::npos) { + listeners()->Append(new StreamingListener(target.substr(0, pos), + target.substr(pos+1))); + } else { + printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", + target.c_str()); + fflush(stdout); + } + } +} +#endif // GTEST_CAN_STREAM_RESULTS_ + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. +void UnitTestImpl::PostFlagParsingInit() { + // Ensures that this function does not execute more than once. + if (!post_flag_parse_init_performed_) { + post_flag_parse_init_performed_ = true; + +#if GTEST_HAS_DEATH_TEST + InitDeathTestSubprocessControlInfo(); + SuppressTestEventsIfInSubprocess(); +#endif // GTEST_HAS_DEATH_TEST + + // Registers parameterized tests. This makes parameterized tests + // available to the UnitTest reflection API without running + // RUN_ALL_TESTS. + RegisterParameterizedTests(); + + // Configures listeners for XML output. This makes it possible for users + // to shut down the default XML output before invoking RUN_ALL_TESTS. + ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Configures listeners for streaming test results to the specified server. + ConfigureStreamingOutput(); +#endif // GTEST_CAN_STREAM_RESULTS_ + } +} + +// A predicate that checks the name of a TestCase against a known +// value. +// +// This is used for implementation of the UnitTest class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestCaseNameIs is copyable. +class TestCaseNameIs { + public: + // Constructor. + explicit TestCaseNameIs(const String& name) + : name_(name) {} + + // Returns true iff the name of test_case matches name_. + bool operator()(const TestCase* test_case) const { + return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + } + + private: + String name_; +}; + +// Finds and returns a TestCase with the given name. If one doesn't +// exist, creates one and returns it. It's the CALLER'S +// RESPONSIBILITY to ensure that this function is only called WHEN THE +// TESTS ARE NOT SHUFFLED. +// +// Arguments: +// +// test_case_name: name of the test case +// type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) { + // Can we find a TestCase with the given name? + const std::vector::const_iterator test_case = + std::find_if(test_cases_.begin(), test_cases_.end(), + TestCaseNameIs(test_case_name)); + + if (test_case != test_cases_.end()) + return *test_case; + + // No. Let's create one. + TestCase* const new_test_case = + new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); + + // Is this a death test case? + if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), + kDeathTestCaseFilter)) { + // Yes. Inserts the test case after the last death test case + // defined so far. This only works when the test cases haven't + // been shuffled. Otherwise we may end up running a death test + // after a non-death test. + ++last_death_test_case_; + test_cases_.insert(test_cases_.begin() + last_death_test_case_, + new_test_case); + } else { + // No. Appends to the end of the list. + test_cases_.push_back(new_test_case); + } + + test_case_indices_.push_back(static_cast(test_case_indices_.size())); + return new_test_case; +} + +// Helpers for setting up / tearing down the given environment. They +// are for use in the ForEach() function. +static void SetUpEnvironment(Environment* env) { env->SetUp(); } +static void TearDownEnvironment(Environment* env) { env->TearDown(); } + +// Runs all tests in this UnitTest object, prints the result, and +// returns true if all tests are successful. If any exception is +// thrown during a test, the test is considered to be failed, but the +// rest of the tests will still be run. +// +// When parameterized tests are enabled, it expands and registers +// parameterized tests first in RegisterParameterizedTests(). +// All other functions called from RunAllTests() may safely assume that +// parameterized tests are ready to be counted and run. +bool UnitTestImpl::RunAllTests() { + // Makes sure InitGoogleTest() was called. + if (!GTestIsInitialized()) { + printf("%s", + "\nThis test program did NOT call ::testing::InitGoogleTest " + "before calling RUN_ALL_TESTS(). Please fix it.\n"); + return false; + } + + // Do not run any test if the --help flag was specified. + if (g_help_flag) + return true; + + // Repeats the call to the post-flag parsing initialization in case the + // user didn't call InitGoogleTest. + PostFlagParsingInit(); + + // Even if sharding is not on, test runners may want to use the + // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding + // protocol. + internal::WriteToShardStatusFileIfNeeded(); + + // True iff we are in a subprocess for running a thread-safe-style + // death test. + bool in_subprocess_for_death_test = false; + +#if GTEST_HAS_DEATH_TEST + in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); +#endif // GTEST_HAS_DEATH_TEST + + const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, + in_subprocess_for_death_test); + + // Compares the full test names with the filter to decide which + // tests to run. + const bool has_tests_to_run = FilterTests(should_shard + ? HONOR_SHARDING_PROTOCOL + : IGNORE_SHARDING_PROTOCOL) > 0; + + // Lists the tests and exits if the --gtest_list_tests flag was specified. + if (GTEST_FLAG(list_tests)) { + // This must be called *after* FilterTests() has been called. + ListTestsMatchingFilter(); + return true; + } + + random_seed_ = GTEST_FLAG(shuffle) ? + GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; + + // True iff at least one test has failed. + bool failed = false; + + TestEventListener* repeater = listeners()->repeater(); + + repeater->OnTestProgramStart(*parent_); + + // How many times to repeat the tests? We don't want to repeat them + // when we are inside the subprocess of a death test. + const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); + // Repeats forever if the repeat count is negative. + const bool forever = repeat < 0; + for (int i = 0; forever || i != repeat; i++) { + // We want to preserve failures generated by ad-hoc test + // assertions executed before RUN_ALL_TESTS(). + ClearNonAdHocTestResult(); + + const TimeInMillis start = GetTimeInMillis(); + + // Shuffles test cases and tests if requested. + if (has_tests_to_run && GTEST_FLAG(shuffle)) { + random()->Reseed(random_seed_); + // This should be done before calling OnTestIterationStart(), + // such that a test event listener can see the actual test order + // in the event. + ShuffleTests(); + } + + // Tells the unit test event listeners that the tests are about to start. + repeater->OnTestIterationStart(*parent_, i); + + // Runs each test case if there is at least one test to run. + if (has_tests_to_run) { + // Sets up all environments beforehand. + repeater->OnEnvironmentsSetUpStart(*parent_); + ForEach(environments_, SetUpEnvironment); + repeater->OnEnvironmentsSetUpEnd(*parent_); + + // Runs the tests only if there was no fatal failure during global + // set-up. + if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_case_count(); + test_index++) { + GetMutableTestCase(test_index)->Run(); + } + } + + // Tears down all environments in reverse order afterwards. + repeater->OnEnvironmentsTearDownStart(*parent_); + std::for_each(environments_.rbegin(), environments_.rend(), + TearDownEnvironment); + repeater->OnEnvironmentsTearDownEnd(*parent_); + } + + elapsed_time_ = GetTimeInMillis() - start; + + // Tells the unit test event listener that the tests have just finished. + repeater->OnTestIterationEnd(*parent_, i); + + // Gets the result and clears it. + if (!Passed()) { + failed = true; + } + + // Restores the original test order after the iteration. This + // allows the user to quickly repro a failure that happens in the + // N-th iteration without repeating the first (N - 1) iterations. + // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in + // case the user somehow changes the value of the flag somewhere + // (it's always safe to unshuffle the tests). + UnshuffleTests(); + + if (GTEST_FLAG(shuffle)) { + // Picks a new random seed for each iteration. + random_seed_ = GetNextRandomSeed(random_seed_); + } + } + + repeater->OnTestProgramEnd(*parent_); + + return !failed; +} + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded() { + const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); + if (test_shard_file != NULL) { + FILE* const file = posix::FOpen(test_shard_file, "w"); + if (file == NULL) { + ColoredPrintf(COLOR_RED, + "Could not write to the test shard status file \"%s\" " + "specified by the %s environment variable.\n", + test_shard_file, kTestShardStatusFile); + fflush(stdout); + exit(EXIT_FAILURE); + } + fclose(file); + } +} + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (i.e., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +bool ShouldShard(const char* total_shards_env, + const char* shard_index_env, + bool in_subprocess_for_death_test) { + if (in_subprocess_for_death_test) { + return false; + } + + const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + + if (total_shards == -1 && shard_index == -1) { + return false; + } else if (total_shards == -1 && shard_index != -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestShardIndex << " = " << shard_index + << ", but have left " << kTestTotalShards << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (total_shards != -1 && shard_index == -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestTotalShards << " = " << total_shards + << ", but have left " << kTestShardIndex << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (shard_index < 0 || shard_index >= total_shards) { + const Message msg = Message() + << "Invalid environment variables: we require 0 <= " + << kTestShardIndex << " < " << kTestTotalShards + << ", but you have " << kTestShardIndex << "=" << shard_index + << ", " << kTestTotalShards << "=" << total_shards << ".\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } + + return total_shards > 1; +} + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error +// and aborts. +Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { + const char* str_val = posix::GetEnv(var); + if (str_val == NULL) { + return default_val; + } + + Int32 result; + if (!ParseInt32(Message() << "The value of environment variable " << var, + str_val, &result)) { + exit(EXIT_FAILURE); + } + return result; +} + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { + return (test_id % total_shards) == shard_index; +} + +// Compares the name of each test with the user-specified filter to +// decide whether the test should be run, then records the result in +// each TestCase and TestInfo object. +// If shard_tests == true, further filters tests based on sharding +// variables in the environment - see +// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. +// Returns the number of tests that should run. +int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { + const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + + // num_runnable_tests are the number of tests that will + // run across all shards (i.e., match filter and are not disabled). + // num_selected_tests are the number of tests to be run on + // this shard. + int num_runnable_tests = 0; + int num_selected_tests = 0; + for (size_t i = 0; i < test_cases_.size(); i++) { + TestCase* const test_case = test_cases_[i]; + const String &test_case_name = test_case->name(); + test_case->set_should_run(false); + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + TestInfo* const test_info = test_case->test_info_list()[j]; + const String test_name(test_info->name()); + // A test is disabled if test case name or test name matches + // kDisableTestFilter. + const bool is_disabled = + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); + test_info->is_disabled_ = is_disabled; + + const bool matches_filter = + internal::UnitTestOptions::FilterMatchesTest(test_case_name, + test_name); + test_info->matches_filter_ = matches_filter; + + const bool is_runnable = + (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && + matches_filter; + + const bool is_selected = is_runnable && + (shard_tests == IGNORE_SHARDING_PROTOCOL || + ShouldRunTestOnShard(total_shards, shard_index, + num_runnable_tests)); + + num_runnable_tests += is_runnable; + num_selected_tests += is_selected; + + test_info->should_run_ = is_selected; + test_case->set_should_run(test_case->should_run() || is_selected); + } + } + return num_selected_tests; +} + +// Prints the names of the tests matching the user-specified filter flag. +void UnitTestImpl::ListTestsMatchingFilter() { + for (size_t i = 0; i < test_cases_.size(); i++) { + const TestCase* const test_case = test_cases_[i]; + bool printed_test_case_name = false; + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + const TestInfo* const test_info = + test_case->test_info_list()[j]; + if (test_info->matches_filter_) { + if (!printed_test_case_name) { + printed_test_case_name = true; + printf("%s.\n", test_case->name()); + } + printf(" %s\n", test_info->name()); + } + } + } + fflush(stdout); +} + +// Sets the OS stack trace getter. +// +// Does nothing if the input and the current OS stack trace getter are +// the same; otherwise, deletes the old getter and makes the input the +// current getter. +void UnitTestImpl::set_os_stack_trace_getter( + OsStackTraceGetterInterface* getter) { + if (os_stack_trace_getter_ != getter) { + delete os_stack_trace_getter_; + os_stack_trace_getter_ = getter; + } +} + +// Returns the current OS stack trace getter if it is not NULL; +// otherwise, creates an OsStackTraceGetter, makes it the current +// getter, and returns it. +OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { + if (os_stack_trace_getter_ == NULL) { + os_stack_trace_getter_ = new OsStackTraceGetter; + } + + return os_stack_trace_getter_; +} + +// Returns the TestResult for the test that's currently running, or +// the TestResult for the ad hoc test if no test is running. +TestResult* UnitTestImpl::current_test_result() { + return current_test_info_ ? + &(current_test_info_->result_) : &ad_hoc_test_result_; +} + +// Shuffles all test cases, and the tests within each test case, +// making sure that death tests are still run first. +void UnitTestImpl::ShuffleTests() { + // Shuffles the death test cases. + ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + + // Shuffles the non-death test cases. + ShuffleRange(random(), last_death_test_case_ + 1, + static_cast(test_cases_.size()), &test_case_indices_); + + // Shuffles the tests inside each test case. + for (size_t i = 0; i < test_cases_.size(); i++) { + test_cases_[i]->ShuffleTests(random()); + } +} + +// Restores the test cases and tests to their order before the first shuffle. +void UnitTestImpl::UnshuffleTests() { + for (size_t i = 0; i < test_cases_.size(); i++) { + // Unshuffles the tests in each test case. + test_cases_[i]->UnshuffleTests(); + // Resets the index of each test case. + test_case_indices_[i] = static_cast(i); + } +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, + int skip_count) { + // We pass skip_count + 1 to skip this wrapper function in addition + // to what the user really wants to skip. + return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); +} + +// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to +// suppress unreachable code warnings. +namespace { +class ClassUniqueToAlwaysTrue {}; +} + +bool IsTrue(bool condition) { return condition; } + +bool AlwaysTrue() { +#if GTEST_HAS_EXCEPTIONS + // This condition is always false so AlwaysTrue() never actually throws, + // but it makes the compiler think that it may throw. + if (IsTrue(false)) + throw ClassUniqueToAlwaysTrue(); +#endif // GTEST_HAS_EXCEPTIONS + return true; +} + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr) { + const size_t prefix_len = strlen(prefix); + if (strncmp(*pstr, prefix, prefix_len) == 0) { + *pstr += prefix_len; + return true; + } + return false; +} + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or NULL if the parsing failed. +const char* ParseFlagValue(const char* str, + const char* flag, + bool def_optional) { + // str and flag must not be NULL. + if (str == NULL || flag == NULL) return NULL; + + // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. + const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); + const size_t flag_len = flag_str.length(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) { + return flag_end; + } + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return NULL; + + // Returns the string after "=". + return flag_end + 1; +} + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true as long as it does +// not start with '0', 'f', or 'F'. +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Converts the string value to a bool. + *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); + return true; +} + +// Parses a string for an Int32 flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + return ParseInt32(Message() << "The value of flag --" << flag, + value_str, value); +} + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseStringFlag(const char* str, const char* flag, String* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + *value = value_str; + return true; +} + +// Determines whether a string has a prefix that Google Test uses for its +// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. +// If Google Test detects that a command line flag has its prefix but is not +// recognized, it will print its help message. Flags starting with +// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test +// internal flags and do not trigger the help message. +static bool HasGoogleTestFlagPrefix(const char* str) { + return (SkipPrefix("--", &str) || + SkipPrefix("-", &str) || + SkipPrefix("/", &str)) && + !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && + (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || + SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); +} + +// Prints a string containing code-encoded text. The following escape +// sequences can be used in the string to control the text color: +// +// @@ prints a single '@' character. +// @R changes the color to red. +// @G changes the color to green. +// @Y changes the color to yellow. +// @D changes to the default terminal text color. +// +// TODO(wan@google.com): Write tests for this once we add stdout +// capturing to Google Test. +static void PrintColorEncoded(const char* str) { + GTestColor color = COLOR_DEFAULT; // The current color. + + // Conceptually, we split the string into segments divided by escape + // sequences. Then we print one segment at a time. At the end of + // each iteration, the str pointer advances to the beginning of the + // next segment. + for (;;) { + const char* p = strchr(str, '@'); + if (p == NULL) { + ColoredPrintf(color, "%s", str); + return; + } + + ColoredPrintf(color, "%s", String(str, p - str).c_str()); + + const char ch = p[1]; + str = p + 2; + if (ch == '@') { + ColoredPrintf(color, "@"); + } else if (ch == 'D') { + color = COLOR_DEFAULT; + } else if (ch == 'R') { + color = COLOR_RED; + } else if (ch == 'G') { + color = COLOR_GREEN; + } else if (ch == 'Y') { + color = COLOR_YELLOW; + } else { + --str; + } + } +} + +static const char kColorEncodedHelpMessage[] = +"This program contains tests written using " GTEST_NAME_ ". You can use the\n" +"following command line flags to control its behavior:\n" +"\n" +"Test Selection:\n" +" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" +" List the names of all tests instead of running them. The name of\n" +" TEST(Foo, Bar) is \"Foo.Bar\".\n" +" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "[@G-@YNEGATIVE_PATTERNS]@D\n" +" Run only the tests whose name matches one of the positive patterns but\n" +" none of the negative patterns. '?' matches any single character; '*'\n" +" matches any substring; ':' separates two patterns.\n" +" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" +" Run all disabled tests too.\n" +"\n" +"Test Execution:\n" +" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" +" Run the tests repeatedly; use a negative count to repeat forever.\n" +" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" +" Randomize tests' orders on every iteration.\n" +" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" +" Random number seed to use for shuffling test orders (between 1 and\n" +" 99999, or 0 to use a seed based on the current time).\n" +"\n" +"Test Output:\n" +" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" +" Enable/disable colored output. The default is @Gauto@D.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" +" Don't print the elapsed time of each test.\n" +" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" + GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" +" Generate an XML report in the given directory or with the given file\n" +" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +#if GTEST_CAN_STREAM_RESULTS_ +" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" +" Stream test results to the given server.\n" +#endif // GTEST_CAN_STREAM_RESULTS_ +"\n" +"Assertion Behavior:\n" +#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" +" Set the default death test style.\n" +#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" +" Turn assertion failures into debugger break-points.\n" +" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" +" Turn assertion failures into C++ exceptions.\n" +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" +" Do not report exceptions as test failures. Instead, allow them\n" +" to crash the program or throw a pop-up (on Windows).\n" +"\n" +"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + "the corresponding\n" +"environment variable of a flag (all letters in upper-case). For example, to\n" +"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "color=no@D or set\n" +"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" +"\n" +"For more information, please read the " GTEST_NAME_ " documentation at\n" +"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" +"(not one in your own code or tests), please report it to\n" +"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. The type parameter CharType can be +// instantiated to either char or wchar_t. +template +void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { + for (int i = 1; i < *argc; i++) { + const String arg_string = StreamableToString(argv[i]); + const char* const arg = arg_string.c_str(); + + using internal::ParseBoolFlag; + using internal::ParseInt32Flag; + using internal::ParseStringFlag; + + // Do we see a Google Test flag? + if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)) + ) { + // Yes. Shift the remainder of the argv list left by one. Note + // that argv has (*argc + 1) elements, the last one always being + // NULL. The following loop moves the trailing NULL element as + // well. + for (int j = i; j != *argc; j++) { + argv[j] = argv[j + 1]; + } + + // Decrements the argument count. + (*argc)--; + + // We also need to decrement the iterator as we just removed + // an element. + i--; + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + } + + if (g_help_flag) { + // We print the help here instead of in RUN_ALL_TESTS(), as the + // latter may not be called at all if the user is using Google + // Test with another testing framework. + PrintColorEncoded(kColorEncodedHelpMessage); + } +} + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +void ParseGoogleTestFlagsOnly(int* argc, char** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} +void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} + +// The internal implementation of InitGoogleTest(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleTestImpl(int* argc, CharType** argv) { + g_init_gtest_count++; + + // We don't want to run the initialization code twice. + if (g_init_gtest_count != 1) return; + + if (*argc <= 0) return; + + internal::g_executable_path = internal::StreamableToString(argv[0]); + +#if GTEST_HAS_DEATH_TEST + + g_argvs.clear(); + for (int i = 0; i != *argc; i++) { + g_argvs.push_back(StreamableToString(argv[i])); + } + +#endif // GTEST_HAS_DEATH_TEST + + ParseGoogleTestFlagsOnly(argc, argv); + GetUnitTestImpl()->PostFlagParsingInit(); +} + +} // namespace internal + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +void InitGoogleTest(int* argc, char** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +void InitGoogleTest(int* argc, wchar_t** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +} // namespace testing -- cgit v1.1 From 5a364c5561ec04e33a6f5d52c14f1bac6f247ea0 Mon Sep 17 00:00:00 2001 From: Juergen Ributzka Date: Fri, 15 Nov 2013 22:34:48 +0000 Subject: [weak vtables] Remove a bunch of weak vtables This patch removes most of the trivial cases of weak vtables by pinning them to a single object file. Differential Revision: http://llvm-reviews.chandlerc.com/D2068 Reviewed by Andy git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194865 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenSchedule.cpp | 66 ++++++++++++---------- utils/TableGen/InstrInfoEmitter.cpp | 10 ++-- utils/TableGen/SetTheory.cpp | 49 +++++++++------- utils/TableGen/TGValueTypes.cpp | 16 +++++- .../googletest/include/gtest/gtest-test-part.h | 2 +- utils/unittest/googletest/include/gtest/gtest.h | 5 +- .../gtest/internal/gtest-death-test-internal.h | 4 +- .../include/gtest/internal/gtest-internal.h | 3 +- .../include/gtest/internal/gtest-param-util.h | 2 +- .../googletest/include/gtest/internal/gtest-port.h | 4 +- utils/unittest/googletest/src/gtest-death-test.cc | 4 ++ utils/unittest/googletest/src/gtest-internal-inl.h | 2 +- utils/unittest/googletest/src/gtest-port.cc | 10 ++++ utils/unittest/googletest/src/gtest.cc | 9 +++ 14 files changed, 118 insertions(+), 68 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index 001e97d..a857a20 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -38,12 +38,15 @@ static void dumpIdxVec(const SmallVectorImpl &V) { // (instrs a, b, ...) Evaluate and union all arguments. Identical to AddOp. struct InstrsOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, - ArrayRef Loc) { - ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); - } + virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef Loc); }; +void InstrsOp::apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef Loc) { + ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); +} + // (instregex "OpcPat",...) Find all instructions matching an opcode pattern. // // TODO: Since this is a prefix match, perform a binary search over the @@ -56,34 +59,37 @@ struct InstRegexOp : public SetTheory::Operator { const CodeGenTarget &Target; InstRegexOp(const CodeGenTarget &t): Target(t) {} - void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, - ArrayRef Loc) { - SmallVector RegexList; - for (DagInit::const_arg_iterator - AI = Expr->arg_begin(), AE = Expr->arg_end(); AI != AE; ++AI) { - StringInit *SI = dyn_cast(*AI); - if (!SI) - PrintFatalError(Loc, "instregex requires pattern string: " - + Expr->getAsString()); - std::string pat = SI->getValue(); - // Implement a python-style prefix match. - if (pat[0] != '^') { - pat.insert(0, "^("); - pat.insert(pat.end(), ')'); - } - RegexList.push_back(new Regex(pat)); - } - for (CodeGenTarget::inst_iterator I = Target.inst_begin(), - E = Target.inst_end(); I != E; ++I) { - for (SmallVectorImpl::iterator - RI = RegexList.begin(), RE = RegexList.end(); RI != RE; ++RI) { - if ((*RI)->match((*I)->TheDef->getName())) - Elts.insert((*I)->TheDef); - } + virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef Loc); +}; + +void InstRegexOp::apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef Loc) { + SmallVector RegexList; + for (DagInit::const_arg_iterator + AI = Expr->arg_begin(), AE = Expr->arg_end(); AI != AE; ++AI) { + StringInit *SI = dyn_cast(*AI); + if (!SI) + PrintFatalError(Loc, "instregex requires pattern string: " + + Expr->getAsString()); + std::string pat = SI->getValue(); + // Implement a python-style prefix match. + if (pat[0] != '^') { + pat.insert(0, "^("); + pat.insert(pat.end(), ')'); + } + RegexList.push_back(new Regex(pat)); + } + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + for (SmallVectorImpl::iterator + RI = RegexList.begin(), RE = RegexList.end(); RI != RE; ++RI) { + if ((*RI)->match((*I)->TheDef->getName())) + Elts.insert((*I)->TheDef); } - DeleteContainerPointers(RegexList); } -}; + DeleteContainerPointers(RegexList); +} /// CodeGenModels ctor interprets machine model records and populates maps. CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index af26353..9e0b74e 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -408,13 +408,14 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "namespace llvm {\n"; OS << "struct " << ClassName << " : public TargetInstrInfo {\n" << " explicit " << ClassName << "(int SO = -1, int DO = -1);\n" + << " virtual ~" << ClassName << "();\n" << "};\n"; OS << "} // End llvm namespace \n"; OS << "#endif // GET_INSTRINFO_HEADER\n\n"; - OS << "\n#ifdef GET_INSTRINFO_CTOR\n"; - OS << "#undef GET_INSTRINFO_CTOR\n"; + OS << "\n#ifdef GET_INSTRINFO_CTOR_DTOR\n"; + OS << "#undef GET_INSTRINFO_CTOR_DTOR\n"; OS << "namespace llvm {\n"; OS << "extern const MCInstrDesc " << TargetName << "Insts[];\n"; @@ -424,10 +425,11 @@ void InstrInfoEmitter::run(raw_ostream &OS) { << " : TargetInstrInfo(SO, DO) {\n" << " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, " - << NumberedInstructions.size() << ");\n}\n"; + << NumberedInstructions.size() << ");\n}\n" + << ClassName << "::~" << ClassName << "() {}\n"; OS << "} // End llvm namespace \n"; - OS << "#endif // GET_INSTRINFO_CTOR\n\n"; + OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n"; emitOperandNameMappings(OS, Target, NumberedInstructions); } diff --git a/utils/TableGen/SetTheory.cpp b/utils/TableGen/SetTheory.cpp index 3e5c38c..0df8c32 100644 --- a/utils/TableGen/SetTheory.cpp +++ b/utils/TableGen/SetTheory.cpp @@ -27,14 +27,16 @@ typedef SetTheory::RecVec RecVec; // (add a, b, ...) Evaluate and union all arguments. struct AddOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); } }; // (sub Add, Sub, ...) Set difference. struct SubOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { if (Expr->arg_size() < 2) PrintFatalError(Loc, "Set difference needs at least two arguments: " + Expr->getAsString()); @@ -49,7 +51,8 @@ struct SubOp : public SetTheory::Operator { // (and S1, S2) Set intersection. struct AndOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { if (Expr->arg_size() != 2) PrintFatalError(Loc, "Set intersection requires two arguments: " + Expr->getAsString()); @@ -68,7 +71,8 @@ struct SetIntBinOp : public SetTheory::Operator { RecSet &Set, int64_t N, RecSet &Elts, ArrayRef Loc) =0; - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { if (Expr->arg_size() != 2) PrintFatalError(Loc, "Operator requires (Op Set, Int) arguments: " + Expr->getAsString()); @@ -84,9 +88,9 @@ struct SetIntBinOp : public SetTheory::Operator { // (shl S, N) Shift left, remove the first N elements. struct ShlOp : public SetIntBinOp { - void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + virtual void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (N < 0) PrintFatalError(Loc, "Positive shift required: " + Expr->getAsString()); @@ -97,9 +101,9 @@ struct ShlOp : public SetIntBinOp { // (trunc S, N) Truncate after the first N elements. struct TruncOp : public SetIntBinOp { - void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + virtual void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (N < 0) PrintFatalError(Loc, "Positive length required: " + Expr->getAsString()); @@ -115,9 +119,9 @@ struct RotOp : public SetIntBinOp { RotOp(bool Rev) : Reverse(Rev) {} - void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + virtual void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (Reverse) N = -N; // N > 0 -> rotate left, N < 0 -> rotate right. @@ -134,9 +138,9 @@ struct RotOp : public SetIntBinOp { // (decimate S, N) Pick every N'th element of S. struct DecimateOp : public SetIntBinOp { - void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + virtual void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (N <= 0) PrintFatalError(Loc, "Positive stride required: " + Expr->getAsString()); @@ -147,7 +151,8 @@ struct DecimateOp : public SetIntBinOp { // (interleave S1, S2, ...) Interleave elements of the arguments. struct InterleaveOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { // Evaluate the arguments individually. SmallVector Args(Expr->getNumArgs()); unsigned MaxSize = 0; @@ -165,7 +170,8 @@ struct InterleaveOp : public SetTheory::Operator { // (sequence "Format", From, To) Generate a sequence of records by name. struct SequenceOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { int Step = 1; if (Expr->arg_size() > 4) PrintFatalError(Loc, "Bad args to (sequence \"Format\", From, To): " + @@ -232,15 +238,16 @@ struct FieldExpander : public SetTheory::Expander { FieldExpander(StringRef fn) : FieldName(fn) {} - void expand(SetTheory &ST, Record *Def, RecSet &Elts) { + virtual void expand(SetTheory &ST, Record *Def, RecSet &Elts) { ST.evaluate(Def->getValueInit(FieldName), Elts, Def->getLoc()); } }; } // end anonymous namespace -void SetTheory::Operator::anchor() { } +// pin vtables to this file +void SetTheory::Operator::anchor() {} +void SetTheory::Expander::anchor() {} -void SetTheory::Expander::anchor() { } SetTheory::SetTheory() { addOperator("add", new AddOp); diff --git a/utils/TableGen/TGValueTypes.cpp b/utils/TableGen/TGValueTypes.cpp index 3ac71a4..81c0d4c 100644 --- a/utils/TableGen/TGValueTypes.cpp +++ b/utils/TableGen/TGValueTypes.cpp @@ -35,9 +35,11 @@ public: } Type(TypeKind K) : Kind(K) {} virtual unsigned getSizeInBits() const = 0; - virtual ~Type() {} + virtual ~Type(); }; +Type::~Type() {} + } class ExtendedIntegerType : public Type { @@ -45,10 +47,11 @@ class ExtendedIntegerType : public Type { public: explicit ExtendedIntegerType(unsigned bits) : Type(TK_ExtendedIntegerType), BitWidth(bits) {} + virtual ~ExtendedIntegerType(); static bool classof(const Type *T) { return T->getKind() == TK_ExtendedIntegerType; } - unsigned getSizeInBits() const { + virtual unsigned getSizeInBits() const { return getBitWidth(); } unsigned getBitWidth() const { @@ -56,16 +59,20 @@ public: } }; +ExtendedIntegerType::~ExtendedIntegerType() {} + + class ExtendedVectorType : public Type { EVT ElementType; unsigned NumElements; public: ExtendedVectorType(EVT elty, unsigned num) : Type(TK_ExtendedVectorType), ElementType(elty), NumElements(num) {} + virtual ~ExtendedVectorType(); static bool classof(const Type *T) { return T->getKind() == TK_ExtendedVectorType; } - unsigned getSizeInBits() const { + virtual unsigned getSizeInBits() const { return getNumElements() * getElementType().getSizeInBits(); } EVT getElementType() const { @@ -76,6 +83,9 @@ public: } }; +ExtendedVectorType::~ExtendedVectorType() {} + + static std::map ExtendedIntegerTypeMap; static std::map, const Type *> diff --git a/utils/unittest/googletest/include/gtest/gtest-test-part.h b/utils/unittest/googletest/include/gtest/gtest-test-part.h index 8aeea14..98e8b84 100644 --- a/utils/unittest/googletest/include/gtest/gtest-test-part.h +++ b/utils/unittest/googletest/include/gtest/gtest-test-part.h @@ -142,7 +142,7 @@ class GTEST_API_ TestPartResultArray { // This interface knows how to report a test part result. class TestPartResultReporterInterface { public: - virtual ~TestPartResultReporterInterface() {} + virtual ~TestPartResultReporterInterface(); virtual void ReportTestPartResult(const TestPartResult& result) = 0; }; diff --git a/utils/unittest/googletest/include/gtest/gtest.h b/utils/unittest/googletest/include/gtest/gtest.h index 1734c44..07ed92b 100644 --- a/utils/unittest/googletest/include/gtest/gtest.h +++ b/utils/unittest/googletest/include/gtest/gtest.h @@ -910,7 +910,7 @@ class GTEST_API_ TestCase { class Environment { public: // The d'tor is virtual as we need to subclass Environment. - virtual ~Environment() {} + virtual ~Environment(); // Override this to define how to set up the environment. virtual void SetUp() {} @@ -928,7 +928,7 @@ class Environment { // the order the corresponding events are fired. class TestEventListener { public: - virtual ~TestEventListener() {} + virtual ~TestEventListener(); // Fired before any test activity starts. virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; @@ -980,6 +980,7 @@ class TestEventListener { // comments about each method please see the definition of TestEventListener // above. class EmptyTestEventListener : public TestEventListener { + virtual void anchor(); public: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h index 7bac2bd..8d53c45 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h @@ -79,7 +79,7 @@ class GTEST_API_ DeathTest { static bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test); DeathTest(); - virtual ~DeathTest() { } + virtual ~DeathTest(); // A helper class that aborts a death test when it's deleted. class ReturnSentinel { @@ -139,7 +139,7 @@ class GTEST_API_ DeathTest { // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: - virtual ~DeathTestFactory() { } + virtual ~DeathTestFactory(); virtual bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) = 0; }; diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h index a94bf28..63f72ac 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h @@ -105,6 +105,7 @@ #if !GTEST_NO_LLVM_RAW_OSTREAM namespace llvm { class convertible_fwd_ostream : public std::ostream { + virtual void anchor(); raw_os_ostream ros_; public: @@ -536,7 +537,7 @@ GTEST_API_ TypeId GetTestTypeId(); // of a Test object. class TestFactoryBase { public: - virtual ~TestFactoryBase() {} + virtual ~TestFactoryBase(); // Creates a test instance to run. The instance is both created and destroyed // within TestInfoImpl::Run() diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h index 0ef9718..3bb2ffb 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h @@ -414,7 +414,7 @@ class TestMetaFactory // and calls RegisterTests() on each of them when asked. class ParameterizedTestCaseInfoBase { public: - virtual ~ParameterizedTestCaseInfoBase() {} + virtual ~ParameterizedTestCaseInfoBase(); // Base part of test case name for display purposes. virtual const string& GetTestCaseName() const = 0; diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-port.h b/utils/unittest/googletest/include/gtest/internal/gtest-port.h index 58f6caf..32fd9c6 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-port.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-port.h @@ -1116,7 +1116,7 @@ class Notification { // problem. class ThreadWithParamBase { public: - virtual ~ThreadWithParamBase() {} + virtual ~ThreadWithParamBase(); virtual void Run() = 0; }; @@ -1290,7 +1290,7 @@ typedef GTestMutexLock MutexLock; // ThreadLocalValueHolderBase. class ThreadLocalValueHolderBase { public: - virtual ~ThreadLocalValueHolderBase() {} + virtual ~ThreadLocalValueHolderBase(); }; // Called by pthread to delete thread-local data stored by diff --git a/utils/unittest/googletest/src/gtest-death-test.cc b/utils/unittest/googletest/src/gtest-death-test.cc index 82453f2..b66325e 100644 --- a/utils/unittest/googletest/src/gtest-death-test.cc +++ b/utils/unittest/googletest/src/gtest-death-test.cc @@ -300,6 +300,8 @@ DeathTest::DeathTest() { } } +DeathTest::~DeathTest() {} + // Creates and returns a death test by dispatching to the current // death test factory. bool DeathTest::Create(const char* statement, const RE* regex, @@ -733,6 +735,8 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { } # else // We are not on Windows. +DeathTestFactory::~DeathTestFactory() {} + // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. diff --git a/utils/unittest/googletest/src/gtest-internal-inl.h b/utils/unittest/googletest/src/gtest-internal-inl.h index 6554cfc..1bae630 100644 --- a/utils/unittest/googletest/src/gtest-internal-inl.h +++ b/utils/unittest/googletest/src/gtest-internal-inl.h @@ -408,7 +408,7 @@ GTEST_API_ FilePath GetCurrentExecutableName(); class OsStackTraceGetterInterface { public: OsStackTraceGetterInterface() {} - virtual ~OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface(); // Returns the current OS stack trace as a String. Parameters: // diff --git a/utils/unittest/googletest/src/gtest-port.cc b/utils/unittest/googletest/src/gtest-port.cc index 7459562..382985e 100644 --- a/utils/unittest/googletest/src/gtest-port.cc +++ b/utils/unittest/googletest/src/gtest-port.cc @@ -746,5 +746,15 @@ const char* StringFromGTestEnv(const char* flag, const char* default_value) { return value == NULL ? default_value : value; } +ThreadWithParamBase::~ThreadWithParamBase() {} +ThreadLocalValueHolderBase::~ThreadLocalValueHolderBase() {} +TestFactoryBase::~TestFactoryBase() {} + } // namespace internal } // namespace testing + +#if !GTEST_NO_LLVM_RAW_OSTREAM +namespace llvm { +void convertible_fwd_ostream::anchor() {} +} +#endif diff --git a/utils/unittest/googletest/src/gtest.cc b/utils/unittest/googletest/src/gtest.cc index 9891928..ca814d1 100644 --- a/utils/unittest/googletest/src/gtest.cc +++ b/utils/unittest/googletest/src/gtest.cc @@ -4863,4 +4863,13 @@ void InitGoogleTest(int* argc, wchar_t** argv) { internal::InitGoogleTestImpl(argc, argv); } +Environment::~Environment() {} +TestPartResultReporterInterface::~TestPartResultReporterInterface() {} +TestEventListener::~TestEventListener() {} +void EmptyTestEventListener::anchor() {} +namespace internal { +OsStackTraceGetterInterface::~OsStackTraceGetterInterface() {} +ParameterizedTestCaseInfoBase::~ParameterizedTestCaseInfoBase() {} +} + } // namespace testing -- cgit v1.1 From 7426308bf047b153dfa1ec359e811258ad4551a3 Mon Sep 17 00:00:00 2001 From: Juergen Ributzka Date: Fri, 15 Nov 2013 23:02:56 +0000 Subject: Fix previous commit (r194865) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194874 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/unittest/googletest/src/gtest-port.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'utils') diff --git a/utils/unittest/googletest/src/gtest-port.cc b/utils/unittest/googletest/src/gtest-port.cc index 382985e..0719b0c 100644 --- a/utils/unittest/googletest/src/gtest-port.cc +++ b/utils/unittest/googletest/src/gtest-port.cc @@ -746,8 +746,10 @@ const char* StringFromGTestEnv(const char* flag, const char* default_value) { return value == NULL ? default_value : value; } +#if GTEST_HAS_PTHREAD ThreadWithParamBase::~ThreadWithParamBase() {} ThreadLocalValueHolderBase::~ThreadLocalValueHolderBase() {} +#endif TestFactoryBase::~TestFactoryBase() {} } // namespace internal -- cgit v1.1 From e553feab843a82e35b81e20ebc736f775c85db32 Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Sat, 16 Nov 2013 00:20:01 +0000 Subject: =?UTF-8?q?Small=20improvement=20to=20InstrinsicEmitter::EmitAttri?= =?UTF-8?q?butes.=20=20This=20change=20removes=20the=20=E2=80=9Cpushing?= =?UTF-8?q?=E2=80=9D=20and=20=E2=80=9Cclearing=E2=80=9D=20of=20the=20Small?= =?UTF-8?q?Vector=20and=20instead=20uses=20const=20arrays=20to=20pass=20th?= =?UTF-8?q?e=20attributeKinds=20to=20AttributeSet::get=20.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch by Aditya Nandakumar. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194899 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/IntrinsicEmitter.cpp | 55 +++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 17 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index 6531dcb..8f137f8 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -572,7 +572,6 @@ EmitAttributes(const std::vector &Ints, raw_ostream &OS) { OS << " AttributeSet AS[" << maxArgAttrs+1 << "];\n"; OS << " unsigned NumAttrs = 0;\n"; OS << " if (id != 0) {\n"; - OS << " SmallVector AttrVec;\n"; OS << " switch(IntrinsicsToAttributesMap[id - "; if (TargetOnly) OS << "Intrinsic::num_intrinsics"; @@ -582,7 +581,7 @@ EmitAttributes(const std::vector &Ints, raw_ostream &OS) { OS << " default: llvm_unreachable(\"Invalid attribute number\");\n"; for (UniqAttrMapTy::const_iterator I = UniqAttributes.begin(), E = UniqAttributes.end(); I != E; ++I) { - OS << " case " << I->second << ":\n"; + OS << " case " << I->second << ": {\n"; const CodeGenIntrinsic &intrinsic = *(I->first); @@ -595,55 +594,77 @@ EmitAttributes(const std::vector &Ints, raw_ostream &OS) { while (ai != ae) { unsigned argNo = intrinsic.ArgumentAttributes[ai].first; - OS << " AttrVec.clear();\n"; + OS << " const Attribute::AttrKind AttrParam" << argNo + 1 <<"[]= {"; + bool addComma = false; do { switch (intrinsic.ArgumentAttributes[ai].second) { case CodeGenIntrinsic::NoCapture: - OS << " AttrVec.push_back(Attribute::NoCapture);\n"; + if (addComma) + OS << ","; + OS << "Attribute::NoCapture"; + addComma = true; break; case CodeGenIntrinsic::ReadOnly: - OS << " AttrVec.push_back(Attribute::ReadOnly);\n"; + if (addComma) + OS << ","; + OS << "Attribute::ReadOnly"; + addComma = true; break; case CodeGenIntrinsic::ReadNone: - OS << " AttrVec.push_back(Attribute::ReadNone);\n"; + if (addComma) + OS << ","; + OS << "Attributes::ReadNone"; + addComma = true; break; } ++ai; } while (ai != ae && intrinsic.ArgumentAttributes[ai].first == argNo); - + OS << "};\n"; OS << " AS[" << numAttrs++ << "] = AttributeSet::get(C, " - << argNo+1 << ", AttrVec);\n"; + << argNo+1 << ", AttrParam" << argNo +1 << ");\n"; } } ModRefKind modRef = getModRefKind(intrinsic); if (!intrinsic.canThrow || modRef || intrinsic.isNoReturn) { - OS << " AttrVec.clear();\n"; - - if (!intrinsic.canThrow) - OS << " AttrVec.push_back(Attribute::NoUnwind);\n"; - if (intrinsic.isNoReturn) - OS << " AttrVec.push_back(Attribute::NoReturn);\n"; + OS << " const Attribute::AttrKind Atts[] = {"; + bool addComma = false; + if (!intrinsic.canThrow) { + OS << "Attribute::NoUnwind"; + addComma = true; + } + if (intrinsic.isNoReturn) { + if (addComma) + OS << ","; + OS << "Attribute::NoReturn"; + addComma = true; + } switch (modRef) { case MRK_none: break; case MRK_readonly: - OS << " AttrVec.push_back(Attribute::ReadOnly);\n"; + if (addComma) + OS << ","; + OS << "Attribute::ReadOnly"; break; case MRK_readnone: - OS << " AttrVec.push_back(Attribute::ReadNone);\n"; + if (addComma) + OS << ","; + OS << "Attribute::ReadNone"; break; } + OS << "};\n"; OS << " AS[" << numAttrs++ << "] = AttributeSet::get(C, " - << "AttributeSet::FunctionIndex, AttrVec);\n"; + << "AttributeSet::FunctionIndex, Atts);\n"; } if (numAttrs) { OS << " NumAttrs = " << numAttrs << ";\n"; OS << " break;\n"; + OS << " }\n"; } else { OS << " return AttributeSet();\n"; } -- cgit v1.1 From 793622668ef3dede3b020f92680cbc0d71bd3f6b Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Sat, 16 Nov 2013 05:26:49 +0000 Subject: gtest-death-test.cc: Move ~DeathTestFactory() to unbreak cygming build since r194865. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194918 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/unittest/googletest/src/gtest-death-test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/unittest/googletest/src/gtest-death-test.cc b/utils/unittest/googletest/src/gtest-death-test.cc index b66325e..b9693d3 100644 --- a/utils/unittest/googletest/src/gtest-death-test.cc +++ b/utils/unittest/googletest/src/gtest-death-test.cc @@ -735,8 +735,6 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { } # else // We are not on Windows. -DeathTestFactory::~DeathTestFactory() {} - // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. @@ -1039,6 +1037,8 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { # endif // !GTEST_OS_WINDOWS +DeathTestFactory::~DeathTestFactory() {} + // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to // by the "test" argument to its address. If the test should be -- cgit v1.1 From b923d2f5f5958719214472906e9810de262ab447 Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Sun, 17 Nov 2013 21:24:41 +0000 Subject: TableGen: Generate an enum for all named Operand types in tblgen'd InstrInfo. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194978 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/InstrInfoEmitter.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'utils') diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index 9e0b74e..d3d9cc1 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -57,6 +57,7 @@ private: std::map, unsigned> &EL, const OperandInfoMapTy &OpInfo, raw_ostream &OS); + void emitOperandTypesEnum(raw_ostream &OS, const CodeGenTarget &Target); void initOperandMapData( const std::vector NumberedInstructions, const std::string &Namespace, @@ -311,6 +312,34 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, } +/// Generate an enum for all the operand types for this target, under the +/// llvm::TargetNamespace::OpTypes namespace. +/// Operand types are all definitions derived of the Operand Target.td class. +void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS, + const CodeGenTarget &Target) { + + const std::string &Namespace = Target.getInstNamespace(); + std::vector Operands = Records.getAllDerivedDefinitions("Operand"); + + OS << "\n#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; + OS << "#undef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; + OS << "namespace llvm {"; + OS << "namespace " << Namespace << " {\n"; + OS << "namespace OpTypes { \n"; + OS << "enum OperandType {\n"; + + for (unsigned oi = 0, oe = Operands.size(); oi != oe; ++oi) { + if (!Operands[oi]->isAnonymous()) + OS << " " << Operands[oi]->getName() << " = " << oi << ",\n"; + } + + OS << " OPERAND_TYPE_LIST_END" << "\n};\n"; + OS << "} // End namespace OpTypes\n"; + OS << "} // End namespace " << Namespace << "\n"; + OS << "} // End namespace llvm\n"; + OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; +} + //===----------------------------------------------------------------------===// // Main Output. //===----------------------------------------------------------------------===// @@ -432,6 +461,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n"; emitOperandNameMappings(OS, Target, NumberedInstructions); + + emitOperandTypesEnum(OS, Target); } void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, -- cgit v1.1 From b21ab43cfc3fa0dacf5c95f04e58b6d804b59a16 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Mon, 18 Nov 2013 09:31:53 +0000 Subject: Revert r194865 and r194874. This change is incorrect. If you delete virtual destructor of both a base class and a subclass, then the following code: Base *foo = new Child(); delete foo; will not cause the destructor for members of Child class. As a result, I observe plently of memory leaks. Notable examples I investigated are: ObjectBuffer and ObjectBufferStream, AttributeImpl and StringSAttributeImpl. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194997 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenSchedule.cpp | 66 ++++++++++------------ utils/TableGen/InstrInfoEmitter.cpp | 10 ++-- utils/TableGen/SetTheory.cpp | 49 +++++++--------- utils/TableGen/TGValueTypes.cpp | 16 +----- .../googletest/include/gtest/gtest-test-part.h | 2 +- utils/unittest/googletest/include/gtest/gtest.h | 5 +- .../gtest/internal/gtest-death-test-internal.h | 4 +- .../include/gtest/internal/gtest-internal.h | 3 +- .../include/gtest/internal/gtest-param-util.h | 2 +- .../googletest/include/gtest/internal/gtest-port.h | 4 +- utils/unittest/googletest/src/gtest-death-test.cc | 2 - utils/unittest/googletest/src/gtest-internal-inl.h | 2 +- utils/unittest/googletest/src/gtest-port.cc | 12 ---- utils/unittest/googletest/src/gtest.cc | 9 --- 14 files changed, 68 insertions(+), 118 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index a857a20..001e97d 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -38,15 +38,12 @@ static void dumpIdxVec(const SmallVectorImpl &V) { // (instrs a, b, ...) Evaluate and union all arguments. Identical to AddOp. struct InstrsOp : public SetTheory::Operator { - virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, - ArrayRef Loc); + void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef Loc) { + ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); + } }; -void InstrsOp::apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, - ArrayRef Loc) { - ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); -} - // (instregex "OpcPat",...) Find all instructions matching an opcode pattern. // // TODO: Since this is a prefix match, perform a binary search over the @@ -59,37 +56,34 @@ struct InstRegexOp : public SetTheory::Operator { const CodeGenTarget &Target; InstRegexOp(const CodeGenTarget &t): Target(t) {} - virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, - ArrayRef Loc); -}; - -void InstRegexOp::apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, - ArrayRef Loc) { - SmallVector RegexList; - for (DagInit::const_arg_iterator - AI = Expr->arg_begin(), AE = Expr->arg_end(); AI != AE; ++AI) { - StringInit *SI = dyn_cast(*AI); - if (!SI) - PrintFatalError(Loc, "instregex requires pattern string: " - + Expr->getAsString()); - std::string pat = SI->getValue(); - // Implement a python-style prefix match. - if (pat[0] != '^') { - pat.insert(0, "^("); - pat.insert(pat.end(), ')'); - } - RegexList.push_back(new Regex(pat)); - } - for (CodeGenTarget::inst_iterator I = Target.inst_begin(), - E = Target.inst_end(); I != E; ++I) { - for (SmallVectorImpl::iterator - RI = RegexList.begin(), RE = RegexList.end(); RI != RE; ++RI) { - if ((*RI)->match((*I)->TheDef->getName())) - Elts.insert((*I)->TheDef); + void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef Loc) { + SmallVector RegexList; + for (DagInit::const_arg_iterator + AI = Expr->arg_begin(), AE = Expr->arg_end(); AI != AE; ++AI) { + StringInit *SI = dyn_cast(*AI); + if (!SI) + PrintFatalError(Loc, "instregex requires pattern string: " + + Expr->getAsString()); + std::string pat = SI->getValue(); + // Implement a python-style prefix match. + if (pat[0] != '^') { + pat.insert(0, "^("); + pat.insert(pat.end(), ')'); + } + RegexList.push_back(new Regex(pat)); + } + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + for (SmallVectorImpl::iterator + RI = RegexList.begin(), RE = RegexList.end(); RI != RE; ++RI) { + if ((*RI)->match((*I)->TheDef->getName())) + Elts.insert((*I)->TheDef); + } } + DeleteContainerPointers(RegexList); } - DeleteContainerPointers(RegexList); -} +}; /// CodeGenModels ctor interprets machine model records and populates maps. CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index d3d9cc1..51ce2a7 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -437,14 +437,13 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "namespace llvm {\n"; OS << "struct " << ClassName << " : public TargetInstrInfo {\n" << " explicit " << ClassName << "(int SO = -1, int DO = -1);\n" - << " virtual ~" << ClassName << "();\n" << "};\n"; OS << "} // End llvm namespace \n"; OS << "#endif // GET_INSTRINFO_HEADER\n\n"; - OS << "\n#ifdef GET_INSTRINFO_CTOR_DTOR\n"; - OS << "#undef GET_INSTRINFO_CTOR_DTOR\n"; + OS << "\n#ifdef GET_INSTRINFO_CTOR\n"; + OS << "#undef GET_INSTRINFO_CTOR\n"; OS << "namespace llvm {\n"; OS << "extern const MCInstrDesc " << TargetName << "Insts[];\n"; @@ -454,11 +453,10 @@ void InstrInfoEmitter::run(raw_ostream &OS) { << " : TargetInstrInfo(SO, DO) {\n" << " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, " - << NumberedInstructions.size() << ");\n}\n" - << ClassName << "::~" << ClassName << "() {}\n"; + << NumberedInstructions.size() << ");\n}\n"; OS << "} // End llvm namespace \n"; - OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n"; + OS << "#endif // GET_INSTRINFO_CTOR\n\n"; emitOperandNameMappings(OS, Target, NumberedInstructions); diff --git a/utils/TableGen/SetTheory.cpp b/utils/TableGen/SetTheory.cpp index 0df8c32..3e5c38c 100644 --- a/utils/TableGen/SetTheory.cpp +++ b/utils/TableGen/SetTheory.cpp @@ -27,16 +27,14 @@ typedef SetTheory::RecVec RecVec; // (add a, b, ...) Evaluate and union all arguments. struct AddOp : public SetTheory::Operator { - virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, - ArrayRef Loc) { + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); } }; // (sub Add, Sub, ...) Set difference. struct SubOp : public SetTheory::Operator { - virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, - ArrayRef Loc) { + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { if (Expr->arg_size() < 2) PrintFatalError(Loc, "Set difference needs at least two arguments: " + Expr->getAsString()); @@ -51,8 +49,7 @@ struct SubOp : public SetTheory::Operator { // (and S1, S2) Set intersection. struct AndOp : public SetTheory::Operator { - virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, - ArrayRef Loc) { + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { if (Expr->arg_size() != 2) PrintFatalError(Loc, "Set intersection requires two arguments: " + Expr->getAsString()); @@ -71,8 +68,7 @@ struct SetIntBinOp : public SetTheory::Operator { RecSet &Set, int64_t N, RecSet &Elts, ArrayRef Loc) =0; - virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, - ArrayRef Loc) { + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { if (Expr->arg_size() != 2) PrintFatalError(Loc, "Operator requires (Op Set, Int) arguments: " + Expr->getAsString()); @@ -88,9 +84,9 @@ struct SetIntBinOp : public SetTheory::Operator { // (shl S, N) Shift left, remove the first N elements. struct ShlOp : public SetIntBinOp { - virtual void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (N < 0) PrintFatalError(Loc, "Positive shift required: " + Expr->getAsString()); @@ -101,9 +97,9 @@ struct ShlOp : public SetIntBinOp { // (trunc S, N) Truncate after the first N elements. struct TruncOp : public SetIntBinOp { - virtual void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (N < 0) PrintFatalError(Loc, "Positive length required: " + Expr->getAsString()); @@ -119,9 +115,9 @@ struct RotOp : public SetIntBinOp { RotOp(bool Rev) : Reverse(Rev) {} - virtual void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (Reverse) N = -N; // N > 0 -> rotate left, N < 0 -> rotate right. @@ -138,9 +134,9 @@ struct RotOp : public SetIntBinOp { // (decimate S, N) Pick every N'th element of S. struct DecimateOp : public SetIntBinOp { - virtual void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (N <= 0) PrintFatalError(Loc, "Positive stride required: " + Expr->getAsString()); @@ -151,8 +147,7 @@ struct DecimateOp : public SetIntBinOp { // (interleave S1, S2, ...) Interleave elements of the arguments. struct InterleaveOp : public SetTheory::Operator { - virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, - ArrayRef Loc) { + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { // Evaluate the arguments individually. SmallVector Args(Expr->getNumArgs()); unsigned MaxSize = 0; @@ -170,8 +165,7 @@ struct InterleaveOp : public SetTheory::Operator { // (sequence "Format", From, To) Generate a sequence of records by name. struct SequenceOp : public SetTheory::Operator { - virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, - ArrayRef Loc) { + void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { int Step = 1; if (Expr->arg_size() > 4) PrintFatalError(Loc, "Bad args to (sequence \"Format\", From, To): " + @@ -238,16 +232,15 @@ struct FieldExpander : public SetTheory::Expander { FieldExpander(StringRef fn) : FieldName(fn) {} - virtual void expand(SetTheory &ST, Record *Def, RecSet &Elts) { + void expand(SetTheory &ST, Record *Def, RecSet &Elts) { ST.evaluate(Def->getValueInit(FieldName), Elts, Def->getLoc()); } }; } // end anonymous namespace -// pin vtables to this file -void SetTheory::Operator::anchor() {} -void SetTheory::Expander::anchor() {} +void SetTheory::Operator::anchor() { } +void SetTheory::Expander::anchor() { } SetTheory::SetTheory() { addOperator("add", new AddOp); diff --git a/utils/TableGen/TGValueTypes.cpp b/utils/TableGen/TGValueTypes.cpp index 81c0d4c..3ac71a4 100644 --- a/utils/TableGen/TGValueTypes.cpp +++ b/utils/TableGen/TGValueTypes.cpp @@ -35,11 +35,9 @@ public: } Type(TypeKind K) : Kind(K) {} virtual unsigned getSizeInBits() const = 0; - virtual ~Type(); + virtual ~Type() {} }; -Type::~Type() {} - } class ExtendedIntegerType : public Type { @@ -47,11 +45,10 @@ class ExtendedIntegerType : public Type { public: explicit ExtendedIntegerType(unsigned bits) : Type(TK_ExtendedIntegerType), BitWidth(bits) {} - virtual ~ExtendedIntegerType(); static bool classof(const Type *T) { return T->getKind() == TK_ExtendedIntegerType; } - virtual unsigned getSizeInBits() const { + unsigned getSizeInBits() const { return getBitWidth(); } unsigned getBitWidth() const { @@ -59,20 +56,16 @@ public: } }; -ExtendedIntegerType::~ExtendedIntegerType() {} - - class ExtendedVectorType : public Type { EVT ElementType; unsigned NumElements; public: ExtendedVectorType(EVT elty, unsigned num) : Type(TK_ExtendedVectorType), ElementType(elty), NumElements(num) {} - virtual ~ExtendedVectorType(); static bool classof(const Type *T) { return T->getKind() == TK_ExtendedVectorType; } - virtual unsigned getSizeInBits() const { + unsigned getSizeInBits() const { return getNumElements() * getElementType().getSizeInBits(); } EVT getElementType() const { @@ -83,9 +76,6 @@ public: } }; -ExtendedVectorType::~ExtendedVectorType() {} - - static std::map ExtendedIntegerTypeMap; static std::map, const Type *> diff --git a/utils/unittest/googletest/include/gtest/gtest-test-part.h b/utils/unittest/googletest/include/gtest/gtest-test-part.h index 98e8b84..8aeea14 100644 --- a/utils/unittest/googletest/include/gtest/gtest-test-part.h +++ b/utils/unittest/googletest/include/gtest/gtest-test-part.h @@ -142,7 +142,7 @@ class GTEST_API_ TestPartResultArray { // This interface knows how to report a test part result. class TestPartResultReporterInterface { public: - virtual ~TestPartResultReporterInterface(); + virtual ~TestPartResultReporterInterface() {} virtual void ReportTestPartResult(const TestPartResult& result) = 0; }; diff --git a/utils/unittest/googletest/include/gtest/gtest.h b/utils/unittest/googletest/include/gtest/gtest.h index 07ed92b..1734c44 100644 --- a/utils/unittest/googletest/include/gtest/gtest.h +++ b/utils/unittest/googletest/include/gtest/gtest.h @@ -910,7 +910,7 @@ class GTEST_API_ TestCase { class Environment { public: // The d'tor is virtual as we need to subclass Environment. - virtual ~Environment(); + virtual ~Environment() {} // Override this to define how to set up the environment. virtual void SetUp() {} @@ -928,7 +928,7 @@ class Environment { // the order the corresponding events are fired. class TestEventListener { public: - virtual ~TestEventListener(); + virtual ~TestEventListener() {} // Fired before any test activity starts. virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; @@ -980,7 +980,6 @@ class TestEventListener { // comments about each method please see the definition of TestEventListener // above. class EmptyTestEventListener : public TestEventListener { - virtual void anchor(); public: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h index 8d53c45..7bac2bd 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h @@ -79,7 +79,7 @@ class GTEST_API_ DeathTest { static bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test); DeathTest(); - virtual ~DeathTest(); + virtual ~DeathTest() { } // A helper class that aborts a death test when it's deleted. class ReturnSentinel { @@ -139,7 +139,7 @@ class GTEST_API_ DeathTest { // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: - virtual ~DeathTestFactory(); + virtual ~DeathTestFactory() { } virtual bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) = 0; }; diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h index 63f72ac..a94bf28 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h @@ -105,7 +105,6 @@ #if !GTEST_NO_LLVM_RAW_OSTREAM namespace llvm { class convertible_fwd_ostream : public std::ostream { - virtual void anchor(); raw_os_ostream ros_; public: @@ -537,7 +536,7 @@ GTEST_API_ TypeId GetTestTypeId(); // of a Test object. class TestFactoryBase { public: - virtual ~TestFactoryBase(); + virtual ~TestFactoryBase() {} // Creates a test instance to run. The instance is both created and destroyed // within TestInfoImpl::Run() diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h index 3bb2ffb..0ef9718 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h @@ -414,7 +414,7 @@ class TestMetaFactory // and calls RegisterTests() on each of them when asked. class ParameterizedTestCaseInfoBase { public: - virtual ~ParameterizedTestCaseInfoBase(); + virtual ~ParameterizedTestCaseInfoBase() {} // Base part of test case name for display purposes. virtual const string& GetTestCaseName() const = 0; diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-port.h b/utils/unittest/googletest/include/gtest/internal/gtest-port.h index 32fd9c6..58f6caf 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-port.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-port.h @@ -1116,7 +1116,7 @@ class Notification { // problem. class ThreadWithParamBase { public: - virtual ~ThreadWithParamBase(); + virtual ~ThreadWithParamBase() {} virtual void Run() = 0; }; @@ -1290,7 +1290,7 @@ typedef GTestMutexLock MutexLock; // ThreadLocalValueHolderBase. class ThreadLocalValueHolderBase { public: - virtual ~ThreadLocalValueHolderBase(); + virtual ~ThreadLocalValueHolderBase() {} }; // Called by pthread to delete thread-local data stored by diff --git a/utils/unittest/googletest/src/gtest-death-test.cc b/utils/unittest/googletest/src/gtest-death-test.cc index b9693d3..6c8b001 100644 --- a/utils/unittest/googletest/src/gtest-death-test.cc +++ b/utils/unittest/googletest/src/gtest-death-test.cc @@ -300,8 +300,6 @@ DeathTest::DeathTest() { } } -DeathTest::~DeathTest() {} - // Creates and returns a death test by dispatching to the current // death test factory. bool DeathTest::Create(const char* statement, const RE* regex, diff --git a/utils/unittest/googletest/src/gtest-internal-inl.h b/utils/unittest/googletest/src/gtest-internal-inl.h index 1bae630..6554cfc 100644 --- a/utils/unittest/googletest/src/gtest-internal-inl.h +++ b/utils/unittest/googletest/src/gtest-internal-inl.h @@ -408,7 +408,7 @@ GTEST_API_ FilePath GetCurrentExecutableName(); class OsStackTraceGetterInterface { public: OsStackTraceGetterInterface() {} - virtual ~OsStackTraceGetterInterface(); + virtual ~OsStackTraceGetterInterface() {} // Returns the current OS stack trace as a String. Parameters: // diff --git a/utils/unittest/googletest/src/gtest-port.cc b/utils/unittest/googletest/src/gtest-port.cc index 0719b0c..7459562 100644 --- a/utils/unittest/googletest/src/gtest-port.cc +++ b/utils/unittest/googletest/src/gtest-port.cc @@ -746,17 +746,5 @@ const char* StringFromGTestEnv(const char* flag, const char* default_value) { return value == NULL ? default_value : value; } -#if GTEST_HAS_PTHREAD -ThreadWithParamBase::~ThreadWithParamBase() {} -ThreadLocalValueHolderBase::~ThreadLocalValueHolderBase() {} -#endif -TestFactoryBase::~TestFactoryBase() {} - } // namespace internal } // namespace testing - -#if !GTEST_NO_LLVM_RAW_OSTREAM -namespace llvm { -void convertible_fwd_ostream::anchor() {} -} -#endif diff --git a/utils/unittest/googletest/src/gtest.cc b/utils/unittest/googletest/src/gtest.cc index ca814d1..9891928 100644 --- a/utils/unittest/googletest/src/gtest.cc +++ b/utils/unittest/googletest/src/gtest.cc @@ -4863,13 +4863,4 @@ void InitGoogleTest(int* argc, wchar_t** argv) { internal::InitGoogleTestImpl(argc, argv); } -Environment::~Environment() {} -TestPartResultReporterInterface::~TestPartResultReporterInterface() {} -TestEventListener::~TestEventListener() {} -void EmptyTestEventListener::anchor() {} -namespace internal { -OsStackTraceGetterInterface::~OsStackTraceGetterInterface() {} -ParameterizedTestCaseInfoBase::~ParameterizedTestCaseInfoBase() {} -} - } // namespace testing -- cgit v1.1 From 38ea7b55ece37f189726ff5bc60e0b5c2754bee4 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Mon, 18 Nov 2013 09:44:36 +0000 Subject: Unbreak the build after r194997 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194998 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/unittest/googletest/src/gtest-death-test.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'utils') diff --git a/utils/unittest/googletest/src/gtest-death-test.cc b/utils/unittest/googletest/src/gtest-death-test.cc index 6c8b001..82453f2 100644 --- a/utils/unittest/googletest/src/gtest-death-test.cc +++ b/utils/unittest/googletest/src/gtest-death-test.cc @@ -1035,8 +1035,6 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { # endif // !GTEST_OS_WINDOWS -DeathTestFactory::~DeathTestFactory() {} - // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to // by the "test" argument to its address. If the test should be -- cgit v1.1 From ea8e1447d1f563f743b6b73739f4ff0912595752 Mon Sep 17 00:00:00 2001 From: "Arnaud A. de Grandmaison" Date: Mon, 18 Nov 2013 10:34:59 +0000 Subject: test-release.sh: tweak RPATH for the binary packages. libtool sets RPATH to "$ORIGIN/../lib:/the/directory/where/it/was/built/lib" so that a developper can use the built or the installed version seamlessly. Our binary packages should not have this developer friendly tweak, as the users of the binaries will not have the build tree. Beside, in case the development tree is a possibly on an automounted share, this can create very bad user experience : they will incur an automount timeout penalty and will get a very bad feeling of llvm/clang's speed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194999 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/release/test-release.sh | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'utils') diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh index 6c17b46..c4cf521 100755 --- a/utils/release/test-release.sh +++ b/utils/release/test-release.sh @@ -180,6 +180,18 @@ if [ "$do_dragonegg" = "yes" ]; then fi fi +# Make sure that a required program is available +function check_program_exists() { + local program="$1" + if ! type -P $program > /dev/null 2>&1 ; then + echo "program '$1' not found !" + exit 1 + fi +} + +check_program_exists 'chrpath' +check_program_exists 'file' +check_program_exists 'objdump' # Make sure that the URLs are valid. function check_valid_urls() { @@ -328,6 +340,21 @@ function test_llvmCore() { cd $BuildDir } +# Clean RPATH. Libtool adds the build directory to the search path, which is +# not necessary --- and even harmful --- for the binary packages we release. +function clean_RPATH() { + local InstallPath="$1" + for Candidate in `find $InstallPath/{bin,lib} -type f`; do + if file $Candidate | grep ELF | egrep 'executable|shared object' > /dev/null 2>&1 ; then + rpath=`objdump -x $Candidate | grep 'RPATH' | sed -e's/^ *RPATH *//'` + if [ -n "$rpath" ]; then + newrpath=`echo $rpath | sed -e's/.*\(\$ORIGIN[^:]*\).*/\1/'` + chrpath -r $newrpath $Candidate 2>&1 > /dev/null 2>&1 + fi + fi + done +} + set -e # Exit if any command fails if [ "$do_checkout" = "yes" ]; then @@ -415,6 +442,7 @@ for Flavor in $Flavors ; do $llvmCore_phase1_objdir $llvmCore_phase1_installdir build_llvmCore 1 $Flavor \ $llvmCore_phase1_objdir + clean_RPATH $llvmCore_phase1_installdir # Test clang if [ "$do_clang" = "yes" ]; then @@ -427,6 +455,7 @@ for Flavor in $Flavors ; do $llvmCore_phase2_objdir $llvmCore_phase2_installdir build_llvmCore 2 $Flavor \ $llvmCore_phase2_objdir + clean_RPATH $llvmCore_phase2_installdir ######################################################################## # Phase 3: Build llvmCore with newly built clang from phase 2. @@ -437,6 +466,7 @@ for Flavor in $Flavors ; do $llvmCore_phase3_objdir $llvmCore_phase3_installdir build_llvmCore 3 $Flavor \ $llvmCore_phase3_objdir + clean_RPATH $llvmCore_phase3_installdir ######################################################################## # Testing: Test phase 3 @@ -478,6 +508,7 @@ for Flavor in $Flavors ; do build_llvmCore 2 $Flavor \ $llvmCore_de_phase2_objdir build_dragonegg 2 $Flavor $llvmCore_de_phase2_installdir $dragonegg_phase2_objdir + clean_RPATH $llvmCore_de_phase2_installdir ######################################################################## # Phase 3: Build llvmCore with newly built dragonegg from phase 2. @@ -489,6 +520,7 @@ for Flavor in $Flavors ; do build_llvmCore 3 $Flavor \ $llvmCore_de_phase3_objdir build_dragonegg 3 $Flavor $llvmCore_de_phase3_installdir $dragonegg_phase3_objdir + clean_RPATH $llvmCore_de_phase3_installdir ######################################################################## # Testing: Test phase 3 -- cgit v1.1 From 354362524a72b3fa43a6c09380b7ae3b2380cbba Mon Sep 17 00:00:00 2001 From: Juergen Ributzka Date: Tue, 19 Nov 2013 00:57:56 +0000 Subject: [weak vtables] Remove a bunch of weak vtables This patch removes most of the trivial cases of weak vtables by pinning them to a single object file. The memory leaks in this version have been fixed. Thanks Alexey for pointing them out. Differential Revision: http://llvm-reviews.chandlerc.com/D2068 Reviewed by Andy git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@195064 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenSchedule.cpp | 68 ++++++++++++---------- utils/TableGen/InstrInfoEmitter.cpp | 10 ++-- utils/TableGen/SetTheory.cpp | 49 +++++++++------- utils/TableGen/TGValueTypes.cpp | 17 +++++- .../googletest/include/gtest/gtest-test-part.h | 2 +- utils/unittest/googletest/include/gtest/gtest.h | 5 +- .../gtest/internal/gtest-death-test-internal.h | 4 +- .../include/gtest/internal/gtest-internal.h | 3 +- .../include/gtest/internal/gtest-param-util.h | 2 +- .../googletest/include/gtest/internal/gtest-port.h | 4 +- utils/unittest/googletest/src/gtest-death-test.cc | 6 ++ utils/unittest/googletest/src/gtest-internal-inl.h | 2 +- utils/unittest/googletest/src/gtest-port.cc | 14 +++++ utils/unittest/googletest/src/gtest.cc | 10 ++++ 14 files changed, 128 insertions(+), 68 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index 001e97d..6da3ad7 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -38,12 +38,16 @@ static void dumpIdxVec(const SmallVectorImpl &V) { // (instrs a, b, ...) Evaluate and union all arguments. Identical to AddOp. struct InstrsOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, - ArrayRef Loc) { - ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); - } + virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef Loc); }; +// Provide out-of-line definition to prevent weak vtable. +void InstrsOp::apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef Loc) { + ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); +} + // (instregex "OpcPat",...) Find all instructions matching an opcode pattern. // // TODO: Since this is a prefix match, perform a binary search over the @@ -56,34 +60,38 @@ struct InstRegexOp : public SetTheory::Operator { const CodeGenTarget &Target; InstRegexOp(const CodeGenTarget &t): Target(t) {} - void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, - ArrayRef Loc) { - SmallVector RegexList; - for (DagInit::const_arg_iterator - AI = Expr->arg_begin(), AE = Expr->arg_end(); AI != AE; ++AI) { - StringInit *SI = dyn_cast(*AI); - if (!SI) - PrintFatalError(Loc, "instregex requires pattern string: " - + Expr->getAsString()); - std::string pat = SI->getValue(); - // Implement a python-style prefix match. - if (pat[0] != '^') { - pat.insert(0, "^("); - pat.insert(pat.end(), ')'); - } - RegexList.push_back(new Regex(pat)); - } - for (CodeGenTarget::inst_iterator I = Target.inst_begin(), - E = Target.inst_end(); I != E; ++I) { - for (SmallVectorImpl::iterator - RI = RegexList.begin(), RE = RegexList.end(); RI != RE; ++RI) { - if ((*RI)->match((*I)->TheDef->getName())) - Elts.insert((*I)->TheDef); - } + virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef Loc); +}; + +// Provide out-of-line definition to prevent weak vtable. +void InstRegexOp::apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef Loc) { + SmallVector RegexList; + for (DagInit::const_arg_iterator + AI = Expr->arg_begin(), AE = Expr->arg_end(); AI != AE; ++AI) { + StringInit *SI = dyn_cast(*AI); + if (!SI) + PrintFatalError(Loc, "instregex requires pattern string: " + + Expr->getAsString()); + std::string pat = SI->getValue(); + // Implement a python-style prefix match. + if (pat[0] != '^') { + pat.insert(0, "^("); + pat.insert(pat.end(), ')'); + } + RegexList.push_back(new Regex(pat)); + } + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + for (SmallVectorImpl::iterator + RI = RegexList.begin(), RE = RegexList.end(); RI != RE; ++RI) { + if ((*RI)->match((*I)->TheDef->getName())) + Elts.insert((*I)->TheDef); } - DeleteContainerPointers(RegexList); } -}; + DeleteContainerPointers(RegexList); +} /// CodeGenModels ctor interprets machine model records and populates maps. CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index 51ce2a7..d3d9cc1 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -437,13 +437,14 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "namespace llvm {\n"; OS << "struct " << ClassName << " : public TargetInstrInfo {\n" << " explicit " << ClassName << "(int SO = -1, int DO = -1);\n" + << " virtual ~" << ClassName << "();\n" << "};\n"; OS << "} // End llvm namespace \n"; OS << "#endif // GET_INSTRINFO_HEADER\n\n"; - OS << "\n#ifdef GET_INSTRINFO_CTOR\n"; - OS << "#undef GET_INSTRINFO_CTOR\n"; + OS << "\n#ifdef GET_INSTRINFO_CTOR_DTOR\n"; + OS << "#undef GET_INSTRINFO_CTOR_DTOR\n"; OS << "namespace llvm {\n"; OS << "extern const MCInstrDesc " << TargetName << "Insts[];\n"; @@ -453,10 +454,11 @@ void InstrInfoEmitter::run(raw_ostream &OS) { << " : TargetInstrInfo(SO, DO) {\n" << " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, " - << NumberedInstructions.size() << ");\n}\n"; + << NumberedInstructions.size() << ");\n}\n" + << ClassName << "::~" << ClassName << "() {}\n"; OS << "} // End llvm namespace \n"; - OS << "#endif // GET_INSTRINFO_CTOR\n\n"; + OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n"; emitOperandNameMappings(OS, Target, NumberedInstructions); diff --git a/utils/TableGen/SetTheory.cpp b/utils/TableGen/SetTheory.cpp index 3e5c38c..ad3d7c7 100644 --- a/utils/TableGen/SetTheory.cpp +++ b/utils/TableGen/SetTheory.cpp @@ -27,14 +27,16 @@ typedef SetTheory::RecVec RecVec; // (add a, b, ...) Evaluate and union all arguments. struct AddOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); } }; // (sub Add, Sub, ...) Set difference. struct SubOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { if (Expr->arg_size() < 2) PrintFatalError(Loc, "Set difference needs at least two arguments: " + Expr->getAsString()); @@ -49,7 +51,8 @@ struct SubOp : public SetTheory::Operator { // (and S1, S2) Set intersection. struct AndOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { if (Expr->arg_size() != 2) PrintFatalError(Loc, "Set intersection requires two arguments: " + Expr->getAsString()); @@ -68,7 +71,8 @@ struct SetIntBinOp : public SetTheory::Operator { RecSet &Set, int64_t N, RecSet &Elts, ArrayRef Loc) =0; - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { if (Expr->arg_size() != 2) PrintFatalError(Loc, "Operator requires (Op Set, Int) arguments: " + Expr->getAsString()); @@ -84,9 +88,9 @@ struct SetIntBinOp : public SetTheory::Operator { // (shl S, N) Shift left, remove the first N elements. struct ShlOp : public SetIntBinOp { - void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + virtual void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (N < 0) PrintFatalError(Loc, "Positive shift required: " + Expr->getAsString()); @@ -97,9 +101,9 @@ struct ShlOp : public SetIntBinOp { // (trunc S, N) Truncate after the first N elements. struct TruncOp : public SetIntBinOp { - void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + virtual void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (N < 0) PrintFatalError(Loc, "Positive length required: " + Expr->getAsString()); @@ -115,9 +119,9 @@ struct RotOp : public SetIntBinOp { RotOp(bool Rev) : Reverse(Rev) {} - void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + virtual void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (Reverse) N = -N; // N > 0 -> rotate left, N < 0 -> rotate right. @@ -134,9 +138,9 @@ struct RotOp : public SetIntBinOp { // (decimate S, N) Pick every N'th element of S. struct DecimateOp : public SetIntBinOp { - void apply2(SetTheory &ST, DagInit *Expr, - RecSet &Set, int64_t N, - RecSet &Elts, ArrayRef Loc) { + virtual void apply2(SetTheory &ST, DagInit *Expr, + RecSet &Set, int64_t N, + RecSet &Elts, ArrayRef Loc) { if (N <= 0) PrintFatalError(Loc, "Positive stride required: " + Expr->getAsString()); @@ -147,7 +151,8 @@ struct DecimateOp : public SetIntBinOp { // (interleave S1, S2, ...) Interleave elements of the arguments. struct InterleaveOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { // Evaluate the arguments individually. SmallVector Args(Expr->getNumArgs()); unsigned MaxSize = 0; @@ -165,7 +170,8 @@ struct InterleaveOp : public SetTheory::Operator { // (sequence "Format", From, To) Generate a sequence of records by name. struct SequenceOp : public SetTheory::Operator { - void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef Loc) { + virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, + ArrayRef Loc) { int Step = 1; if (Expr->arg_size() > 4) PrintFatalError(Loc, "Bad args to (sequence \"Format\", From, To): " + @@ -232,15 +238,16 @@ struct FieldExpander : public SetTheory::Expander { FieldExpander(StringRef fn) : FieldName(fn) {} - void expand(SetTheory &ST, Record *Def, RecSet &Elts) { + virtual void expand(SetTheory &ST, Record *Def, RecSet &Elts) { ST.evaluate(Def->getValueInit(FieldName), Elts, Def->getLoc()); } }; } // end anonymous namespace -void SetTheory::Operator::anchor() { } +// Pin the vtables to this file. +void SetTheory::Operator::anchor() {} +void SetTheory::Expander::anchor() {} -void SetTheory::Expander::anchor() { } SetTheory::SetTheory() { addOperator("add", new AddOp); diff --git a/utils/TableGen/TGValueTypes.cpp b/utils/TableGen/TGValueTypes.cpp index 3ac71a4..b0bbdf9 100644 --- a/utils/TableGen/TGValueTypes.cpp +++ b/utils/TableGen/TGValueTypes.cpp @@ -35,9 +35,12 @@ public: } Type(TypeKind K) : Kind(K) {} virtual unsigned getSizeInBits() const = 0; - virtual ~Type() {} + virtual ~Type(); }; +// Provide out-of-line definition to prevent weak vtable. +Type::~Type() {} + } class ExtendedIntegerType : public Type { @@ -45,10 +48,11 @@ class ExtendedIntegerType : public Type { public: explicit ExtendedIntegerType(unsigned bits) : Type(TK_ExtendedIntegerType), BitWidth(bits) {} + virtual ~ExtendedIntegerType(); static bool classof(const Type *T) { return T->getKind() == TK_ExtendedIntegerType; } - unsigned getSizeInBits() const { + virtual unsigned getSizeInBits() const { return getBitWidth(); } unsigned getBitWidth() const { @@ -56,16 +60,20 @@ public: } }; +// Provide out-of-line definition to prevent weak vtable. +ExtendedIntegerType::~ExtendedIntegerType() {} + class ExtendedVectorType : public Type { EVT ElementType; unsigned NumElements; public: ExtendedVectorType(EVT elty, unsigned num) : Type(TK_ExtendedVectorType), ElementType(elty), NumElements(num) {} + virtual ~ExtendedVectorType(); static bool classof(const Type *T) { return T->getKind() == TK_ExtendedVectorType; } - unsigned getSizeInBits() const { + virtual unsigned getSizeInBits() const { return getNumElements() * getElementType().getSizeInBits(); } EVT getElementType() const { @@ -76,6 +84,9 @@ public: } }; +// Provide out-of-line definition to prevent weak vtable. +ExtendedVectorType::~ExtendedVectorType() {} + static std::map ExtendedIntegerTypeMap; static std::map, const Type *> diff --git a/utils/unittest/googletest/include/gtest/gtest-test-part.h b/utils/unittest/googletest/include/gtest/gtest-test-part.h index 8aeea14..98e8b84 100644 --- a/utils/unittest/googletest/include/gtest/gtest-test-part.h +++ b/utils/unittest/googletest/include/gtest/gtest-test-part.h @@ -142,7 +142,7 @@ class GTEST_API_ TestPartResultArray { // This interface knows how to report a test part result. class TestPartResultReporterInterface { public: - virtual ~TestPartResultReporterInterface() {} + virtual ~TestPartResultReporterInterface(); virtual void ReportTestPartResult(const TestPartResult& result) = 0; }; diff --git a/utils/unittest/googletest/include/gtest/gtest.h b/utils/unittest/googletest/include/gtest/gtest.h index 1734c44..07ed92b 100644 --- a/utils/unittest/googletest/include/gtest/gtest.h +++ b/utils/unittest/googletest/include/gtest/gtest.h @@ -910,7 +910,7 @@ class GTEST_API_ TestCase { class Environment { public: // The d'tor is virtual as we need to subclass Environment. - virtual ~Environment() {} + virtual ~Environment(); // Override this to define how to set up the environment. virtual void SetUp() {} @@ -928,7 +928,7 @@ class Environment { // the order the corresponding events are fired. class TestEventListener { public: - virtual ~TestEventListener() {} + virtual ~TestEventListener(); // Fired before any test activity starts. virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; @@ -980,6 +980,7 @@ class TestEventListener { // comments about each method please see the definition of TestEventListener // above. class EmptyTestEventListener : public TestEventListener { + virtual void anchor(); public: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h index 7bac2bd..8d53c45 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h @@ -79,7 +79,7 @@ class GTEST_API_ DeathTest { static bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test); DeathTest(); - virtual ~DeathTest() { } + virtual ~DeathTest(); // A helper class that aborts a death test when it's deleted. class ReturnSentinel { @@ -139,7 +139,7 @@ class GTEST_API_ DeathTest { // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: - virtual ~DeathTestFactory() { } + virtual ~DeathTestFactory(); virtual bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) = 0; }; diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h index a94bf28..63f72ac 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h @@ -105,6 +105,7 @@ #if !GTEST_NO_LLVM_RAW_OSTREAM namespace llvm { class convertible_fwd_ostream : public std::ostream { + virtual void anchor(); raw_os_ostream ros_; public: @@ -536,7 +537,7 @@ GTEST_API_ TypeId GetTestTypeId(); // of a Test object. class TestFactoryBase { public: - virtual ~TestFactoryBase() {} + virtual ~TestFactoryBase(); // Creates a test instance to run. The instance is both created and destroyed // within TestInfoImpl::Run() diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h index 0ef9718..3bb2ffb 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h @@ -414,7 +414,7 @@ class TestMetaFactory // and calls RegisterTests() on each of them when asked. class ParameterizedTestCaseInfoBase { public: - virtual ~ParameterizedTestCaseInfoBase() {} + virtual ~ParameterizedTestCaseInfoBase(); // Base part of test case name for display purposes. virtual const string& GetTestCaseName() const = 0; diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-port.h b/utils/unittest/googletest/include/gtest/internal/gtest-port.h index 58f6caf..32fd9c6 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-port.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-port.h @@ -1116,7 +1116,7 @@ class Notification { // problem. class ThreadWithParamBase { public: - virtual ~ThreadWithParamBase() {} + virtual ~ThreadWithParamBase(); virtual void Run() = 0; }; @@ -1290,7 +1290,7 @@ typedef GTestMutexLock MutexLock; // ThreadLocalValueHolderBase. class ThreadLocalValueHolderBase { public: - virtual ~ThreadLocalValueHolderBase() {} + virtual ~ThreadLocalValueHolderBase(); }; // Called by pthread to delete thread-local data stored by diff --git a/utils/unittest/googletest/src/gtest-death-test.cc b/utils/unittest/googletest/src/gtest-death-test.cc index 82453f2..314dba2 100644 --- a/utils/unittest/googletest/src/gtest-death-test.cc +++ b/utils/unittest/googletest/src/gtest-death-test.cc @@ -300,6 +300,9 @@ DeathTest::DeathTest() { } } +// Pin the vtable to this file. +DeathTest::~DeathTest() {} + // Creates and returns a death test by dispatching to the current // death test factory. bool DeathTest::Create(const char* statement, const RE* regex, @@ -1091,6 +1094,9 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, return true; } +// Pin the vtable to this file. +DeathTestFactory::~DeathTestFactory() {} + // Splits a given string on a given delimiter, populating a given // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // ::std::string, so we can use it here. diff --git a/utils/unittest/googletest/src/gtest-internal-inl.h b/utils/unittest/googletest/src/gtest-internal-inl.h index 6554cfc..1bae630 100644 --- a/utils/unittest/googletest/src/gtest-internal-inl.h +++ b/utils/unittest/googletest/src/gtest-internal-inl.h @@ -408,7 +408,7 @@ GTEST_API_ FilePath GetCurrentExecutableName(); class OsStackTraceGetterInterface { public: OsStackTraceGetterInterface() {} - virtual ~OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface(); // Returns the current OS stack trace as a String. Parameters: // diff --git a/utils/unittest/googletest/src/gtest-port.cc b/utils/unittest/googletest/src/gtest-port.cc index 7459562..94fc57f 100644 --- a/utils/unittest/googletest/src/gtest-port.cc +++ b/utils/unittest/googletest/src/gtest-port.cc @@ -746,5 +746,19 @@ const char* StringFromGTestEnv(const char* flag, const char* default_value) { return value == NULL ? default_value : value; } +// Pin the vtables to this file. +#if GTEST_HAS_PTHREAD +ThreadWithParamBase::~ThreadWithParamBase() {} +ThreadLocalValueHolderBase::~ThreadLocalValueHolderBase() {} +#endif +TestFactoryBase::~TestFactoryBase() {} + } // namespace internal } // namespace testing + +// Pin the vtable to this file. +#if !GTEST_NO_LLVM_RAW_OSTREAM +namespace llvm { +void convertible_fwd_ostream::anchor() {} +} +#endif diff --git a/utils/unittest/googletest/src/gtest.cc b/utils/unittest/googletest/src/gtest.cc index 9891928..bf850c6 100644 --- a/utils/unittest/googletest/src/gtest.cc +++ b/utils/unittest/googletest/src/gtest.cc @@ -4863,4 +4863,14 @@ void InitGoogleTest(int* argc, wchar_t** argv) { internal::InitGoogleTestImpl(argc, argv); } +// Pin the vtables to this file. +Environment::~Environment() {} +TestPartResultReporterInterface::~TestPartResultReporterInterface() {} +TestEventListener::~TestEventListener() {} +void EmptyTestEventListener::anchor() {} +namespace internal { +OsStackTraceGetterInterface::~OsStackTraceGetterInterface() {} +ParameterizedTestCaseInfoBase::~ParameterizedTestCaseInfoBase() {} +} + } // namespace testing -- cgit v1.1 From 9d7c776d32c8a4d64b37a91c2d627629cf1498ef Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 19 Nov 2013 06:35:35 +0000 Subject: Merging r195092: ------------------------------------------------------------------------ r195092 | ributzka | 2013-11-18 19:08:35 -0800 (Mon, 18 Nov 2013) | 5 lines [weak vtables] Place class definitions into anonymous namespaces to prevent weak vtables. This patch places class definitions in implementation files into anonymous namespaces to prevent weak vtables. This eliminates the need of providing an out-of-line definition to pin the vtable explicitly to the file. ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_34@195111 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CodeGenSchedule.cpp | 68 +++++++++++++++++--------------------- utils/TableGen/TGValueTypes.cpp | 10 ++---- 2 files changed, 33 insertions(+), 45 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index 6da3ad7..dd06433 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -36,17 +36,14 @@ static void dumpIdxVec(const SmallVectorImpl &V) { } #endif +namespace { // (instrs a, b, ...) Evaluate and union all arguments. Identical to AddOp. struct InstrsOp : public SetTheory::Operator { virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, - ArrayRef Loc); -}; - -// Provide out-of-line definition to prevent weak vtable. -void InstrsOp::apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, ArrayRef Loc) { - ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); -} + ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc); + } +}; // (instregex "OpcPat",...) Find all instructions matching an opcode pattern. // @@ -60,38 +57,35 @@ struct InstRegexOp : public SetTheory::Operator { const CodeGenTarget &Target; InstRegexOp(const CodeGenTarget &t): Target(t) {} - virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, - ArrayRef Loc); -}; - -// Provide out-of-line definition to prevent weak vtable. -void InstRegexOp::apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, - ArrayRef Loc) { - SmallVector RegexList; - for (DagInit::const_arg_iterator - AI = Expr->arg_begin(), AE = Expr->arg_end(); AI != AE; ++AI) { - StringInit *SI = dyn_cast(*AI); - if (!SI) - PrintFatalError(Loc, "instregex requires pattern string: " - + Expr->getAsString()); - std::string pat = SI->getValue(); - // Implement a python-style prefix match. - if (pat[0] != '^') { - pat.insert(0, "^("); - pat.insert(pat.end(), ')'); - } - RegexList.push_back(new Regex(pat)); - } - for (CodeGenTarget::inst_iterator I = Target.inst_begin(), - E = Target.inst_end(); I != E; ++I) { - for (SmallVectorImpl::iterator - RI = RegexList.begin(), RE = RegexList.end(); RI != RE; ++RI) { - if ((*RI)->match((*I)->TheDef->getName())) - Elts.insert((*I)->TheDef); + void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, + ArrayRef Loc) { + SmallVector RegexList; + for (DagInit::const_arg_iterator + AI = Expr->arg_begin(), AE = Expr->arg_end(); AI != AE; ++AI) { + StringInit *SI = dyn_cast(*AI); + if (!SI) + PrintFatalError(Loc, "instregex requires pattern string: " + + Expr->getAsString()); + std::string pat = SI->getValue(); + // Implement a python-style prefix match. + if (pat[0] != '^') { + pat.insert(0, "^("); + pat.insert(pat.end(), ')'); + } + RegexList.push_back(new Regex(pat)); + } + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + for (SmallVectorImpl::iterator + RI = RegexList.begin(), RE = RegexList.end(); RI != RE; ++RI) { + if ((*RI)->match((*I)->TheDef->getName())) + Elts.insert((*I)->TheDef); + } } + DeleteContainerPointers(RegexList); } - DeleteContainerPointers(RegexList); -} +}; +} // end anonymous namespace /// CodeGenModels ctor interprets machine model records and populates maps. CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, diff --git a/utils/TableGen/TGValueTypes.cpp b/utils/TableGen/TGValueTypes.cpp index b0bbdf9..f4893f5 100644 --- a/utils/TableGen/TGValueTypes.cpp +++ b/utils/TableGen/TGValueTypes.cpp @@ -43,12 +43,12 @@ Type::~Type() {} } +namespace { class ExtendedIntegerType : public Type { unsigned BitWidth; public: explicit ExtendedIntegerType(unsigned bits) : Type(TK_ExtendedIntegerType), BitWidth(bits) {} - virtual ~ExtendedIntegerType(); static bool classof(const Type *T) { return T->getKind() == TK_ExtendedIntegerType; } @@ -60,16 +60,12 @@ public: } }; -// Provide out-of-line definition to prevent weak vtable. -ExtendedIntegerType::~ExtendedIntegerType() {} - class ExtendedVectorType : public Type { EVT ElementType; unsigned NumElements; public: ExtendedVectorType(EVT elty, unsigned num) : Type(TK_ExtendedVectorType), ElementType(elty), NumElements(num) {} - virtual ~ExtendedVectorType(); static bool classof(const Type *T) { return T->getKind() == TK_ExtendedVectorType; } @@ -83,9 +79,7 @@ public: return NumElements; } }; - -// Provide out-of-line definition to prevent weak vtable. -ExtendedVectorType::~ExtendedVectorType() {} +} // end anonymous namespace static std::map ExtendedIntegerTypeMap; -- cgit v1.1 From 3c031bdef960479def2e01f28be506dcbdeb8758 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 20 Nov 2013 04:56:36 +0000 Subject: Merging r195193: ------------------------------------------------------------------------ r195193 | void | 2013-11-19 20:55:20 -0800 (Tue, 19 Nov 2013) | 5 lines Add -triple option. The -triple option is used to create a named tarball of the release binaries. Also disable the RPATH modifications on Mac OS X. It's not needed. ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_34@195194 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/release/test-release.sh | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh index c4cf521..cdb0b60 100755 --- a/utils/release/test-release.sh +++ b/utils/release/test-release.sh @@ -26,6 +26,7 @@ Base_url="http://llvm.org/svn/llvm-project" Release="" Release_no_dot="" RC="" +Triple="" do_checkout="yes" do_ada="no" do_clang="yes" @@ -44,6 +45,7 @@ function usage() { echo " -release X.Y The release number to test." echo " -rc NUM The pre-release candidate number." echo " -final The final release candidate." + echo " -triple TRIPLE The target triple for this machine." echo " -j NUM Number of compile jobs to run. [default: 3]" echo " -build-dir DIR Directory to perform testing in. [default: pwd]" echo " -no-checkout Don't checkout the sources from SVN." @@ -72,6 +74,10 @@ while [ $# -gt 0 ]; do -final | --final ) RC=final ;; + -triple | --triple ) + shift + Triple="$1" + ;; -j* ) NumJobs="`echo $1 | sed -e 's,-j\([0-9]*\),\1,g'`" if [ -z "$NumJobs" ]; then @@ -135,6 +141,10 @@ if [ -z "$RC" ]; then echo "error: no release candidate number specified" exit 1 fi +if [ -z "$Triple" ]; then + echo "error: no target triple specified" + exit 1 +fi # Figure out how many make processes to run. if [ -z "$NumJobs" ]; then @@ -159,6 +169,13 @@ cd $BuildDir LogDir=$BuildDir/logs mkdir -p $LogDir +# Final package name. +Package=clang+llvm-$Release +if [ $RC != "final" ]; then + Package=$Package-$RC +fi +Package=$Package-$Triple + # Find compilers. if [ "$do_dragonegg" = "yes" ]; then gcc_compiler="$GCC" @@ -189,9 +206,11 @@ function check_program_exists() { fi } -check_program_exists 'chrpath' -check_program_exists 'file' -check_program_exists 'objdump' +if [ `uname -s` != "Darwin" ]; then + check_program_exists 'chrpath' + check_program_exists 'file' + check_program_exists 'objdump' +fi # Make sure that the URLs are valid. function check_valid_urls() { @@ -343,6 +362,9 @@ function test_llvmCore() { # Clean RPATH. Libtool adds the build directory to the search path, which is # not necessary --- and even harmful --- for the binary packages we release. function clean_RPATH() { + if [ `uname -s` = "Darwin" ]; then + return + fi local InstallPath="$1" for Candidate in `find $InstallPath/{bin,lib} -type f`; do if file $Candidate | grep ELF | egrep 'executable|shared object' > /dev/null 2>&1 ; then @@ -355,6 +377,16 @@ function clean_RPATH() { done } +# Create a package of the release binaries. +function package_release() { + cwd=`pwd` + cd $BuildDir/Phase3/Release + mv llvmCore-$Release-$RC.install $Package + tar cfz $BuildDir/$Package.tar.gz $Package + mv $Package llvmCore-$Release-$RC.install + cd $cwd +} + set -e # Exit if any command fails if [ "$do_checkout" = "yes" ]; then @@ -550,9 +582,12 @@ for Flavor in $Flavors ; do done ) 2>&1 | tee $LogDir/testing.$Release-$RC.log +package_release + set +e # Woo hoo! echo "### Testing Finished ###" +echo "### Package: $Package.tar.gz" echo "### Logs: $LogDir" exit 0 -- cgit v1.1 From d20d4e58d91ce99a78b71af070bee327896b2366 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 20 Nov 2013 04:59:22 +0000 Subject: Merging r195102: ------------------------------------------------------------------------ r195102 | void | 2013-11-18 20:58:46 -0800 (Mon, 18 Nov 2013) | 1 line Add lld to projects to tag. ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_34@195195 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/release/tag.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/release/tag.sh b/utils/release/tag.sh index 5e3f69a..6c5039d 100755 --- a/utils/release/tag.sh +++ b/utils/release/tag.sh @@ -17,7 +17,7 @@ set -e release="" rc="" rebranch="no" -projects="llvm cfe dragonegg test-suite compiler-rt libcxx clang-tools-extra polly lldb" +projects="llvm cfe dragonegg test-suite compiler-rt libcxx clang-tools-extra polly lldb lld" base_url="https://llvm.org/svn/llvm-project" -- cgit v1.1 From d49c8fca79093f3eaaae3ee03ada65ef258f80b8 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 24 Nov 2013 05:30:06 +0000 Subject: Merging r195567: ------------------------------------------------------------------------ r195567 | void | 2013-11-23 21:29:35 -0800 (Sat, 23 Nov 2013) | 1 line Default to a better compression algorithm. ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_34@195568 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/release/test-release.sh | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh index cdb0b60..91dac4c 100755 --- a/utils/release/test-release.sh +++ b/utils/release/test-release.sh @@ -27,6 +27,7 @@ Release="" Release_no_dot="" RC="" Triple="" +use_gzip="no" do_checkout="yes" do_ada="no" do_clang="yes" @@ -58,6 +59,7 @@ function usage() { echo " -test-debug Test the debug build. [default: no]" echo " -test-asserts Test with asserts on. [default: no]" echo " -no-compare-files Don't test that phase 2 and 3 files are identical." + echo " -use-gzip Use gzip instead of xz." } while [ $# -gt 0 ]; do @@ -119,6 +121,9 @@ while [ $# -gt 0 ]; do -no-compare-files | --no-compare-files ) do_compare="no" ;; + -use-gzip | --use-gzip ) + use_gzip="yes" + ;; -help | --help | -h | --h | -\? ) usage exit 0 @@ -382,7 +387,11 @@ function package_release() { cwd=`pwd` cd $BuildDir/Phase3/Release mv llvmCore-$Release-$RC.install $Package - tar cfz $BuildDir/$Package.tar.gz $Package + if [ "$use_gzip" = "yes" ]; then + tar cfz $BuildDir/$Package.tar.gz $Package + else + tar cfJ $BuildDir/$Package.tar.xz $Package + fi mv $Package llvmCore-$Release-$RC.install cd $cwd } @@ -588,6 +597,10 @@ set +e # Woo hoo! echo "### Testing Finished ###" -echo "### Package: $Package.tar.gz" +if [ "$use_gzip" = "yes" ]; then + echo "### Package: $Package.tar.gz" +else + echo "### Package: $Package.tar.xz" +fi echo "### Logs: $LogDir" exit 0 -- cgit v1.1