diff --git a/tests/unit/test_documentation_consistency.py b/tests/unit/test_documentation_consistency.py index c5b9a77..3ddbc59 100644 --- a/tests/unit/test_documentation_consistency.py +++ b/tests/unit/test_documentation_consistency.py @@ -148,6 +148,7 @@ TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY = ( "test_training_m85_release_index_public_docs_acceptance_inventory_alignment_self_lock", "test_training_m86_release_index_final_closure_delivery_index_self_lock", "test_training_m87_release_index_final_closure_delivery_index_guard_self_lock", + "test_training_m88_release_index_final_closure_delivery_guard_source_self_lock", "test_training_m53_release_index_doc_category_coverage_is_exact", "test_training_case_product_doc_reflects_current_m40_maturity", ) @@ -713,6 +714,9 @@ class DocumentationConsistencyTests(unittest.TestCase): "release_index_final_closure_delivery_guard_self_lock": ( "test_training_m87_release_index_final_closure_delivery_index_guard_self_lock" ), + "release_index_final_closure_delivery_guard_source_self_lock": ( + "test_training_m88_release_index_final_closure_delivery_guard_source_self_lock" + ), "per_doc_helper_exact_category_coverage": ( "test_training_m53_release_index_doc_category_coverage_is_exact" ), @@ -895,6 +899,7 @@ class DocumentationConsistencyTests(unittest.TestCase): "test_training_m85_release_index_public_docs_acceptance_inventory_alignment_self_lock", "test_training_m86_release_index_final_closure_delivery_index_self_lock", "test_training_m87_release_index_final_closure_delivery_index_guard_self_lock", + "test_training_m88_release_index_final_closure_delivery_guard_source_self_lock", "test_training_m53_release_index_doc_category_coverage_is_exact", "test_training_case_product_doc_reflects_current_m40_maturity", ) @@ -3108,6 +3113,123 @@ class DocumentationConsistencyTests(unittest.TestCase): guard_name, ) + def test_training_m88_release_index_final_closure_delivery_guard_source_self_lock( + self, + ) -> None: + guard_name = ( + "test_training_m88_release_index_final_closure_delivery_guard_source_self_lock" + ) + guarded_method_name = ( + "test_training_m87_release_index_final_closure_delivery_index_guard_self_lock" + ) + final_closure_guard_name = ( + "test_training_m86_release_index_final_closure_delivery_index_self_lock" + ) + module_source = Path(__file__).read_text(encoding="utf-8") + module_tree = ast.parse(module_source) + test_case_name = f"{type(self).__module__}.{type(self).__qualname__}" + functions_by_name = { + node.name: node + for node in ast.walk(module_tree) + if isinstance(node, ast.FunctionDef) + } + + def local_assignment_node(method_name: str, local_name: str) -> ast.AST: + self.assertIn(method_name, functions_by_name) + assignments = tuple( + node.value + for node in ast.walk(functions_by_name[method_name]) + if ( + isinstance(node, ast.Assign) + and len(node.targets) == 1 + and isinstance(node.targets[0], ast.Name) + and node.targets[0].id == local_name + ) + ) + + self.assertEqual(len(assignments), 1) + return assignments[0] + + role_mapping = ast.literal_eval( + local_assignment_node( + "test_training_m41_release_index_guard_inventory_is_current", + "required_guard_tests_by_role", + ) + ) + role_methods = tuple(role_mapping.values()) + expected_inventory = ast.literal_eval( + local_assignment_node( + "test_training_m52_release_index_guard_inventory_order_and_uniqueness_self_lock", + "expected_inventory", + ) + ) + closure_methods = ast.literal_eval( + local_assignment_node(final_closure_guard_name, "closure_methods") + ) + delivery_methods = ( + *closure_methods, + final_closure_guard_name, + guarded_method_name, + guard_name, + ) + delivery_start = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index( + delivery_methods[0] + ) + guarded_delivery_node = local_assignment_node( + guarded_method_name, + "delivery_methods", + ) + + self.assertEqual( + ast.literal_eval(local_assignment_node(guarded_method_name, "guard_name")), + guarded_method_name, + ) + self.assertEqual( + ast.literal_eval( + local_assignment_node(guarded_method_name, "final_closure_guard_name") + ), + final_closure_guard_name, + ) + self.assertIsInstance(guarded_delivery_node, ast.Tuple) + self.assertEqual(len(guarded_delivery_node.elts), 2) + self.assertIsInstance(guarded_delivery_node.elts[0], ast.Starred) + self.assertIsInstance(guarded_delivery_node.elts[0].value, ast.Name) + self.assertEqual(guarded_delivery_node.elts[0].value.id, "closure_methods") + self.assertIsInstance(guarded_delivery_node.elts[1], ast.Name) + self.assertEqual( + guarded_delivery_node.elts[1].id, + "final_closure_guard_name", + ) + self.assertEqual( + TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[ + delivery_start : delivery_start + len(delivery_methods) + ], + delivery_methods, + ) + for method_name in delivery_methods: + with self.subTest(method_name=method_name): + self.assertEqual( + TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.count( + method_name + ), + 1, + ) + self.assertEqual(role_methods.count(method_name), 1) + self.assertEqual(expected_inventory.count(method_name), 1) + + loader = unittest.TestLoader() + suite = loader.loadTestsFromName(f"{test_case_name}.{method_name}") + + self.assertEqual(loader.errors, []) + self.assertEqual(suite.countTestCases(), 1) + + self.assertEqual( + role_mapping.get("release_index_final_closure_delivery_guard_source_self_lock"), + guard_name, + ) + self.assertEqual(CURRENT_TRAINING_DOC_MATURITY_MARKER, "M1-M40") + self.assertEqual(CURRENT_TRAINING_DOC_MATURITY_SPAN, "through M40") + def test_training_m47_release_index_per_doc_helper_inventory_self_lock_is_current(self) -> None: helper_name = "_release_index_missing_required_snippets_by_doc" docs_guard_name = "test_training_readmes_expose_m1_m40_release_index_without_raw_test_modules"