1from __future__ import absolute_import
2import os
3import re
4import operator
5
6import lit.Test
7import lit.TestRunner
8import lit.util
9from lit.formats.base import TestFormat
10
11
12class LLDBTest(TestFormat):
13    def __init__(self, dotest_cmd):
14        self.dotest_cmd = dotest_cmd
15
16    def getTestsInDirectory(self, testSuite, path_in_suite, litConfig,
17                            localConfig):
18        source_path = testSuite.getSourcePath(path_in_suite)
19        for filename in os.listdir(source_path):
20            # Ignore dot files and excluded tests.
21            if (filename.startswith('.') or filename in localConfig.excludes):
22                continue
23
24            # Ignore files that don't start with 'Test'.
25            if not filename.startswith('Test'):
26                continue
27
28            filepath = os.path.join(source_path, filename)
29            if not os.path.isdir(filepath):
30                base, ext = os.path.splitext(filename)
31                if ext in localConfig.suffixes:
32                    yield lit.Test.Test(testSuite, path_in_suite +
33                                        (filename, ), localConfig)
34
35    def execute(self, test, litConfig):
36        if litConfig.noExecute:
37            return lit.Test.PASS, ''
38
39        if not getattr(test.config, 'lldb_enable_python', False):
40            return (lit.Test.UNSUPPORTED, 'Python module disabled')
41
42        if test.config.unsupported:
43            return (lit.Test.UNSUPPORTED, 'Test is unsupported')
44
45        testPath, testFile = os.path.split(test.getSourcePath())
46
47        # The Python used to run lit can be different from the Python LLDB was
48        # build with.
49        executable = test.config.python_executable
50
51        isLuaTest = testFile == test.config.lua_test_entry
52
53        # On Windows, the system does not always correctly interpret
54        # shebang lines.  To make sure we can execute the tests, add
55        # python exe as the first parameter of the command.
56        cmd = [executable] + self.dotest_cmd + [testPath, '-p', testFile]
57
58        if isLuaTest:
59            luaExecutable = test.config.lua_executable
60            cmd.extend(['--env', 'LUA_EXECUTABLE=%s' % luaExecutable])
61
62        timeoutInfo = None
63        try:
64            out, err, exitCode = lit.util.executeCommand(
65                cmd,
66                env=test.config.environment,
67                timeout=litConfig.maxIndividualTestTime)
68        except lit.util.ExecuteCommandTimeoutException as e:
69            out = e.out
70            err = e.err
71            exitCode = e.exitCode
72            timeoutInfo = 'Reached timeout of {} seconds'.format(
73                litConfig.maxIndividualTestTime)
74
75        output = """Script:\n--\n%s\n--\nExit Code: %d\n""" % (
76            ' '.join(cmd), exitCode)
77        if timeoutInfo is not None:
78            output += """Timeout: %s\n""" % (timeoutInfo,)
79        output += "\n"
80
81        if out:
82            output += """Command Output (stdout):\n--\n%s\n--\n""" % (out,)
83        if err:
84            output += """Command Output (stderr):\n--\n%s\n--\n""" % (err,)
85
86        if timeoutInfo:
87            return lit.Test.TIMEOUT, output
88
89        # Parse the dotest output from stderr.
90        result_regex = r"\((\d+) passes, (\d+) failures, (\d+) errors, (\d+) skipped, (\d+) expected failures, (\d+) unexpected successes\)"
91        results = re.search(result_regex, err)
92
93        # If parsing fails mark this test as unresolved.
94        if not results:
95            return lit.Test.UNRESOLVED, output
96
97        passes = int(results.group(1))
98        failures = int(results.group(2))
99        errors = int(results.group(3))
100        skipped = int(results.group(4))
101        expected_failures = int(results.group(5))
102        unexpected_successes = int(results.group(6))
103
104        if exitCode:
105            # Mark this test as FAIL if at least one test failed.
106            if failures > 0:
107                return lit.Test.FAIL, output
108            lit_results = [(failures, lit.Test.FAIL),
109                           (errors, lit.Test.UNRESOLVED),
110                           (unexpected_successes, lit.Test.XPASS)]
111        else:
112            # Mark this test as PASS if at least one test passed.
113            if passes > 0:
114                return lit.Test.PASS, output
115            lit_results = [(passes, lit.Test.PASS),
116                           (skipped, lit.Test.UNSUPPORTED),
117                           (expected_failures, lit.Test.XFAIL)]
118
119        # Return the lit result code with the maximum occurrence. Only look at
120        # the first element and rely on the original order to break ties.
121        return max(lit_results, key=operator.itemgetter(0))[1], output
122