def _configure( self, contracts_options: List[Dict[str, Any]], contract_types: Optional[List[str]] = None, graph: Optional[ImportGraph] = None, ): session_options = {"root_package": "mypackage"} if not contract_types: contract_types = [ "always_passes: tests.helpers.contracts.AlwaysPassesContract", "always_fails: tests.helpers.contracts.AlwaysFailsContract", "fields: tests.helpers.contracts.FieldsContract", "forbidden: tests.helpers.contracts.ForbiddenImportContract", ] session_options["contract_types"] = contract_types # type: ignore reader = FakeUserOptionReader( UserOptions(session_options=session_options, contracts_options=contracts_options)) settings.configure(USER_OPTION_READERS=[reader], GRAPH_BUILDER=FakeGraphBuilder(), PRINTER=FakePrinter()) if graph is None: graph = self._build_default_graph() settings.GRAPH_BUILDER.inject_graph(graph)
def test_debug_mode_doesnt_swallow_exception(self): some_exception = RuntimeError("There was some sort of exception.") reader = ExceptionRaisingUserOptionReader(exception=some_exception) settings.configure( USER_OPTION_READERS=[reader], GRAPH_BUILDER=FakeGraphBuilder(), PRINTER=FakePrinter() ) with pytest.raises(some_exception.__class__, match=str(some_exception)): lint_imports(is_debug_mode=True)
def test_builder_is_called_with_root_packages(self): builder = FakeGraphBuilder() root_package_names = ["mypackageone", "mypackagetwo"] settings.configure(GRAPH_BUILDER=builder, PRINTER=FakePrinter()) create_report( UserOptions(session_options={"root_packages": root_package_names}, contracts_options=[])) assert builder.build_arguments[ "root_package_names"] == root_package_names
def test_non_debug_mode_prints_exception(self): some_exception = RuntimeError("There was some sort of exception.") reader = ExceptionRaisingUserOptionReader(exception=some_exception) settings.configure( USER_OPTION_READERS=[reader], GRAPH_BUILDER=FakeGraphBuilder(), PRINTER=FakePrinter() ) lint_imports(is_debug_mode=False) settings.PRINTER.pop_and_assert( """There was some sort of exception. """ )
def test_graph_can_be_mutated_without_affecting_other_contracts(self): # The MutationCheckContract checks that there are a certain number of modules and imports # in the graph, then adds one more module and one more import. We can check two such # contracts and the second one will fail, if the graph gets mutated by other contracts. session_options = { "root_package": "mypackage", "contract_types": ["mutation_check: tests.helpers.contracts.MutationCheckContract"], } reader = FakeUserOptionReader( UserOptions( session_options=session_options, contracts_options=[ { "type": "mutation_check", "name": "Contract one", "number_of_modules": "5", "number_of_imports": "2", }, { "type": "mutation_check", "name": "Contract two", "number_of_modules": "5", "number_of_imports": "2", }, ], ) ) settings.configure( USER_OPTION_READERS=[reader], GRAPH_BUILDER=FakeGraphBuilder(), PRINTER=FakePrinter() ) graph = ImportGraph() # Create a graph with five modules and two imports. for module in ("one", "two", "three", "four", "five"): graph.add_module(module) graph.add_import(importer="one", imported="two") graph.add_import(importer="one", imported="three") settings.GRAPH_BUILDER.inject_graph(graph) result = lint_imports(is_debug_mode=True) assert result == SUCCESS
def test_render_broken_contract(): settings.configure(PRINTER=FakePrinter()) contract = ForbiddenContract( name="Forbid contract", session_options={"root_packages": ["mypackage"]}, contract_options={ "source_modules": ("mypackage.one", "mypackage.two", "mypackage.three"), "forbidden_modules": ( "mypackage.blue", "mypackage.green", "mypackage.yellow", "mypackage.purple", ), }, ) check = ContractCheck( kept=False, metadata={ "invalid_chains": [ { "upstream_module": "mypackage.purple", "downstream_module": "mypackage.two", "chains": [[ { "importer": "mypackage.two", "imported": "mypackage.utils", "line_numbers": (9, ), }, { "importer": "mypackage.utils", "imported": "mypackage.purple", "line_numbers": (1, ), }, ]], }, { "upstream_module": "mypackage.green", "downstream_module": "mypackage.three", "chains": [[{ "importer": "mypackage.three", "imported": "mypackage.green", "line_numbers": (4, ), }]], }, ] }, ) contract.render_broken_contract(check) settings.PRINTER.pop_and_assert(""" mypackage.two is not allowed to import mypackage.purple: - mypackage.two -> mypackage.utils (l.9) mypackage.utils -> mypackage.purple (l.1) mypackage.three is not allowed to import mypackage.green: - mypackage.three -> mypackage.green (l.4) """)
def test_render_broken_contract(): settings.configure(PRINTER=FakePrinter()) contract = LayersContract( name="Layers contract", session_options={"root_packages": ["mypackage"]}, contract_options={"containers": ["mypackage"], "layers": ["high", "medium", "low"]}, ) check = ContractCheck( kept=False, metadata={ "invalid_chains": [ { "higher_layer": "mypackage.high", "lower_layer": "mypackage.low", "chains": [ [ { "importer": "mypackage.low.blue", "imported": "mypackage.utils.red", "line_numbers": (8, 16), }, { "importer": "mypackage.utils.red", "imported": "mypackage.utils.yellow", "line_numbers": (1,), }, { "importer": "mypackage.utils.yellow", "imported": "mypackage.high.green", "line_numbers": (3,), }, ], [ { "importer": "mypackage.low.purple", "imported": "mypackage.high.brown", "line_numbers": (9,), } ], ], }, { "higher_layer": "mypackage.medium", "lower_layer": "mypackage.low", "chains": [ [ { "importer": "mypackage.low.blue", "imported": "mypackage.medium.yellow", "line_numbers": (6,), } ] ], }, { "higher_layer": "mypackage.high", "lower_layer": "mypackage.medium", "chains": [ [ { "importer": "mypackage.medium", "imported": "mypackage.high.cyan.alpha", "line_numbers": (2,), } ] ], }, ] }, ) contract.render_broken_contract(check) settings.PRINTER.pop_and_assert( """ mypackage.low is not allowed to import mypackage.high: - mypackage.low.blue -> mypackage.utils.red (l.8, l.16) mypackage.utils.red -> mypackage.utils.yellow (l.1) mypackage.utils.yellow -> mypackage.high.green (l.3) - mypackage.low.purple -> mypackage.high.brown (l.9) mypackage.low is not allowed to import mypackage.medium: - mypackage.low.blue -> mypackage.medium.yellow (l.6) mypackage.medium is not allowed to import mypackage.high: - mypackage.medium -> mypackage.high.cyan.alpha (l.2) """ )
def test_render_broken_contract(): settings.configure(PRINTER=FakePrinter()) contract = IndependenceContract( name="Independence contract", session_options={"root_packages": ["mypackage"]}, contract_options={ "modules": ["mypackage.blue", "mypackage.green", "mypackage.yellow"] }, ) check = ContractCheck( kept=False, metadata={ "invalid_chains": [ { "upstream_module": "mypackage.yellow", "downstream_module": "mypackage.blue", "chains": [ [ { "importer": "mypackage.blue.foo", "imported": "mypackage.utils.red", "line_numbers": (16, 102), }, { "importer": "mypackage.utils.red", "imported": "mypackage.utils.brown", "line_numbers": (1, ), }, { "importer": "mypackage.utils.brown", "imported": "mypackage.yellow.bar", "line_numbers": (3, ), }, ], [{ "importer": "mypackage.blue.bar", "imported": "mypackage.yellow.baz", "line_numbers": (5, ), }], ], }, { "upstream_module": "mypackage.green", "downstream_module": "mypackage.yellow", "chains": [[{ "importer": "mypackage.yellow.foo", "imported": "mypackage.green.bar", "line_numbers": (15, ), }]], }, ] }, ) contract.render_broken_contract(check) settings.PRINTER.pop_and_assert(""" mypackage.blue is not allowed to import mypackage.yellow: - mypackage.blue.foo -> mypackage.utils.red (l.16, l.102) mypackage.utils.red -> mypackage.utils.brown (l.1) mypackage.utils.brown -> mypackage.yellow.bar (l.3) - mypackage.blue.bar -> mypackage.yellow.baz (l.5) mypackage.yellow is not allowed to import mypackage.green: - mypackage.yellow.foo -> mypackage.green.bar (l.15) """)