blob: ea10051d8506f52dbe4713ac2788f345c55c8856 [file] [log] [blame]
Laszlo Nagybc687582016-01-12 22:38:41 +00001# -*- 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
7import libscanbuild.runner as sut
8from . import fixtures
9import unittest
10import re
11import os
12import os.path
13
14
15def 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
33class 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
55class 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
90class 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
138class 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([])
183def method_without_expecteds(opts):
184 return 0
185
186
187@sut.require(['this', 'that'])
188def method_with_expecteds(opts):
189 return 0
190
191
192@sut.require([])
193def method_exception_from_inside(opts):
194 raise Exception('here is one')
195
196
197class 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())