blob: 2d090622332924fca47ce0495df507982347c72d [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('crash', fwds['error_type'])
154 self.assertEqual(1, fwds['exit_code'])
155 self.assertTrue(len(fwds['error_output']) > 0)
156
157
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000158class ReportFailureTest(unittest.TestCase):
Laszlo Nagybc687582016-01-12 22:38:41 +0000159
160 def assertUnderFailures(self, path):
161 self.assertEqual('failures', os.path.basename(os.path.dirname(path)))
162
163 def test_report_failure_create_files(self):
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000164 with libear.TemporaryDirectory() as tmpdir:
Laszlo Nagybc687582016-01-12 22:38:41 +0000165 # create input file
166 filename = os.path.join(tmpdir, 'test.c')
167 with open(filename, 'w') as handle:
168 handle.write('int main() { return 0')
169 uname_msg = ' '.join(os.uname()) + os.linesep
170 error_msg = 'this is my error output'
171 # execute test
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000172 opts = {
173 'clang': 'clang',
174 'directory': os.getcwd(),
175 'flags': [],
176 'file': filename,
177 'output_dir': tmpdir,
178 'language': 'c',
179 'error_type': 'other_error',
180 'error_output': error_msg,
181 'exit_code': 13
182 }
Laszlo Nagybc687582016-01-12 22:38:41 +0000183 sut.report_failure(opts)
184 # verify the result
185 result = dict()
186 pp_file = None
187 for root, _, files in os.walk(tmpdir):
188 keys = [os.path.join(root, name) for name in files]
189 for key in keys:
190 with open(key, 'r') as handle:
191 result[key] = handle.readlines()
192 if re.match(r'^(.*/)+clang(.*)\.i$', key):
193 pp_file = key
194
195 # prepocessor file generated
196 self.assertUnderFailures(pp_file)
197 # info file generated and content dumped
198 info_file = pp_file + '.info.txt'
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000199 self.assertTrue(info_file in result)
Laszlo Nagybc687582016-01-12 22:38:41 +0000200 self.assertEqual('Other Error\n', result[info_file][1])
201 self.assertEqual(uname_msg, result[info_file][3])
202 # error file generated and content dumped
203 error_file = pp_file + '.stderr.txt'
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000204 self.assertTrue(error_file in result)
Laszlo Nagybc687582016-01-12 22:38:41 +0000205 self.assertEqual([error_msg], result[error_file])
206
207
208class AnalyzerTest(unittest.TestCase):
209
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000210 def test_nodebug_macros_appended(self):
211 def test(flags):
212 spy = Spy()
213 opts = {'flags': flags, 'force_debug': True}
214 self.assertEqual(spy.success,
215 sut.filter_debug_flags(opts, spy.call))
216 return spy.arg['flags']
217
218 self.assertEqual(['-UNDEBUG'], test([]))
219 self.assertEqual(['-DNDEBUG', '-UNDEBUG'], test(['-DNDEBUG']))
220 self.assertEqual(['-DSomething', '-UNDEBUG'], test(['-DSomething']))
221
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000222 def test_set_language_fall_through(self):
223 def language(expected, input):
224 spy = Spy()
225 input.update({'compiler': 'c', 'file': 'test.c'})
Laszlo Nagybc687582016-01-12 22:38:41 +0000226 self.assertEqual(spy.success, sut.language_check(input, spy.call))
227 self.assertEqual(expected, spy.arg['language'])
228
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000229 language('c', {'language': 'c', 'flags': []})
230 language('c++', {'language': 'c++', 'flags': []})
Laszlo Nagybc687582016-01-12 22:38:41 +0000231
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000232 def test_set_language_stops_on_not_supported(self):
233 spy = Spy()
234 input = {
235 'compiler': 'c',
236 'flags': [],
237 'file': 'test.java',
238 'language': 'java'
239 }
240 self.assertIsNone(sut.language_check(input, spy.call))
241 self.assertIsNone(spy.arg)
242
243 def test_set_language_sets_flags(self):
244 def flags(expected, input):
245 spy = Spy()
246 input.update({'compiler': 'c', 'file': 'test.c'})
247 self.assertEqual(spy.success, sut.language_check(input, spy.call))
248 self.assertEqual(expected, spy.arg['flags'])
249
250 flags(['-x', 'c'], {'language': 'c', 'flags': []})
251 flags(['-x', 'c++'], {'language': 'c++', 'flags': []})
252
253 def test_set_language_from_filename(self):
254 def language(expected, input):
255 spy = Spy()
256 input.update({'language': None, 'flags': []})
257 self.assertEqual(spy.success, sut.language_check(input, spy.call))
258 self.assertEqual(expected, spy.arg['language'])
259
260 language('c', {'file': 'file.c', 'compiler': 'c'})
261 language('c++', {'file': 'file.c', 'compiler': 'c++'})
262 language('c++', {'file': 'file.cxx', 'compiler': 'c'})
263 language('c++', {'file': 'file.cxx', 'compiler': 'c++'})
264 language('c++', {'file': 'file.cpp', 'compiler': 'c++'})
265 language('c-cpp-output', {'file': 'file.i', 'compiler': 'c'})
266 language('c++-cpp-output', {'file': 'file.i', 'compiler': 'c++'})
267
268 def test_arch_loop_sets_flags(self):
269 def flags(archs):
270 spy = Spy()
271 input = {'flags': [], 'arch_list': archs}
Laszlo Nagybc687582016-01-12 22:38:41 +0000272 sut.arch_check(input, spy.call)
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000273 return spy.arg['flags']
Laszlo Nagybc687582016-01-12 22:38:41 +0000274
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000275 self.assertEqual([], flags([]))
276 self.assertEqual(['-arch', 'i386'], flags(['i386']))
277 self.assertEqual(['-arch', 'i386'], flags(['i386', 'ppc']))
278 self.assertEqual(['-arch', 'sparc'], flags(['i386', 'sparc']))
Laszlo Nagybc687582016-01-12 22:38:41 +0000279
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000280 def test_arch_loop_stops_on_not_supported(self):
281 def stop(archs):
282 spy = Spy()
283 input = {'flags': [], 'arch_list': archs}
284 self.assertIsNone(sut.arch_check(input, spy.call))
285 self.assertIsNone(spy.arg)
Laszlo Nagybc687582016-01-12 22:38:41 +0000286
Laszlo Nagy8bd63e52016-04-19 12:03:03 +0000287 stop(['ppc'])
288 stop(['ppc64'])
Laszlo Nagybc687582016-01-12 22:38:41 +0000289
290
291@sut.require([])
292def method_without_expecteds(opts):
293 return 0
294
295
296@sut.require(['this', 'that'])
297def method_with_expecteds(opts):
298 return 0
299
300
301@sut.require([])
302def method_exception_from_inside(opts):
303 raise Exception('here is one')
304
305
306class RequireDecoratorTest(unittest.TestCase):
307
308 def test_method_without_expecteds(self):
309 self.assertEqual(method_without_expecteds(dict()), 0)
310 self.assertEqual(method_without_expecteds({}), 0)
311 self.assertEqual(method_without_expecteds({'this': 2}), 0)
312 self.assertEqual(method_without_expecteds({'that': 3}), 0)
313
314 def test_method_with_expecteds(self):
315 self.assertRaises(KeyError, method_with_expecteds, dict())
316 self.assertRaises(KeyError, method_with_expecteds, {})
317 self.assertRaises(KeyError, method_with_expecteds, {'this': 2})
318 self.assertRaises(KeyError, method_with_expecteds, {'that': 3})
319 self.assertEqual(method_with_expecteds({'this': 0, 'that': 3}), 0)
320
321 def test_method_exception_not_caught(self):
322 self.assertRaises(Exception, method_exception_from_inside, dict())