blob: 4b51e6528495a529d19ff19876f9ebd22dfd7df4 [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
Laszlo Nagy8bd63e52016-04-19 12:03:03 +00007import libear
Laszlo Nagybc687582016-01-12 22:38:41 +00008import libscanbuild.runner as sut
Laszlo Nagybc687582016-01-12 22:38:41 +00009import unittest
10import re
11import os
12import os.path
13
14
Laszlo Nagy8bd63e52016-04-19 12:03:03 +000015class FilteringFlagsTest(unittest.TestCase):
Laszlo Nagybc687582016-01-12 22:38:41 +000016
Laszlo Nagy8bd63e52016-04-19 12:03:03 +000017 def test_language_captured(self):
18 def test(flags):
19 cmd = ['clang', '-c', 'source.c'] + flags
20 opts = sut.classify_parameters(cmd)
21 return opts['language']
22
23 self.assertEqual(None, test([]))
24 self.assertEqual('c', test(['-x', 'c']))
25 self.assertEqual('cpp', test(['-x', 'cpp']))
26
27 def test_arch(self):
28 def test(flags):
29 cmd = ['clang', '-c', 'source.c'] + flags
30 opts = sut.classify_parameters(cmd)
31 return opts['arch_list']
32
33 self.assertEqual([], test([]))
34 self.assertEqual(['mips'], test(['-arch', 'mips']))
35 self.assertEqual(['mips', 'i386'],
36 test(['-arch', 'mips', '-arch', 'i386']))
37
38 def assertFlagsChanged(self, expected, flags):
39 cmd = ['clang', '-c', 'source.c'] + flags
40 opts = sut.classify_parameters(cmd)
41 self.assertEqual(expected, opts['flags'])
42
43 def assertFlagsUnchanged(self, flags):
44 self.assertFlagsChanged(flags, flags)
45
46 def assertFlagsFiltered(self, flags):
47 self.assertFlagsChanged([], flags)
48
49 def test_optimalizations_pass(self):
50 self.assertFlagsUnchanged(['-O'])
51 self.assertFlagsUnchanged(['-O1'])
52 self.assertFlagsUnchanged(['-Os'])
53 self.assertFlagsUnchanged(['-O2'])
54 self.assertFlagsUnchanged(['-O3'])
55
56 def test_include_pass(self):
57 self.assertFlagsUnchanged([])
58 self.assertFlagsUnchanged(['-include', '/usr/local/include'])
59 self.assertFlagsUnchanged(['-I.'])
60 self.assertFlagsUnchanged(['-I', '.'])
61 self.assertFlagsUnchanged(['-I/usr/local/include'])
62 self.assertFlagsUnchanged(['-I', '/usr/local/include'])
63 self.assertFlagsUnchanged(['-I/opt', '-I', '/opt/otp/include'])
64 self.assertFlagsUnchanged(['-isystem', '/path'])
65 self.assertFlagsUnchanged(['-isystem=/path'])
66
67 def test_define_pass(self):
68 self.assertFlagsUnchanged(['-DNDEBUG'])
69 self.assertFlagsUnchanged(['-UNDEBUG'])
70 self.assertFlagsUnchanged(['-Dvar1=val1', '-Dvar2=val2'])
71 self.assertFlagsUnchanged(['-Dvar="val ues"'])
72
73 def test_output_filtered(self):
74 self.assertFlagsFiltered(['-o', 'source.o'])
75
76 def test_some_warning_filtered(self):
77 self.assertFlagsFiltered(['-Wall'])
78 self.assertFlagsFiltered(['-Wnoexcept'])
79 self.assertFlagsFiltered(['-Wreorder', '-Wunused', '-Wundef'])
80 self.assertFlagsUnchanged(['-Wno-reorder', '-Wno-unused'])
81
82 def test_compile_only_flags_pass(self):
83 self.assertFlagsUnchanged(['-std=C99'])
84 self.assertFlagsUnchanged(['-nostdinc'])
85 self.assertFlagsUnchanged(['-isystem', '/image/debian'])
86 self.assertFlagsUnchanged(['-iprefix', '/usr/local'])
87 self.assertFlagsUnchanged(['-iquote=me'])
88 self.assertFlagsUnchanged(['-iquote', 'me'])
89
90 def test_compile_and_link_flags_pass(self):
91 self.assertFlagsUnchanged(['-fsinged-char'])
92 self.assertFlagsUnchanged(['-fPIC'])
93 self.assertFlagsUnchanged(['-stdlib=libc++'])
94 self.assertFlagsUnchanged(['--sysroot', '/'])
95 self.assertFlagsUnchanged(['-isysroot', '/'])
96
97 def test_some_flags_filtered(self):
98 self.assertFlagsFiltered(['-g'])
99 self.assertFlagsFiltered(['-fsyntax-only'])
100 self.assertFlagsFiltered(['-save-temps'])
101 self.assertFlagsFiltered(['-init', 'my_init'])
102 self.assertFlagsFiltered(['-sectorder', 'a', 'b', 'c'])
103
104
105class Spy(object):
106 def __init__(self):
107 self.arg = None
108 self.success = 0
109
110 def call(self, params):
111 self.arg = params
112 return self.success
Laszlo Nagybc687582016-01-12 22:38:41 +0000113
114
115class RunAnalyzerTest(unittest.TestCase):
116
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000117 @staticmethod
118 def run_analyzer(content, failures_report):
119 with libear.TemporaryDirectory() as tmpdir:
120 filename = os.path.join(tmpdir, 'test.cpp')
121 with open(filename, 'w') as handle:
122 handle.write(content)
123
124 opts = {
125 'clang': 'clang',
126 'directory': os.getcwd(),
127 'flags': [],
128 'direct_args': [],
129 'file': filename,
130 'output_dir': tmpdir,
131 'output_format': 'plist',
132 'output_failures': failures_report
133 }
134 spy = Spy()
135 result = sut.run_analyzer(opts, spy.call)
136 return (result, spy.arg)
137
Laszlo Nagybc687582016-01-12 22:38:41 +0000138 def test_run_analyzer(self):
139 content = "int div(int n, int d) { return n / d; }"
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000140 (result, fwds) = RunAnalyzerTest.run_analyzer(content, False)
Laszlo Nagybc687582016-01-12 22:38:41 +0000141 self.assertEqual(None, fwds)
142 self.assertEqual(0, result['exit_code'])
143
144 def test_run_analyzer_crash(self):
145 content = "int div(int n, int d) { return n / d }"
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000146 (result, fwds) = RunAnalyzerTest.run_analyzer(content, False)
Laszlo Nagybc687582016-01-12 22:38:41 +0000147 self.assertEqual(None, fwds)
148 self.assertEqual(1, result['exit_code'])
149
150 def test_run_analyzer_crash_and_forwarded(self):
151 content = "int div(int n, int d) { return n / d }"
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000152 (_, fwds) = RunAnalyzerTest.run_analyzer(content, True)
Laszlo Nagybc687582016-01-12 22:38:41 +0000153 self.assertEqual(1, fwds['exit_code'])
154 self.assertTrue(len(fwds['error_output']) > 0)
155
156
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000157class ReportFailureTest(unittest.TestCase):
Laszlo Nagybc687582016-01-12 22:38:41 +0000158
159 def assertUnderFailures(self, path):
160 self.assertEqual('failures', os.path.basename(os.path.dirname(path)))
161
162 def test_report_failure_create_files(self):
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000163 with libear.TemporaryDirectory() as tmpdir:
Laszlo Nagybc687582016-01-12 22:38:41 +0000164 # create input file
165 filename = os.path.join(tmpdir, 'test.c')
166 with open(filename, 'w') as handle:
167 handle.write('int main() { return 0')
168 uname_msg = ' '.join(os.uname()) + os.linesep
169 error_msg = 'this is my error output'
170 # execute test
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000171 opts = {
172 'clang': 'clang',
173 'directory': os.getcwd(),
174 'flags': [],
175 'file': filename,
176 'output_dir': tmpdir,
177 'language': 'c',
178 'error_type': 'other_error',
179 'error_output': error_msg,
180 'exit_code': 13
181 }
Laszlo Nagybc687582016-01-12 22:38:41 +0000182 sut.report_failure(opts)
183 # verify the result
184 result = dict()
185 pp_file = None
186 for root, _, files in os.walk(tmpdir):
187 keys = [os.path.join(root, name) for name in files]
188 for key in keys:
189 with open(key, 'r') as handle:
190 result[key] = handle.readlines()
191 if re.match(r'^(.*/)+clang(.*)\.i$', key):
192 pp_file = key
193
194 # prepocessor file generated
195 self.assertUnderFailures(pp_file)
196 # info file generated and content dumped
197 info_file = pp_file + '.info.txt'
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000198 self.assertTrue(info_file in result)
Laszlo Nagybc687582016-01-12 22:38:41 +0000199 self.assertEqual('Other Error\n', result[info_file][1])
200 self.assertEqual(uname_msg, result[info_file][3])
201 # error file generated and content dumped
202 error_file = pp_file + '.stderr.txt'
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000203 self.assertTrue(error_file in result)
Laszlo Nagybc687582016-01-12 22:38:41 +0000204 self.assertEqual([error_msg], result[error_file])
205
206
207class AnalyzerTest(unittest.TestCase):
208
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000209 def test_nodebug_macros_appended(self):
210 def test(flags):
211 spy = Spy()
212 opts = {'flags': flags, 'force_debug': True}
213 self.assertEqual(spy.success,
214 sut.filter_debug_flags(opts, spy.call))
215 return spy.arg['flags']
216
217 self.assertEqual(['-UNDEBUG'], test([]))
218 self.assertEqual(['-DNDEBUG', '-UNDEBUG'], test(['-DNDEBUG']))
219 self.assertEqual(['-DSomething', '-UNDEBUG'], test(['-DSomething']))
220
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000221 def test_set_language_fall_through(self):
222 def language(expected, input):
223 spy = Spy()
224 input.update({'compiler': 'c', 'file': 'test.c'})
Laszlo Nagybc687582016-01-12 22:38:41 +0000225 self.assertEqual(spy.success, sut.language_check(input, spy.call))
226 self.assertEqual(expected, spy.arg['language'])
227
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000228 language('c', {'language': 'c', 'flags': []})
229 language('c++', {'language': 'c++', 'flags': []})
Laszlo Nagybc687582016-01-12 22:38:41 +0000230
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000231 def test_set_language_stops_on_not_supported(self):
232 spy = Spy()
233 input = {
234 'compiler': 'c',
235 'flags': [],
236 'file': 'test.java',
237 'language': 'java'
238 }
239 self.assertIsNone(sut.language_check(input, spy.call))
240 self.assertIsNone(spy.arg)
241
242 def test_set_language_sets_flags(self):
243 def flags(expected, input):
244 spy = Spy()
245 input.update({'compiler': 'c', 'file': 'test.c'})
246 self.assertEqual(spy.success, sut.language_check(input, spy.call))
247 self.assertEqual(expected, spy.arg['flags'])
248
249 flags(['-x', 'c'], {'language': 'c', 'flags': []})
250 flags(['-x', 'c++'], {'language': 'c++', 'flags': []})
251
252 def test_set_language_from_filename(self):
253 def language(expected, input):
254 spy = Spy()
255 input.update({'language': None, 'flags': []})
256 self.assertEqual(spy.success, sut.language_check(input, spy.call))
257 self.assertEqual(expected, spy.arg['language'])
258
259 language('c', {'file': 'file.c', 'compiler': 'c'})
260 language('c++', {'file': 'file.c', 'compiler': 'c++'})
261 language('c++', {'file': 'file.cxx', 'compiler': 'c'})
262 language('c++', {'file': 'file.cxx', 'compiler': 'c++'})
263 language('c++', {'file': 'file.cpp', 'compiler': 'c++'})
264 language('c-cpp-output', {'file': 'file.i', 'compiler': 'c'})
265 language('c++-cpp-output', {'file': 'file.i', 'compiler': 'c++'})
266
267 def test_arch_loop_sets_flags(self):
268 def flags(archs):
269 spy = Spy()
270 input = {'flags': [], 'arch_list': archs}
Laszlo Nagybc687582016-01-12 22:38:41 +0000271 sut.arch_check(input, spy.call)
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000272 return spy.arg['flags']
Laszlo Nagybc687582016-01-12 22:38:41 +0000273
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000274 self.assertEqual([], flags([]))
275 self.assertEqual(['-arch', 'i386'], flags(['i386']))
276 self.assertEqual(['-arch', 'i386'], flags(['i386', 'ppc']))
277 self.assertEqual(['-arch', 'sparc'], flags(['i386', 'sparc']))
Laszlo Nagybc687582016-01-12 22:38:41 +0000278
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000279 def test_arch_loop_stops_on_not_supported(self):
280 def stop(archs):
281 spy = Spy()
282 input = {'flags': [], 'arch_list': archs}
283 self.assertIsNone(sut.arch_check(input, spy.call))
284 self.assertIsNone(spy.arg)
Laszlo Nagybc687582016-01-12 22:38:41 +0000285
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000286 stop(['ppc'])
287 stop(['ppc64'])
Laszlo Nagybc687582016-01-12 22:38:41 +0000288
289
290@sut.require([])
291def method_without_expecteds(opts):
292 return 0
293
294
295@sut.require(['this', 'that'])
296def method_with_expecteds(opts):
297 return 0
298
299
300@sut.require([])
301def method_exception_from_inside(opts):
302 raise Exception('here is one')
303
304
305class RequireDecoratorTest(unittest.TestCase):
306
307 def test_method_without_expecteds(self):
308 self.assertEqual(method_without_expecteds(dict()), 0)
309 self.assertEqual(method_without_expecteds({}), 0)
310 self.assertEqual(method_without_expecteds({'this': 2}), 0)
311 self.assertEqual(method_without_expecteds({'that': 3}), 0)
312
313 def test_method_with_expecteds(self):
314 self.assertRaises(KeyError, method_with_expecteds, dict())
315 self.assertRaises(KeyError, method_with_expecteds, {})
316 self.assertRaises(KeyError, method_with_expecteds, {'this': 2})
317 self.assertRaises(KeyError, method_with_expecteds, {'that': 3})
318 self.assertEqual(method_with_expecteds({'this': 0, 'that': 3}), 0)
319
320 def test_method_exception_not_caught(self):
321 self.assertRaises(Exception, method_exception_from_inside, dict())