2 # Copyright 2021 The Chromium Authors
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
12 class DecoratedFilenameTest(unittest.TestCase):
13 def testCHeaderClassification(self):
14 self.assertTrue(add_header.IsCSystemHeader('<stdlib.h>'))
15 self.assertFalse(add_header.IsCSystemHeader('<type_traits>'))
16 self.assertFalse(add_header.IsCSystemHeader('"moo.h"'))
18 def testCXXHeaderClassification(self):
19 self.assertFalse(add_header.IsCXXSystemHeader('<stdlib.h>'))
20 self.assertTrue(add_header.IsCXXSystemHeader('<type_traits>'))
21 self.assertFalse(add_header.IsCXXSystemHeader('"moo.h"'))
23 def testUserHeaderClassification(self):
24 self.assertFalse(add_header.IsUserHeader('<stdlib.h>'))
25 self.assertFalse(add_header.IsUserHeader('<type_traits>'))
26 self.assertTrue(add_header.IsUserHeader('"moo.h"'))
28 def testClassifyHeader(self):
29 self.assertEqual(add_header.ClassifyHeader('<stdlib.h>'),
30 add_header._HEADER_TYPE_C_SYSTEM)
31 self.assertEqual(add_header.ClassifyHeader('<type_traits>'),
32 add_header._HEADER_TYPE_CXX_SYSTEM)
33 self.assertEqual(add_header.ClassifyHeader('"moo.h"'),
34 add_header._HEADER_TYPE_USER)
35 self.assertEqual(add_header.ClassifyHeader('invalid'),
36 add_header._HEADER_TYPE_INVALID)
39 class FindIncludesTest(unittest.TestCase):
41 begin, end = add_header.FindIncludes([])
42 self.assertEqual(begin, -1)
43 self.assertEqual(end, -1)
45 def testNoIncludes(self):
46 begin, end = add_header.FindIncludes(['a'])
47 self.assertEqual(begin, -1)
48 self.assertEqual(end, -1)
50 def testOneInclude(self):
51 begin, end = add_header.FindIncludes(['#include <algorithm>'])
52 self.assertEqual(begin, 0)
53 self.assertEqual(end, 1)
55 def testIncludeWithInlineComment(self):
56 begin, end = add_header.FindIncludes(
57 ['#include "moo.h" // TODO: Add more sounds.'])
58 self.assertEqual(begin, 0)
59 self.assertEqual(end, 1)
61 def testNewlinesBetweenIncludes(self):
62 begin, end = add_header.FindIncludes(
63 ['#include <utility>', '', '#include "moo.h"'])
64 self.assertEqual(begin, 0)
65 self.assertEqual(end, 3)
67 def testCommentsBetweenIncludes(self):
68 begin, end = add_header.FindIncludes([
69 '#include <utility>', '// TODO: Add goat support.', '#include "moo.h"'
71 self.assertEqual(begin, 0)
72 self.assertEqual(end, 3)
74 def testEmptyLinesNotIncluded(self):
75 begin, end = add_header.FindIncludes(
76 ['', '#include <utility>', '', '#include "moo.h"', ''])
77 self.assertEqual(begin, 1)
78 self.assertEqual(end, 4)
80 def testCommentsNotIncluded(self):
81 begin, end = add_header.FindIncludes([
82 '// Cow module.', '#include <utility>', '// For cow speech synthesis.',
83 '#include "moo.h"', '// TODO: Add Linux audio support.'
85 self.assertEqual(begin, 1)
86 self.assertEqual(end, 4)
88 def testNonIncludesLinesBeforeIncludesIgnored(self):
89 begin, end = add_header.FindIncludes(
90 ['#ifndef COW_H_', '#define COW_H_', '#include "moo.h"'])
91 self.assertEqual(begin, 2)
92 self.assertEqual(end, 3)
94 def testNonIncludesLinesAfterIncludesTerminates(self):
95 begin, end = add_header.FindIncludes([
96 '#include "moo.h"', '#ifndef COW_MESSAGES_H_', '#define COW_MESSAGE_H_'
98 self.assertEqual(begin, 0)
99 self.assertEqual(end, 1)
102 class IncludeTest(unittest.TestCase):
103 def testToSource(self):
105 add_header.Include('<moo.h>', 'include', [], None).ToSource(),
106 ['#include <moo.h>'])
108 def testIncludeWithPreambleToSource(self):
110 add_header.Include('"moo.h"', 'include', ['// preamble'],
112 ['// preamble', '#include "moo.h"'])
114 def testIncludeWithInlineCommentToSource(self):
116 add_header.Include('"moo.h"', 'include', [],
117 ' inline comment').ToSource(),
118 ['#include "moo.h" // inline comment'])
120 def testIncludeWithPreambleAndInlineCommentToSource(self):
121 # Make sure whitespace is vaguely normalized too.
123 add_header.Include('"moo.h"', 'include', [
124 '// preamble with trailing space ',
125 ], ' inline comment with trailing space ').ToSource(), [
126 '// preamble with trailing space',
127 '#include "moo.h" // inline comment with trailing space'
130 def testImportToSource(self):
132 add_header.Include('"moo.h"', 'import', [], None).ToSource(),
136 class ParseIncludesTest(unittest.TestCase):
137 def testInvalid(self):
138 self.assertIsNone(add_header.ParseIncludes(['invalid']))
140 def testInclude(self):
141 includes = add_header.ParseIncludes(['#include "moo.h"'])
142 self.assertEqual(len(includes), 1)
143 self.assertEqual(includes[0].decorated_name, '"moo.h"')
144 self.assertEqual(includes[0].directive, 'include')
145 self.assertEqual(includes[0].preamble, [])
146 self.assertIsNone(includes[0].inline_comment)
147 self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER)
148 self.assertFalse(includes[0].is_primary_header)
150 def testIncludeSurroundedByWhitespace(self):
151 includes = add_header.ParseIncludes([' #include "moo.h" '])
152 self.assertEqual(len(includes), 1)
153 self.assertEqual(includes[0].decorated_name, '"moo.h"')
154 self.assertEqual(includes[0].directive, 'include')
155 self.assertEqual(includes[0].preamble, [])
156 self.assertIsNone(includes[0].inline_comment)
157 self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER)
158 self.assertFalse(includes[0].is_primary_header)
160 def testImport(self):
161 includes = add_header.ParseIncludes(['#import "moo.h"'])
162 self.assertEqual(len(includes), 1)
163 self.assertEqual(includes[0].decorated_name, '"moo.h"')
164 self.assertEqual(includes[0].directive, 'import')
165 self.assertEqual(includes[0].preamble, [])
166 self.assertIsNone(includes[0].inline_comment)
167 self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER)
168 self.assertFalse(includes[0].is_primary_header)
170 def testIncludeWithPreamble(self):
171 includes = add_header.ParseIncludes(
172 ['// preamble comment ', '#include "moo.h"'])
173 self.assertEqual(len(includes), 1)
174 self.assertEqual(includes[0].decorated_name, '"moo.h"')
175 self.assertEqual(includes[0].directive, 'include')
176 self.assertEqual(includes[0].preamble, ['// preamble comment '])
177 self.assertIsNone(includes[0].inline_comment)
178 self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER)
179 self.assertFalse(includes[0].is_primary_header)
181 def testIncludeWithInvalidPreamble(self):
183 add_header.ParseIncludes(['// orphan comment', '', '#include "moo.h"']))
185 def testIncludeWIthInlineComment(self):
186 includes = add_header.ParseIncludes(['#include "moo.h"// For SFX '])
187 self.assertEqual(len(includes), 1)
188 self.assertEqual(includes[0].decorated_name, '"moo.h"')
189 self.assertEqual(includes[0].directive, 'include')
190 self.assertEqual(includes[0].preamble, [])
191 self.assertEqual(includes[0].inline_comment, ' For SFX ')
192 self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER)
193 self.assertFalse(includes[0].is_primary_header)
195 def testIncludeWithInlineCommentAndPreamble(self):
196 includes = add_header.ParseIncludes(
197 ['// preamble comment ', '#include "moo.h" // For SFX '])
198 self.assertEqual(len(includes), 1)
199 self.assertEqual(includes[0].decorated_name, '"moo.h"')
200 self.assertEqual(includes[0].directive, 'include')
201 self.assertEqual(includes[0].preamble, ['// preamble comment '])
202 self.assertEqual(includes[0].inline_comment, ' For SFX ')
203 self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER)
204 self.assertFalse(includes[0].is_primary_header)
206 def testMultipleIncludes(self):
207 includes = add_header.ParseIncludes([
208 '#include <time.h>', '', '#include "moo.h" // For SFX ',
209 '// TODO: Implement death ray.', '#import "goat.h"'
211 self.assertEqual(len(includes), 3)
212 self.assertEqual(includes[0].decorated_name, '<time.h>')
213 self.assertEqual(includes[0].directive, 'include')
214 self.assertEqual(includes[0].preamble, [])
215 self.assertIsNone(includes[0].inline_comment)
216 self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_C_SYSTEM)
217 self.assertFalse(includes[0].is_primary_header)
218 self.assertEqual(includes[1].decorated_name, '"moo.h"')
219 self.assertEqual(includes[1].directive, 'include')
220 self.assertEqual(includes[1].preamble, [])
221 self.assertEqual(includes[1].inline_comment, ' For SFX ')
222 self.assertEqual(includes[1].header_type, add_header._HEADER_TYPE_USER)
223 self.assertFalse(includes[1].is_primary_header)
224 self.assertEqual(includes[2].decorated_name, '"goat.h"')
225 self.assertEqual(includes[2].directive, 'import')
226 self.assertEqual(includes[2].preamble, ['// TODO: Implement death ray.'])
227 self.assertIsNone(includes[2].inline_comment)
228 self.assertEqual(includes[2].header_type, add_header._HEADER_TYPE_USER)
229 self.assertFalse(includes[2].is_primary_header)
232 class MarkPrimaryIncludeTest(unittest.TestCase):
233 def _extract_primary_name(self, includes):
234 for include in includes:
235 if include.is_primary_header:
236 return include.decorated_name
238 def testNoOpOnHeader(self):
239 includes = [add_header.Include('"cow.h"', 'include', [], None)]
240 add_header.MarkPrimaryInclude(includes, 'cow.h')
241 self.assertIsNone(self._extract_primary_name(includes))
243 def testSystemHeaderNotMatched(self):
244 includes = [add_header.Include('<cow.h>', 'include', [], None)]
245 add_header.MarkPrimaryInclude(includes, 'cow.cc')
246 self.assertIsNone(self._extract_primary_name(includes))
248 def testExactMatch(self):
250 add_header.Include('"cow.h"', 'include', [], None),
251 add_header.Include('"cow_posix.h"', 'include', [], None),
253 add_header.MarkPrimaryInclude(includes, 'cow.cc')
254 self.assertEqual(self._extract_primary_name(includes), '"cow.h"')
256 def testFuzzyMatch(self):
257 includes = [add_header.Include('"cow.h"', 'include', [], None)]
258 add_header.MarkPrimaryInclude(includes, 'cow_linux_unittest.cc')
259 self.assertEqual(self._extract_primary_name(includes), '"cow.h"')
261 def testFuzzymatchInReverse(self):
262 includes = [add_header.Include('"cow.h"', 'include', [], None)]
263 add_header.MarkPrimaryInclude(includes, 'cow_uitest_aura.cc')
264 self.assertEqual(self._extract_primary_name(includes), '"cow.h"')
266 def testFuzzyMatchDoesntMatchDifferentSuffixes(self):
267 includes = [add_header.Include('"cow_posix.h"', 'include', [], None)]
268 add_header.MarkPrimaryInclude(includes, 'cow_windows.cc')
269 self.assertIsNone(self._extract_primary_name(includes))
271 def testMarksMostSpecific(self):
273 add_header.Include('"cow.h"', 'include', [], None),
274 add_header.Include('"cow_posix.h"', 'include', [], None),
276 add_header.MarkPrimaryInclude(includes, 'cow_posix.cc')
277 self.assertEqual(self._extract_primary_name(includes), '"cow_posix.h"')
279 def testFullPathMatch(self):
280 includes = [add_header.Include('"zfs/impl/cow.h"', 'include', [], None)]
281 add_header.MarkPrimaryInclude(includes, 'zfs/impl/cow.cc')
282 self.assertEqual(self._extract_primary_name(includes), '"zfs/impl/cow.h"')
284 def testTopmostDirectoryDoesNotMatch(self):
285 includes = [add_header.Include('"animal/impl/cow.h"', 'include', [], None)]
286 add_header.MarkPrimaryInclude(includes, 'zfs/impl/cow.cc')
287 self.assertIsNone(self._extract_primary_name(includes))
289 def testSubstantiallySimilarPaths(self):
291 add_header.Include('"farm/public/animal/cow.h"', 'include', [], None)
293 add_header.MarkPrimaryInclude(includes, 'farm/animal/cow.cc')
294 self.assertEqual(self._extract_primary_name(includes),
295 '"farm/public/animal/cow.h"')
297 def testSubstantiallySimilarPathsAndExactMatch(self):
299 add_header.Include('"ui/gfx/ipc/geometry/gfx_param_traits.h"',
300 'include', [], None),
301 add_header.Include('"ui/gfx/ipc/gfx_param_traits.h"', 'include', [],
304 add_header.MarkPrimaryInclude(includes, 'ui/gfx/ipc/gfx_param_traits.cc')
305 self.assertEqual(self._extract_primary_name(includes),
306 '"ui/gfx/ipc/gfx_param_traits.h"')
308 def testNoMatchingSubdirectories(self):
309 includes = [add_header.Include('"base/zfs/cow.h"', 'include', [], None)]
310 add_header.MarkPrimaryInclude(includes, 'base/animal/cow.cc')
311 self.assertIsNone(self._extract_primary_name(includes))
314 class SerializeIncludesTest(unittest.TestCase):
315 def testSystemHeaders(self):
316 source = add_header.SerializeIncludes([
317 add_header.Include('<stdlib.h>', 'include', [], None),
318 add_header.Include('<map>', 'include', [], None),
320 self.assertEqual(source, ['#include <stdlib.h>', '', '#include <map>'])
322 def testUserHeaders(self):
323 source = add_header.SerializeIncludes([
324 add_header.Include('"goat.h"', 'include', [], None),
325 add_header.Include('"moo.h"', 'include', [], None),
327 self.assertEqual(source, ['#include "goat.h"', '#include "moo.h"'])
329 def testSystemAndUserHeaders(self):
330 source = add_header.SerializeIncludes([
331 add_header.Include('<stdlib.h>', 'include', [], None),
332 add_header.Include('<map>', 'include', [], None),
333 add_header.Include('"moo.h"', 'include', [], None),
337 ['#include <stdlib.h>', '', '#include <map>', '', '#include "moo.h"'])
339 def testPrimaryAndSystemHeaders(self):
340 primary_header = add_header.Include('"cow.h"', 'include', [], None)
341 primary_header.is_primary_header = True
342 source = add_header.SerializeIncludes([
344 add_header.Include('<stdlib.h>', 'include', [], None),
345 add_header.Include('<map>', 'include', [], None),
349 ['#include "cow.h"', '', '#include <stdlib.h>', '', '#include <map>'])
351 def testPrimaryAndUserHeaders(self):
352 primary_header = add_header.Include('"cow.h"', 'include', [], None)
353 primary_header.is_primary_header = True
354 source = add_header.SerializeIncludes([
356 add_header.Include('"moo.h"', 'include', [], None),
358 self.assertEqual(source, ['#include "cow.h"', '', '#include "moo.h"'])
360 def testPrimarySystemAndUserHeaders(self):
361 primary_header = add_header.Include('"cow.h"', 'include', [], None)
362 primary_header.is_primary_header = True
363 source = add_header.SerializeIncludes([
365 add_header.Include('<stdlib.h>', 'include', [], None),
366 add_header.Include('<map>', 'include', [], None),
367 add_header.Include('"moo.h"', 'include', [], None),
369 self.assertEqual(source, [
370 '#include "cow.h"', '', '#include <stdlib.h>', '', '#include <map>', '',
374 def testSpecialHeaders(self):
376 primary_header = add_header.Include('"cow.h"', 'include', [], None)
377 primary_header.is_primary_header = True
378 includes.append(primary_header)
379 includes.append(add_header.Include('<winsock2.h>', 'include', [], None))
380 includes.append(add_header.Include('<windows.h>', 'include', [], None))
381 includes.append(add_header.Include('<ws2tcpip.h>', 'include', [], None))
382 includes.append(add_header.Include('<shobjidl.h>', 'include', [], None))
383 includes.append(add_header.Include('<atlbase.h>', 'include', [], None))
384 includes.append(add_header.Include('<ole2.h>', 'include', [], None))
385 includes.append(add_header.Include('<unknwn.h>', 'include', [], None))
386 includes.append(add_header.Include('<objbase.h>', 'include', [], None))
387 includes.append(add_header.Include('<tchar.h>', 'include', [], None))
388 includes.append(add_header.Include('<string.h>', 'include', [], None))
389 includes.append(add_header.Include('<stddef.h>', 'include', [], None))
390 includes.append(add_header.Include('<stdio.h>', 'include', [], None))
391 includes.append(add_header.Include('"moo.h"', 'include', [], None))
392 random.shuffle(includes)
393 source = add_header.SerializeIncludes(includes)
394 self.assertEqual(source, [
395 '#include "cow.h"', '', '#include <winsock2.h>', '#include <windows.h>',
396 '#include <ws2tcpip.h>', '#include <shobjidl.h>',
397 '#include <atlbase.h>', '#include <ole2.h>', '#include <unknwn.h>',
398 '#include <objbase.h>', '#include <tchar.h>', '#include <stddef.h>',
399 '#include <stdio.h>', '#include <string.h>', '', '#include "moo.h"'
403 class AddHeaderToSourceTest(unittest.TestCase):
404 def testAddInclude(self):
405 source = add_header.AddHeaderToSource(
406 'cow.cc', '\n'.join([
407 '// Copyright info here.', '', '#include <utility>',
408 '// For cow speech synthesis.',
409 '#include "moo.h" // TODO: Add Linux audio support.',
410 '#include <time.h>', '#include "cow.h"', 'namespace bovine {', '',
411 '// TODO: Implement.', '} // namespace bovine'
415 '// Copyright info here.', '', '#include "cow.h"', '',
416 '#include <time.h>', '', '#include <memory>', '#include <utility>',
417 '', '// For cow speech synthesis.',
418 '#include "moo.h" // TODO: Add Linux audio support.',
419 'namespace bovine {', '', '// TODO: Implement.',
420 '} // namespace bovine', ''
423 def testAlreadyIncluded(self):
424 # To make sure the original source is returned unmodified, the input source
425 # intentionally scrambles the #include order.
427 '// Copyright info here.', '', '#include "moo.h"', '#include <utility>',
428 '#include <memory>', '#include "cow.h"', 'namespace bovine {', '',
429 '// TODO: Implement.', '} // namespace bovine'
431 self.assertEqual(add_header.AddHeaderToSource('cow.cc', source, '<memory>'),
434 def testConditionalIncludesLeftALone(self):
435 # TODO(dcheng): Conditional header handling could probably be more clever.
436 # But for the moment, this is probably Good Enough.
437 source = add_header.AddHeaderToSource(
438 'cow.cc', '\n'.join([
439 '// Copyright info here.', '', '#include "cow.h"',
440 '#include <utility>', '// For cow speech synthesis.',
441 '#include "moo.h" // TODO: Add Linux audio support.',
442 '#if defined(USE_AURA)', '#include <memory>',
443 '#endif // defined(USE_AURA)'
447 '// Copyright info here.', '', '#include "cow.h"', '',
448 '#include <memory>', '#include <utility>', '',
449 '// For cow speech synthesis.',
450 '#include "moo.h" // TODO: Add Linux audio support.',
451 '#if defined(USE_AURA)', '#include <memory>',
452 '#endif // defined(USE_AURA)', ''
455 def testRemoveInclude(self):
456 source = add_header.AddHeaderToSource(
459 '// Copyright info here.', '', '#include <memory>',
460 '#include <utility>', '// For cow speech synthesis.',
461 '#include "moo.h" // TODO: Add Linux audio support.',
462 '#include <time.h>', '#include "cow.h"', 'namespace bovine {', '',
463 '// TODO: Implement.', '} // namespace bovine'
469 '// Copyright info here.', '', '#include "cow.h"', '',
470 '#include <time.h>', '', '#include <memory>', '',
471 '// For cow speech synthesis.',
472 '#include "moo.h" // TODO: Add Linux audio support.',
473 'namespace bovine {', '', '// TODO: Implement.',
474 '} // namespace bovine', ''
478 if __name__ == '__main__':