diff --git a/tests/unit/test_documentation_consistency.py b/tests/unit/test_documentation_consistency.py index 53acfa1..16a74e1 100644 --- a/tests/unit/test_documentation_consistency.py +++ b/tests/unit/test_documentation_consistency.py @@ -134,6 +134,7 @@ TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY = ( "test_training_m71_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_source_shape_self_lock", "test_training_m72_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_rejects_dynamic_sources", "test_training_m73_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostics_are_locked", + "test_training_m74_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_self_lock", "test_training_m53_release_index_doc_category_coverage_is_exact", "test_training_case_product_doc_reflects_current_m40_maturity", ) @@ -643,6 +644,9 @@ class DocumentationConsistencyTests(unittest.TestCase): "required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostics": ( "test_training_m73_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostics_are_locked" ), + "required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostic_fixture_inventory": ( + "test_training_m74_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_self_lock" + ), "per_doc_helper_exact_category_coverage": ( "test_training_m53_release_index_doc_category_coverage_is_exact" ), @@ -811,6 +815,7 @@ class DocumentationConsistencyTests(unittest.TestCase): "test_training_m71_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_source_shape_self_lock", "test_training_m72_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_rejects_dynamic_sources", "test_training_m73_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostics_are_locked", + "test_training_m74_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_self_lock", "test_training_m53_release_index_doc_category_coverage_is_exact", "test_training_case_product_doc_reflects_current_m40_maturity", ) @@ -1553,6 +1558,106 @@ class DocumentationConsistencyTests(unittest.TestCase): source ) + def test_training_m74_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_self_lock( + self, + ) -> None: + guard_name = ( + "test_training_m74_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_self_lock" + ) + m73_guard_name = ( + "test_training_m73_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostics_are_locked" + ) + expected_fixture_diagnostics = ( + ("missing_assignment", "must have one assignment"), + ("duplicate_top_level_assignment", "must have one assignment"), + ("multiple_assignment_targets", "must use one simple assignment"), + ( + "empty_tuple", + "must be a literal triplet tuple assignment", + ), + ( + "two_item_tuple", + "must be a literal triplet tuple assignment", + ), + ( + "four_item_tuple", + "must be a literal triplet tuple assignment", + ), + ("integer_literal_method_name", "must use literal method names"), + ("none_literal_method_name", "must use literal method names"), + ) + allowed_diagnostic_snippets = ( + "must have one assignment", + "must use one simple assignment", + "must be a literal triplet tuple assignment", + "must use literal method names", + ) + module_source = Path(__file__).read_text(encoding="utf-8") + module_tree = ast.parse(module_source) + m73_methods = tuple( + node + for node in ast.walk(module_tree) + if isinstance(node, ast.FunctionDef) and node.name == m73_guard_name + ) + + self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY) + self.assertEqual(len(m73_methods), 1) + m73_method = m73_methods[0] + invalid_source_assignments = tuple( + node + for node in ast.walk(m73_method) + if ( + isinstance(node, ast.Assign) + and len(node.targets) == 1 + and isinstance(node.targets[0], ast.Name) + and node.targets[0].id == "invalid_sources" + ) + ) + + self.assertEqual(len(invalid_source_assignments), 1) + invalid_sources = invalid_source_assignments[0].value + self.assertIsInstance(invalid_sources, ast.Dict) + fixture_diagnostics = tuple( + (fixture_key.value, fixture_value.elts[1].value) + for fixture_key, fixture_value in zip( + invalid_sources.keys, + invalid_sources.values, + ) + ) + + fixture_names = tuple(name for name, _ in fixture_diagnostics) + self.assertEqual(fixture_diagnostics, expected_fixture_diagnostics) + self.assertEqual(len(fixture_names), len(set(fixture_names))) + for fixture_name, diagnostic_snippet in fixture_diagnostics: + with self.subTest(fixture_name=fixture_name): + self.assertTrue(diagnostic_snippet) + self.assertIn(diagnostic_snippet, allowed_diagnostic_snippets) + + invalid_source_loops = tuple( + node + for node in ast.walk(m73_method) + if ( + isinstance(node, ast.For) + and isinstance(node.iter, ast.Call) + and isinstance(node.iter.func, ast.Attribute) + and node.iter.func.attr == "items" + and isinstance(node.iter.func.value, ast.Name) + and node.iter.func.value.id == "invalid_sources" + ) + ) + self.assertEqual(len(invalid_source_loops), 1) + invalid_source_loop = ( + ast.get_source_segment(module_source, invalid_source_loops[0]) + or "" + ) + for loop_reference in ( + "fixture_name, (source, error_snippet)", + "self.subTest(fixture_name=fixture_name)", + "_release_index_exactness_bridge_guard_method_names_from_source", + ): + with self.subTest(loop_reference=loop_reference): + self.assertIn(loop_reference, invalid_source_loop) + 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"