Index: tools/clang/pass_to_move/add_header_test.py |
diff --git a/tools/clang/pass_to_move/add_header_test.py b/tools/clang/pass_to_move/add_header_test.py |
new file mode 100755 |
index 0000000000000000000000000000000000000000..7d12c880b13f5315db4007eaa61f095f4ace4f6d |
--- /dev/null |
+++ b/tools/clang/pass_to_move/add_header_test.py |
@@ -0,0 +1,417 @@ |
+#!/usr/bin/env python |
+# Copyright 2015 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+import unittest |
+ |
+import add_header |
+ |
+ |
+class DecoratedFilenameTest(unittest.TestCase): |
+ |
+ def testCHeaderClassification(self): |
+ self.assertTrue(add_header.IsCSystemHeader('<stdlib.h>')) |
+ self.assertFalse(add_header.IsCSystemHeader('<type_traits>')) |
+ self.assertFalse(add_header.IsCSystemHeader('"moo.h"')) |
+ |
+ def testCXXHeaderClassification(self): |
+ self.assertFalse(add_header.IsCXXSystemHeader('<stdlib.h>')) |
+ self.assertTrue(add_header.IsCXXSystemHeader('<type_traits>')) |
+ self.assertFalse(add_header.IsCXXSystemHeader('"moo.h"')) |
+ |
+ def testUserHeaderClassification(self): |
+ self.assertFalse(add_header.IsUserHeader('<stdlib.h>')) |
+ self.assertFalse(add_header.IsUserHeader('<type_traits>')) |
+ self.assertTrue(add_header.IsUserHeader('"moo.h"')) |
+ |
+ def testClassifyHeader(self): |
+ self.assertEqual( |
+ add_header.ClassifyHeader('<stdlib.h>'), |
+ add_header._HEADER_TYPE_C_SYSTEM) |
+ self.assertEqual( |
+ add_header.ClassifyHeader('<type_traits>'), |
+ add_header._HEADER_TYPE_CXX_SYSTEM) |
+ self.assertEqual( |
+ add_header.ClassifyHeader('"moo.h"'), add_header._HEADER_TYPE_USER) |
+ self.assertEqual( |
+ add_header.ClassifyHeader('invalid'), add_header._HEADER_TYPE_INVALID) |
+ |
+ |
+class FindIncludesTest(unittest.TestCase): |
+ |
+ def testEmpty(self): |
+ begin, end = add_header.FindIncludes([]) |
+ self.assertEqual(begin, -1) |
+ self.assertEqual(end, -1) |
+ |
+ def testNoIncludes(self): |
+ begin, end = add_header.FindIncludes(['a']) |
+ self.assertEqual(begin, -1) |
+ self.assertEqual(end, -1) |
+ |
+ def testOneInclude(self): |
+ begin, end = add_header.FindIncludes(['#include <algorithm>']) |
+ self.assertEqual(begin, 0) |
+ self.assertEqual(end, 1) |
+ |
+ def testIncludeWithInlineComment(self): |
+ begin, end = add_header.FindIncludes( |
+ ['#include "moo.h" // TODO: Add more sounds.']) |
+ self.assertEqual(begin, 0) |
+ self.assertEqual(end, 1) |
+ |
+ def testNewlinesBetweenIncludes(self): |
+ begin, end = add_header.FindIncludes(['#include <utility>', '', |
+ '#include "moo.h"']) |
+ self.assertEqual(begin, 0) |
+ self.assertEqual(end, 3) |
+ |
+ def testCommentsBetweenIncludes(self): |
+ begin, end = add_header.FindIncludes( |
+ ['#include <utility>', '// TODO: Add goat support.', '#include "moo.h"' |
+ ]) |
+ self.assertEqual(begin, 0) |
+ self.assertEqual(end, 3) |
+ |
+ def testEmptyLinesNotIncluded(self): |
+ begin, end = add_header.FindIncludes(['', '#include <utility>', '', |
+ '#include "moo.h"', '']) |
+ self.assertEqual(begin, 1) |
+ self.assertEqual(end, 4) |
+ |
+ def testCommentsNotIncluded(self): |
+ begin, end = add_header.FindIncludes( |
+ ['// Cow module.', '#include <utility>', '// For cow speech synthesis.', |
+ '#include "moo.h"', '// TODO: Add Linux audio support.']) |
+ self.assertEqual(begin, 1) |
+ self.assertEqual(end, 4) |
+ |
+ def testNonIncludesLinesBeforeIncludesIgnored(self): |
+ begin, end = add_header.FindIncludes(['#ifndef COW_H_', '#define COW_H_', |
+ '#include "moo.h"']) |
+ self.assertEqual(begin, 2) |
+ self.assertEqual(end, 3) |
+ |
+ def testNonIncludesLinesAfterIncludesTerminates(self): |
+ begin, end = add_header.FindIncludes( |
+ ['#include "moo.h"', '#ifndef COW_MESSAGES_H_', '#define COW_MESSAGE_H_' |
+ ]) |
+ self.assertEqual(begin, 0) |
+ self.assertEqual(end, 1) |
+ |
+ |
+class IncludeTest(unittest.TestCase): |
+ |
+ def testToSource(self): |
+ self.assertEqual( |
+ add_header.Include('<moo.h>', 'include', [], None).ToSource(), |
+ ['#include <moo.h>']) |
+ |
+ def testIncludeWithPreambleToSource(self): |
+ self.assertEqual( |
+ add_header.Include('"moo.h"', 'include', ['//preamble'], |
+ None).ToSource(), ['// preamble' |
+ '#include "moo.h"']) |
+ |
+ def testIncludeWithPreambleToSource(self): |
+ self.assertEqual( |
+ add_header.Include('"moo.h"', 'include', [], |
+ ' inline comment').ToSource(), |
+ ['#include "moo.h" // inline comment']) |
+ |
+ def testIncludeWithPreambleAndInlineCommentToSource(self): |
+ # Make sure whitespace is vaguely normalized too. |
+ self.assertEqual( |
+ add_header.Include('"moo.h"', 'include', |
+ ['// preamble with trailing space ',], |
+ ' inline comment with trailing space ').ToSource(), |
+ ['// preamble with trailing space', |
+ '#include "moo.h" // inline comment with trailing space']) |
+ |
+ def testImportToSource(self): |
+ self.assertEqual( |
+ add_header.Include('"moo.h"', 'import', [], None).ToSource(), |
+ ['#import "moo.h"']) |
+ |
+ |
+class ParseIncludesTest(unittest.TestCase): |
+ |
+ def testInvalid(self): |
+ self.assertIsNone(add_header.ParseIncludes(['invalid'])) |
+ |
+ def testInclude(self): |
+ includes = add_header.ParseIncludes(['#include "moo.h"']) |
+ self.assertEqual(len(includes), 1) |
+ self.assertEqual(includes[0].decorated_name, '"moo.h"') |
+ self.assertEqual(includes[0].directive, 'include') |
+ self.assertEqual(includes[0].preamble, []) |
+ self.assertIsNone(includes[0].inline_comment) |
+ self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER) |
+ self.assertFalse(includes[0].is_primary_header) |
+ |
+ def testIncludeSurroundedByWhitespace(self): |
+ includes = add_header.ParseIncludes([' #include "moo.h" ']) |
+ self.assertEqual(len(includes), 1) |
+ self.assertEqual(includes[0].decorated_name, '"moo.h"') |
+ self.assertEqual(includes[0].directive, 'include') |
+ self.assertEqual(includes[0].preamble, []) |
+ self.assertIsNone(includes[0].inline_comment) |
+ self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER) |
+ self.assertFalse(includes[0].is_primary_header) |
+ |
+ def testImport(self): |
+ includes = add_header.ParseIncludes(['#import "moo.h"']) |
+ self.assertEqual(len(includes), 1) |
+ self.assertEqual(includes[0].decorated_name, '"moo.h"') |
+ self.assertEqual(includes[0].directive, 'import') |
+ self.assertEqual(includes[0].preamble, []) |
+ self.assertIsNone(includes[0].inline_comment) |
+ self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER) |
+ self.assertFalse(includes[0].is_primary_header) |
+ |
+ def testIncludeWithPreamble(self): |
+ includes = add_header.ParseIncludes(['// preamble comment ', |
+ '#include "moo.h"']) |
+ self.assertEqual(len(includes), 1) |
+ self.assertEqual(includes[0].decorated_name, '"moo.h"') |
+ self.assertEqual(includes[0].directive, 'include') |
+ self.assertEqual(includes[0].preamble, ['// preamble comment ']) |
+ self.assertIsNone(includes[0].inline_comment) |
+ self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER) |
+ self.assertFalse(includes[0].is_primary_header) |
+ |
+ def testIncludeWithInvalidPreamble(self): |
+ self.assertIsNone(add_header.ParseIncludes(['// orphan comment', '', |
+ '#include "moo.h"'])) |
+ |
+ def testIncludeWIthInlineComment(self): |
+ includes = add_header.ParseIncludes(['#include "moo.h"// For SFX ']) |
+ self.assertEqual(len(includes), 1) |
+ self.assertEqual(includes[0].decorated_name, '"moo.h"') |
+ self.assertEqual(includes[0].directive, 'include') |
+ self.assertEqual(includes[0].preamble, []) |
+ self.assertEqual(includes[0].inline_comment, ' For SFX ') |
+ self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER) |
+ self.assertFalse(includes[0].is_primary_header) |
+ |
+ def testIncludeWithInlineCommentAndPreamble(self): |
+ includes = add_header.ParseIncludes(['// preamble comment ', |
+ '#include "moo.h" // For SFX ']) |
+ self.assertEqual(len(includes), 1) |
+ self.assertEqual(includes[0].decorated_name, '"moo.h"') |
+ self.assertEqual(includes[0].directive, 'include') |
+ self.assertEqual(includes[0].preamble, ['// preamble comment ']) |
+ self.assertEqual(includes[0].inline_comment, ' For SFX ') |
+ self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_USER) |
+ self.assertFalse(includes[0].is_primary_header) |
+ |
+ def testMultipleIncludes(self): |
+ includes = add_header.ParseIncludes( |
+ ['#include <time.h>', '', '#include "moo.h" // For SFX ', |
+ '// TODO: Implement death ray.', '#import "goat.h"']) |
+ self.assertEqual(len(includes), 3) |
+ self.assertEqual(includes[0].decorated_name, '<time.h>') |
+ self.assertEqual(includes[0].directive, 'include') |
+ self.assertEqual(includes[0].preamble, []) |
+ self.assertIsNone(includes[0].inline_comment) |
+ self.assertEqual(includes[0].header_type, add_header._HEADER_TYPE_C_SYSTEM) |
+ self.assertFalse(includes[0].is_primary_header) |
+ self.assertEqual(includes[1].decorated_name, '"moo.h"') |
+ self.assertEqual(includes[1].directive, 'include') |
+ self.assertEqual(includes[1].preamble, []) |
+ self.assertEqual(includes[1].inline_comment, ' For SFX ') |
+ self.assertEqual(includes[1].header_type, add_header._HEADER_TYPE_USER) |
+ self.assertFalse(includes[1].is_primary_header) |
+ self.assertEqual(includes[2].decorated_name, '"goat.h"') |
+ self.assertEqual(includes[2].directive, 'import') |
+ self.assertEqual(includes[2].preamble, ['// TODO: Implement death ray.']) |
+ self.assertIsNone(includes[2].inline_comment) |
+ self.assertEqual(includes[2].header_type, add_header._HEADER_TYPE_USER) |
+ self.assertFalse(includes[2].is_primary_header) |
+ |
+ |
+class MarkPrimaryIncludeTest(unittest.TestCase): |
+ |
+ def extractPrimaryName(self, includes): |
+ for include in includes: |
+ if include.is_primary_header: |
+ return include.decorated_name |
+ |
+ def testNoOpOnHeader(self): |
+ includes = [add_header.Include('"cow.h"', 'include', [], None)] |
+ add_header.MarkPrimaryInclude(includes, 'cow.h') |
+ self.assertIsNone(self.extractPrimaryName(includes)) |
+ |
+ def testSystemHeaderNotMatched(self): |
+ includes = [add_header.Include('<cow.h>', 'include', [], None)] |
+ add_header.MarkPrimaryInclude(includes, 'cow.cc') |
+ self.assertIsNone(self.extractPrimaryName(includes)) |
+ |
+ def testExactMatch(self): |
+ includes = [ |
+ add_header.Include('"cow.h"', 'include', [], None), |
+ add_header.Include('"cow_posix.h"', 'include', [], None), |
+ ] |
+ add_header.MarkPrimaryInclude(includes, 'cow.cc') |
+ self.assertEqual(self.extractPrimaryName(includes), '"cow.h"') |
+ |
+ def testFuzzyMatch(self): |
+ includes = [add_header.Include('"cow.h"', 'include', [], None)] |
+ add_header.MarkPrimaryInclude(includes, 'cow_linux_unittest.cc') |
+ self.assertEqual(self.extractPrimaryName(includes), '"cow.h"') |
+ |
+ def testFuzzymatchInReverse(self): |
+ includes = [add_header.Include('"cow.h"', 'include', [], None)] |
+ add_header.MarkPrimaryInclude(includes, 'cow_uitest_aura.cc') |
+ self.assertEqual(self.extractPrimaryName(includes), '"cow.h"') |
+ |
+ def testFuzzyMatchDoesntMatchDifferentSuffixes(self): |
+ includes = [add_header.Include('"cow_posix.h"', 'include', [], None)] |
+ add_header.MarkPrimaryInclude(includes, 'cow_windows.cc') |
+ self.assertIsNone(self.extractPrimaryName(includes)) |
+ |
+ def testMarksMostSpecific(self): |
+ includes = [ |
+ add_header.Include('"cow.h"', 'include', [], None), |
+ add_header.Include('"cow_posix.h"', 'include', [], None), |
+ ] |
+ add_header.MarkPrimaryInclude(includes, 'cow_posix.cc') |
+ self.assertEqual(self.extractPrimaryName(includes), '"cow_posix.h"') |
+ |
+ def testFullPathMatch(self): |
+ includes = [add_header.Include('"zfs/impl/cow.h"', 'include', [], None)] |
+ add_header.MarkPrimaryInclude(includes, 'zfs/impl/cow.cc') |
+ self.assertEqual(self.extractPrimaryName(includes), '"zfs/impl/cow.h"') |
+ |
+ def testTopmostDirectoryDoesNotMatch(self): |
+ includes = [add_header.Include('"animal/impl/cow.h"', 'include', [], None)] |
+ add_header.MarkPrimaryInclude(includes, 'zfs/impl/cow.cc') |
+ self.assertIsNone(self.extractPrimaryName(includes)) |
+ |
+ def testSubstantiallySimilarPaths(self): |
+ includes = [add_header.Include('"farm/public/animal/cow.h"', 'include', [], |
+ None)] |
+ add_header.MarkPrimaryInclude(includes, 'farm/animal/cow.cc') |
+ self.assertEqual( |
+ self.extractPrimaryName(includes), '"farm/public/animal/cow.h"') |
+ |
+ def testNoMatchingSubdirectories(self): |
+ includes = [add_header.Include('"base/zfs/cow.h"', 'include', [], None)] |
+ add_header.MarkPrimaryInclude(includes, 'base/animal/cow.cc') |
+ self.assertIsNone(self.extractPrimaryName(includes)) |
+ |
+ |
+class SerializeIncludesTest(unittest.TestCase): |
+ |
+ def testSystemHeaders(self): |
+ source = add_header.SerializeIncludes([ |
+ add_header.Include('<stdlib.h>', 'include', [], None), |
+ add_header.Include('<map>', 'include', [], None), |
+ ]) |
+ self.assertEqual(source, ['#include <stdlib.h>', '', '#include <map>']) |
+ |
+ def testUserHeaders(self): |
+ source = add_header.SerializeIncludes([ |
+ add_header.Include('"goat.h"', 'include', [], None), |
+ add_header.Include('"moo.h"', 'include', [], None), |
+ ]) |
+ self.assertEqual(source, ['#include "goat.h"', '#include "moo.h"']) |
+ |
+ def testSystemAndUserHeaders(self): |
+ source = add_header.SerializeIncludes([ |
+ add_header.Include('<stdlib.h>', 'include', [], None), |
+ add_header.Include('<map>', 'include', [], None), |
+ add_header.Include('"moo.h"', 'include', [], None), |
+ ]) |
+ self.assertEqual(source, ['#include <stdlib.h>', '', '#include <map>', '', |
+ '#include "moo.h"']) |
+ |
+ def testPrimaryAndSystemHeaders(self): |
+ primary_header = add_header.Include('"cow.h"', 'include', [], None) |
+ primary_header.is_primary_header = True |
+ source = add_header.SerializeIncludes([ |
+ primary_header, |
+ add_header.Include('<stdlib.h>', 'include', [], None), |
+ add_header.Include('<map>', 'include', [], None), |
+ ]) |
+ self.assertEqual(source, [ |
+ '#include "cow.h"', '', '#include <stdlib.h>', '', '#include <map>' |
+ ]) |
+ |
+ def testPrimaryAndUserHeaders(self): |
+ primary_header = add_header.Include('"cow.h"', 'include', [], None) |
+ primary_header.is_primary_header = True |
+ source = add_header.SerializeIncludes([ |
+ primary_header, |
+ add_header.Include('"moo.h"', 'include', [], None), |
+ ]) |
+ self.assertEqual(source, ['#include "cow.h"', '', '#include "moo.h"']) |
+ |
+ def testPrimarySystemAndUserHeaders(self): |
+ primary_header = add_header.Include('"cow.h"', 'include', [], None) |
+ primary_header.is_primary_header = True |
+ source = add_header.SerializeIncludes([ |
+ primary_header, |
+ add_header.Include('<stdlib.h>', 'include', [], None), |
+ add_header.Include('<map>', 'include', [], None), |
+ add_header.Include('"moo.h"', 'include', [], None), |
+ ]) |
+ self.assertEqual(source, [ |
+ '#include "cow.h"', '', '#include <stdlib.h>', '', '#include <map>', '', |
+ '#include "moo.h"' |
+ ]) |
+ |
+ |
+class InsertHeaderIntoSourceTest(unittest.TestCase): |
+ |
+ def testAddInclude(self): |
+ source = add_header.InsertHeaderIntoSource('cow.cc', '\n'.join( |
+ ['// Copyright info here.', '', '#include <utility>', |
+ '// For cow speech synthesis.', |
+ '#include "moo.h" // TODO: Add Linux audio support.', |
+ '#include <time.h>', '#include "cow.h"', 'namespace bovine {', '', |
+ '// TODO: Implement.', '} // namespace bovine']), '<memory>') |
+ self.assertEqual( |
+ source, |
+ '\n'.join(['// Copyright info here.', '', '#include "cow.h"', '', |
+ '#include <time.h>', '', '#include <memory>', |
+ '#include <utility>', '', '// For cow speech synthesis.', |
+ '#include "moo.h" // TODO: Add Linux audio support.', |
+ 'namespace bovine {', '', '// TODO: Implement.', |
+ '} // namespace bovine', ''])) |
+ |
+ def testAlreadyIncluded(self): |
+ # To make sure the original source is returned unmodified, the input source |
+ # intentionally scrambles the #include order. |
+ source = '\n'.join([ |
+ '// Copyright info here.', '', '#include "moo.h"', '#include <utility>', |
+ '#include <memory>', '#include "cow.h"', 'namespace bovine {', '', |
+ '// TODO: Implement.', '} // namespace bovine' |
+ ]) |
+ self.assertEqual( |
+ add_header.InsertHeaderIntoSource('cow.cc', source, '<memory>'), source) |
+ |
+ def testConditionalIncludesLeftALone(self): |
+ # TODO(dcheng): Conditional header handling could probably be more clever. |
+ # But for the moment, this is probably Good Enough. |
+ source = add_header.InsertHeaderIntoSource( |
+ 'cow.cc', |
+ '\n'.join(['// Copyright info here.', '', '#include "cow.h"', |
+ '#include <utility>', '// For cow speech synthesis.', |
+ '#include "moo.h" // TODO: Add Linux audio support.', |
+ '#if defined(USE_AURA)' |
+ '#include <memory>', '#endif // defined(USE_AURA)']), |
+ '<memory>') |
+ self.assertEqual( |
+ source, |
+ '\n'.join(['// Copyright info here.', '', '#include "cow.h"', '', |
+ '#include <memory>', '#include <utility>', '', |
+ '// For cow speech synthesis.', |
+ '#include "moo.h" // TODO: Add Linux audio support.', |
+ '#if defined(USE_AURA)' |
+ '#include <memory>', '#endif // defined(USE_AURA)', ''])) |
+ |
+ |
+if __name__ == '__main__': |
+ unittest.main() |