def test_not_passing_rules_with_import_from() -> None: """ Test result with a set rules that accept files. """ # Given dep_rules = { "module": [ModuleWildcard("module%"), ModuleWildcard("amodule.submodule")] } configuration = Configuration(dep_rules) source_file = SourceFile( Module("module"), SourceCode("from amodule import othermodule, submodule\n") ) report_printer = Mock() use_case = CheckDependenciesUC( configuration, report_printer, PARSER, iter([source_file]) ) # When with pytest.raises(ForbiddenDepencyError): use_case.run() # Then assert set(report_printer.print_report.call_args[0][0]) == set( ( DependencyError( Module("module"), Module("amodule.othermodule"), tuple(sorted(dep_rules["module"])), ), ) )
def test_passing_rules(source_files) -> None: """ Test result with a set rules that accept files. """ # Given configuration = Configuration( dependency_rules={ SIMPLE_FILE.module: [ModuleWildcard("module%"), ModuleWildcard("amodule")], "amodule.*": [ ModuleWildcard("module"), ModuleWildcard("module.inside.*"), ModuleWildcard("amodule%"), ], }) report_printer = Mock() use_case = CheckDependenciesUC(configuration, report_printer, PARSER, source_files) # When use_case.run() # Then report_printer.print_report.assert_called_with([], set(), 3)
def _get_rules(self, module: Module) -> Rules: """ Return rules in configuration that match a given module. """ matching_rules: Rules = set() for module_wildcard, rules in self.configuration.dependency_rules.items( ): if re.match( "{}$".format( self.parser.wildcard_to_regex( ModuleWildcard(module_wildcard))), module, ): matching_rules.update( (ModuleWildcard(module_wildcard), r) for r in rules) return matching_rules
def wildcard_to_regex(self, module: ModuleWildcard) -> str: """ Return a regex expression for the Module from wildcard """ module_regex = module.replace(".", "\\.").replace("*", ".*") module_regex = module_regex.replace("[!", "[^").replace("?", ".?") # Special char including a module along with all its sub-modules: module_regex = module_regex.replace("%", r"(\..*)?$") return module_regex
def test_passing_case() -> None: """ Test a passing case. """ # Given dependency = Dependency(Module("toto")) rules: Rules = [ (ModuleWildcard("toto"), ModuleWildcard("to*")), (ModuleWildcard("toto"), ModuleWildcard("titi.tata")), ] # When error = None try: check_dependency(PARSER, dependency, rules) except NotAllowedDependencyException as exception: error = exception # Then assert not error
def test_passing_rules_with_import_from() -> None: """ Test result with a set rules that accept files. """ # Given configuration = Configuration( dependency_rules={ "module": [ModuleWildcard("module%"), ModuleWildcard("amodule.submodule")] } ) source_file = SourceFile("module", SourceCode("from amodule import submodule")) report_printer = Mock() use_case = CheckDependenciesUC( configuration, report_printer, PARSER, iter([source_file]) ) # When use_case.run() # Then assert report_printer.print_report.call_args[0][0] == []
def test_empty() -> None: """ Test empty case. """ # Given module = ModuleWildcard("") # When regex = PARSER.wildcard_to_regex(module) # Then assert regex == ""
def test_simple_module() -> None: """ Test simple case. """ # Given module = ModuleWildcard("toto") # When regex = PARSER.wildcard_to_regex(module) # Then assert re.match(regex, "toto") assert not re.match(regex, "tata") assert not re.match(regex, "titi.toto")
def test_percentage() -> None: """ Test percentage case """ # Given module = ModuleWildcard("toto.tata%") # When regex = PARSER.wildcard_to_regex(module) # Then assert re.match(regex, "toto.tata") assert re.match(regex, "toto.tata.titi") assert re.match(regex, "toto.tata.titi.tutu.tototata.tititutu") assert not re.match(regex, "toto") assert not re.match(regex, "toto.tata_123")
def test_nominal(source_files) -> None: """ Test result with a set source files. """ # Given dependencies_writer = Mock() use_case = BuildConfigurationUC(dependencies_writer, PARSER, source_files, "python") # When use_case.run() # Then dependencies_writer.write.assert_called() # type: ignore configuration = dependencies_writer.write.call_args[0][0] assert not configuration.local_init dependency_rules = { module_regex: set(rules) for module_regex, rules in configuration.dependency_rules.items() } assert dependency_rules == { "simple_module": set( ( ModuleWildcard("module"), ModuleWildcard("module.inside.module"), ModuleWildcard("amodule"), ) ), "amodule.local_module": set( ( ModuleWildcard("module"), ModuleWildcard("module.inside.module"), ModuleWildcard("amodule"), ModuleWildcard("amodule.inside"), ) ), "amodule.std_module": set( (ModuleWildcard("module"), ModuleWildcard("module.inside.module")) ), }
def test_asterisk() -> None: """ Test asterisk case """ # Given module = ModuleWildcard("toto*.*") # When regex = PARSER.wildcard_to_regex(module) # Then assert re.match(regex, "toto.tata") assert re.match(regex, "toto_2351.titi") assert re.match(regex, "toto_azerty.titi.toto.tata") assert not re.match(regex, "toto") assert not re.match(regex, "tototata") assert not re.match(regex, "toti.toto")
def test_quesiton_mark() -> None: """ Test question mark case """ # Given module = ModuleWildcard("t?to.?at?") # When regex = PARSER.wildcard_to_regex(module) # Then assert re.match(regex, "toto.tata") assert re.match(regex, "t2to.bato") assert re.match(regex, "t#to.!at&") assert not re.match(regex, "toto") assert not re.match(regex, "tata") assert not re.match(regex, "toti.toto")
def test_not_passing_rules(source_files) -> None: """ Test result with a set rules that not accept files. """ # Given dep_rules = { "simple_module": [ModuleWildcard("module.*"), ModuleWildcard("amodule")], "amodule.local_module": [ ModuleWildcard("module"), ModuleWildcard("module.inside.*"), ModuleWildcard("amod"), ], "amodule.std_module": [ModuleWildcard("mod")], } configuration = Configuration(dependency_rules=dep_rules) report_printer = Mock() use_case = CheckDependenciesUC(configuration, report_printer, PARSER, source_files) # When with pytest.raises(ForbiddenDepencyError): use_case.run() # Then simple = SIMPLE_FILE.module local = FILE_WITH_LOCAL_IMPORT.module std = FILE_WITH_STD_IMPORT.module assert set(report_printer.print_report.call_args[0][0]) == set( ( DependencyError( simple, Module("module"), tuple(sorted(dep_rules["simple_module"])) ), DependencyError( local, Module("amodule.aclass"), tuple(sorted(dep_rules["amodule.local_module"])), ), DependencyError( local, Module("amodule.inside.aclass"), tuple(sorted(dep_rules["amodule.local_module"])), ), DependencyError( std, Module("module"), tuple(sorted(dep_rules["amodule.std_module"])) ), DependencyError( std, Module("module.inside.module"), tuple(sorted(dep_rules["amodule.std_module"])), ), ) )
def run(self) -> None: """ Build configuration from existing source files. """ global_dependencies: Dict[Module, Dependencies] = {} for source_file in self.source_files: dependencies = get_dependencies(source_file, self.parser) dependencies = self.std_lib_filter.filter(dependencies) global_dependencies[source_file.module] = dependencies dependency_rules = {} for module, dependencies in global_dependencies.items(): dependency_rules[str(module)] = [ ModuleWildcard(dependency.main_import) for dependency in dependencies ] self.printer.write(Configuration(dependency_rules))
def run(self) -> None: errors = [] nb_files = 0 for source_file in self.source_files: nb_files += 1 for error in self._iter_error(source_file): errors.append(error) all_rules: Rules = set( (ModuleWildcard(wildcard), rule) for wildcard, rules in self.configuration.dependency_rules.items() for rule in rules) unused = all_rules.difference(self.used_rules) self.report_printer.print_report(errors, unused, nb_files) if self.configuration.error_on_unused and unused: raise ForbiddenUnusedRuleError if errors: raise ForbiddenDepencyError
def test_not_passing_case() -> None: """ Test a not passing case. """ # Given dependency = Dependency(Module("toto.tata")) rules: Rules = [ (ModuleWildcard("toto.*"), ModuleWildcard("toto")), (ModuleWildcard("toto.*"), ModuleWildcard("te.*")), (ModuleWildcard("toto.*"), ModuleWildcard("titi\\.tata")), ] # When with raises(NotAllowedDependencyException) as error: check_dependency(PARSER, dependency, rules) # Then assert error assert error.value.dependency == dependency.main_import assert error.value.authorized_modules == [r for _, r in rules]
def test_error_on_unused(source_files) -> None: """ Test result with a set rules that accept files. """ # Given configuration = Configuration( dependency_rules={ SIMPLE_FILE.module: [ModuleWildcard("module%"), ModuleWildcard("amodule")], "amodule.*": [ ModuleWildcard("module"), ModuleWildcard("module.inside.*"), ModuleWildcard("amodule%"), ModuleWildcard("unused%"), ], "unused_wildcard.*": [ModuleWildcard("unused%")], }, error_on_unused=True, ) report_printer = Mock() use_case = CheckDependenciesUC(configuration, report_printer, PARSER, source_files) # When with pytest.raises(ForbiddenUnusedRuleError): use_case.run() # Then report_printer.print_report.assert_called_with( [], { (ModuleWildcard("amodule.*"), ModuleWildcard("unused%")), (ModuleWildcard("unused_wildcard.*"), ModuleWildcard("unused%")), }, 3, )