Laszlo Nagy | bc68758 | 2016-01-12 22:38:41 +0000 | [diff] [blame^] | 1 | # -*- coding: utf-8 -*- |
| 2 | # The LLVM Compiler Infrastructure |
| 3 | # |
| 4 | # This file is distributed under the University of Illinois Open Source |
| 5 | # License. See LICENSE.TXT for details. |
| 6 | |
| 7 | import libscanbuild.runner as sut |
| 8 | from . import fixtures |
| 9 | import unittest |
| 10 | import re |
| 11 | import os |
| 12 | import os.path |
| 13 | |
| 14 | |
| 15 | def run_analyzer(content, opts): |
| 16 | with fixtures.TempDir() as tmpdir: |
| 17 | filename = os.path.join(tmpdir, 'test.cpp') |
| 18 | with open(filename, 'w') as handle: |
| 19 | handle.write(content) |
| 20 | |
| 21 | opts.update({ |
| 22 | 'directory': os.getcwd(), |
| 23 | 'clang': 'clang', |
| 24 | 'file': filename, |
| 25 | 'language': 'c++', |
| 26 | 'analyze': ['--analyze', '-x', 'c++', filename], |
| 27 | 'output': ['-o', tmpdir]}) |
| 28 | spy = fixtures.Spy() |
| 29 | result = sut.run_analyzer(opts, spy.call) |
| 30 | return (result, spy.arg) |
| 31 | |
| 32 | |
| 33 | class RunAnalyzerTest(unittest.TestCase): |
| 34 | |
| 35 | def test_run_analyzer(self): |
| 36 | content = "int div(int n, int d) { return n / d; }" |
| 37 | (result, fwds) = run_analyzer(content, dict()) |
| 38 | self.assertEqual(None, fwds) |
| 39 | self.assertEqual(0, result['exit_code']) |
| 40 | |
| 41 | def test_run_analyzer_crash(self): |
| 42 | content = "int div(int n, int d) { return n / d }" |
| 43 | (result, fwds) = run_analyzer(content, dict()) |
| 44 | self.assertEqual(None, fwds) |
| 45 | self.assertEqual(1, result['exit_code']) |
| 46 | |
| 47 | def test_run_analyzer_crash_and_forwarded(self): |
| 48 | content = "int div(int n, int d) { return n / d }" |
| 49 | (_, fwds) = run_analyzer(content, {'output_failures': True}) |
| 50 | self.assertEqual('crash', fwds['error_type']) |
| 51 | self.assertEqual(1, fwds['exit_code']) |
| 52 | self.assertTrue(len(fwds['error_output']) > 0) |
| 53 | |
| 54 | |
| 55 | class SetAnalyzerOutputTest(fixtures.TestCase): |
| 56 | |
| 57 | def test_not_defined(self): |
| 58 | with fixtures.TempDir() as tmpdir: |
| 59 | opts = {'output_dir': tmpdir} |
| 60 | spy = fixtures.Spy() |
| 61 | sut.set_analyzer_output(opts, spy.call) |
| 62 | self.assertTrue(os.path.exists(spy.arg['output'][1])) |
| 63 | self.assertTrue(os.path.isdir(spy.arg['output'][1])) |
| 64 | |
| 65 | def test_html(self): |
| 66 | with fixtures.TempDir() as tmpdir: |
| 67 | opts = {'output_dir': tmpdir, 'output_format': 'html'} |
| 68 | spy = fixtures.Spy() |
| 69 | sut.set_analyzer_output(opts, spy.call) |
| 70 | self.assertTrue(os.path.exists(spy.arg['output'][1])) |
| 71 | self.assertTrue(os.path.isdir(spy.arg['output'][1])) |
| 72 | |
| 73 | def test_plist_html(self): |
| 74 | with fixtures.TempDir() as tmpdir: |
| 75 | opts = {'output_dir': tmpdir, 'output_format': 'plist-html'} |
| 76 | spy = fixtures.Spy() |
| 77 | sut.set_analyzer_output(opts, spy.call) |
| 78 | self.assertTrue(os.path.exists(spy.arg['output'][1])) |
| 79 | self.assertTrue(os.path.isfile(spy.arg['output'][1])) |
| 80 | |
| 81 | def test_plist(self): |
| 82 | with fixtures.TempDir() as tmpdir: |
| 83 | opts = {'output_dir': tmpdir, 'output_format': 'plist'} |
| 84 | spy = fixtures.Spy() |
| 85 | sut.set_analyzer_output(opts, spy.call) |
| 86 | self.assertTrue(os.path.exists(spy.arg['output'][1])) |
| 87 | self.assertTrue(os.path.isfile(spy.arg['output'][1])) |
| 88 | |
| 89 | |
| 90 | class ReportFailureTest(fixtures.TestCase): |
| 91 | |
| 92 | def assertUnderFailures(self, path): |
| 93 | self.assertEqual('failures', os.path.basename(os.path.dirname(path))) |
| 94 | |
| 95 | def test_report_failure_create_files(self): |
| 96 | with fixtures.TempDir() as tmpdir: |
| 97 | # create input file |
| 98 | filename = os.path.join(tmpdir, 'test.c') |
| 99 | with open(filename, 'w') as handle: |
| 100 | handle.write('int main() { return 0') |
| 101 | uname_msg = ' '.join(os.uname()) + os.linesep |
| 102 | error_msg = 'this is my error output' |
| 103 | # execute test |
| 104 | opts = {'directory': os.getcwd(), |
| 105 | 'clang': 'clang', |
| 106 | 'file': filename, |
| 107 | 'report': ['-fsyntax-only', '-E', filename], |
| 108 | 'language': 'c', |
| 109 | 'output_dir': tmpdir, |
| 110 | 'error_type': 'other_error', |
| 111 | 'error_output': error_msg, |
| 112 | 'exit_code': 13} |
| 113 | sut.report_failure(opts) |
| 114 | # verify the result |
| 115 | result = dict() |
| 116 | pp_file = None |
| 117 | for root, _, files in os.walk(tmpdir): |
| 118 | keys = [os.path.join(root, name) for name in files] |
| 119 | for key in keys: |
| 120 | with open(key, 'r') as handle: |
| 121 | result[key] = handle.readlines() |
| 122 | if re.match(r'^(.*/)+clang(.*)\.i$', key): |
| 123 | pp_file = key |
| 124 | |
| 125 | # prepocessor file generated |
| 126 | self.assertUnderFailures(pp_file) |
| 127 | # info file generated and content dumped |
| 128 | info_file = pp_file + '.info.txt' |
| 129 | self.assertIn(info_file, result) |
| 130 | self.assertEqual('Other Error\n', result[info_file][1]) |
| 131 | self.assertEqual(uname_msg, result[info_file][3]) |
| 132 | # error file generated and content dumped |
| 133 | error_file = pp_file + '.stderr.txt' |
| 134 | self.assertIn(error_file, result) |
| 135 | self.assertEqual([error_msg], result[error_file]) |
| 136 | |
| 137 | |
| 138 | class AnalyzerTest(unittest.TestCase): |
| 139 | |
| 140 | def test_set_language(self): |
| 141 | def test(expected, input): |
| 142 | spy = fixtures.Spy() |
| 143 | self.assertEqual(spy.success, sut.language_check(input, spy.call)) |
| 144 | self.assertEqual(expected, spy.arg['language']) |
| 145 | |
| 146 | l = 'language' |
| 147 | f = 'file' |
| 148 | i = 'c++' |
| 149 | test('c', {f: 'file.c', l: 'c', i: False}) |
| 150 | test('c++', {f: 'file.c', l: 'c++', i: False}) |
| 151 | test('c++', {f: 'file.c', i: True}) |
| 152 | test('c', {f: 'file.c', i: False}) |
| 153 | test('c++', {f: 'file.cxx', i: False}) |
| 154 | test('c-cpp-output', {f: 'file.i', i: False}) |
| 155 | test('c++-cpp-output', {f: 'file.i', i: True}) |
| 156 | test('c-cpp-output', {f: 'f.i', l: 'c-cpp-output', i: True}) |
| 157 | |
| 158 | def test_arch_loop(self): |
| 159 | def test(input): |
| 160 | spy = fixtures.Spy() |
| 161 | sut.arch_check(input, spy.call) |
| 162 | return spy.arg |
| 163 | |
| 164 | input = {'key': 'value'} |
| 165 | self.assertEqual(input, test(input)) |
| 166 | |
| 167 | input = {'archs_seen': ['i386']} |
| 168 | self.assertEqual({'arch': 'i386'}, test(input)) |
| 169 | |
| 170 | input = {'archs_seen': ['ppc']} |
| 171 | self.assertEqual(None, test(input)) |
| 172 | |
| 173 | input = {'archs_seen': ['i386', 'ppc']} |
| 174 | self.assertEqual({'arch': 'i386'}, test(input)) |
| 175 | |
| 176 | input = {'archs_seen': ['i386', 'sparc']} |
| 177 | result = test(input) |
| 178 | self.assertTrue(result == {'arch': 'i386'} or |
| 179 | result == {'arch': 'sparc'}) |
| 180 | |
| 181 | |
| 182 | @sut.require([]) |
| 183 | def method_without_expecteds(opts): |
| 184 | return 0 |
| 185 | |
| 186 | |
| 187 | @sut.require(['this', 'that']) |
| 188 | def method_with_expecteds(opts): |
| 189 | return 0 |
| 190 | |
| 191 | |
| 192 | @sut.require([]) |
| 193 | def method_exception_from_inside(opts): |
| 194 | raise Exception('here is one') |
| 195 | |
| 196 | |
| 197 | class RequireDecoratorTest(unittest.TestCase): |
| 198 | |
| 199 | def test_method_without_expecteds(self): |
| 200 | self.assertEqual(method_without_expecteds(dict()), 0) |
| 201 | self.assertEqual(method_without_expecteds({}), 0) |
| 202 | self.assertEqual(method_without_expecteds({'this': 2}), 0) |
| 203 | self.assertEqual(method_without_expecteds({'that': 3}), 0) |
| 204 | |
| 205 | def test_method_with_expecteds(self): |
| 206 | self.assertRaises(KeyError, method_with_expecteds, dict()) |
| 207 | self.assertRaises(KeyError, method_with_expecteds, {}) |
| 208 | self.assertRaises(KeyError, method_with_expecteds, {'this': 2}) |
| 209 | self.assertRaises(KeyError, method_with_expecteds, {'that': 3}) |
| 210 | self.assertEqual(method_with_expecteds({'this': 0, 'that': 3}), 0) |
| 211 | |
| 212 | def test_method_exception_not_caught(self): |
| 213 | self.assertRaises(Exception, method_exception_from_inside, dict()) |