1#!/usr/bin/env python3 2# Copyright 2016 Google Inc. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS-IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16from absl.testing import parameterized 17from fruit_test_common import * 18 19class TestDefnHIncludes(parameterized.TestCase): 20 def test_defn_file_inclusion(self): 21 if os.sep != '/': 22 # This only works in platforms where paths are /-separated. 23 return 24 include_pattern = re.compile(' *#include *<(.*)> *') 25 26 fruit_headers_root_absolute_path = os.path.abspath(PATH_TO_FRUIT_STATIC_HEADERS) 27 28 includes = {} 29 for root, _, files in os.walk(fruit_headers_root_absolute_path): 30 for file in files: 31 if file.endswith('.h'): 32 path = os.path.join(root, file) 33 with open(path, 'r') as f: 34 current_includes = set() 35 for line in f.readlines(): 36 # Remove the newline 37 line = line[:-1] 38 matches = re.match(include_pattern, line) 39 if matches: 40 current_includes.add(matches.groups()[0]) 41 root_relative_path = root.replace(fruit_headers_root_absolute_path, '') 42 relative_path = os.path.join(root_relative_path, file) 43 if relative_path.startswith(os.sep): 44 relative_path = relative_path[1:] 45 includes[relative_path] = current_includes 46 47 for defn_file, defn_file_includes in includes.items(): 48 if defn_file.endswith('.defn.h'): 49 main_header_file = defn_file.replace('.defn.h', '.h') 50 # This is a special case where we don't follow the convention, so we need to specify the corresponding main 51 # header file explicitly. 52 if defn_file == 'fruit/impl/component_functors.defn.h': 53 main_header_file = 'fruit/component.h' 54 55 # The .defn.h files for headers in fruit/ are in fruit/impl/ 56 alternative_main_header_file = main_header_file.replace('fruit/impl/', 'fruit/') 57 58 if main_header_file not in includes and alternative_main_header_file not in includes: 59 raise Exception('Can\'t find the .h header corresponding to: %s. Considered: %s' % (defn_file, (main_header_file, alternative_main_header_file))) 60 if main_header_file not in defn_file_includes and alternative_main_header_file not in defn_file_includes: 61 raise Exception('%s should have included %s, but it includes only: %s' % (defn_file, main_header_file, defn_file_includes)) 62 if main_header_file in includes and defn_file not in includes[main_header_file]: 63 raise Exception('%s should have included %s, but it includes only: %s' % (main_header_file, defn_file, includes[main_header_file])) 64 if alternative_main_header_file in includes and defn_file not in includes[alternative_main_header_file]: 65 raise Exception('%s should have included %s, but it includes only: %s' % (main_header_file, defn_file, includes[alternative_main_header_file])) 66 for other_header, other_header_includes in includes.items(): 67 if other_header not in (main_header_file, alternative_main_header_file) and defn_file in other_header_includes: 68 raise Exception('Unexpected direct include: %s includes %s' % (other_header, defn_file)) 69 70if __name__ == '__main__': 71 absltest.main() 72