summaryrefslogtreecommitdiff
path: root/utils/lit/lit/formats/googletest.py
blob: 29a92c4e960b6ce1a90bf56e5a6abf22e8e729a8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
from __future__ import absolute_import
import os
import subprocess
import sys

import lit.Test
import lit.TestRunner
import lit.util
from .base import TestFormat

kIsWindows = sys.platform in ['win32', 'cygwin']

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)

        # 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)
            if kIsWindows:
              lines = lines.replace('\r', '')
            lines = lines.split('\n')
        except Exception as exc:
            out = exc.output if isinstance(exc, subprocess.CalledProcessError) else ''
            litConfig.warning("unable to discover google-tests in %r: %s. Process output: %s"
                              % (path, sys.exc_info()[1], out))
            raise StopIteration

        nested_tests = []
        for ln in lines:
            # The test name list includes trailing comments beginning with
            # a '#' on some lines, so skip those. We don't support test names
            # that use escaping to embed '#' into their name as the names come
            # from C++ class and method names where such things are hard and
            # uninteresting to support.
            ln = ln.split('#', 1)[0].rstrip()
            if not ln.lstrip():
                continue

            if 'Running main() from gtest_main.cc' in ln:
                # Upstream googletest prints this to stdout prior to running
                # tests. LLVM removed that print statement in r61540, but we
                # handle it here in case upstream googletest is being used.
                continue

            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)
            elif any([name.startswith('DISABLED_')
                      for name in nested_tests + [ln]]):
                # Gtest will internally skip these tests. No need to launch a
                # child process for it.
                continue
            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, file_path=execpath)

    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 = namePrefix + '/' + testName

        cmd = [testPath, '--gtest_filter=' + testName]
        if litConfig.useValgrind:
            cmd = litConfig.valgrindArgs + cmd

        if litConfig.noExecute:
            return lit.Test.PASS, ''

        try:
            out, err, exitCode = lit.util.executeCommand(
                cmd, env=test.config.environment,
                timeout=litConfig.maxIndividualTestTime)
        except lit.util.ExecuteCommandTimeoutException:
            return (lit.Test.TIMEOUT,
                    'Reached timeout of {} seconds'.format(
                        litConfig.maxIndividualTestTime)
                   )

        if exitCode:
            return lit.Test.FAIL, out + err

        passing_test_line = '[  PASSED  ] 1 test.'
        if passing_test_line not in out:
            msg = ('Unable to find %r in gtest output:\n\n%s%s' %
                   (passing_test_line, out, err))
            return lit.Test.UNRESOLVED, msg

        return lit.Test.PASS,''