1import unittest 2from os import sys, path 3 4is_standalone = __name__ == '__main__' and __package__ is None 5if is_standalone: 6 sys.path.append(path.abspath(path.join(path.dirname(__file__), ".."))) 7 from ccompiler_opt import CCompilerOpt 8else: 9 from numpy.distutils.ccompiler_opt import CCompilerOpt 10 11arch_compilers = dict( 12 x86 = ("gcc", "clang", "icc", "iccw", "msvc"), 13 x64 = ("gcc", "clang", "icc", "iccw", "msvc"), 14 ppc64 = ("gcc", "clang"), 15 ppc64le = ("gcc", "clang"), 16 armhf = ("gcc", "clang"), 17 aarch64 = ("gcc", "clang"), 18 narch = ("gcc",) 19) 20 21class FakeCCompilerOpt(CCompilerOpt): 22 fake_info = ("arch", "compiler", "extra_args") 23 def __init__(self, *args, **kwargs): 24 CCompilerOpt.__init__(self, None, **kwargs) 25 def dist_compile(self, sources, flags, **kwargs): 26 return sources 27 def dist_info(self): 28 return FakeCCompilerOpt.fake_info 29 @staticmethod 30 def dist_log(*args, stderr=False): 31 pass 32 33class _TestConfFeatures(FakeCCompilerOpt): 34 """A hook to check the sanity of configured features 35- before it called by the abstract class '_Feature' 36 """ 37 38 def conf_features_partial(self): 39 conf_all = self.conf_features 40 for feature_name, feature in conf_all.items(): 41 self.test_feature( 42 "attribute conf_features", 43 conf_all, feature_name, feature 44 ) 45 46 conf_partial = FakeCCompilerOpt.conf_features_partial(self) 47 for feature_name, feature in conf_partial.items(): 48 self.test_feature( 49 "conf_features_partial()", 50 conf_partial, feature_name, feature 51 ) 52 return conf_partial 53 54 def test_feature(self, log, search_in, feature_name, feature_dict): 55 error_msg = ( 56 "during validate '{}' within feature '{}', " 57 "march '{}' and compiler '{}'\n>> " 58 ).format(log, feature_name, self.cc_march, self.cc_name) 59 60 if not feature_name.isupper(): 61 raise AssertionError(error_msg + "feature name must be in uppercase") 62 63 for option, val in feature_dict.items(): 64 self.test_option_types(error_msg, option, val) 65 self.test_duplicates(error_msg, option, val) 66 67 self.test_implies(error_msg, search_in, feature_name, feature_dict) 68 self.test_group(error_msg, search_in, feature_name, feature_dict) 69 self.test_extra_checks(error_msg, search_in, feature_name, feature_dict) 70 71 def test_option_types(self, error_msg, option, val): 72 for tp, available in ( 73 ((str, list), ( 74 "implies", "headers", "flags", "group", "detect", "extra_checks" 75 )), 76 ((str,), ("disable",)), 77 ((int,), ("interest",)), 78 ((bool,), ("implies_detect",)), 79 ((bool, type(None)), ("autovec",)), 80 ) : 81 found_it = option in available 82 if not found_it: 83 continue 84 if not isinstance(val, tp): 85 error_tp = [t.__name__ for t in (*tp,)] 86 error_tp = ' or '.join(error_tp) 87 raise AssertionError(error_msg + 88 "expected '%s' type for option '%s' not '%s'" % ( 89 error_tp, option, type(val).__name__ 90 )) 91 break 92 93 if not found_it: 94 raise AssertionError(error_msg + "invalid option name '%s'" % option) 95 96 def test_duplicates(self, error_msg, option, val): 97 if option not in ( 98 "implies", "headers", "flags", "group", "detect", "extra_checks" 99 ) : return 100 101 if isinstance(val, str): 102 val = val.split() 103 104 if len(val) != len(set(val)): 105 raise AssertionError(error_msg + "duplicated values in option '%s'" % option) 106 107 def test_implies(self, error_msg, search_in, feature_name, feature_dict): 108 if feature_dict.get("disabled") is not None: 109 return 110 implies = feature_dict.get("implies", "") 111 if not implies: 112 return 113 if isinstance(implies, str): 114 implies = implies.split() 115 116 if feature_name in implies: 117 raise AssertionError(error_msg + "feature implies itself") 118 119 for impl in implies: 120 impl_dict = search_in.get(impl) 121 if impl_dict is not None: 122 if "disable" in impl_dict: 123 raise AssertionError(error_msg + "implies disabled feature '%s'" % impl) 124 continue 125 raise AssertionError(error_msg + "implies non-exist feature '%s'" % impl) 126 127 def test_group(self, error_msg, search_in, feature_name, feature_dict): 128 if feature_dict.get("disabled") is not None: 129 return 130 group = feature_dict.get("group", "") 131 if not group: 132 return 133 if isinstance(group, str): 134 group = group.split() 135 136 for f in group: 137 impl_dict = search_in.get(f) 138 if not impl_dict or "disable" in impl_dict: 139 continue 140 raise AssertionError(error_msg + 141 "in option 'group', '%s' already exists as a feature name" % f 142 ) 143 144 def test_extra_checks(self, error_msg, search_in, feature_name, feature_dict): 145 if feature_dict.get("disabled") is not None: 146 return 147 extra_checks = feature_dict.get("extra_checks", "") 148 if not extra_checks: 149 return 150 if isinstance(extra_checks, str): 151 extra_checks = extra_checks.split() 152 153 for f in extra_checks: 154 impl_dict = search_in.get(f) 155 if not impl_dict or "disable" in impl_dict: 156 continue 157 raise AssertionError(error_msg + 158 "in option 'extra_checks', extra test case '%s' already exists as a feature name" % f 159 ) 160 161class TestConfFeatures(unittest.TestCase): 162 def __init__(self, methodName="runTest"): 163 unittest.TestCase.__init__(self, methodName) 164 self.setup() 165 166 def setup(self): 167 FakeCCompilerOpt.conf_nocache = True 168 169 def test_features(self): 170 for arch, compilers in arch_compilers.items(): 171 for cc in compilers: 172 FakeCCompilerOpt.fake_info = (arch, cc, "") 173 _TestConfFeatures() 174 175if is_standalone: 176 unittest.main() 177