4524 lines
202 KiB
Python
4524 lines
202 KiB
Python
import ast
|
|
import re
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
PROJECT_README = ROOT / "README.md"
|
|
TRAINING_PRODUCT_DOC = ROOT / "docs" / "training_case_engine_m1_m6_product_readme.md"
|
|
TRAINING_PACKAGE_SMOKE_DOC = ROOT / "docs" / "examples" / "training_case_package_smoke_m6.md"
|
|
TRAINING_DOCS_CLI_TEST = ROOT / "tests" / "unit" / "test_training_case_docs_cli_m10.py"
|
|
TRAINING_DASHBOARD_HTML = ROOT / "src" / "web" / "index.html"
|
|
TRAINING_DASHBOARD_APP = ROOT / "src" / "web" / "app.js"
|
|
API_SERVER = ROOT / "src" / "api" / "server.py"
|
|
OFFLINE_CHECKS_SCRIPT = ROOT / "scripts" / "run_offline_checks.py"
|
|
CURRENT_TRAINING_DOC_MATURITY_END = 40
|
|
CURRENT_TRAINING_DOC_MATURITY_MARKER = f"M1-M{CURRENT_TRAINING_DOC_MATURITY_END}"
|
|
CURRENT_TRAINING_DOC_MATURITY_SPAN = f"through M{CURRENT_TRAINING_DOC_MATURITY_END}"
|
|
CURRENT_TRAINING_DOC_MATURITY_PHRASE = (
|
|
f"current product maturity {CURRENT_TRAINING_DOC_MATURITY_SPAN}"
|
|
)
|
|
TRAINING_M24_M29_DOCUMENTATION_TEST_INVENTORY = {
|
|
"m1_m40_maturity_wording": (
|
|
"test_training_case_product_doc_reflects_current_m40_maturity",
|
|
),
|
|
"route_surface": (
|
|
"test_training_case_product_doc_api_routes_match_server_route_request",
|
|
"test_training_case_public_route_registry_is_documented_and_supported",
|
|
"test_training_case_product_doc_api_surface_wording_matches_public_routes",
|
|
"test_training_dashboard_routes_are_documented_public_api_routes",
|
|
),
|
|
"dashboard_public_docs_privacy": (
|
|
"test_training_readmes_name_dashboard_privacy_and_offline_registry_coverage",
|
|
"test_training_dashboard_and_public_docs_keep_privacy_wording_exclusionary",
|
|
),
|
|
"offline_registry_coverage": (
|
|
"test_training_readmes_name_dashboard_privacy_and_offline_registry_coverage",
|
|
),
|
|
}
|
|
TRAINING_M24_M29_PACKAGE_DOCS_INVENTORY_TEST = (
|
|
"test_m24_m29_package_docs_privacy_test_inventory_is_current"
|
|
)
|
|
TRAINING_CASE_ACCEPTANCE_TEST_MANIFEST = (
|
|
"test_training_case_engine_m1",
|
|
"test_training_api_m2",
|
|
"test_training_dashboard_m3",
|
|
"test_training_api_m4",
|
|
"test_training_case_import_export_m5",
|
|
"test_training_public_api_contract_m8",
|
|
"test_training_api_error_contract_m9",
|
|
"test_training_case_docs_cli_m10",
|
|
"test_training_public_export_privacy_m15",
|
|
"test_documentation_consistency",
|
|
)
|
|
TRAINING_CASE_REQUIRED_ACCEPTANCE_TEST_MODULES = (
|
|
"test_training_case_engine_m1",
|
|
"test_training_api_m2",
|
|
"test_training_dashboard_m3",
|
|
"test_training_api_m4",
|
|
"test_training_case_import_export_m5",
|
|
"test_training_public_api_contract_m8",
|
|
"test_training_api_error_contract_m9",
|
|
"test_training_case_docs_cli_m10",
|
|
"test_training_public_export_privacy_m15",
|
|
"test_documentation_consistency",
|
|
)
|
|
TRAINING_PUBLIC_API_ROUTE_REGISTRY = (
|
|
("GET", "/training/cases"),
|
|
("POST", "/training/cases/import"),
|
|
("GET", "/training/cases/export"),
|
|
("GET", "/training/cases/{case_id}"),
|
|
("POST", "/training/attempts"),
|
|
("POST", "/training/attempts/{attempt_id}/annotations"),
|
|
("POST", "/training/attempts/{attempt_id}/submit"),
|
|
("GET", "/training/progress"),
|
|
)
|
|
TRAINING_DASHBOARD_ROUTE_REGISTRY = (
|
|
("GET", "/training/cases"),
|
|
("GET", "/training/progress"),
|
|
("POST", "/training/attempts"),
|
|
("POST", "/training/attempts/{attempt_id}/annotations"),
|
|
("POST", "/training/attempts/{attempt_id}/submit"),
|
|
)
|
|
TRAINING_ROUTE_SURFACE_WORDING = {
|
|
("GET", "/training/cases"): ("list cases", "status", "skill tag", "instrument", "limit filters"),
|
|
("POST", "/training/cases/import"): ("import a versioned public package", "cases plus tasks"),
|
|
("GET", "/training/cases/export"): ("export a public package", "same case filters"),
|
|
("GET", "/training/cases/{case_id}"): ("read one public case",),
|
|
("POST", "/training/attempts"): ("start an attempt", "case"),
|
|
("POST", "/training/attempts/{attempt_id}/annotations"): ("save an annotation payload", "attempt"),
|
|
("POST", "/training/attempts/{attempt_id}/submit"): ("submit an attempt", "optional score"),
|
|
("GET", "/training/progress"): ("list progress", "user", "skill tag", "limit filters"),
|
|
}
|
|
TRAINING_DASHBOARD_PUBLIC_WORDING = (
|
|
"available cases",
|
|
"user progress",
|
|
"attempt start",
|
|
"annotation note save",
|
|
"attempt submit",
|
|
"public case fields only",
|
|
)
|
|
TRAINING_ACCEPTANCE_VALIDATION_DOC_SNIPPETS = (
|
|
"M35 acceptance posture",
|
|
"Training Case acceptance manifest",
|
|
"focused milestone test suites",
|
|
"offline checks",
|
|
"public validation",
|
|
)
|
|
TRAINING_M41_RELEASE_INDEX_DOCS = (PROJECT_README, TRAINING_PRODUCT_DOC)
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY = (
|
|
"test_training_readmes_expose_m1_m40_release_index_without_raw_test_modules",
|
|
"test_training_m41_release_index_guard_inventory_is_current",
|
|
"test_training_m41_release_index_inventory_shape_is_stable",
|
|
"test_training_m47_release_index_per_doc_helper_inventory_self_lock_is_current",
|
|
"test_training_m48_release_index_per_doc_helper_keeps_doc_tuple_shape",
|
|
"test_training_m49_release_index_per_doc_helper_handles_empty_docs_without_mutation",
|
|
"test_training_m50_release_index_helper_accepts_flattened_inventory_complete_doc",
|
|
"test_training_m54_release_index_required_snippet_inventory_category_shape_is_locked",
|
|
"test_training_m55_release_index_required_snippet_inventory_source_shape_is_locked",
|
|
"test_training_m56_release_index_required_snippet_inventory_source_shape_rejects_dynamic_fixtures",
|
|
"test_training_m57_release_index_required_snippet_inventory_source_shape_diagnostics_are_locked",
|
|
"test_training_m58_release_index_required_snippet_inventory_source_shape_accepts_literal_fixtures",
|
|
"test_training_m59_release_index_required_snippet_inventory_source_shape_preserves_literal_order",
|
|
"test_training_m60_release_index_source_shape_fixture_guard_inventory_self_lock_is_current",
|
|
"test_training_m61_release_index_source_shape_fixture_guard_methods_constant_source_shape_is_locked",
|
|
"test_training_m62_release_index_source_shape_fixture_guard_methods_reject_dynamic_constant_sources",
|
|
"test_training_m63_release_index_source_shape_fixture_guard_methods_constant_diagnostics_are_locked",
|
|
"test_training_m64_release_index_source_shape_fixture_guard_methods_accept_valid_literal_sources",
|
|
"test_training_m65_release_index_source_shape_fixture_guard_methods_constant_inventory_exactness_self_lock",
|
|
"test_training_m66_release_index_source_shape_fixture_guard_methods_constant_source_exactness_self_lock",
|
|
"test_training_m67_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_self_lock",
|
|
"test_training_m69_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_duplicate_negative_fixture_self_lock",
|
|
"test_training_m70_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_duplicate_guard_positive_diagnostic_self_lock",
|
|
"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_m75_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_self_lock",
|
|
"test_training_m76_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_rejects_dynamic_sources",
|
|
"test_training_m77_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_edge_diagnostics_are_locked",
|
|
"test_training_m78_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_accepts_ordered_literal_sources",
|
|
"test_training_m79_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_self_lock",
|
|
"test_training_m80_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_negative_fixture_self_lock",
|
|
"test_training_m81_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_self_lock",
|
|
"test_training_m82_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_rejects_dynamic_sources",
|
|
"test_training_m83_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_edge_diagnostics_are_locked",
|
|
"test_training_m84_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_inventory_self_lock",
|
|
"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_m89_release_index_final_closure_delivery_guard_source_chain_self_lock",
|
|
"test_training_m90_release_index_final_closure_delivery_guard_source_chain_source_shape_self_lock",
|
|
"test_training_m91_release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_self_lock",
|
|
"test_training_m92_release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_registration_self_lock",
|
|
"test_training_m53_release_index_doc_category_coverage_is_exact",
|
|
"test_training_case_product_doc_reflects_current_m40_maturity",
|
|
)
|
|
TRAINING_M41_RELEASE_INDEX_EXACTNESS_BRIDGE_GUARD_METHODS = (
|
|
"test_training_m65_release_index_source_shape_fixture_guard_methods_constant_inventory_exactness_self_lock",
|
|
"test_training_m66_release_index_source_shape_fixture_guard_methods_constant_source_exactness_self_lock",
|
|
"test_training_m67_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_self_lock",
|
|
)
|
|
TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS = (
|
|
"test_training_m55_release_index_required_snippet_inventory_source_shape_is_locked",
|
|
"test_training_m56_release_index_required_snippet_inventory_source_shape_rejects_dynamic_fixtures",
|
|
"test_training_m57_release_index_required_snippet_inventory_source_shape_diagnostics_are_locked",
|
|
"test_training_m58_release_index_required_snippet_inventory_source_shape_accepts_literal_fixtures",
|
|
"test_training_m59_release_index_required_snippet_inventory_source_shape_preserves_literal_order",
|
|
"test_training_m60_release_index_source_shape_fixture_guard_inventory_self_lock_is_current",
|
|
"test_training_m61_release_index_source_shape_fixture_guard_methods_constant_source_shape_is_locked",
|
|
"test_training_m62_release_index_source_shape_fixture_guard_methods_reject_dynamic_constant_sources",
|
|
"test_training_m63_release_index_source_shape_fixture_guard_methods_constant_diagnostics_are_locked",
|
|
"test_training_m64_release_index_source_shape_fixture_guard_methods_accept_valid_literal_sources",
|
|
)
|
|
TRAINING_M41_RELEASE_INDEX_DIAGNOSTIC_FIXTURE_INVENTORY_GUARD_CLUSTER = (
|
|
"test_training_m74_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_self_lock",
|
|
"test_training_m75_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_self_lock",
|
|
"test_training_m76_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_rejects_dynamic_sources",
|
|
"test_training_m77_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_edge_diagnostics_are_locked",
|
|
"test_training_m78_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_accepts_ordered_literal_sources",
|
|
)
|
|
TRAINING_M41_RELEASE_INDEX_DIAGNOSTIC_FIXTURE_INVENTORY_GUARD_CLUSTER_GOVERNANCE_METHODS = (
|
|
"test_training_m79_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_self_lock",
|
|
"test_training_m80_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_negative_fixture_self_lock",
|
|
"test_training_m81_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_self_lock",
|
|
"test_training_m82_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_rejects_dynamic_sources",
|
|
"test_training_m83_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_edge_diagnostics_are_locked",
|
|
)
|
|
TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY = (
|
|
(
|
|
"current_m1_m40_marker",
|
|
(
|
|
"M1-M40",
|
|
"through M40",
|
|
"current product maturity through M40",
|
|
),
|
|
),
|
|
(
|
|
"acceptance_offline_validation",
|
|
(
|
|
"M35 acceptance posture",
|
|
"Training Case acceptance manifest",
|
|
"focused milestone test suites",
|
|
"offline checks",
|
|
"public validation",
|
|
),
|
|
),
|
|
(
|
|
"public_api_privacy_contracts",
|
|
(
|
|
"API contract coverage",
|
|
"error contract coverage",
|
|
"privacy contract coverage",
|
|
),
|
|
),
|
|
(
|
|
"package_smoke_offline_registry",
|
|
(
|
|
"package smoke",
|
|
"training_case_package",
|
|
),
|
|
),
|
|
(
|
|
"dashboard_public_docs_privacy",
|
|
(
|
|
"dashboard_js_syntax",
|
|
"dashboard and public docs privacy smoke coverage",
|
|
),
|
|
),
|
|
(
|
|
"single_set_docker_deployment",
|
|
(
|
|
"single-set local Docker deployment",
|
|
),
|
|
),
|
|
(
|
|
"docker_smoke_guard_coverage",
|
|
(
|
|
"Docker smoke guard coverage",
|
|
),
|
|
),
|
|
)
|
|
TRAINING_M41_RELEASE_INDEX_DOC_SNIPPETS = tuple(
|
|
snippet
|
|
for _, snippets in TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
for snippet in snippets
|
|
)
|
|
TRAINING_M41_STALE_RELEASE_INVENTORY_NAMES = ("m1_m28_maturity_wording",)
|
|
TRAINING_M41_STALE_RELEASE_WORDING = (
|
|
"M1-M39",
|
|
"through M39",
|
|
"through-M39",
|
|
)
|
|
TRAINING_RAW_TEST_MODULE_PATTERN = r"\btest_training_[a-z0-9_]+"
|
|
TRAINING_PUBLIC_PRIVACY_DOCS = (PROJECT_README, TRAINING_PRODUCT_DOC, TRAINING_PACKAGE_SMOKE_DOC)
|
|
TRAINING_PUBLIC_ERROR_DOCS = (PROJECT_README, TRAINING_PRODUCT_DOC)
|
|
TRAINING_PUBLIC_ERROR_RAW_WORDING_DOCS = (
|
|
PROJECT_README,
|
|
TRAINING_PRODUCT_DOC,
|
|
TRAINING_PACKAGE_SMOKE_DOC,
|
|
)
|
|
TRAINING_PUBLIC_ERROR_CATALOG_SNIPPETS = (
|
|
"Training public error catalog",
|
|
"deterministic public validation errors",
|
|
"`400` with `invalid_json_body`",
|
|
"`400` with `missing_required_json_field:<field>`",
|
|
"`400` with `invalid_json_field:<field>`",
|
|
"`400` with `invalid_path_param:<field>`",
|
|
"`400` with `invalid_limit_query_param:limit`",
|
|
"`404` with `not_found`",
|
|
"`500` with `internal_server_error`",
|
|
"masks raw internals",
|
|
"Package CLI public errors",
|
|
"one-line JSON",
|
|
"`input_file_not_found`",
|
|
"`input_path_is_directory`",
|
|
"invalid output targets",
|
|
)
|
|
TRAINING_PUBLIC_ERROR_FORBIDDEN_RAW_WORDING = (
|
|
"Traceback",
|
|
"stack trace",
|
|
"[Errno",
|
|
"FileNotFoundError",
|
|
"IsADirectoryError",
|
|
"OSError",
|
|
"No such file or directory",
|
|
"Permission denied",
|
|
)
|
|
TRAINING_PUBLIC_PRIVACY_FORBIDDEN_TERMS = (
|
|
"answer" + "_key",
|
|
"answer " + "key",
|
|
"private " + "answer",
|
|
"answer " + "detail",
|
|
"solution " + "key",
|
|
"solution_" + "key",
|
|
)
|
|
TRAINING_PUBLIC_PRIVACY_MATERIAL_PHRASES = (
|
|
"private solution material",
|
|
"internal solution details",
|
|
)
|
|
LOCAL_DOCKER_POLICY_DOCS = (PROJECT_README, TRAINING_PRODUCT_DOC)
|
|
LOCAL_DOCKER_DOCUMENTATION_GUARD_TEST_INVENTORY = (
|
|
"test_readmes_describe_single_set_local_docker_deployment_policy",
|
|
"test_readmes_lock_single_set_docker_smoke_command_shape",
|
|
)
|
|
LOCAL_DOCKER_DOCUMENTATION_GUARD_SOURCE_CONSTANTS = (
|
|
"LOCAL_DOCKER_POLICY_DOCS",
|
|
"LOCAL_DOCKER_REBUILD_COMMANDS",
|
|
"LOCAL_DOCKER_SMOKE_COMMANDS",
|
|
"LOCAL_DOCKER_COMPOSE_PREFIX",
|
|
)
|
|
LOCAL_DOCKER_DEPLOY_DIR = "/root/deploy/ai-ict"
|
|
LOCAL_DOCKER_COMPOSE_PROJECT = "ai-ict"
|
|
LOCAL_DOCKER_CONTAINER = "ai-ict"
|
|
LOCAL_DOCKER_COMPOSE_FILE = f"{LOCAL_DOCKER_DEPLOY_DIR}/docker-compose.yml"
|
|
LOCAL_DOCKER_COMPOSE_PREFIX = (
|
|
f"docker compose -p {LOCAL_DOCKER_COMPOSE_PROJECT} -f {LOCAL_DOCKER_COMPOSE_FILE}"
|
|
)
|
|
LOCAL_DOCKER_REBUILD_COMMANDS = (
|
|
f"{LOCAL_DOCKER_COMPOSE_PREFIX} down --remove-orphans",
|
|
f"{LOCAL_DOCKER_COMPOSE_PREFIX} up -d --build",
|
|
)
|
|
LOCAL_DOCKER_SMOKE_COMMANDS = (
|
|
f"{LOCAL_DOCKER_COMPOSE_PREFIX} ps",
|
|
"test \"$(docker ps --filter label=com.docker.compose.project=ai-ict --format '{{.Names}}' | wc -l | tr -d ' ')\" = \"1\"",
|
|
"test \"$(docker ps --filter name=^/ai-ict$ --format '{{.Names}}' | wc -l | tr -d ' ')\" = \"1\"",
|
|
"test \"$(docker inspect -f '{{.State.Health.Status}}' ai-ict)\" = \"healthy\"",
|
|
)
|
|
LOCAL_DOCKER_POLICY_REQUIRED_SNIPPETS = (
|
|
"single-set local Docker deployment",
|
|
"compose project `ai-ict`",
|
|
"container `ai-ict`",
|
|
"deploy directory `/root/deploy/ai-ict`",
|
|
"exactly one active deployment set",
|
|
"one active `ai-ict` container",
|
|
"do not create a second local stack or a second `ai-ict` container",
|
|
*LOCAL_DOCKER_REBUILD_COMMANDS,
|
|
*LOCAL_DOCKER_SMOKE_COMMANDS,
|
|
)
|
|
LOCAL_DOCKER_POLICY_FORBIDDEN_ENCOURAGEMENT = (
|
|
"create another local stack",
|
|
"create a second active deployment set",
|
|
"run parallel local stacks",
|
|
"keep multiple active deployment sets",
|
|
"start an extra ai-ict container",
|
|
"duplicate ai-ict containers",
|
|
)
|
|
TRAINING_PUBLIC_PRIVACY_EXCLUSION_WORDS = (
|
|
"scrub",
|
|
"omit",
|
|
"reject",
|
|
"keep",
|
|
"out of",
|
|
"do not",
|
|
"does not",
|
|
"without",
|
|
"hides",
|
|
"not return",
|
|
)
|
|
TRAINING_DASHBOARD_FETCH_PATTERNS = (
|
|
(("GET", "/training/cases"), r"fetchJson\('/training/cases'\)"),
|
|
(("GET", "/training/progress"), r"fetchJson\('/training/progress'\)"),
|
|
(("POST", "/training/attempts"), r"fetchJson\('/training/attempts',\s*\{\s*method:\s*'POST'"),
|
|
(
|
|
("POST", "/training/attempts/{attempt_id}/annotations"),
|
|
r"fetchJson\(`/training/attempts/\$\{[^}]+\}/annotations`,\s*\{\s*method:\s*'POST'",
|
|
),
|
|
(
|
|
("POST", "/training/attempts/{attempt_id}/submit"),
|
|
r"fetchJson\(`/training/attempts/\$\{[^}]+\}/submit`,\s*\{\s*method:\s*'POST'",
|
|
),
|
|
)
|
|
|
|
|
|
def _training_api_surface_rows_from_product_doc() -> tuple[tuple[str, str, str], ...]:
|
|
text = _training_product_doc_section("API Surface")
|
|
rows = []
|
|
for method, path, capability in re.findall(
|
|
r"^\|\s*([A-Z]+)\s*\|\s*`([^`]+)`\s*\|\s*([^|\n]+?)\s*\|",
|
|
text,
|
|
re.MULTILINE,
|
|
):
|
|
if path.startswith("/training/"):
|
|
rows.append((method, path, " ".join(capability.split()).lower()))
|
|
return tuple(rows)
|
|
|
|
|
|
def _training_api_routes_from_product_doc() -> tuple[tuple[str, str], ...]:
|
|
return tuple((method, path) for method, path, _capability in _training_api_surface_rows_from_product_doc())
|
|
|
|
|
|
def _supported_training_routes_from_route_request() -> tuple[tuple[str, str], ...]:
|
|
source = _route_request_source()
|
|
routes = list(
|
|
re.findall(
|
|
r'if method == "(GET|POST)" and path == "(/training/[^"]+)":',
|
|
source,
|
|
)
|
|
)
|
|
|
|
for pattern, route in (
|
|
(
|
|
r'if method == "GET" and len\(path_parts\) == 3 and path_parts\[:2\] == \["training", "cases"\]:\s+case_id = _parse_path_int\(path_parts\[2\], "case_id"\)',
|
|
("GET", "/training/cases/{case_id}"),
|
|
),
|
|
(
|
|
r'if method == "POST" and len\(path_parts\) == 4 and path_parts\[:2\] == \["training", "attempts"\] and path_parts\[3\] == "annotations":\s+attempt_id = _parse_path_int\(path_parts\[2\], "attempt_id"\)',
|
|
("POST", "/training/attempts/{attempt_id}/annotations"),
|
|
),
|
|
(
|
|
r'if method == "POST" and len\(path_parts\) == 4 and path_parts\[:2\] == \["training", "attempts"\] and path_parts\[3\] == "submit":\s+attempt_id = _parse_path_int\(path_parts\[2\], "attempt_id"\)',
|
|
("POST", "/training/attempts/{attempt_id}/submit"),
|
|
),
|
|
):
|
|
if re.search(pattern, source):
|
|
routes.append(route)
|
|
return tuple(routes)
|
|
|
|
|
|
def _training_dashboard_routes_from_app() -> tuple[tuple[str, str], ...]:
|
|
source = TRAINING_DASHBOARD_APP.read_text(encoding="utf-8")
|
|
routes = []
|
|
for route, pattern in TRAINING_DASHBOARD_FETCH_PATTERNS:
|
|
if re.search(pattern, source, re.DOTALL):
|
|
routes.append(route)
|
|
return tuple(routes)
|
|
|
|
|
|
def _training_dashboard_fetch_paths_from_app() -> tuple[str, ...]:
|
|
source = TRAINING_DASHBOARD_APP.read_text(encoding="utf-8")
|
|
paths = []
|
|
for match in re.finditer(r"fetchJson\(\s*['`](?P<path>/training/[^'`]+)['`]", source):
|
|
path = re.sub(r"\$\{[^}]+\}", "{attempt_id}", match.group("path"))
|
|
paths.append(path.split("?", 1)[0])
|
|
return tuple(paths)
|
|
|
|
|
|
def _route_request_source() -> str:
|
|
source = API_SERVER.read_text(encoding="utf-8")
|
|
match = re.search(r"^def route_request\(.*?(?=^class APIRequestHandler)", source, re.DOTALL | re.MULTILINE)
|
|
if match is None:
|
|
raise AssertionError("src/api/server.py is missing route_request")
|
|
return match.group(0)
|
|
|
|
|
|
def _training_product_doc_section(heading: str) -> str:
|
|
text = TRAINING_PRODUCT_DOC.read_text(encoding="utf-8")
|
|
match = re.search(
|
|
rf"^## {re.escape(heading)}\n(?P<section>.*?)(?:\n## |\Z)",
|
|
text,
|
|
re.DOTALL | re.MULTILINE,
|
|
)
|
|
if match is None:
|
|
raise AssertionError(f"Training product README is missing the {heading} section")
|
|
return match.group("section")
|
|
|
|
|
|
def _training_validation_section() -> str:
|
|
return _training_product_doc_section("Validation And Errors")
|
|
|
|
|
|
def _local_docker_deployment_section(path: Path) -> str:
|
|
text = path.read_text(encoding="utf-8")
|
|
match = re.search(
|
|
r"^## Local Docker [Dd]eployment\n(?P<section>.*?)(?:\n## |\Z)",
|
|
text,
|
|
re.DOTALL | re.MULTILINE,
|
|
)
|
|
if match is None:
|
|
raise AssertionError(f"{path} is missing the Local Docker deployment section")
|
|
return match.group("section")
|
|
|
|
|
|
def _local_docker_command_lines(text: str) -> tuple[str, ...]:
|
|
return tuple(
|
|
line.strip()
|
|
for line in text.splitlines()
|
|
if line.strip().startswith(("docker ", "test "))
|
|
)
|
|
|
|
|
|
def _training_public_privacy_lines(text: str) -> tuple[str, ...]:
|
|
lines = []
|
|
for line in text.splitlines():
|
|
lower_line = line.lower()
|
|
if any(phrase in lower_line for phrase in TRAINING_PUBLIC_PRIVACY_MATERIAL_PHRASES):
|
|
lines.append(lower_line.strip())
|
|
return tuple(lines)
|
|
|
|
|
|
def _test_method_names_from_file(path: Path, class_name: str) -> tuple[str, ...]:
|
|
tree = ast.parse(path.read_text(encoding="utf-8"))
|
|
for node in tree.body:
|
|
if isinstance(node, ast.ClassDef) and node.name == class_name:
|
|
return tuple(
|
|
item.name
|
|
for item in node.body
|
|
if isinstance(item, ast.FunctionDef) and item.name.startswith("test_")
|
|
)
|
|
raise AssertionError(f"{path} is missing {class_name}")
|
|
|
|
|
|
def _release_index_missing_required_snippets_by_doc(
|
|
text_by_doc: dict[Path, str],
|
|
) -> dict[Path, tuple[tuple[str, str], ...]]:
|
|
return {
|
|
path: tuple(
|
|
(surface, snippet)
|
|
for surface, snippets in TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
for snippet in snippets
|
|
if snippet not in text
|
|
)
|
|
for path, text in text_by_doc.items()
|
|
}
|
|
|
|
|
|
class DocumentationConsistencyTests(unittest.TestCase):
|
|
def test_readme_lists_script_output_json_environment_variables(self) -> None:
|
|
script_env_vars = set()
|
|
for path in (ROOT / "scripts").glob("*.py"):
|
|
script_env_vars.update(re.findall(r'"([A-Z0-9_]+OUTPUT_JSON)"', path.read_text(encoding="utf-8")))
|
|
readme = (ROOT / "README.md").read_text(encoding="utf-8")
|
|
|
|
missing = sorted(name for name in script_env_vars if name not in readme)
|
|
|
|
self.assertEqual(missing, [])
|
|
|
|
def test_training_case_product_doc_lists_public_m1_m21_surface(self) -> None:
|
|
text = TRAINING_PRODUCT_DOC.read_text(encoding="utf-8")
|
|
|
|
for snippet in (
|
|
"Training panel",
|
|
"/training/cases",
|
|
"/training/cases/{case_id}",
|
|
"/training/cases/export",
|
|
"/training/cases/import",
|
|
"/training/attempts",
|
|
"/training/attempts/{attempt_id}/annotations",
|
|
"/training/attempts/{attempt_id}/submit",
|
|
"/training/progress",
|
|
".venv/bin/python scripts/run_training_case_package.py",
|
|
".venv/bin/python scripts/run_offline_checks.py",
|
|
"private solution material",
|
|
"Data Isolation Guarantees",
|
|
):
|
|
with self.subTest(snippet=snippet):
|
|
self.assertIn(snippet, text)
|
|
|
|
def test_training_case_product_doc_reflects_current_m40_maturity(self) -> None:
|
|
text = TRAINING_PRODUCT_DOC.read_text(encoding="utf-8")
|
|
|
|
for snippet in (
|
|
CURRENT_TRAINING_DOC_MATURITY_MARKER,
|
|
"API contract coverage",
|
|
"error contract coverage",
|
|
"fixture/schema contract",
|
|
"offline checks registry smoke",
|
|
"public response privacy contract coverage",
|
|
"dashboard and public docs privacy smoke coverage",
|
|
):
|
|
with self.subTest(snippet=snippet):
|
|
self.assertIn(snippet, text)
|
|
|
|
for stale_snippet in ("M1-M25", "through M25", *TRAINING_M41_STALE_RELEASE_WORDING):
|
|
with self.subTest(stale_snippet=stale_snippet):
|
|
self.assertNotIn(stale_snippet, text)
|
|
|
|
def test_training_readmes_expose_m1_m40_release_index_without_raw_test_modules(self) -> None:
|
|
text_by_doc = {
|
|
path: path.read_text(encoding="utf-8")
|
|
for path in TRAINING_M41_RELEASE_INDEX_DOCS
|
|
}
|
|
missing_required_by_doc = _release_index_missing_required_snippets_by_doc(text_by_doc)
|
|
|
|
for path, text in text_by_doc.items():
|
|
for surface, _ in TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY:
|
|
missing_surface_snippets = tuple(
|
|
snippet
|
|
for missing_surface, snippet in missing_required_by_doc[path]
|
|
if missing_surface == surface
|
|
)
|
|
with self.subTest(path=path.name, surface=surface):
|
|
self.assertEqual(missing_surface_snippets, ())
|
|
|
|
with self.subTest(path=path.name, guard="stale_wording"):
|
|
for stale_snippet in TRAINING_M41_STALE_RELEASE_WORDING:
|
|
self.assertNotIn(stale_snippet, text)
|
|
|
|
with self.subTest(path=path.name, guard="raw_test_modules"):
|
|
self.assertIsNone(re.search(TRAINING_RAW_TEST_MODULE_PATTERN, text))
|
|
|
|
def test_training_case_m24_m29_documentation_test_inventory_is_current(self) -> None:
|
|
test_names = set(
|
|
_test_method_names_from_file(Path(__file__), "DocumentationConsistencyTests")
|
|
)
|
|
package_docs_test_names = set(
|
|
_test_method_names_from_file(TRAINING_DOCS_CLI_TEST, "TrainingCaseDocsCliM10Tests")
|
|
)
|
|
inventory_names = tuple(
|
|
name
|
|
for names in TRAINING_M24_M29_DOCUMENTATION_TEST_INVENTORY.values()
|
|
for name in names
|
|
)
|
|
unique_inventory_names = set(inventory_names)
|
|
text = TRAINING_PRODUCT_DOC.read_text(encoding="utf-8")
|
|
|
|
self.assertEqual(len(inventory_names), 8)
|
|
self.assertEqual(len(unique_inventory_names), 7)
|
|
self.assertEqual(sorted(TRAINING_M24_M29_DOCUMENTATION_TEST_INVENTORY), [
|
|
"dashboard_public_docs_privacy",
|
|
"m1_m40_maturity_wording",
|
|
"offline_registry_coverage",
|
|
"route_surface",
|
|
])
|
|
for surface, names in TRAINING_M24_M29_DOCUMENTATION_TEST_INVENTORY.items():
|
|
with self.subTest(surface=surface):
|
|
self.assertTrue(names)
|
|
for name in names:
|
|
self.assertIn(name, test_names)
|
|
|
|
self.assertIn(
|
|
TRAINING_M24_M29_PACKAGE_DOCS_INVENTORY_TEST,
|
|
package_docs_test_names,
|
|
)
|
|
self.assertIn(CURRENT_TRAINING_DOC_MATURITY_MARKER, text)
|
|
self.assertIn(CURRENT_TRAINING_DOC_MATURITY_SPAN, text)
|
|
|
|
def test_training_m41_release_index_guard_inventory_is_current(self) -> None:
|
|
module_path = Path(__file__)
|
|
module_source = module_path.read_text(encoding="utf-8")
|
|
test_names = set(
|
|
_test_method_names_from_file(module_path, "DocumentationConsistencyTests")
|
|
)
|
|
required_guard_tests_by_role = {
|
|
"docs_coverage": (
|
|
"test_training_readmes_expose_m1_m40_release_index_without_raw_test_modules"
|
|
),
|
|
"inventory_self_lock": (
|
|
"test_training_m41_release_index_guard_inventory_is_current"
|
|
),
|
|
"inventory_shape": "test_training_m41_release_index_inventory_shape_is_stable",
|
|
"per_doc_helper_self_lock": (
|
|
"test_training_m47_release_index_per_doc_helper_inventory_self_lock_is_current"
|
|
),
|
|
"per_doc_helper_tuple_shape": (
|
|
"test_training_m48_release_index_per_doc_helper_keeps_doc_tuple_shape"
|
|
),
|
|
"per_doc_helper_empty_docs": (
|
|
"test_training_m49_release_index_per_doc_helper_handles_empty_docs_without_mutation"
|
|
),
|
|
"per_doc_helper_flattened_complete_doc": (
|
|
"test_training_m50_release_index_helper_accepts_flattened_inventory_complete_doc"
|
|
),
|
|
"required_snippet_inventory_category_shape": (
|
|
"test_training_m54_release_index_required_snippet_inventory_category_shape_is_locked"
|
|
),
|
|
"required_snippet_inventory_source_shape": (
|
|
"test_training_m55_release_index_required_snippet_inventory_source_shape_is_locked"
|
|
),
|
|
"required_snippet_inventory_source_shape_negative_fixtures": (
|
|
"test_training_m56_release_index_required_snippet_inventory_source_shape_rejects_dynamic_fixtures"
|
|
),
|
|
"required_snippet_inventory_source_shape_diagnostics": (
|
|
"test_training_m57_release_index_required_snippet_inventory_source_shape_diagnostics_are_locked"
|
|
),
|
|
"required_snippet_inventory_source_shape_positive_fixtures": (
|
|
"test_training_m58_release_index_required_snippet_inventory_source_shape_accepts_literal_fixtures"
|
|
),
|
|
"required_snippet_inventory_source_shape_literal_order": (
|
|
"test_training_m59_release_index_required_snippet_inventory_source_shape_preserves_literal_order"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_self_lock": (
|
|
"test_training_m60_release_index_source_shape_fixture_guard_inventory_self_lock_is_current"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_source_lock": (
|
|
"test_training_m61_release_index_source_shape_fixture_guard_methods_constant_source_shape_is_locked"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_negative_sources": (
|
|
"test_training_m62_release_index_source_shape_fixture_guard_methods_reject_dynamic_constant_sources"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_diagnostics": (
|
|
"test_training_m63_release_index_source_shape_fixture_guard_methods_constant_diagnostics_are_locked"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_positive_sources": (
|
|
"test_training_m64_release_index_source_shape_fixture_guard_methods_accept_valid_literal_sources"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_inventory_exactness": (
|
|
"test_training_m65_release_index_source_shape_fixture_guard_methods_constant_inventory_exactness_self_lock"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_source_exactness": (
|
|
"test_training_m66_release_index_source_shape_fixture_guard_methods_constant_source_exactness_self_lock"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge": (
|
|
"test_training_m67_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_self_lock"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_duplicate_negative_fixture": (
|
|
"test_training_m69_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_duplicate_negative_fixture_self_lock"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_duplicate_guard_positive_diagnostic": (
|
|
"test_training_m70_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_duplicate_guard_positive_diagnostic_self_lock"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_source_shape": (
|
|
"test_training_m71_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_source_shape_self_lock"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_negative_sources": (
|
|
"test_training_m72_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_rejects_dynamic_sources"
|
|
),
|
|
"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"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape": (
|
|
"test_training_m75_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_self_lock"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_negative_sources": (
|
|
"test_training_m76_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_rejects_dynamic_sources"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_edge_diagnostics": (
|
|
"test_training_m77_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_edge_diagnostics_are_locked"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_positive_order_sources": (
|
|
"test_training_m78_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_accepts_ordered_literal_sources"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster": (
|
|
"test_training_m79_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_self_lock"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_negative_fixture": (
|
|
"test_training_m80_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_negative_fixture_self_lock"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape": (
|
|
"test_training_m81_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_self_lock"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_negative_sources": (
|
|
"test_training_m82_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_rejects_dynamic_sources"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_edge_diagnostics": (
|
|
"test_training_m83_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_edge_diagnostics_are_locked"
|
|
),
|
|
"required_snippet_inventory_source_shape_fixture_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_inventory_self_lock": (
|
|
"test_training_m84_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_inventory_self_lock"
|
|
),
|
|
"release_index_public_docs_acceptance_inventory_alignment": (
|
|
"test_training_m85_release_index_public_docs_acceptance_inventory_alignment_self_lock"
|
|
),
|
|
"release_index_final_closure_delivery": (
|
|
"test_training_m86_release_index_final_closure_delivery_index_self_lock"
|
|
),
|
|
"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"
|
|
),
|
|
"release_index_final_closure_delivery_guard_source_chain_self_lock": (
|
|
"test_training_m89_release_index_final_closure_delivery_guard_source_chain_self_lock"
|
|
),
|
|
"release_index_final_closure_delivery_guard_source_chain_source_shape_self_lock": (
|
|
"test_training_m90_release_index_final_closure_delivery_guard_source_chain_source_shape_self_lock"
|
|
),
|
|
"release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_self_lock": (
|
|
"test_training_m91_release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_self_lock"
|
|
),
|
|
"release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_registration_self_lock": (
|
|
"test_training_m92_release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_registration_self_lock"
|
|
),
|
|
"per_doc_helper_exact_category_coverage": (
|
|
"test_training_m53_release_index_doc_category_coverage_is_exact"
|
|
),
|
|
"stale_wording": "test_training_case_product_doc_reflects_current_m40_maturity",
|
|
}
|
|
required_guard_tests = tuple(required_guard_tests_by_role.values())
|
|
required_release_snippets = (
|
|
CURRENT_TRAINING_DOC_MATURITY_MARKER,
|
|
CURRENT_TRAINING_DOC_MATURITY_SPAN,
|
|
CURRENT_TRAINING_DOC_MATURITY_PHRASE,
|
|
*TRAINING_ACCEPTANCE_VALIDATION_DOC_SNIPPETS,
|
|
"API contract coverage",
|
|
"error contract coverage",
|
|
"privacy contract coverage",
|
|
"package smoke",
|
|
"training_case_package",
|
|
"dashboard_js_syntax",
|
|
"dashboard and public docs privacy smoke coverage",
|
|
"single-set local Docker deployment",
|
|
"Docker smoke guard coverage",
|
|
)
|
|
required_stale_inventory_names = ("m1_m28_maturity_wording",)
|
|
required_stale_wording = ("M1-M39", "through M39", "through-M39")
|
|
expected_release_snippets = tuple(
|
|
snippet
|
|
for _, snippets in TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
for snippet in snippets
|
|
)
|
|
active_release_inventory_values = "\n".join(
|
|
(
|
|
*TRAINING_M24_M29_DOCUMENTATION_TEST_INVENTORY,
|
|
*TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY,
|
|
*(
|
|
category
|
|
for category, _ in TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
),
|
|
*TRAINING_M41_RELEASE_INDEX_DOC_SNIPPETS,
|
|
CURRENT_TRAINING_DOC_MATURITY_MARKER,
|
|
CURRENT_TRAINING_DOC_MATURITY_SPAN,
|
|
CURRENT_TRAINING_DOC_MATURITY_PHRASE,
|
|
)
|
|
)
|
|
guard_match = re.search(
|
|
rf"^ def {TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[0]}"
|
|
r"\(.*?(?=^ def |\Z)",
|
|
module_source,
|
|
re.DOTALL | re.MULTILINE,
|
|
)
|
|
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_DOCS,
|
|
(PROJECT_README, TRAINING_PRODUCT_DOC),
|
|
)
|
|
self.assertEqual(TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY, required_guard_tests)
|
|
self.assertEqual(len(required_guard_tests), len(set(required_guard_tests)))
|
|
self.assertEqual(
|
|
sorted(
|
|
category
|
|
for category, _ in TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
),
|
|
[
|
|
"acceptance_offline_validation",
|
|
"current_m1_m40_marker",
|
|
"dashboard_public_docs_privacy",
|
|
"docker_smoke_guard_coverage",
|
|
"package_smoke_offline_registry",
|
|
"public_api_privacy_contracts",
|
|
"single_set_docker_deployment",
|
|
],
|
|
)
|
|
self.assertEqual(TRAINING_M41_RELEASE_INDEX_DOC_SNIPPETS, expected_release_snippets)
|
|
self.assertEqual(
|
|
TRAINING_M41_STALE_RELEASE_INVENTORY_NAMES,
|
|
required_stale_inventory_names,
|
|
)
|
|
self.assertEqual(TRAINING_M41_STALE_RELEASE_WORDING, required_stale_wording)
|
|
self.assertEqual(CURRENT_TRAINING_DOC_MATURITY_MARKER, "M1-M40")
|
|
self.assertEqual(CURRENT_TRAINING_DOC_MATURITY_SPAN, "through M40")
|
|
self.assertEqual(
|
|
CURRENT_TRAINING_DOC_MATURITY_PHRASE,
|
|
"current product maturity through M40",
|
|
)
|
|
|
|
for role, guard_test in required_guard_tests_by_role.items():
|
|
with self.subTest(release_index_guard=role):
|
|
loader = unittest.TestLoader()
|
|
suite = loader.loadTestsFromName(
|
|
f"{type(self).__module__}.DocumentationConsistencyTests.{guard_test}"
|
|
)
|
|
|
|
self.assertIn(guard_test, test_names)
|
|
self.assertEqual(loader.errors, [])
|
|
self.assertGreater(suite.countTestCases(), 0)
|
|
self.assertIsNotNone(guard_match)
|
|
guard_source = guard_match.group(0)
|
|
for guard_reference in (
|
|
"TRAINING_M41_RELEASE_INDEX_DOCS",
|
|
"TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY",
|
|
"_release_index_missing_required_snippets_by_doc",
|
|
"missing_required_by_doc[path]",
|
|
"TRAINING_M41_STALE_RELEASE_WORDING",
|
|
"TRAINING_RAW_TEST_MODULE_PATTERN",
|
|
):
|
|
with self.subTest(guard_reference=guard_reference):
|
|
self.assertIn(guard_reference, guard_source)
|
|
|
|
complete_release_doc = "\n".join(TRAINING_M41_RELEASE_INDEX_DOC_SNIPPETS)
|
|
missing_surface, missing_snippet = next(
|
|
(surface, snippets[0])
|
|
for surface, snippets in TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
)
|
|
missing_release_doc = complete_release_doc.replace(missing_snippet, "", 1)
|
|
negative_fixture_missing_by_doc = _release_index_missing_required_snippets_by_doc(
|
|
{
|
|
PROJECT_README: missing_release_doc,
|
|
TRAINING_PRODUCT_DOC: complete_release_doc,
|
|
}
|
|
)
|
|
|
|
self.assertEqual(negative_fixture_missing_by_doc[TRAINING_PRODUCT_DOC], ())
|
|
self.assertEqual(
|
|
negative_fixture_missing_by_doc[PROJECT_README],
|
|
((missing_surface, missing_snippet),),
|
|
)
|
|
|
|
for surface, snippets in TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY:
|
|
with self.subTest(surface=surface):
|
|
self.assertTrue(snippets)
|
|
|
|
for snippet in required_release_snippets:
|
|
with self.subTest(snippet=snippet):
|
|
self.assertIn(snippet, TRAINING_M41_RELEASE_INDEX_DOC_SNIPPETS)
|
|
|
|
for stale_value in (
|
|
*required_stale_inventory_names,
|
|
*required_stale_wording,
|
|
):
|
|
with self.subTest(stale_value=stale_value):
|
|
self.assertNotIn(stale_value, active_release_inventory_values)
|
|
|
|
def test_training_m52_release_index_guard_inventory_order_and_uniqueness_self_lock(self) -> None:
|
|
expected_inventory = (
|
|
"test_training_readmes_expose_m1_m40_release_index_without_raw_test_modules",
|
|
"test_training_m41_release_index_guard_inventory_is_current",
|
|
"test_training_m41_release_index_inventory_shape_is_stable",
|
|
"test_training_m47_release_index_per_doc_helper_inventory_self_lock_is_current",
|
|
"test_training_m48_release_index_per_doc_helper_keeps_doc_tuple_shape",
|
|
"test_training_m49_release_index_per_doc_helper_handles_empty_docs_without_mutation",
|
|
"test_training_m50_release_index_helper_accepts_flattened_inventory_complete_doc",
|
|
"test_training_m54_release_index_required_snippet_inventory_category_shape_is_locked",
|
|
"test_training_m55_release_index_required_snippet_inventory_source_shape_is_locked",
|
|
"test_training_m56_release_index_required_snippet_inventory_source_shape_rejects_dynamic_fixtures",
|
|
"test_training_m57_release_index_required_snippet_inventory_source_shape_diagnostics_are_locked",
|
|
"test_training_m58_release_index_required_snippet_inventory_source_shape_accepts_literal_fixtures",
|
|
"test_training_m59_release_index_required_snippet_inventory_source_shape_preserves_literal_order",
|
|
"test_training_m60_release_index_source_shape_fixture_guard_inventory_self_lock_is_current",
|
|
"test_training_m61_release_index_source_shape_fixture_guard_methods_constant_source_shape_is_locked",
|
|
"test_training_m62_release_index_source_shape_fixture_guard_methods_reject_dynamic_constant_sources",
|
|
"test_training_m63_release_index_source_shape_fixture_guard_methods_constant_diagnostics_are_locked",
|
|
"test_training_m64_release_index_source_shape_fixture_guard_methods_accept_valid_literal_sources",
|
|
"test_training_m65_release_index_source_shape_fixture_guard_methods_constant_inventory_exactness_self_lock",
|
|
"test_training_m66_release_index_source_shape_fixture_guard_methods_constant_source_exactness_self_lock",
|
|
"test_training_m67_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_self_lock",
|
|
"test_training_m69_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_duplicate_negative_fixture_self_lock",
|
|
"test_training_m70_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_duplicate_guard_positive_diagnostic_self_lock",
|
|
"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_m75_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_self_lock",
|
|
"test_training_m76_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_rejects_dynamic_sources",
|
|
"test_training_m77_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_edge_diagnostics_are_locked",
|
|
"test_training_m78_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_accepts_ordered_literal_sources",
|
|
"test_training_m79_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_self_lock",
|
|
"test_training_m80_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_negative_fixture_self_lock",
|
|
"test_training_m81_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_self_lock",
|
|
"test_training_m82_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_rejects_dynamic_sources",
|
|
"test_training_m83_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_edge_diagnostics_are_locked",
|
|
"test_training_m84_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_inventory_self_lock",
|
|
"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_m89_release_index_final_closure_delivery_guard_source_chain_self_lock",
|
|
"test_training_m90_release_index_final_closure_delivery_guard_source_chain_source_shape_self_lock",
|
|
"test_training_m91_release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_self_lock",
|
|
"test_training_m92_release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_registration_self_lock",
|
|
"test_training_m53_release_index_doc_category_coverage_is_exact",
|
|
"test_training_case_product_doc_reflects_current_m40_maturity",
|
|
)
|
|
helper_guard_sequence = (
|
|
"test_training_m47_release_index_per_doc_helper_inventory_self_lock_is_current",
|
|
"test_training_m48_release_index_per_doc_helper_keeps_doc_tuple_shape",
|
|
"test_training_m49_release_index_per_doc_helper_handles_empty_docs_without_mutation",
|
|
"test_training_m50_release_index_helper_accepts_flattened_inventory_complete_doc",
|
|
)
|
|
test_case_name = f"{type(self).__module__}.{type(self).__qualname__}"
|
|
|
|
self.assertEqual(TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY, expected_inventory)
|
|
self.assertEqual(
|
|
len(TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY),
|
|
len(set(TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)),
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[3:7],
|
|
helper_guard_sequence,
|
|
)
|
|
for method_name in TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY:
|
|
with self.subTest(method_name=method_name):
|
|
loader = unittest.TestLoader()
|
|
suite = loader.loadTestsFromName(f"{test_case_name}.{method_name}")
|
|
|
|
self.assertEqual(loader.errors, [])
|
|
self.assertEqual(suite.countTestCases(), 1)
|
|
|
|
def test_training_m60_release_index_source_shape_fixture_guard_inventory_self_lock_is_current(
|
|
self,
|
|
) -> None:
|
|
expected_source_shape_fixture_guards = (
|
|
"test_training_m55_release_index_required_snippet_inventory_source_shape_is_locked",
|
|
"test_training_m56_release_index_required_snippet_inventory_source_shape_rejects_dynamic_fixtures",
|
|
"test_training_m57_release_index_required_snippet_inventory_source_shape_diagnostics_are_locked",
|
|
"test_training_m58_release_index_required_snippet_inventory_source_shape_accepts_literal_fixtures",
|
|
"test_training_m59_release_index_required_snippet_inventory_source_shape_preserves_literal_order",
|
|
"test_training_m60_release_index_source_shape_fixture_guard_inventory_self_lock_is_current",
|
|
"test_training_m61_release_index_source_shape_fixture_guard_methods_constant_source_shape_is_locked",
|
|
"test_training_m62_release_index_source_shape_fixture_guard_methods_reject_dynamic_constant_sources",
|
|
"test_training_m63_release_index_source_shape_fixture_guard_methods_constant_diagnostics_are_locked",
|
|
"test_training_m64_release_index_source_shape_fixture_guard_methods_accept_valid_literal_sources",
|
|
)
|
|
expected_literal_source_shape_fixture_guards = (
|
|
expected_source_shape_fixture_guards[:5]
|
|
)
|
|
test_case_name = f"{type(self).__module__}.{type(self).__qualname__}"
|
|
self_lock_name = (
|
|
"test_training_m60_release_index_source_shape_fixture_guard_inventory_self_lock_is_current"
|
|
)
|
|
source_shape_inventory_start = (
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
expected_source_shape_fixture_guards[0]
|
|
)
|
|
)
|
|
source_shape_inventory_end = source_shape_inventory_start + len(
|
|
expected_source_shape_fixture_guards
|
|
)
|
|
discovered_method_names = _test_method_names_from_file(
|
|
Path(__file__),
|
|
"DocumentationConsistencyTests",
|
|
)
|
|
source_shape_start = discovered_method_names.index(
|
|
expected_literal_source_shape_fixture_guards[0]
|
|
)
|
|
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS,
|
|
expected_source_shape_fixture_guards,
|
|
)
|
|
self.assertEqual(
|
|
len(TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS),
|
|
len(set(TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS)),
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[
|
|
source_shape_inventory_start:source_shape_inventory_end
|
|
],
|
|
TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS,
|
|
)
|
|
self.assertEqual(
|
|
discovered_method_names[
|
|
source_shape_start : source_shape_start
|
|
+ len(expected_literal_source_shape_fixture_guards)
|
|
],
|
|
expected_literal_source_shape_fixture_guards,
|
|
)
|
|
self.assertIn(self_lock_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
for method_name in TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS:
|
|
with self.subTest(method_name=method_name):
|
|
loader = unittest.TestLoader()
|
|
suite = loader.loadTestsFromName(f"{test_case_name}.{method_name}")
|
|
|
|
self.assertEqual(loader.errors, [])
|
|
self.assertEqual(suite.countTestCases(), 1)
|
|
|
|
@staticmethod
|
|
def _release_index_source_shape_fixture_guard_method_names_from_source(
|
|
module_source: str,
|
|
) -> tuple[str, ...]:
|
|
constant_name = "TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS"
|
|
module_tree = ast.parse(module_source)
|
|
|
|
constant_assignments = tuple(
|
|
node
|
|
for node in module_tree.body
|
|
if isinstance(node, ast.Assign)
|
|
and len(node.targets) == 1
|
|
and isinstance(node.targets[0], ast.Name)
|
|
and node.targets[0].id == constant_name
|
|
)
|
|
|
|
if len(constant_assignments) != 1:
|
|
raise AssertionError(
|
|
"source shape fixture guard methods must have one assignment"
|
|
)
|
|
|
|
constant_source = constant_assignments[0].value
|
|
disallowed_source_nodes = (
|
|
ast.Call,
|
|
ast.DictComp,
|
|
ast.GeneratorExp,
|
|
ast.List,
|
|
ast.ListComp,
|
|
ast.Name,
|
|
ast.SetComp,
|
|
ast.Starred,
|
|
)
|
|
dynamic_source_node = next(
|
|
(
|
|
node
|
|
for node in ast.walk(constant_source)
|
|
if isinstance(node, disallowed_source_nodes)
|
|
),
|
|
None,
|
|
)
|
|
if dynamic_source_node is not None:
|
|
dynamic_node = type(dynamic_source_node).__name__
|
|
raise AssertionError(
|
|
"source shape fixture guard methods use dynamic source node "
|
|
f"{dynamic_node}"
|
|
)
|
|
|
|
if not isinstance(constant_source, ast.Tuple):
|
|
raise AssertionError(
|
|
"source shape fixture guard methods must be a literal tuple assignment"
|
|
)
|
|
|
|
if not constant_source.elts or not all(
|
|
isinstance(element, ast.Constant) and isinstance(element.value, str)
|
|
for element in constant_source.elts
|
|
):
|
|
raise AssertionError(
|
|
"source shape fixture guard methods must use literal method names"
|
|
)
|
|
|
|
try:
|
|
method_names = ast.literal_eval(constant_source)
|
|
except (SyntaxError, ValueError) as exc:
|
|
raise AssertionError(
|
|
"source shape fixture guard methods must use literal method names"
|
|
) from exc
|
|
|
|
if not all(isinstance(method_name, str) for method_name in method_names):
|
|
raise AssertionError(
|
|
"source shape fixture guard methods must use literal method names"
|
|
)
|
|
|
|
return method_names
|
|
|
|
def test_training_m61_release_index_source_shape_fixture_guard_methods_constant_source_shape_is_locked(
|
|
self,
|
|
) -> None:
|
|
expected_source_shape_fixture_guards = (
|
|
"test_training_m55_release_index_required_snippet_inventory_source_shape_is_locked",
|
|
"test_training_m56_release_index_required_snippet_inventory_source_shape_rejects_dynamic_fixtures",
|
|
"test_training_m57_release_index_required_snippet_inventory_source_shape_diagnostics_are_locked",
|
|
"test_training_m58_release_index_required_snippet_inventory_source_shape_accepts_literal_fixtures",
|
|
"test_training_m59_release_index_required_snippet_inventory_source_shape_preserves_literal_order",
|
|
"test_training_m60_release_index_source_shape_fixture_guard_inventory_self_lock_is_current",
|
|
"test_training_m61_release_index_source_shape_fixture_guard_methods_constant_source_shape_is_locked",
|
|
"test_training_m62_release_index_source_shape_fixture_guard_methods_reject_dynamic_constant_sources",
|
|
"test_training_m63_release_index_source_shape_fixture_guard_methods_constant_diagnostics_are_locked",
|
|
"test_training_m64_release_index_source_shape_fixture_guard_methods_accept_valid_literal_sources",
|
|
)
|
|
module_source = Path(__file__).read_text(encoding="utf-8")
|
|
|
|
self.assertEqual(
|
|
self._release_index_source_shape_fixture_guard_method_names_from_source(
|
|
module_source
|
|
),
|
|
expected_source_shape_fixture_guards,
|
|
)
|
|
|
|
def test_training_m62_release_index_source_shape_fixture_guard_methods_reject_dynamic_constant_sources(
|
|
self,
|
|
) -> None:
|
|
constant_name = "TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS"
|
|
first_method = (
|
|
"test_training_m55_release_index_required_snippet_inventory_source_shape_is_locked"
|
|
)
|
|
second_method = (
|
|
"test_training_m56_release_index_required_snippet_inventory_source_shape_rejects_dynamic_fixtures"
|
|
)
|
|
invalid_sources = {
|
|
"tuple_call": (
|
|
f"{constant_name} = tuple([{first_method!r}, {second_method!r}])",
|
|
"dynamic source node Call",
|
|
),
|
|
"sorted_call": (
|
|
f"{constant_name} = sorted(({first_method!r}, {second_method!r}))",
|
|
"dynamic source node Call",
|
|
),
|
|
"name_alias": (
|
|
f"fixture_guard_methods = ({first_method!r}, {second_method!r})\n"
|
|
f"{constant_name} = fixture_guard_methods",
|
|
"dynamic source node Name",
|
|
),
|
|
"list_literal": (
|
|
f"{constant_name} = [{first_method!r}, {second_method!r}]",
|
|
"dynamic source node List",
|
|
),
|
|
"list_comprehension": (
|
|
f"{constant_name} = [method for method in ({first_method!r}, {second_method!r})]",
|
|
"dynamic source node ListComp",
|
|
),
|
|
}
|
|
|
|
for fixture_name, (source, error_snippet) in invalid_sources.items():
|
|
with self.subTest(fixture_name=fixture_name):
|
|
with self.assertRaisesRegex(AssertionError, re.escape(error_snippet)):
|
|
self._release_index_source_shape_fixture_guard_method_names_from_source(
|
|
source
|
|
)
|
|
|
|
def test_training_m63_release_index_source_shape_fixture_guard_methods_constant_diagnostics_are_locked(
|
|
self,
|
|
) -> None:
|
|
constant_name = "TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS"
|
|
guard_name = (
|
|
"test_training_m63_release_index_source_shape_fixture_guard_methods_constant_diagnostics_are_locked"
|
|
)
|
|
invalid_sources = {
|
|
"missing_constant_assignment": (
|
|
"UNRELATED_FIXTURE_GUARD_METHODS = ('literal_method_alpha',)",
|
|
"must have one assignment",
|
|
),
|
|
"duplicate_constant_assignment": (
|
|
f"{constant_name} = ('literal_method_alpha',)\n"
|
|
f"{constant_name} = ('literal_method_beta',)",
|
|
"must have one assignment",
|
|
),
|
|
"empty_tuple_assignment": (
|
|
f"{constant_name} = ()",
|
|
"must use literal method names",
|
|
),
|
|
"integer_method_name": (
|
|
f"{constant_name} = ('literal_method_alpha', 123)",
|
|
"must use literal method names",
|
|
),
|
|
"none_method_name": (
|
|
f"{constant_name} = ('literal_method_alpha', None)",
|
|
"must use literal method names",
|
|
),
|
|
}
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
for fixture_name, (source, error_snippet) in invalid_sources.items():
|
|
with self.subTest(fixture_name=fixture_name):
|
|
with self.assertRaisesRegex(AssertionError, re.escape(error_snippet)):
|
|
self._release_index_source_shape_fixture_guard_method_names_from_source(
|
|
source
|
|
)
|
|
|
|
def test_training_m64_release_index_source_shape_fixture_guard_methods_accept_valid_literal_sources(
|
|
self,
|
|
) -> None:
|
|
constant_name = "TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS"
|
|
guard_name = (
|
|
"test_training_m64_release_index_source_shape_fixture_guard_methods_accept_valid_literal_sources"
|
|
)
|
|
expected_literal_order = (
|
|
"literal_method_gamma",
|
|
"literal_method_alpha",
|
|
"literal_method_beta",
|
|
)
|
|
ordered_source = f"""
|
|
{constant_name} = (
|
|
{expected_literal_order[0]!r},
|
|
{expected_literal_order[1]!r},
|
|
{expected_literal_order[2]!r},
|
|
)
|
|
"""
|
|
single_item_source = f"{constant_name} = ('literal_method_single',)"
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
source_method_names = (
|
|
self._release_index_source_shape_fixture_guard_method_names_from_source(
|
|
ordered_source
|
|
)
|
|
)
|
|
|
|
self.assertEqual(source_method_names, expected_literal_order)
|
|
self.assertNotEqual(source_method_names, tuple(sorted(source_method_names)))
|
|
self.assertEqual(
|
|
self._release_index_source_shape_fixture_guard_method_names_from_source(
|
|
single_item_source
|
|
),
|
|
("literal_method_single",),
|
|
)
|
|
|
|
def test_training_m65_release_index_source_shape_fixture_guard_methods_constant_inventory_exactness_self_lock(
|
|
self,
|
|
) -> None:
|
|
expected_source_shape_fixture_guards = (
|
|
"test_training_m55_release_index_required_snippet_inventory_source_shape_is_locked",
|
|
"test_training_m56_release_index_required_snippet_inventory_source_shape_rejects_dynamic_fixtures",
|
|
"test_training_m57_release_index_required_snippet_inventory_source_shape_diagnostics_are_locked",
|
|
"test_training_m58_release_index_required_snippet_inventory_source_shape_accepts_literal_fixtures",
|
|
"test_training_m59_release_index_required_snippet_inventory_source_shape_preserves_literal_order",
|
|
"test_training_m60_release_index_source_shape_fixture_guard_inventory_self_lock_is_current",
|
|
"test_training_m61_release_index_source_shape_fixture_guard_methods_constant_source_shape_is_locked",
|
|
"test_training_m62_release_index_source_shape_fixture_guard_methods_reject_dynamic_constant_sources",
|
|
"test_training_m63_release_index_source_shape_fixture_guard_methods_constant_diagnostics_are_locked",
|
|
"test_training_m64_release_index_source_shape_fixture_guard_methods_accept_valid_literal_sources",
|
|
)
|
|
guard_name = (
|
|
"test_training_m65_release_index_source_shape_fixture_guard_methods_constant_inventory_exactness_self_lock"
|
|
)
|
|
test_case_name = f"{type(self).__module__}.{type(self).__qualname__}"
|
|
source_shape_start = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
expected_source_shape_fixture_guards[0]
|
|
)
|
|
source_shape_end = source_shape_start + len(expected_source_shape_fixture_guards)
|
|
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS,
|
|
expected_source_shape_fixture_guards,
|
|
)
|
|
self.assertEqual(
|
|
len(TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS),
|
|
len(set(TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS)),
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[
|
|
source_shape_start:source_shape_end
|
|
],
|
|
TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS,
|
|
)
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
for method_name in TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS:
|
|
with self.subTest(method_name=method_name):
|
|
loader = unittest.TestLoader()
|
|
suite = loader.loadTestsFromName(f"{test_case_name}.{method_name}")
|
|
|
|
self.assertEqual(loader.errors, [])
|
|
self.assertEqual(suite.countTestCases(), 1)
|
|
|
|
def test_training_m66_release_index_source_shape_fixture_guard_methods_constant_source_exactness_self_lock(
|
|
self,
|
|
) -> None:
|
|
expected_source_shape_fixture_guards = (
|
|
"test_training_m55_release_index_required_snippet_inventory_source_shape_is_locked",
|
|
"test_training_m56_release_index_required_snippet_inventory_source_shape_rejects_dynamic_fixtures",
|
|
"test_training_m57_release_index_required_snippet_inventory_source_shape_diagnostics_are_locked",
|
|
"test_training_m58_release_index_required_snippet_inventory_source_shape_accepts_literal_fixtures",
|
|
"test_training_m59_release_index_required_snippet_inventory_source_shape_preserves_literal_order",
|
|
"test_training_m60_release_index_source_shape_fixture_guard_inventory_self_lock_is_current",
|
|
"test_training_m61_release_index_source_shape_fixture_guard_methods_constant_source_shape_is_locked",
|
|
"test_training_m62_release_index_source_shape_fixture_guard_methods_reject_dynamic_constant_sources",
|
|
"test_training_m63_release_index_source_shape_fixture_guard_methods_constant_diagnostics_are_locked",
|
|
"test_training_m64_release_index_source_shape_fixture_guard_methods_accept_valid_literal_sources",
|
|
)
|
|
guard_name = (
|
|
"test_training_m66_release_index_source_shape_fixture_guard_methods_constant_source_exactness_self_lock"
|
|
)
|
|
module_source = Path(__file__).read_text(encoding="utf-8")
|
|
source_method_names = (
|
|
self._release_index_source_shape_fixture_guard_method_names_from_source(
|
|
module_source
|
|
)
|
|
)
|
|
|
|
self.assertEqual(
|
|
source_method_names,
|
|
TRAINING_M41_RELEASE_INDEX_SOURCE_SHAPE_FIXTURE_GUARD_METHODS,
|
|
)
|
|
self.assertEqual(source_method_names, expected_source_shape_fixture_guards)
|
|
self.assertEqual(len(source_method_names), len(set(source_method_names)))
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
|
|
def test_training_m67_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_self_lock(
|
|
self,
|
|
) -> None:
|
|
exactness_bridge_guard_names = (
|
|
TRAINING_M41_RELEASE_INDEX_EXACTNESS_BRIDGE_GUARD_METHODS
|
|
)
|
|
(
|
|
inventory_exactness_guard,
|
|
source_exactness_guard,
|
|
guard_name,
|
|
) = exactness_bridge_guard_names
|
|
test_case_name = f"{type(self).__module__}.{type(self).__qualname__}"
|
|
|
|
for method_name in exactness_bridge_guard_names:
|
|
with self.subTest(method_name=method_name):
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_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)
|
|
|
|
inventory_exactness_index = (
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
inventory_exactness_guard
|
|
)
|
|
)
|
|
source_exactness_index = (
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
source_exactness_guard
|
|
)
|
|
)
|
|
bridge_exactness_index = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
guard_name
|
|
)
|
|
self.assertEqual(source_exactness_index, inventory_exactness_index + 1)
|
|
self.assertEqual(bridge_exactness_index, source_exactness_index + 1)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[
|
|
inventory_exactness_index : bridge_exactness_index + 1
|
|
],
|
|
exactness_bridge_guard_names,
|
|
)
|
|
|
|
def test_training_m69_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_duplicate_negative_fixture_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m69_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_duplicate_negative_fixture_self_lock"
|
|
)
|
|
exactness_bridge_guard_names = (
|
|
TRAINING_M41_RELEASE_INDEX_EXACTNESS_BRIDGE_GUARD_METHODS
|
|
)
|
|
bridge_exactness_guard = exactness_bridge_guard_names[-1]
|
|
synthetic_duplicate_inventory = (
|
|
*TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY,
|
|
bridge_exactness_guard,
|
|
)
|
|
exact_once_counts = tuple(
|
|
synthetic_duplicate_inventory.count(method_name)
|
|
for method_name in exactness_bridge_guard_names
|
|
)
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
self.assertEqual(
|
|
synthetic_duplicate_inventory[:-1],
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY,
|
|
)
|
|
self.assertNotEqual(exact_once_counts, (1, 1, 1))
|
|
self.assertEqual(exact_once_counts, (1, 1, 2))
|
|
|
|
def test_training_m70_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_duplicate_guard_positive_diagnostic_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m70_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_duplicate_guard_positive_diagnostic_self_lock"
|
|
)
|
|
exactness_bridge_guard_names = (
|
|
TRAINING_M41_RELEASE_INDEX_EXACTNESS_BRIDGE_GUARD_METHODS
|
|
)
|
|
exact_once_counts = tuple(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.count(method_name)
|
|
for method_name in exactness_bridge_guard_names
|
|
)
|
|
bridge_start = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
exactness_bridge_guard_names[0]
|
|
)
|
|
bridge_indices = tuple(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(method_name)
|
|
for method_name in exactness_bridge_guard_names
|
|
)
|
|
test_case_name = f"{type(self).__module__}.{type(self).__qualname__}"
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
self.assertEqual(exact_once_counts, (1, 1, 1))
|
|
self.assertEqual(
|
|
bridge_indices,
|
|
tuple(range(bridge_start, bridge_start + len(exactness_bridge_guard_names))),
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[
|
|
bridge_start : bridge_start + len(exactness_bridge_guard_names)
|
|
],
|
|
exactness_bridge_guard_names,
|
|
)
|
|
for method_name in exactness_bridge_guard_names:
|
|
with self.subTest(method_name=method_name):
|
|
loader = unittest.TestLoader()
|
|
suite = loader.loadTestsFromName(f"{test_case_name}.{method_name}")
|
|
|
|
self.assertEqual(loader.errors, [])
|
|
self.assertEqual(suite.countTestCases(), 1)
|
|
|
|
@staticmethod
|
|
def _release_index_exactness_bridge_guard_method_names_from_source(
|
|
module_source: str,
|
|
) -> tuple[str, ...]:
|
|
constant_name = "TRAINING_M41_RELEASE_INDEX_EXACTNESS_BRIDGE_GUARD_METHODS"
|
|
module_tree = ast.parse(module_source)
|
|
top_level_writes = tuple(
|
|
node
|
|
for node in module_tree.body
|
|
if (
|
|
isinstance(node, ast.Assign)
|
|
and any(
|
|
isinstance(target, ast.Name) and target.id == constant_name
|
|
for target in node.targets
|
|
)
|
|
)
|
|
or (
|
|
isinstance(node, (ast.AnnAssign, ast.AugAssign))
|
|
and isinstance(node.target, ast.Name)
|
|
and node.target.id == constant_name
|
|
)
|
|
)
|
|
|
|
if len(top_level_writes) != 1:
|
|
raise AssertionError("exactness bridge guard methods must have one assignment")
|
|
|
|
constant_assignment = top_level_writes[0]
|
|
if (
|
|
not isinstance(constant_assignment, ast.Assign)
|
|
or len(constant_assignment.targets) != 1
|
|
or not isinstance(constant_assignment.targets[0], ast.Name)
|
|
or constant_assignment.targets[0].id != constant_name
|
|
):
|
|
raise AssertionError(
|
|
"exactness bridge guard methods must use one simple assignment"
|
|
)
|
|
|
|
constant_source = constant_assignment.value
|
|
disallowed_source_node_types = (
|
|
ast.Call,
|
|
ast.DictComp,
|
|
ast.GeneratorExp,
|
|
ast.List,
|
|
ast.ListComp,
|
|
ast.Name,
|
|
ast.SetComp,
|
|
ast.Starred,
|
|
)
|
|
dynamic_source_node = next(
|
|
(
|
|
node
|
|
for node in ast.walk(constant_source)
|
|
if isinstance(node, disallowed_source_node_types)
|
|
),
|
|
None,
|
|
)
|
|
if dynamic_source_node is not None:
|
|
dynamic_node = type(dynamic_source_node).__name__
|
|
raise AssertionError(
|
|
"exactness bridge guard methods use dynamic source node "
|
|
f"{dynamic_node}"
|
|
)
|
|
|
|
if not isinstance(constant_source, ast.Tuple) or len(constant_source.elts) != 3:
|
|
raise AssertionError(
|
|
"exactness bridge guard methods must be a literal triplet tuple assignment"
|
|
)
|
|
|
|
if not all(
|
|
isinstance(element, ast.Constant) and isinstance(element.value, str)
|
|
for element in constant_source.elts
|
|
):
|
|
raise AssertionError(
|
|
"exactness bridge guard methods must use literal method names"
|
|
)
|
|
|
|
try:
|
|
method_names = ast.literal_eval(constant_source)
|
|
except (SyntaxError, ValueError) as exc:
|
|
raise AssertionError(
|
|
"exactness bridge guard methods must use literal method names"
|
|
) from exc
|
|
|
|
if (
|
|
not isinstance(method_names, tuple)
|
|
or len(method_names) != 3
|
|
or not all(isinstance(method_name, str) for method_name in method_names)
|
|
):
|
|
raise AssertionError(
|
|
"exactness bridge guard methods must use literal method names"
|
|
)
|
|
|
|
return method_names
|
|
|
|
def test_training_m71_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_source_shape_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m71_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_source_shape_self_lock"
|
|
)
|
|
expected_bridge_methods = (
|
|
"test_training_m65_release_index_source_shape_fixture_guard_methods_constant_inventory_exactness_self_lock",
|
|
"test_training_m66_release_index_source_shape_fixture_guard_methods_constant_source_exactness_self_lock",
|
|
"test_training_m67_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_self_lock",
|
|
)
|
|
module_source = Path(__file__).read_text(encoding="utf-8")
|
|
source_bridge_methods = (
|
|
self._release_index_exactness_bridge_guard_method_names_from_source(
|
|
module_source
|
|
)
|
|
)
|
|
|
|
self.assertEqual(
|
|
source_bridge_methods,
|
|
TRAINING_M41_RELEASE_INDEX_EXACTNESS_BRIDGE_GUARD_METHODS,
|
|
)
|
|
self.assertEqual(source_bridge_methods, expected_bridge_methods)
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
|
|
def test_training_m72_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_rejects_dynamic_sources(
|
|
self,
|
|
) -> None:
|
|
constant_name = "TRAINING_M41_RELEASE_INDEX_EXACTNESS_BRIDGE_GUARD_METHODS"
|
|
guard_name = (
|
|
"test_training_m72_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_rejects_dynamic_sources"
|
|
)
|
|
first_method = (
|
|
"test_training_m65_release_index_source_shape_fixture_guard_methods_constant_inventory_exactness_self_lock"
|
|
)
|
|
second_method = (
|
|
"test_training_m66_release_index_source_shape_fixture_guard_methods_constant_source_exactness_self_lock"
|
|
)
|
|
third_method = (
|
|
"test_training_m67_release_index_source_shape_fixture_guard_methods_constant_inventory_source_exactness_bridge_self_lock"
|
|
)
|
|
invalid_sources = {
|
|
"list_literal": (
|
|
f"{constant_name} = [{first_method!r}, {second_method!r}, {third_method!r}]",
|
|
"dynamic source node List",
|
|
),
|
|
"name_alias": (
|
|
f"bridge_methods = ({first_method!r}, {second_method!r}, {third_method!r})\n"
|
|
f"{constant_name} = bridge_methods",
|
|
"dynamic source node Name",
|
|
),
|
|
"tuple_call": (
|
|
f"{constant_name} = tuple(({first_method!r}, {second_method!r}, {third_method!r}))",
|
|
"dynamic source node Call",
|
|
),
|
|
"starred_tuple": (
|
|
f"{constant_name} = ({first_method!r}, *({second_method!r},), {third_method!r})",
|
|
"dynamic source node Starred",
|
|
),
|
|
"list_comprehension": (
|
|
f"{constant_name} = "
|
|
f"[method for method in ({first_method!r}, {second_method!r}, {third_method!r})]",
|
|
"dynamic source node ListComp",
|
|
),
|
|
"generator_expression": (
|
|
f"{constant_name} = "
|
|
f"(method for method in ({first_method!r}, {second_method!r}, {third_method!r}))",
|
|
"dynamic source node GeneratorExp",
|
|
),
|
|
}
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
for fixture_name, (source, error_snippet) in invalid_sources.items():
|
|
with self.subTest(fixture_name=fixture_name):
|
|
with self.assertRaisesRegex(AssertionError, re.escape(error_snippet)):
|
|
self._release_index_exactness_bridge_guard_method_names_from_source(
|
|
source
|
|
)
|
|
|
|
def test_training_m73_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostics_are_locked(
|
|
self,
|
|
) -> None:
|
|
constant_name = "TRAINING_M41_RELEASE_INDEX_EXACTNESS_BRIDGE_GUARD_METHODS"
|
|
guard_name = (
|
|
"test_training_m73_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostics_are_locked"
|
|
)
|
|
literal_methods = (
|
|
"literal_bridge_alpha",
|
|
"literal_bridge_beta",
|
|
"literal_bridge_gamma",
|
|
)
|
|
valid_triplet_source = (
|
|
f"({literal_methods[0]!r}, {literal_methods[1]!r}, "
|
|
f"{literal_methods[2]!r})"
|
|
)
|
|
invalid_sources = {
|
|
"missing_assignment": (
|
|
"UNRELATED_BRIDGE_GUARD_METHODS = ('literal_bridge_alpha',)",
|
|
"must have one assignment",
|
|
),
|
|
"duplicate_top_level_assignment": (
|
|
f"{constant_name} = {valid_triplet_source}\n"
|
|
f"{constant_name} = {valid_triplet_source}",
|
|
"must have one assignment",
|
|
),
|
|
"multiple_assignment_targets": (
|
|
f"{constant_name} = bridge_methods = {valid_triplet_source}",
|
|
"must use one simple assignment",
|
|
),
|
|
"empty_tuple": (
|
|
f"{constant_name} = ()",
|
|
"must be a literal triplet tuple assignment",
|
|
),
|
|
"two_item_tuple": (
|
|
f"{constant_name} = ({literal_methods[0]!r}, {literal_methods[1]!r})",
|
|
"must be a literal triplet tuple assignment",
|
|
),
|
|
"four_item_tuple": (
|
|
f"{constant_name} = ("
|
|
f"{literal_methods[0]!r}, {literal_methods[1]!r}, "
|
|
f"{literal_methods[2]!r}, 'literal_bridge_delta')",
|
|
"must be a literal triplet tuple assignment",
|
|
),
|
|
"integer_literal_method_name": (
|
|
f"{constant_name} = ({literal_methods[0]!r}, 123, {literal_methods[2]!r})",
|
|
"must use literal method names",
|
|
),
|
|
"none_literal_method_name": (
|
|
f"{constant_name} = ({literal_methods[0]!r}, None, {literal_methods[2]!r})",
|
|
"must use literal method names",
|
|
),
|
|
}
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
for fixture_name, (source, error_snippet) in invalid_sources.items():
|
|
with self.subTest(fixture_name=fixture_name):
|
|
with self.assertRaisesRegex(AssertionError, re.escape(error_snippet)):
|
|
self._release_index_exactness_bridge_guard_method_names_from_source(
|
|
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)
|
|
|
|
@staticmethod
|
|
def _release_index_m74_diagnostic_fixture_inventory_source_nodes(
|
|
m74_method: ast.FunctionDef,
|
|
) -> tuple[ast.Tuple, ast.Tuple]:
|
|
local_names = (
|
|
"expected_fixture_diagnostics",
|
|
"allowed_diagnostic_snippets",
|
|
)
|
|
disallowed_source_node_types = (
|
|
ast.BinOp,
|
|
ast.Call,
|
|
ast.Dict,
|
|
ast.DictComp,
|
|
ast.GeneratorExp,
|
|
ast.List,
|
|
ast.ListComp,
|
|
ast.Name,
|
|
ast.Set,
|
|
ast.SetComp,
|
|
ast.Starred,
|
|
)
|
|
source_nodes = []
|
|
|
|
for local_name in local_names:
|
|
def local_write(node: ast.AST) -> bool:
|
|
if isinstance(node, ast.Assign):
|
|
targets = node.targets
|
|
elif isinstance(node, (ast.AnnAssign, ast.AugAssign)):
|
|
targets = (node.target,)
|
|
else:
|
|
return False
|
|
return any(
|
|
isinstance(target, ast.Name) and target.id == local_name
|
|
for target in targets
|
|
)
|
|
|
|
writes = tuple(
|
|
node for node in ast.walk(m74_method) if local_write(node)
|
|
)
|
|
|
|
if len(writes) != 1:
|
|
raise AssertionError(
|
|
"diagnostic fixture inventory source shape must have one "
|
|
f"{local_name} assignment"
|
|
)
|
|
|
|
assignment = writes[0]
|
|
if (
|
|
not isinstance(assignment, ast.Assign)
|
|
or len(assignment.targets) != 1
|
|
or not isinstance(assignment.targets[0], ast.Name)
|
|
or assignment.targets[0].id != local_name
|
|
):
|
|
raise AssertionError(
|
|
"diagnostic fixture inventory source shape must use one "
|
|
f"simple {local_name} assignment"
|
|
)
|
|
|
|
source_node = assignment.value
|
|
dynamic_source_node = next(
|
|
(
|
|
node
|
|
for node in ast.walk(source_node)
|
|
if isinstance(node, disallowed_source_node_types)
|
|
),
|
|
None,
|
|
)
|
|
if dynamic_source_node is not None:
|
|
dynamic_node = type(dynamic_source_node).__name__
|
|
raise AssertionError(
|
|
"diagnostic fixture inventory source shape uses dynamic "
|
|
f"source node {dynamic_node}"
|
|
)
|
|
|
|
if not isinstance(source_node, ast.Tuple) or not source_node.elts:
|
|
raise AssertionError(
|
|
"diagnostic fixture inventory source shape must use "
|
|
"literal tuple assignments"
|
|
)
|
|
|
|
source_nodes.append(source_node)
|
|
|
|
return (source_nodes[0], source_nodes[1])
|
|
|
|
def test_training_m75_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m75_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_self_lock"
|
|
)
|
|
m74_guard_name = (
|
|
"test_training_m74_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_self_lock"
|
|
)
|
|
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"),
|
|
)
|
|
expected_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)
|
|
m74_methods = tuple(
|
|
node
|
|
for node in ast.walk(module_tree)
|
|
if isinstance(node, ast.FunctionDef) and node.name == m74_guard_name
|
|
)
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
self.assertEqual(len(m74_methods), 1)
|
|
m74_method = m74_methods[0]
|
|
fixture_source, snippet_source = (
|
|
self._release_index_m74_diagnostic_fixture_inventory_source_nodes(
|
|
m74_method
|
|
)
|
|
)
|
|
|
|
self.assertIsInstance(fixture_source, ast.Tuple)
|
|
self.assertIsInstance(snippet_source, ast.Tuple)
|
|
fixture_diagnostics = ast.literal_eval(fixture_source)
|
|
diagnostic_snippets = ast.literal_eval(snippet_source)
|
|
self.assertEqual(fixture_diagnostics, expected_fixture_diagnostics)
|
|
self.assertEqual(diagnostic_snippets, expected_allowed_diagnostic_snippets)
|
|
self.assertNotEqual(fixture_diagnostics, tuple(sorted(fixture_diagnostics)))
|
|
self.assertNotEqual(diagnostic_snippets, tuple(sorted(diagnostic_snippets)))
|
|
|
|
self.assertEqual(len(fixture_source.elts), 8)
|
|
self.assertTrue(
|
|
all(
|
|
isinstance(fixture_tuple, ast.Tuple) and len(fixture_tuple.elts) == 2
|
|
for fixture_tuple in fixture_source.elts
|
|
)
|
|
)
|
|
fixture_literal_nodes = tuple(
|
|
fixture_literal
|
|
for fixture_tuple in fixture_source.elts
|
|
for fixture_literal in fixture_tuple.elts
|
|
)
|
|
self.assertTrue(
|
|
all(
|
|
isinstance(fixture_literal, ast.Constant)
|
|
and isinstance(fixture_literal.value, str)
|
|
for fixture_literal in fixture_literal_nodes
|
|
)
|
|
)
|
|
self.assertEqual(len(snippet_source.elts), 4)
|
|
self.assertTrue(
|
|
all(
|
|
isinstance(snippet_literal, ast.Constant)
|
|
and isinstance(snippet_literal.value, str)
|
|
and bool(snippet_literal.value)
|
|
for snippet_literal in snippet_source.elts
|
|
)
|
|
)
|
|
|
|
def test_training_m76_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_rejects_dynamic_sources(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m76_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_rejects_dynamic_sources"
|
|
)
|
|
fixture_pair = "('missing_assignment', 'must have one assignment')"
|
|
snippet = "'must have one assignment'"
|
|
valid_fixture_source = f"({fixture_pair},)"
|
|
valid_snippet_source = f"({snippet},)"
|
|
|
|
def synthetic_m74_method(
|
|
fixture_source: str,
|
|
snippet_source: str,
|
|
prefix: str = "",
|
|
) -> ast.FunctionDef:
|
|
module_tree = ast.parse(
|
|
"def test_training_m74_synthetic_guard(self):\n"
|
|
f"{prefix}"
|
|
f" expected_fixture_diagnostics = {fixture_source}\n"
|
|
f" allowed_diagnostic_snippets = {snippet_source}\n"
|
|
)
|
|
self.assertEqual(len(module_tree.body), 1)
|
|
method = module_tree.body[0]
|
|
self.assertIsInstance(method, ast.FunctionDef)
|
|
return method
|
|
|
|
invalid_sources = {
|
|
"fixture_list_literal": (
|
|
f"[{fixture_pair}]",
|
|
valid_snippet_source,
|
|
"",
|
|
"List",
|
|
),
|
|
"fixture_name_alias": (
|
|
"fixture_diagnostics",
|
|
valid_snippet_source,
|
|
f" fixture_diagnostics = ({fixture_pair},)\n",
|
|
"Name",
|
|
),
|
|
"fixture_tuple_call": (
|
|
f"tuple(({fixture_pair},))",
|
|
valid_snippet_source,
|
|
"",
|
|
"Call",
|
|
),
|
|
"fixture_dict_literal": (
|
|
"{'missing_assignment': 'must have one assignment'}",
|
|
valid_snippet_source,
|
|
"",
|
|
"Dict",
|
|
),
|
|
"fixture_set_literal": (
|
|
f"{{{fixture_pair}}}",
|
|
valid_snippet_source,
|
|
"",
|
|
"Set",
|
|
),
|
|
"fixture_list_comprehension": (
|
|
f"[diagnostic for diagnostic in ({fixture_pair},)]",
|
|
valid_snippet_source,
|
|
"",
|
|
"ListComp",
|
|
),
|
|
"snippet_generator_expression": (
|
|
valid_fixture_source,
|
|
f"(snippet for snippet in ({snippet},))",
|
|
"",
|
|
"GeneratorExp",
|
|
),
|
|
"snippet_starred_tuple": (
|
|
valid_fixture_source,
|
|
f"(*({snippet},),)",
|
|
"",
|
|
"Starred",
|
|
),
|
|
}
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
for fixture_name, (
|
|
fixture_source,
|
|
snippet_source,
|
|
prefix,
|
|
node_type,
|
|
) in invalid_sources.items():
|
|
with self.subTest(fixture_name=fixture_name):
|
|
with self.assertRaisesRegex(
|
|
AssertionError,
|
|
re.escape(f"dynamic source node {node_type}"),
|
|
):
|
|
self._release_index_m74_diagnostic_fixture_inventory_source_nodes(
|
|
synthetic_m74_method(fixture_source, snippet_source, prefix)
|
|
)
|
|
|
|
def test_training_m77_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_edge_diagnostics_are_locked(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m77_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_edge_diagnostics_are_locked"
|
|
)
|
|
fixture_pair = "('missing_assignment', 'must have one assignment')"
|
|
snippet = "'must have one assignment'"
|
|
valid_fixture_source = f"({fixture_pair},)"
|
|
valid_snippet_source = f"({snippet},)"
|
|
expected_assignment = (
|
|
f" expected_fixture_diagnostics = {valid_fixture_source}\n"
|
|
)
|
|
allowed_assignment = (
|
|
f" allowed_diagnostic_snippets = {valid_snippet_source}\n"
|
|
)
|
|
|
|
def synthetic_m74_method(source_body: str) -> ast.FunctionDef:
|
|
module_tree = ast.parse(
|
|
"def test_training_m74_synthetic_guard(self):\n"
|
|
f"{source_body}"
|
|
)
|
|
self.assertEqual(len(module_tree.body), 1)
|
|
method = module_tree.body[0]
|
|
self.assertIsInstance(method, ast.FunctionDef)
|
|
return method
|
|
|
|
invalid_sources = {
|
|
"missing_expected_assignment": (
|
|
allowed_assignment,
|
|
"must have one expected_fixture_diagnostics assignment",
|
|
),
|
|
"duplicate_expected_assignment": (
|
|
f"{expected_assignment}{expected_assignment}{allowed_assignment}",
|
|
"must have one expected_fixture_diagnostics assignment",
|
|
),
|
|
"annotated_expected_assignment": (
|
|
f" expected_fixture_diagnostics: tuple = {valid_fixture_source}\n"
|
|
f"{allowed_assignment}",
|
|
"must use one simple expected_fixture_diagnostics assignment",
|
|
),
|
|
"augmented_expected_assignment": (
|
|
f" expected_fixture_diagnostics += {valid_fixture_source}\n"
|
|
f"{allowed_assignment}",
|
|
"must use one simple expected_fixture_diagnostics assignment",
|
|
),
|
|
"missing_allowed_assignment": (
|
|
expected_assignment,
|
|
"must have one allowed_diagnostic_snippets assignment",
|
|
),
|
|
"duplicate_allowed_assignment": (
|
|
f"{expected_assignment}{allowed_assignment}{allowed_assignment}",
|
|
"must have one allowed_diagnostic_snippets assignment",
|
|
),
|
|
"annotated_allowed_assignment": (
|
|
f"{expected_assignment}"
|
|
f" allowed_diagnostic_snippets: tuple = {valid_snippet_source}\n",
|
|
"must use one simple allowed_diagnostic_snippets assignment",
|
|
),
|
|
"augmented_allowed_assignment": (
|
|
f"{expected_assignment}"
|
|
f" allowed_diagnostic_snippets += {valid_snippet_source}\n",
|
|
"must use one simple allowed_diagnostic_snippets assignment",
|
|
),
|
|
"fixture_scalar_string": (
|
|
f" expected_fixture_diagnostics = {snippet}\n"
|
|
f"{allowed_assignment}",
|
|
"literal tuple assignments",
|
|
),
|
|
"snippet_scalar_string": (
|
|
f"{expected_assignment}"
|
|
f" allowed_diagnostic_snippets = {snippet}\n",
|
|
"literal tuple assignments",
|
|
),
|
|
"fixture_empty_tuple": (
|
|
f" expected_fixture_diagnostics = ()\n{allowed_assignment}",
|
|
"literal tuple assignments",
|
|
),
|
|
"snippet_empty_tuple": (
|
|
f"{expected_assignment} allowed_diagnostic_snippets = ()\n",
|
|
"literal tuple assignments",
|
|
),
|
|
"fixture_empty_list": (
|
|
f" expected_fixture_diagnostics = []\n{allowed_assignment}",
|
|
"dynamic source node List",
|
|
),
|
|
"snippet_empty_list": (
|
|
f"{expected_assignment} allowed_diagnostic_snippets = []\n",
|
|
"dynamic source node List",
|
|
),
|
|
}
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
for fixture_name, (source_body, error_snippet) in invalid_sources.items():
|
|
with self.subTest(fixture_name=fixture_name):
|
|
with self.assertRaisesRegex(
|
|
AssertionError,
|
|
re.escape(error_snippet),
|
|
):
|
|
self._release_index_m74_diagnostic_fixture_inventory_source_nodes(
|
|
synthetic_m74_method(source_body)
|
|
)
|
|
|
|
def test_training_m78_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_accepts_ordered_literal_sources(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m78_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_accepts_ordered_literal_sources"
|
|
)
|
|
expected_fixture_diagnostics = (
|
|
("zeta_fixture_gap", "zeta diagnostic stays literal"),
|
|
("alpha_fixture_gap", "alpha diagnostic stays literal"),
|
|
("mango_fixture_gap", "mango diagnostic stays literal"),
|
|
)
|
|
expected_allowed_diagnostic_snippets = (
|
|
"zeta diagnostic stays literal",
|
|
"alpha diagnostic stays literal",
|
|
"mango diagnostic stays literal",
|
|
)
|
|
disallowed_source_node_types = (
|
|
ast.BinOp,
|
|
ast.Call,
|
|
ast.Dict,
|
|
ast.DictComp,
|
|
ast.GeneratorExp,
|
|
ast.List,
|
|
ast.ListComp,
|
|
ast.Name,
|
|
ast.Set,
|
|
ast.SetComp,
|
|
ast.Starred,
|
|
)
|
|
|
|
def synthetic_m74_method() -> ast.FunctionDef:
|
|
module_tree = ast.parse(
|
|
"def test_training_m74_synthetic_guard(self):\n"
|
|
" expected_fixture_diagnostics = (\n"
|
|
" ('zeta_fixture_gap', 'zeta diagnostic stays literal'),\n"
|
|
" ('alpha_fixture_gap', 'alpha diagnostic stays literal'),\n"
|
|
" ('mango_fixture_gap', 'mango diagnostic stays literal'),\n"
|
|
" )\n"
|
|
" allowed_diagnostic_snippets = (\n"
|
|
" 'zeta diagnostic stays literal',\n"
|
|
" 'alpha diagnostic stays literal',\n"
|
|
" 'mango diagnostic stays literal',\n"
|
|
" )\n"
|
|
)
|
|
self.assertEqual(len(module_tree.body), 1)
|
|
method = module_tree.body[0]
|
|
self.assertIsInstance(method, ast.FunctionDef)
|
|
return method
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
fixture_source, snippet_source = (
|
|
self._release_index_m74_diagnostic_fixture_inventory_source_nodes(
|
|
synthetic_m74_method()
|
|
)
|
|
)
|
|
|
|
self.assertIsInstance(fixture_source, ast.Tuple)
|
|
self.assertIsInstance(snippet_source, ast.Tuple)
|
|
fixture_diagnostics = ast.literal_eval(fixture_source)
|
|
diagnostic_snippets = ast.literal_eval(snippet_source)
|
|
self.assertEqual(fixture_diagnostics, expected_fixture_diagnostics)
|
|
self.assertEqual(diagnostic_snippets, expected_allowed_diagnostic_snippets)
|
|
self.assertNotEqual(
|
|
expected_fixture_diagnostics,
|
|
tuple(sorted(expected_fixture_diagnostics)),
|
|
)
|
|
self.assertNotEqual(
|
|
expected_allowed_diagnostic_snippets,
|
|
tuple(sorted(expected_allowed_diagnostic_snippets)),
|
|
)
|
|
|
|
self.assertTrue(
|
|
all(
|
|
isinstance(fixture_tuple, ast.Tuple) and len(fixture_tuple.elts) == 2
|
|
for fixture_tuple in fixture_source.elts
|
|
)
|
|
)
|
|
fixture_literal_nodes = tuple(
|
|
fixture_literal
|
|
for fixture_tuple in fixture_source.elts
|
|
for fixture_literal in fixture_tuple.elts
|
|
)
|
|
self.assertTrue(
|
|
all(
|
|
isinstance(fixture_literal, ast.Constant)
|
|
and isinstance(fixture_literal.value, str)
|
|
for fixture_literal in fixture_literal_nodes
|
|
)
|
|
)
|
|
self.assertTrue(
|
|
all(
|
|
isinstance(snippet_literal, ast.Constant)
|
|
and isinstance(snippet_literal.value, str)
|
|
for snippet_literal in snippet_source.elts
|
|
)
|
|
)
|
|
self.assertFalse(
|
|
any(
|
|
isinstance(node, disallowed_source_node_types)
|
|
for node in (
|
|
*ast.walk(fixture_source),
|
|
*ast.walk(snippet_source),
|
|
)
|
|
)
|
|
)
|
|
|
|
def test_training_m79_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m79_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_self_lock"
|
|
)
|
|
diagnostic_fixture_inventory_guard_cluster = (
|
|
TRAINING_M41_RELEASE_INDEX_DIAGNOSTIC_FIXTURE_INVENTORY_GUARD_CLUSTER
|
|
)
|
|
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__}"
|
|
|
|
def local_assignment_value(method_name: str, local_name: str) -> ast.AST:
|
|
methods = tuple(
|
|
node
|
|
for node in ast.walk(module_tree)
|
|
if isinstance(node, ast.FunctionDef) and node.name == method_name
|
|
)
|
|
self.assertEqual(len(methods), 1)
|
|
assignments = tuple(
|
|
node.value
|
|
for node in ast.walk(methods[0])
|
|
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_value(
|
|
"test_training_m41_release_index_guard_inventory_is_current",
|
|
"required_guard_tests_by_role",
|
|
)
|
|
)
|
|
expected_inventory = ast.literal_eval(
|
|
local_assignment_value(
|
|
"test_training_m52_release_index_guard_inventory_order_and_uniqueness_self_lock",
|
|
"expected_inventory",
|
|
)
|
|
)
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
self.assertEqual(len(diagnostic_fixture_inventory_guard_cluster), 5)
|
|
for method_name in diagnostic_fixture_inventory_guard_cluster:
|
|
with self.subTest(method_name=method_name):
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_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)
|
|
|
|
cluster_start = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
diagnostic_fixture_inventory_guard_cluster[0]
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[
|
|
cluster_start : cluster_start
|
|
+ len(diagnostic_fixture_inventory_guard_cluster)
|
|
],
|
|
diagnostic_fixture_inventory_guard_cluster,
|
|
)
|
|
self.assertEqual(
|
|
tuple(
|
|
method_name
|
|
for method_name in role_mapping.values()
|
|
if method_name in diagnostic_fixture_inventory_guard_cluster
|
|
),
|
|
diagnostic_fixture_inventory_guard_cluster,
|
|
)
|
|
self.assertEqual(
|
|
tuple(
|
|
method_name
|
|
for method_name in expected_inventory
|
|
if method_name in diagnostic_fixture_inventory_guard_cluster
|
|
),
|
|
diagnostic_fixture_inventory_guard_cluster,
|
|
)
|
|
|
|
def test_training_m80_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_negative_fixture_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m80_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_negative_fixture_self_lock"
|
|
)
|
|
diagnostic_fixture_inventory_guard_cluster = (
|
|
TRAINING_M41_RELEASE_INDEX_DIAGNOSTIC_FIXTURE_INVENTORY_GUARD_CLUSTER
|
|
)
|
|
base_inventory = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY
|
|
cluster_start = base_inventory.index(diagnostic_fixture_inventory_guard_cluster[0])
|
|
separator_method = base_inventory[0]
|
|
|
|
def validate_diagnostic_fixture_inventory_guard_cluster(
|
|
inventory: tuple[str, ...],
|
|
) -> None:
|
|
missing_methods = tuple(
|
|
method_name
|
|
for method_name in diagnostic_fixture_inventory_guard_cluster
|
|
if method_name not in inventory
|
|
)
|
|
if missing_methods:
|
|
raise AssertionError(
|
|
"missing diagnostic fixture inventory guard cluster method "
|
|
f"{missing_methods[0]}"
|
|
)
|
|
|
|
duplicate_methods = tuple(
|
|
method_name
|
|
for method_name in diagnostic_fixture_inventory_guard_cluster
|
|
if inventory.count(method_name) != 1
|
|
)
|
|
if duplicate_methods:
|
|
raise AssertionError(
|
|
"duplicate diagnostic fixture inventory guard cluster method "
|
|
f"{duplicate_methods[0]}"
|
|
)
|
|
|
|
cluster_positions = tuple(
|
|
inventory.index(method_name)
|
|
for method_name in diagnostic_fixture_inventory_guard_cluster
|
|
)
|
|
ordered_positions = tuple(sorted(cluster_positions))
|
|
expected_positions = tuple(
|
|
range(ordered_positions[0], ordered_positions[0] + len(ordered_positions))
|
|
)
|
|
if ordered_positions != expected_positions:
|
|
raise AssertionError(
|
|
"contiguous diagnostic fixture inventory guard cluster positions "
|
|
f"{ordered_positions}"
|
|
)
|
|
|
|
ordered_cluster = inventory[
|
|
ordered_positions[0] : ordered_positions[0]
|
|
+ len(diagnostic_fixture_inventory_guard_cluster)
|
|
]
|
|
if ordered_cluster != diagnostic_fixture_inventory_guard_cluster:
|
|
raise AssertionError(
|
|
"order diagnostic fixture inventory guard cluster mismatch "
|
|
f"{ordered_cluster}"
|
|
)
|
|
|
|
negative_inventories = {
|
|
"missing": (
|
|
tuple(
|
|
method_name
|
|
for method_name in base_inventory
|
|
if method_name != diagnostic_fixture_inventory_guard_cluster[2]
|
|
),
|
|
"missing",
|
|
),
|
|
"duplicate": (
|
|
(*base_inventory, diagnostic_fixture_inventory_guard_cluster[1]),
|
|
"duplicate",
|
|
),
|
|
"contiguous": (
|
|
(
|
|
*base_inventory[: cluster_start + 2],
|
|
separator_method,
|
|
*base_inventory[cluster_start + 2 :],
|
|
),
|
|
"contiguous",
|
|
),
|
|
"order": (
|
|
(
|
|
*base_inventory[:cluster_start],
|
|
diagnostic_fixture_inventory_guard_cluster[1],
|
|
diagnostic_fixture_inventory_guard_cluster[0],
|
|
*diagnostic_fixture_inventory_guard_cluster[2:],
|
|
*base_inventory[
|
|
cluster_start
|
|
+ len(diagnostic_fixture_inventory_guard_cluster) :
|
|
],
|
|
),
|
|
"order",
|
|
),
|
|
}
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
validate_diagnostic_fixture_inventory_guard_cluster(base_inventory)
|
|
for fixture_name, (
|
|
synthetic_inventory,
|
|
diagnostic_snippet,
|
|
) in negative_inventories.items():
|
|
with self.subTest(fixture_name=fixture_name):
|
|
with self.assertRaisesRegex(
|
|
AssertionError,
|
|
re.escape(diagnostic_snippet),
|
|
):
|
|
validate_diagnostic_fixture_inventory_guard_cluster(
|
|
synthetic_inventory
|
|
)
|
|
|
|
@staticmethod
|
|
def _release_index_diagnostic_fixture_inventory_guard_cluster_from_source(
|
|
module_source: str,
|
|
) -> tuple[str, ...]:
|
|
constant_name = (
|
|
"TRAINING_M41_RELEASE_INDEX_DIAGNOSTIC_FIXTURE_INVENTORY_GUARD_CLUSTER"
|
|
)
|
|
disallowed_source_node_types = (
|
|
ast.Call,
|
|
ast.Dict,
|
|
ast.GeneratorExp,
|
|
ast.List,
|
|
ast.ListComp,
|
|
ast.Name,
|
|
ast.Set,
|
|
ast.Starred,
|
|
)
|
|
module_tree = ast.parse(module_source)
|
|
|
|
def assigns_constant(node: ast.AST) -> bool:
|
|
if isinstance(node, ast.Assign):
|
|
targets = node.targets
|
|
elif isinstance(node, (ast.AnnAssign, ast.AugAssign)):
|
|
targets = (node.target,)
|
|
else:
|
|
return False
|
|
return any(
|
|
isinstance(target, ast.Name) and target.id == constant_name
|
|
for target in targets
|
|
)
|
|
|
|
constant_assignments = tuple(
|
|
node for node in module_tree.body if assigns_constant(node)
|
|
)
|
|
|
|
if len(constant_assignments) != 1:
|
|
raise AssertionError(
|
|
"diagnostic fixture inventory guard cluster must have one assignment"
|
|
)
|
|
|
|
constant_assignment = constant_assignments[0]
|
|
if (
|
|
not isinstance(constant_assignment, ast.Assign)
|
|
or len(constant_assignment.targets) != 1
|
|
or not isinstance(constant_assignment.targets[0], ast.Name)
|
|
):
|
|
raise AssertionError(
|
|
"diagnostic fixture inventory guard cluster must be a simple assignment"
|
|
)
|
|
|
|
constant_source = constant_assignment.value
|
|
dynamic_source_node = next(
|
|
(
|
|
node
|
|
for node in ast.walk(constant_source)
|
|
if isinstance(node, disallowed_source_node_types)
|
|
),
|
|
None,
|
|
)
|
|
if dynamic_source_node is not None:
|
|
dynamic_node = type(dynamic_source_node).__name__
|
|
raise AssertionError(
|
|
"diagnostic fixture inventory guard cluster uses dynamic source node "
|
|
f"{dynamic_node}"
|
|
)
|
|
|
|
if not isinstance(constant_source, ast.Tuple):
|
|
raise AssertionError(
|
|
"diagnostic fixture inventory guard cluster must be a literal tuple assignment"
|
|
)
|
|
|
|
if not constant_source.elts or not all(
|
|
isinstance(method_node, ast.Constant)
|
|
and isinstance(method_node.value, str)
|
|
for method_node in constant_source.elts
|
|
):
|
|
raise AssertionError(
|
|
"diagnostic fixture inventory guard cluster must use literal method names"
|
|
)
|
|
|
|
try:
|
|
method_names = ast.literal_eval(constant_source)
|
|
except (SyntaxError, ValueError) as exc:
|
|
raise AssertionError(
|
|
"diagnostic fixture inventory guard cluster must use literal method names"
|
|
) from exc
|
|
|
|
if not all(isinstance(method_name, str) for method_name in method_names):
|
|
raise AssertionError(
|
|
"diagnostic fixture inventory guard cluster must use literal method names"
|
|
)
|
|
|
|
return method_names
|
|
|
|
def test_training_m81_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m81_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_self_lock"
|
|
)
|
|
expected_cluster = (
|
|
"test_training_m74_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_self_lock",
|
|
"test_training_m75_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_self_lock",
|
|
"test_training_m76_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_rejects_dynamic_sources",
|
|
"test_training_m77_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_edge_diagnostics_are_locked",
|
|
"test_training_m78_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_source_shape_accepts_ordered_literal_sources",
|
|
)
|
|
module_source = Path(__file__).read_text(encoding="utf-8")
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
constant_cluster = (
|
|
self._release_index_diagnostic_fixture_inventory_guard_cluster_from_source(
|
|
module_source
|
|
)
|
|
)
|
|
|
|
self.assertEqual(constant_cluster, expected_cluster)
|
|
self.assertEqual(len(constant_cluster), 5)
|
|
self.assertEqual(len(constant_cluster), len(set(constant_cluster)))
|
|
for method_name in constant_cluster:
|
|
with self.subTest(method_name=method_name):
|
|
self.assertIn(
|
|
method_name,
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY,
|
|
)
|
|
|
|
def test_training_m82_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_rejects_dynamic_sources(
|
|
self,
|
|
) -> None:
|
|
constant_name = (
|
|
"TRAINING_M41_RELEASE_INDEX_DIAGNOSTIC_FIXTURE_INVENTORY_GUARD_CLUSTER"
|
|
)
|
|
guard_name = (
|
|
"test_training_m82_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_rejects_dynamic_sources"
|
|
)
|
|
first_method = "literal_method_alpha"
|
|
second_method = "literal_method_beta"
|
|
invalid_sources = {
|
|
"list_literal": (
|
|
f"{constant_name} = [{first_method!r}, {second_method!r}]",
|
|
"dynamic source node List",
|
|
),
|
|
"name_reference": (
|
|
f"fixture_guard_methods = ({first_method!r}, {second_method!r})\n"
|
|
f"{constant_name} = fixture_guard_methods",
|
|
"dynamic source node Name",
|
|
),
|
|
"tuple_call": (
|
|
f"{constant_name} = tuple(({first_method!r}, {second_method!r}))",
|
|
"dynamic source node Call",
|
|
),
|
|
"sorted_call": (
|
|
f"{constant_name} = sorted(({first_method!r}, {second_method!r}))",
|
|
"dynamic source node Call",
|
|
),
|
|
"set_literal": (
|
|
f"{constant_name} = {{{first_method!r}, {second_method!r}}}",
|
|
"dynamic source node Set",
|
|
),
|
|
"dict_literal": (
|
|
f"{constant_name} = {{{first_method!r}: {second_method!r}}}",
|
|
"dynamic source node Dict",
|
|
),
|
|
"list_comprehension": (
|
|
f"{constant_name} = [method for method in ({first_method!r}, {second_method!r})]",
|
|
"dynamic source node ListComp",
|
|
),
|
|
"generator_expression": (
|
|
f"{constant_name} = (method for method in ({first_method!r}, {second_method!r}))",
|
|
"dynamic source node GeneratorExp",
|
|
),
|
|
"starred_tuple": (
|
|
f"fixture_guard_methods = ({second_method!r},)\n"
|
|
f"{constant_name} = ({first_method!r}, *fixture_guard_methods)",
|
|
"dynamic source node Starred",
|
|
),
|
|
}
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
for fixture_name, (source, error_snippet) in invalid_sources.items():
|
|
with self.subTest(fixture_name=fixture_name):
|
|
with self.assertRaisesRegex(AssertionError, re.escape(error_snippet)):
|
|
self._release_index_diagnostic_fixture_inventory_guard_cluster_from_source(
|
|
source
|
|
)
|
|
|
|
def test_training_m83_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_edge_diagnostics_are_locked(
|
|
self,
|
|
) -> None:
|
|
constant_name = (
|
|
"TRAINING_M41_RELEASE_INDEX_DIAGNOSTIC_FIXTURE_INVENTORY_GUARD_CLUSTER"
|
|
)
|
|
guard_name = (
|
|
"test_training_m83_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_edge_diagnostics_are_locked"
|
|
)
|
|
first_method = "literal_method_alpha"
|
|
second_method = "literal_method_beta"
|
|
invalid_sources = {
|
|
"missing_target_assignment": (
|
|
"UNRELATED_FIXTURE_GUARD_CLUSTER = ()",
|
|
"must have one assignment",
|
|
),
|
|
"duplicate_top_level_assignments": (
|
|
f"{constant_name} = ({first_method!r},)\n"
|
|
f"{constant_name} = ({second_method!r},)",
|
|
"must have one assignment",
|
|
),
|
|
"annotated_assignment": (
|
|
f"{constant_name}: tuple[str, ...] = ({first_method!r},)",
|
|
"must be a simple assignment",
|
|
),
|
|
"augmented_assignment": (
|
|
f"{constant_name} += ({first_method!r},)",
|
|
"must be a simple assignment",
|
|
),
|
|
"empty_tuple_assignment": (
|
|
f"{constant_name} = ()",
|
|
"must use literal method names",
|
|
),
|
|
"integer_literal_method_name": (
|
|
f"{constant_name} = ({first_method!r}, 123)",
|
|
"must use literal method names",
|
|
),
|
|
"none_literal_method_name": (
|
|
f"{constant_name} = ({first_method!r}, None)",
|
|
"must use literal method names",
|
|
),
|
|
"scalar_string_assignment": (
|
|
f"{constant_name} = {first_method!r}",
|
|
"must be a literal tuple assignment",
|
|
),
|
|
}
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
for fixture_name, (source, error_snippet) in invalid_sources.items():
|
|
with self.subTest(fixture_name=fixture_name):
|
|
with self.assertRaisesRegex(AssertionError, re.escape(error_snippet)):
|
|
self._release_index_diagnostic_fixture_inventory_guard_cluster_from_source(
|
|
source
|
|
)
|
|
|
|
def test_training_m84_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_inventory_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m84_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_inventory_self_lock"
|
|
)
|
|
expected_governance_methods = (
|
|
"test_training_m79_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_self_lock",
|
|
"test_training_m80_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_negative_fixture_self_lock",
|
|
"test_training_m81_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_self_lock",
|
|
"test_training_m82_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_rejects_dynamic_sources",
|
|
"test_training_m83_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_edge_diagnostics_are_locked",
|
|
)
|
|
governance_methods = (
|
|
TRAINING_M41_RELEASE_INDEX_DIAGNOSTIC_FIXTURE_INVENTORY_GUARD_CLUSTER_GOVERNANCE_METHODS
|
|
)
|
|
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__}"
|
|
|
|
def local_assignment_value(method_name: str, local_name: str) -> ast.AST:
|
|
methods = tuple(
|
|
node
|
|
for node in ast.walk(module_tree)
|
|
if isinstance(node, ast.FunctionDef) and node.name == method_name
|
|
)
|
|
self.assertEqual(len(methods), 1)
|
|
assignments = tuple(
|
|
node.value
|
|
for node in ast.walk(methods[0])
|
|
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_value(
|
|
"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_value(
|
|
"test_training_m52_release_index_guard_inventory_order_and_uniqueness_self_lock",
|
|
"expected_inventory",
|
|
)
|
|
)
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
self.assertIn(guard_name, role_methods)
|
|
self.assertIn(guard_name, expected_inventory)
|
|
self.assertEqual(governance_methods, expected_governance_methods)
|
|
self.assertEqual(len(governance_methods), len(set(governance_methods)))
|
|
for method_name in governance_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)
|
|
|
|
governance_start = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
governance_methods[0]
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[
|
|
governance_start : governance_start + len(governance_methods)
|
|
],
|
|
governance_methods,
|
|
)
|
|
self.assertEqual(
|
|
tuple(
|
|
method_name
|
|
for method_name in role_methods
|
|
if method_name in governance_methods
|
|
),
|
|
governance_methods,
|
|
)
|
|
self.assertEqual(
|
|
tuple(
|
|
method_name
|
|
for method_name in expected_inventory
|
|
if method_name in governance_methods
|
|
),
|
|
governance_methods,
|
|
)
|
|
|
|
def test_training_m85_release_index_public_docs_acceptance_inventory_alignment_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m85_release_index_public_docs_acceptance_inventory_alignment_self_lock"
|
|
)
|
|
recent_closure_methods = (
|
|
"test_training_m79_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_self_lock",
|
|
"test_training_m80_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_negative_fixture_self_lock",
|
|
"test_training_m81_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_self_lock",
|
|
"test_training_m82_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_rejects_dynamic_sources",
|
|
"test_training_m83_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_edge_diagnostics_are_locked",
|
|
"test_training_m84_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_inventory_self_lock",
|
|
)
|
|
grouped_inventory = TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
inventory_by_category = dict(grouped_inventory)
|
|
flattened_required_snippets = tuple(
|
|
snippet
|
|
for _, snippets in grouped_inventory
|
|
for snippet in snippets
|
|
)
|
|
text_by_doc = {
|
|
path: path.read_text(encoding="utf-8")
|
|
for path in TRAINING_M41_RELEASE_INDEX_DOCS
|
|
}
|
|
missing_by_doc = _release_index_missing_required_snippets_by_doc(text_by_doc)
|
|
module_source = Path(__file__).read_text(encoding="utf-8")
|
|
module_tree = ast.parse(module_source)
|
|
|
|
def local_assignment_value(method_name: str, local_name: str) -> ast.AST:
|
|
methods = tuple(
|
|
node
|
|
for node in ast.walk(module_tree)
|
|
if isinstance(node, ast.FunctionDef) and node.name == method_name
|
|
)
|
|
self.assertEqual(len(methods), 1)
|
|
assignments = tuple(
|
|
node.value
|
|
for node in ast.walk(methods[0])
|
|
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_value(
|
|
"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_value(
|
|
"test_training_m52_release_index_guard_inventory_order_and_uniqueness_self_lock",
|
|
"expected_inventory",
|
|
)
|
|
)
|
|
|
|
self.assertEqual(tuple(text_by_doc), TRAINING_M41_RELEASE_INDEX_DOCS)
|
|
self.assertEqual(tuple(missing_by_doc), TRAINING_M41_RELEASE_INDEX_DOCS)
|
|
for path in TRAINING_M41_RELEASE_INDEX_DOCS:
|
|
with self.subTest(path=path.name):
|
|
self.assertEqual(missing_by_doc[path], ())
|
|
|
|
self.assertEqual(
|
|
inventory_by_category["acceptance_offline_validation"],
|
|
TRAINING_ACCEPTANCE_VALIDATION_DOC_SNIPPETS,
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_DOC_SNIPPETS,
|
|
flattened_required_snippets,
|
|
)
|
|
for category, snippets in grouped_inventory:
|
|
with self.subTest(category=category):
|
|
self.assertTrue(snippets)
|
|
self.assertEqual(
|
|
tuple(category for category, _ in grouped_inventory),
|
|
tuple(inventory_by_category),
|
|
)
|
|
|
|
recent_start = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
recent_closure_methods[0]
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[
|
|
recent_start : recent_start + len(recent_closure_methods)
|
|
],
|
|
recent_closure_methods,
|
|
)
|
|
for method_name in recent_closure_methods:
|
|
with self.subTest(method_name=method_name):
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.count(
|
|
method_name
|
|
),
|
|
1,
|
|
)
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
self.assertIn(guard_name, role_methods)
|
|
self.assertIn(guard_name, expected_inventory)
|
|
|
|
def test_training_m86_release_index_final_closure_delivery_index_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = "test_training_m86_release_index_final_closure_delivery_index_self_lock"
|
|
closure_methods = (
|
|
"test_training_m79_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_self_lock",
|
|
"test_training_m80_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_negative_fixture_self_lock",
|
|
"test_training_m81_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_self_lock",
|
|
"test_training_m82_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_rejects_dynamic_sources",
|
|
"test_training_m83_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_constant_source_shape_edge_diagnostics_are_locked",
|
|
"test_training_m84_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_inventory_self_lock",
|
|
"test_training_m85_release_index_public_docs_acceptance_inventory_alignment_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__}"
|
|
|
|
def local_assignment_value(method_name: str, local_name: str) -> ast.AST:
|
|
methods = tuple(
|
|
node
|
|
for node in ast.walk(module_tree)
|
|
if isinstance(node, ast.FunctionDef) and node.name == method_name
|
|
)
|
|
self.assertEqual(len(methods), 1)
|
|
assignments = tuple(
|
|
node.value
|
|
for node in ast.walk(methods[0])
|
|
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_value(
|
|
"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_value(
|
|
"test_training_m52_release_index_guard_inventory_order_and_uniqueness_self_lock",
|
|
"expected_inventory",
|
|
)
|
|
)
|
|
m84_governance_methods = ast.literal_eval(
|
|
local_assignment_value(
|
|
"test_training_m84_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_inventory_self_lock",
|
|
"expected_governance_methods",
|
|
)
|
|
)
|
|
delivery_methods = (*closure_methods, guard_name)
|
|
closure_start = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
closure_methods[0]
|
|
)
|
|
m79_m83_methods = closure_methods[:5]
|
|
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[
|
|
closure_start : closure_start + len(closure_methods)
|
|
],
|
|
closure_methods,
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[
|
|
closure_start : closure_start + len(delivery_methods)
|
|
],
|
|
delivery_methods,
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_DIAGNOSTIC_FIXTURE_INVENTORY_GUARD_CLUSTER_GOVERNANCE_METHODS,
|
|
m79_m83_methods,
|
|
)
|
|
self.assertEqual(m84_governance_methods, m79_m83_methods)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
"test_training_m85_release_index_public_docs_acceptance_inventory_alignment_self_lock"
|
|
),
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
"test_training_m84_release_index_source_shape_fixture_guard_methods_constant_exactness_bridge_triplet_diagnostic_fixture_inventory_guard_cluster_inventory_self_lock"
|
|
)
|
|
+ 1,
|
|
)
|
|
|
|
for method_name in closure_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(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.count(guard_name),
|
|
1,
|
|
)
|
|
self.assertEqual(role_methods.count(guard_name), 1)
|
|
self.assertEqual(expected_inventory.count(guard_name), 1)
|
|
self.assertEqual(CURRENT_TRAINING_DOC_MATURITY_MARKER, "M1-M40")
|
|
self.assertEqual(CURRENT_TRAINING_DOC_MATURITY_SPAN, "through M40")
|
|
self.assertEqual(
|
|
CURRENT_TRAINING_DOC_MATURITY_PHRASE,
|
|
"current product maturity through M40",
|
|
)
|
|
for path in TRAINING_M41_RELEASE_INDEX_DOCS:
|
|
text = path.read_text(encoding="utf-8")
|
|
with self.subTest(path=path.name):
|
|
self.assertIn(CURRENT_TRAINING_DOC_MATURITY_MARKER, text)
|
|
self.assertIn(CURRENT_TRAINING_DOC_MATURITY_SPAN, text)
|
|
|
|
def test_training_m87_release_index_final_closure_delivery_index_guard_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_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: ast.get_source_segment(module_source, node) or ""
|
|
for node in ast.walk(module_tree)
|
|
if isinstance(node, ast.FunctionDef)
|
|
}
|
|
|
|
def local_assignment_value(method_name: str, local_name: str) -> ast.AST:
|
|
methods = tuple(
|
|
node
|
|
for node in ast.walk(module_tree)
|
|
if isinstance(node, ast.FunctionDef) and node.name == method_name
|
|
)
|
|
self.assertEqual(len(methods), 1)
|
|
assignments = tuple(
|
|
node.value
|
|
for node in ast.walk(methods[0])
|
|
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_value(
|
|
"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_value(
|
|
"test_training_m52_release_index_guard_inventory_order_and_uniqueness_self_lock",
|
|
"expected_inventory",
|
|
)
|
|
)
|
|
closure_methods = ast.literal_eval(
|
|
local_assignment_value(final_closure_guard_name, "closure_methods")
|
|
)
|
|
delivery_methods = (*closure_methods, final_closure_guard_name)
|
|
delivery_start = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
delivery_methods[0]
|
|
)
|
|
|
|
self.assertIn(final_closure_guard_name, functions_by_name)
|
|
for source_reference in (
|
|
"delivery_methods = (*closure_methods, guard_name)",
|
|
"closure_start : closure_start + len(delivery_methods)",
|
|
"CURRENT_TRAINING_DOC_MATURITY_MARKER, \"M1-M40\"",
|
|
"CURRENT_TRAINING_DOC_MATURITY_SPAN, \"through M40\"",
|
|
):
|
|
with self.subTest(source_reference=source_reference):
|
|
self.assertIn(
|
|
source_reference,
|
|
functions_by_name[final_closure_guard_name],
|
|
)
|
|
|
|
self.assertEqual(delivery_methods[-1], 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(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.count(guard_name),
|
|
1,
|
|
)
|
|
self.assertEqual(role_methods.count(guard_name), 1)
|
|
self.assertEqual(expected_inventory.count(guard_name), 1)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(guard_name),
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
final_closure_guard_name
|
|
)
|
|
+ 1,
|
|
)
|
|
self.assertEqual(
|
|
role_mapping["release_index_final_closure_delivery_guard_self_lock"],
|
|
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_m89_release_index_final_closure_delivery_guard_source_chain_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m89_release_index_final_closure_delivery_guard_source_chain_self_lock"
|
|
)
|
|
final_closure_guard_name = (
|
|
"test_training_m86_release_index_final_closure_delivery_index_self_lock"
|
|
)
|
|
delivery_guard_name = (
|
|
"test_training_m87_release_index_final_closure_delivery_index_guard_self_lock"
|
|
)
|
|
source_guard_name = (
|
|
"test_training_m88_release_index_final_closure_delivery_guard_source_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")
|
|
)
|
|
source_delivery_node = local_assignment_node(
|
|
source_guard_name,
|
|
"delivery_methods",
|
|
)
|
|
delivery_chain = (
|
|
*closure_methods,
|
|
final_closure_guard_name,
|
|
delivery_guard_name,
|
|
source_guard_name,
|
|
guard_name,
|
|
)
|
|
chain_methods = delivery_chain[-4:]
|
|
chain_start = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
delivery_chain[0]
|
|
)
|
|
|
|
self.assertEqual(
|
|
ast.literal_eval(
|
|
local_assignment_node(source_guard_name, "final_closure_guard_name")
|
|
),
|
|
final_closure_guard_name,
|
|
)
|
|
self.assertEqual(
|
|
ast.literal_eval(
|
|
local_assignment_node(source_guard_name, "guarded_method_name")
|
|
),
|
|
delivery_guard_name,
|
|
)
|
|
self.assertIsInstance(source_delivery_node, ast.Tuple)
|
|
self.assertEqual(len(source_delivery_node.elts), 4)
|
|
self.assertIsInstance(source_delivery_node.elts[0], ast.Starred)
|
|
self.assertIsInstance(source_delivery_node.elts[0].value, ast.Name)
|
|
self.assertEqual(source_delivery_node.elts[0].value.id, "closure_methods")
|
|
self.assertEqual(
|
|
tuple(
|
|
node.id
|
|
for node in source_delivery_node.elts[1:]
|
|
if isinstance(node, ast.Name)
|
|
),
|
|
("final_closure_guard_name", "guarded_method_name", "guard_name"),
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[
|
|
chain_start : chain_start + len(delivery_chain)
|
|
],
|
|
delivery_chain,
|
|
)
|
|
self.assertEqual(
|
|
tuple(
|
|
method_name
|
|
for method_name in role_methods
|
|
if method_name in chain_methods
|
|
),
|
|
chain_methods,
|
|
)
|
|
self.assertEqual(
|
|
tuple(
|
|
method_name
|
|
for method_name in expected_inventory
|
|
if method_name in chain_methods
|
|
),
|
|
chain_methods,
|
|
)
|
|
self.assertEqual(
|
|
role_mapping.get(
|
|
"release_index_final_closure_delivery_guard_source_chain_self_lock"
|
|
),
|
|
guard_name,
|
|
)
|
|
for method_name in chain_methods:
|
|
with self.subTest(method_name=method_name):
|
|
loader = unittest.TestLoader()
|
|
suite = loader.loadTestsFromName(f"{test_case_name}.{method_name}")
|
|
|
|
self.assertEqual(loader.errors, [])
|
|
self.assertEqual(suite.countTestCases(), 1)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.count(
|
|
method_name
|
|
),
|
|
1,
|
|
)
|
|
|
|
def test_training_m90_release_index_final_closure_delivery_guard_source_chain_source_shape_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m90_release_index_final_closure_delivery_guard_source_chain_source_shape_self_lock"
|
|
)
|
|
guarded_method_name = (
|
|
"test_training_m89_release_index_final_closure_delivery_guard_source_chain_self_lock"
|
|
)
|
|
expected_guard_chain_names = (
|
|
"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",
|
|
guarded_method_name,
|
|
)
|
|
module_source = Path(__file__).read_text(encoding="utf-8")
|
|
module_tree = ast.parse(module_source)
|
|
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",
|
|
)
|
|
)
|
|
guarded_chain_names = tuple(
|
|
ast.literal_eval(local_assignment_node(guarded_method_name, local_name))
|
|
for local_name in (
|
|
"final_closure_guard_name",
|
|
"delivery_guard_name",
|
|
"source_guard_name",
|
|
"guard_name",
|
|
)
|
|
)
|
|
delivery_chain_node = local_assignment_node(
|
|
guarded_method_name,
|
|
"delivery_chain",
|
|
)
|
|
chain_methods_node = local_assignment_node(
|
|
guarded_method_name,
|
|
"chain_methods",
|
|
)
|
|
|
|
self.assertEqual(guarded_chain_names, expected_guard_chain_names)
|
|
self.assertIsInstance(delivery_chain_node, ast.Tuple)
|
|
self.assertEqual(len(delivery_chain_node.elts), 5)
|
|
self.assertIsInstance(delivery_chain_node.elts[0], ast.Starred)
|
|
self.assertIsInstance(delivery_chain_node.elts[0].value, ast.Name)
|
|
self.assertEqual(delivery_chain_node.elts[0].value.id, "closure_methods")
|
|
self.assertEqual(
|
|
tuple(
|
|
node.id
|
|
for node in delivery_chain_node.elts[1:]
|
|
if isinstance(node, ast.Name)
|
|
),
|
|
(
|
|
"final_closure_guard_name",
|
|
"delivery_guard_name",
|
|
"source_guard_name",
|
|
"guard_name",
|
|
),
|
|
)
|
|
self.assertIsInstance(chain_methods_node, ast.Subscript)
|
|
self.assertIsInstance(chain_methods_node.value, ast.Name)
|
|
self.assertEqual(chain_methods_node.value.id, "delivery_chain")
|
|
self.assertIsInstance(chain_methods_node.slice, ast.Slice)
|
|
self.assertIsInstance(chain_methods_node.slice.lower, ast.UnaryOp)
|
|
self.assertIsInstance(chain_methods_node.slice.lower.op, ast.USub)
|
|
self.assertIsInstance(chain_methods_node.slice.lower.operand, ast.Constant)
|
|
self.assertEqual(chain_methods_node.slice.lower.operand.value, 4)
|
|
self.assertIsNone(chain_methods_node.slice.upper)
|
|
self.assertIsNone(chain_methods_node.slice.step)
|
|
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(guard_name),
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
guarded_method_name
|
|
)
|
|
+ 1,
|
|
)
|
|
self.assertEqual(
|
|
role_mapping.get(
|
|
"release_index_final_closure_delivery_guard_source_chain_source_shape_self_lock"
|
|
),
|
|
guard_name,
|
|
)
|
|
self.assertEqual(role_methods.count(guard_name), 1)
|
|
self.assertEqual(expected_inventory.count(guard_name), 1)
|
|
|
|
def test_training_m91_release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m91_release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_self_lock"
|
|
)
|
|
source_shape_guard_name = (
|
|
"test_training_m90_release_index_final_closure_delivery_guard_source_chain_source_shape_self_lock"
|
|
)
|
|
expected_local_names = (
|
|
"final_closure_guard_name",
|
|
"delivery_guard_name",
|
|
"source_guard_name",
|
|
"guard_name",
|
|
)
|
|
expected_lookup_source = (
|
|
"ast.literal_eval(local_assignment_node(guarded_method_name, local_name))"
|
|
)
|
|
module_source = Path(__file__).read_text(encoding="utf-8")
|
|
module_tree = ast.parse(module_source)
|
|
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]
|
|
|
|
guarded_chain_names_node = local_assignment_node(
|
|
source_shape_guard_name,
|
|
"guarded_chain_names",
|
|
)
|
|
|
|
self.assertIsInstance(guarded_chain_names_node, ast.Call)
|
|
self.assertIsInstance(guarded_chain_names_node.func, ast.Name)
|
|
self.assertEqual(guarded_chain_names_node.func.id, "tuple")
|
|
self.assertEqual(len(guarded_chain_names_node.args), 1)
|
|
guarded_chain_generator = guarded_chain_names_node.args[0]
|
|
self.assertIsInstance(guarded_chain_generator, ast.GeneratorExp)
|
|
self.assertEqual(len(guarded_chain_generator.generators), 1)
|
|
generator_clause = guarded_chain_generator.generators[0]
|
|
self.assertIsInstance(generator_clause.target, ast.Name)
|
|
self.assertEqual(generator_clause.target.id, "local_name")
|
|
self.assertIsInstance(generator_clause.iter, ast.Tuple)
|
|
self.assertEqual(
|
|
ast.literal_eval(generator_clause.iter),
|
|
expected_local_names,
|
|
)
|
|
for element in generator_clause.iter.elts:
|
|
with self.subTest(local_name_node=ast.dump(element)):
|
|
self.assertIsInstance(element, ast.Constant)
|
|
self.assertIsInstance(element.value, str)
|
|
self.assertEqual(
|
|
ast.get_source_segment(module_source, guarded_chain_generator.elt),
|
|
expected_lookup_source,
|
|
)
|
|
|
|
self.assertIn(guard_name, TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.count(guard_name),
|
|
1,
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.count(
|
|
source_shape_guard_name
|
|
),
|
|
1,
|
|
)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(guard_name),
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
source_shape_guard_name
|
|
)
|
|
+ 1,
|
|
)
|
|
|
|
def test_training_m92_release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_registration_self_lock(
|
|
self,
|
|
) -> None:
|
|
guard_name = (
|
|
"test_training_m92_release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_registration_self_lock"
|
|
)
|
|
local_names_guard_name = (
|
|
"test_training_m91_release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_self_lock"
|
|
)
|
|
role_key = (
|
|
"release_index_final_closure_delivery_guard_source_chain_source_shape_local_names_registration_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",
|
|
)
|
|
)
|
|
registration_pair = (local_names_guard_name, guard_name)
|
|
local_names_guard_index = TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.index(
|
|
local_names_guard_name
|
|
)
|
|
|
|
self.assertEqual(role_mapping.get(role_key), guard_name)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY[
|
|
local_names_guard_index : local_names_guard_index
|
|
+ len(registration_pair)
|
|
],
|
|
registration_pair,
|
|
)
|
|
self.assertEqual(
|
|
tuple(method_name for method_name in role_methods if method_name in registration_pair),
|
|
registration_pair,
|
|
)
|
|
self.assertEqual(
|
|
tuple(
|
|
method_name
|
|
for method_name in expected_inventory
|
|
if method_name in registration_pair
|
|
),
|
|
registration_pair,
|
|
)
|
|
for method_name in registration_pair:
|
|
with self.subTest(method_name=method_name):
|
|
loader = unittest.TestLoader()
|
|
suite = loader.loadTestsFromName(f"{test_case_name}.{method_name}")
|
|
|
|
self.assertEqual(loader.errors, [])
|
|
self.assertEqual(suite.countTestCases(), 1)
|
|
self.assertEqual(
|
|
TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY.count(
|
|
method_name
|
|
),
|
|
1,
|
|
)
|
|
|
|
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"
|
|
inventory_guard_name = "test_training_m41_release_index_guard_inventory_is_current"
|
|
module_source = Path(__file__).read_text(encoding="utf-8")
|
|
module_tree = ast.parse(module_source)
|
|
functions_by_name = {
|
|
node.name: ast.get_source_segment(module_source, node) or ""
|
|
for node in ast.walk(module_tree)
|
|
if isinstance(node, ast.FunctionDef)
|
|
}
|
|
|
|
self.assertEqual(
|
|
[
|
|
node.name
|
|
for node in module_tree.body
|
|
if isinstance(node, ast.FunctionDef) and node.name == helper_name
|
|
],
|
|
[helper_name],
|
|
)
|
|
for guard_name in (docs_guard_name, inventory_guard_name):
|
|
with self.subTest(guard_name=guard_name):
|
|
self.assertIn(guard_name, functions_by_name)
|
|
self.assertIn(helper_name, functions_by_name[guard_name])
|
|
|
|
inventory_guard_source = functions_by_name[inventory_guard_name]
|
|
for fixture_reference in (
|
|
"PROJECT_README: missing_release_doc",
|
|
"TRAINING_PRODUCT_DOC: complete_release_doc",
|
|
"negative_fixture_missing_by_doc[TRAINING_PRODUCT_DOC], ()",
|
|
"negative_fixture_missing_by_doc[PROJECT_README]",
|
|
):
|
|
with self.subTest(fixture_reference=fixture_reference):
|
|
self.assertIn(fixture_reference, inventory_guard_source)
|
|
|
|
def test_training_m48_release_index_per_doc_helper_keeps_doc_tuple_shape(self) -> None:
|
|
complete_release_doc = "\n".join(TRAINING_M41_RELEASE_INDEX_DOC_SNIPPETS)
|
|
all_required_snippets = tuple(
|
|
(surface, snippet)
|
|
for surface, snippets in TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
for snippet in snippets
|
|
)
|
|
expected_missing = tuple(
|
|
required_snippet
|
|
for required_snippet in all_required_snippets
|
|
if required_snippet[1]
|
|
in (CURRENT_TRAINING_DOC_MATURITY_MARKER, "API contract coverage")
|
|
)
|
|
missing_release_doc = complete_release_doc
|
|
for _, snippet in expected_missing:
|
|
missing_release_doc = missing_release_doc.replace(snippet, "", 1)
|
|
docs_by_name = {
|
|
"missing-release-index.md": missing_release_doc,
|
|
"complete-release-index.md": complete_release_doc,
|
|
}
|
|
original_docs_by_name = dict(docs_by_name)
|
|
|
|
missing_by_doc = _release_index_missing_required_snippets_by_doc(docs_by_name)
|
|
|
|
self.assertEqual(len(expected_missing), 2)
|
|
self.assertEqual(tuple(missing_by_doc), tuple(docs_by_name))
|
|
self.assertEqual(missing_by_doc["missing-release-index.md"], expected_missing)
|
|
self.assertIsInstance(missing_by_doc["missing-release-index.md"], tuple)
|
|
self.assertEqual(missing_by_doc["complete-release-index.md"], ())
|
|
self.assertIsInstance(missing_by_doc["complete-release-index.md"], tuple)
|
|
self.assertEqual(docs_by_name, original_docs_by_name)
|
|
|
|
def test_training_m49_release_index_per_doc_helper_handles_empty_docs_without_mutation(self) -> None:
|
|
complete_release_doc = "\n".join(TRAINING_M41_RELEASE_INDEX_DOC_SNIPPETS)
|
|
docs_by_name = {"complete-release-index.md": complete_release_doc}
|
|
original_docs_by_name = dict(docs_by_name)
|
|
|
|
empty_missing_by_doc = _release_index_missing_required_snippets_by_doc({})
|
|
complete_missing_by_doc = _release_index_missing_required_snippets_by_doc(docs_by_name)
|
|
|
|
self.assertEqual(empty_missing_by_doc, {})
|
|
self.assertEqual(docs_by_name, original_docs_by_name)
|
|
self.assertEqual(complete_missing_by_doc["complete-release-index.md"], ())
|
|
|
|
def test_training_m50_release_index_helper_accepts_flattened_inventory_complete_doc(self) -> None:
|
|
flattened_required_snippets = tuple(
|
|
snippet
|
|
for _, snippets in TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
for snippet in snippets
|
|
)
|
|
complete_release_doc = "\n".join(flattened_required_snippets)
|
|
docs_by_name = {"synthetic-complete-release.md": complete_release_doc}
|
|
|
|
missing_by_doc = _release_index_missing_required_snippets_by_doc(docs_by_name)
|
|
|
|
self.assertTrue(flattened_required_snippets)
|
|
self.assertEqual(len(flattened_required_snippets), len(set(flattened_required_snippets)))
|
|
self.assertEqual(missing_by_doc, {"synthetic-complete-release.md": ()})
|
|
|
|
def test_training_m54_release_index_required_snippet_inventory_category_shape_is_locked(self) -> None:
|
|
inventory = TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
inventory_by_category = dict(inventory)
|
|
expected_categories = (
|
|
"current_m1_m40_marker",
|
|
"acceptance_offline_validation",
|
|
"public_api_privacy_contracts",
|
|
"package_smoke_offline_registry",
|
|
"dashboard_public_docs_privacy",
|
|
"single_set_docker_deployment",
|
|
"docker_smoke_guard_coverage",
|
|
)
|
|
flattened_snippets = tuple(
|
|
snippet
|
|
for category in expected_categories
|
|
for snippet in inventory_by_category[category]
|
|
)
|
|
|
|
self.assertEqual(tuple(category for category, _ in inventory), expected_categories)
|
|
self.assertEqual(len(expected_categories), len(set(expected_categories)))
|
|
for category in expected_categories:
|
|
with self.subTest(category=category):
|
|
snippets = inventory_by_category[category]
|
|
self.assertTrue(snippets)
|
|
for snippet in snippets:
|
|
self.assertIsInstance(snippet, str)
|
|
self.assertNotEqual(snippet, "")
|
|
|
|
self.assertEqual(TRAINING_M41_RELEASE_INDEX_DOC_SNIPPETS, flattened_snippets)
|
|
self.assertEqual(len(flattened_snippets), len(set(flattened_snippets)))
|
|
|
|
@staticmethod
|
|
def _release_index_required_snippet_inventory_source_categories(
|
|
module_source: str,
|
|
) -> tuple[str, ...]:
|
|
inventory_name = "TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY"
|
|
|
|
def assignment_targets(node: ast.AST):
|
|
if isinstance(node, ast.Assign):
|
|
return tuple(node.targets)
|
|
if isinstance(node, (ast.AnnAssign, ast.AugAssign)):
|
|
return (node.target,)
|
|
return ()
|
|
|
|
module_tree = ast.parse(module_source)
|
|
inventory_assignments = tuple(
|
|
node
|
|
for node in module_tree.body
|
|
if any(
|
|
isinstance(target, ast.Name) and target.id == inventory_name
|
|
for target in assignment_targets(node)
|
|
)
|
|
)
|
|
|
|
if len(inventory_assignments) != 1:
|
|
raise AssertionError(
|
|
"release index required snippet inventory must have one assignment"
|
|
)
|
|
|
|
inventory_source = getattr(inventory_assignments[0], "value", None)
|
|
if not isinstance(inventory_source, ast.Tuple):
|
|
raise AssertionError(
|
|
"release index required snippet inventory must be a literal tuple assignment"
|
|
)
|
|
|
|
disallowed_source_nodes = (
|
|
ast.Call,
|
|
ast.Dict,
|
|
ast.DictComp,
|
|
ast.GeneratorExp,
|
|
ast.ListComp,
|
|
ast.SetComp,
|
|
ast.Starred,
|
|
)
|
|
dynamic_source_node = next(
|
|
(
|
|
node
|
|
for node in ast.walk(inventory_source)
|
|
if isinstance(node, disallowed_source_nodes)
|
|
),
|
|
None,
|
|
)
|
|
if dynamic_source_node is not None:
|
|
dynamic_node = type(dynamic_source_node).__name__
|
|
raise AssertionError(
|
|
"release index required snippet inventory uses dynamic source node "
|
|
f"{dynamic_node}"
|
|
)
|
|
|
|
try:
|
|
inventory = ast.literal_eval(inventory_source)
|
|
except (SyntaxError, ValueError) as exc:
|
|
raise AssertionError(
|
|
"release index required snippet inventory must use literal snippets"
|
|
) from exc
|
|
|
|
if not all(
|
|
isinstance(group, tuple)
|
|
and len(group) == 2
|
|
and isinstance(group[0], str)
|
|
and isinstance(group[1], (tuple, list))
|
|
and group[1]
|
|
and all(isinstance(snippet, str) and snippet for snippet in group[1])
|
|
for group in inventory
|
|
):
|
|
raise AssertionError(
|
|
"release index required snippet inventory groups must be "
|
|
"literal category and snippet pairs"
|
|
)
|
|
|
|
return tuple(category for category, _ in inventory)
|
|
|
|
def test_training_m55_release_index_required_snippet_inventory_source_shape_is_locked(self) -> None:
|
|
module_source = Path(__file__).read_text(encoding="utf-8")
|
|
expected_categories = (
|
|
"current_m1_m40_marker",
|
|
"acceptance_offline_validation",
|
|
"public_api_privacy_contracts",
|
|
"package_smoke_offline_registry",
|
|
"dashboard_public_docs_privacy",
|
|
"single_set_docker_deployment",
|
|
"docker_smoke_guard_coverage",
|
|
)
|
|
source_group_order = (
|
|
self._release_index_required_snippet_inventory_source_categories(
|
|
module_source
|
|
)
|
|
)
|
|
|
|
self.assertEqual(source_group_order, expected_categories)
|
|
|
|
def test_training_m56_release_index_required_snippet_inventory_source_shape_rejects_dynamic_fixtures(
|
|
self,
|
|
) -> None:
|
|
inventory_name = "TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY"
|
|
invalid_sources = {
|
|
"dict_assignment": (
|
|
f"{inventory_name} = {{'literal_category': ('literal snippet',)}}",
|
|
"literal tuple assignment",
|
|
),
|
|
"call_snippets": (
|
|
f"{inventory_name} = (('literal_category', make_snippets()),)",
|
|
"dynamic source node Call",
|
|
),
|
|
"name_snippets": (
|
|
f"{inventory_name} = (('literal_category', snippets),)",
|
|
"must use literal snippets",
|
|
),
|
|
"starred_snippets": (
|
|
f"{inventory_name} = (('literal_category', (*('literal snippet',),)),)",
|
|
"dynamic source node Starred",
|
|
),
|
|
"comprehension_snippets": (
|
|
f"{inventory_name} = "
|
|
"(('literal_category', [item for item in ('literal snippet',)]),)",
|
|
"dynamic source node ListComp",
|
|
),
|
|
}
|
|
|
|
for fixture_name, (source, error_snippet) in invalid_sources.items():
|
|
with self.subTest(fixture_name=fixture_name):
|
|
with self.assertRaisesRegex(AssertionError, re.escape(error_snippet)):
|
|
self._release_index_required_snippet_inventory_source_categories(
|
|
source
|
|
)
|
|
|
|
def test_training_m57_release_index_required_snippet_inventory_source_shape_diagnostics_are_locked(
|
|
self,
|
|
) -> None:
|
|
inventory_name = "TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY"
|
|
group_shape_error = "literal category and snippet pairs"
|
|
invalid_sources = {
|
|
"zero_inventory_assignment": (
|
|
"UNRELATED_RELEASE_INDEX_INVENTORY = ()",
|
|
"must have one assignment",
|
|
),
|
|
"duplicate_inventory_assignment": (
|
|
f"{inventory_name} = (('literal_category', ('literal snippet',)),)\n"
|
|
f"{inventory_name} = (('second_literal_category', ('second literal snippet',)),)",
|
|
"must have one assignment",
|
|
),
|
|
"malformed_group_tuple": (
|
|
f"{inventory_name} = (('literal_category', ('literal snippet',), 'extra'),)",
|
|
group_shape_error,
|
|
),
|
|
"empty_snippet_group": (
|
|
f"{inventory_name} = (('literal_category', ()),)",
|
|
group_shape_error,
|
|
),
|
|
"non_string_category": (
|
|
f"{inventory_name} = ((7, ('literal snippet',)),)",
|
|
group_shape_error,
|
|
),
|
|
"non_string_snippet": (
|
|
f"{inventory_name} = (('literal_category', (7,)),)",
|
|
group_shape_error,
|
|
),
|
|
"empty_snippet": (
|
|
f"{inventory_name} = (('literal_category', ('',)),)",
|
|
group_shape_error,
|
|
),
|
|
}
|
|
|
|
for fixture_name, (source, error_snippet) in invalid_sources.items():
|
|
with self.subTest(fixture_name=fixture_name):
|
|
with self.assertRaisesRegex(AssertionError, re.escape(error_snippet)):
|
|
self._release_index_required_snippet_inventory_source_categories(
|
|
source
|
|
)
|
|
|
|
def test_training_m58_release_index_required_snippet_inventory_source_shape_accepts_literal_fixtures(
|
|
self,
|
|
) -> None:
|
|
source = """
|
|
TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY = (
|
|
(
|
|
"gamma_literal_category",
|
|
(
|
|
"gamma release note",
|
|
"gamma release detail",
|
|
),
|
|
),
|
|
(
|
|
"alpha_literal_category",
|
|
[
|
|
"alpha release note",
|
|
"alpha release detail",
|
|
],
|
|
),
|
|
(
|
|
"beta_literal_category",
|
|
(
|
|
"beta release note",
|
|
),
|
|
),
|
|
)
|
|
"""
|
|
expected_categories = (
|
|
"gamma_literal_category",
|
|
"alpha_literal_category",
|
|
"beta_literal_category",
|
|
)
|
|
|
|
source_group_order = (
|
|
self._release_index_required_snippet_inventory_source_categories(source)
|
|
)
|
|
|
|
self.assertEqual(source_group_order, expected_categories)
|
|
self.assertNotEqual(source_group_order, tuple(sorted(source_group_order)))
|
|
|
|
def test_training_m59_release_index_required_snippet_inventory_source_shape_preserves_literal_order(
|
|
self,
|
|
) -> None:
|
|
source = """
|
|
TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY = (
|
|
(
|
|
"literal_order_third_category",
|
|
(
|
|
"third literal order signal",
|
|
),
|
|
),
|
|
(
|
|
"literal_order_first_category",
|
|
(
|
|
"first literal order signal",
|
|
),
|
|
),
|
|
(
|
|
"literal_order_second_category",
|
|
(
|
|
"second literal order signal",
|
|
),
|
|
),
|
|
)
|
|
"""
|
|
expected_categories = (
|
|
"literal_order_third_category",
|
|
"literal_order_first_category",
|
|
"literal_order_second_category",
|
|
)
|
|
|
|
source_group_order = (
|
|
self._release_index_required_snippet_inventory_source_categories(source)
|
|
)
|
|
|
|
self.assertNotEqual(expected_categories, tuple(sorted(expected_categories)))
|
|
self.assertEqual(source_group_order, expected_categories)
|
|
|
|
def test_training_m53_release_index_doc_category_coverage_is_exact(self) -> None:
|
|
inventory = TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
inventory_by_category = dict(inventory)
|
|
expected_categories = tuple(category for category, _ in inventory)
|
|
expected_complete_results = {
|
|
category: (inventory_by_category[category], ())
|
|
for category in expected_categories
|
|
}
|
|
|
|
def category_results(text: str):
|
|
missing_pairs = _release_index_missing_required_snippets_by_doc(
|
|
{"release-index-doc.md": text}
|
|
)["release-index-doc.md"]
|
|
missing_by_category = {
|
|
category: tuple(
|
|
snippet
|
|
for missing_category, snippet in missing_pairs
|
|
if missing_category == category
|
|
)
|
|
for category in expected_categories
|
|
}
|
|
return {
|
|
category: (
|
|
tuple(
|
|
snippet
|
|
for snippet in inventory_by_category[category]
|
|
if snippet not in missing_by_category[category]
|
|
),
|
|
missing_by_category[category],
|
|
)
|
|
for category in expected_categories
|
|
}
|
|
|
|
for path in TRAINING_M41_RELEASE_INDEX_DOCS:
|
|
with self.subTest(path=path.name):
|
|
self.assertEqual(
|
|
category_results(path.read_text(encoding="utf-8")),
|
|
expected_complete_results,
|
|
)
|
|
|
|
synthetic_missing_category = expected_categories[-1]
|
|
synthetic_missing_doc = "\n".join(
|
|
snippet
|
|
for category in expected_categories
|
|
if category != synthetic_missing_category
|
|
for snippet in inventory_by_category[category]
|
|
)
|
|
expected_missing_results = dict(expected_complete_results)
|
|
expected_missing_results[synthetic_missing_category] = (
|
|
(),
|
|
inventory_by_category[synthetic_missing_category],
|
|
)
|
|
|
|
self.assertEqual(
|
|
category_results(synthetic_missing_doc),
|
|
expected_missing_results,
|
|
)
|
|
|
|
def test_training_m41_release_index_inventory_shape_is_stable(self) -> None:
|
|
module_tree = ast.parse(Path(__file__).read_text(encoding="utf-8"))
|
|
inventory_assignments = [
|
|
node
|
|
for node in module_tree.body
|
|
if isinstance(node, ast.Assign)
|
|
for target in node.targets
|
|
if (
|
|
isinstance(target, ast.Name)
|
|
and target.id == "TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY"
|
|
)
|
|
]
|
|
expected_group_order = (
|
|
"current_m1_m40_marker",
|
|
"acceptance_offline_validation",
|
|
"public_api_privacy_contracts",
|
|
"package_smoke_offline_registry",
|
|
"dashboard_public_docs_privacy",
|
|
"single_set_docker_deployment",
|
|
"docker_smoke_guard_coverage",
|
|
)
|
|
grouped_inventory = TRAINING_M41_RELEASE_INDEX_REQUIRED_SNIPPET_INVENTORY
|
|
grouped_snippets = tuple(
|
|
snippet
|
|
for _, snippets in grouped_inventory
|
|
for snippet in snippets
|
|
)
|
|
active_release_inventory = (
|
|
*TRAINING_M41_RELEASE_INDEX_GUARD_TEST_INVENTORY,
|
|
*(category for category, _ in grouped_inventory),
|
|
*grouped_snippets,
|
|
CURRENT_TRAINING_DOC_MATURITY_MARKER,
|
|
CURRENT_TRAINING_DOC_MATURITY_SPAN,
|
|
)
|
|
|
|
self.assertEqual(len(inventory_assignments), 1)
|
|
inventory_source = inventory_assignments[0].value
|
|
self.assertIsInstance(inventory_source, ast.Tuple)
|
|
source_group_order = tuple(
|
|
ast.literal_eval(group_node.elts[0])
|
|
for group_node in inventory_source.elts
|
|
if isinstance(group_node, ast.Tuple) and len(group_node.elts) == 2
|
|
)
|
|
|
|
self.assertEqual(source_group_order, expected_group_order)
|
|
self.assertEqual(len(source_group_order), len(set(source_group_order)))
|
|
self.assertEqual(tuple(category for category, _ in grouped_inventory), expected_group_order)
|
|
for group_name, snippets in grouped_inventory:
|
|
with self.subTest(group_name=group_name):
|
|
self.assertTrue(snippets)
|
|
|
|
self.assertEqual(TRAINING_M41_RELEASE_INDEX_DOC_SNIPPETS, grouped_snippets)
|
|
self.assertEqual(len(grouped_snippets), len(set(grouped_snippets)))
|
|
self.assertIn("M1-M40", active_release_inventory)
|
|
self.assertIn("through M40", active_release_inventory)
|
|
for stale_value in (
|
|
*TRAINING_M41_STALE_RELEASE_INVENTORY_NAMES,
|
|
"M1-M39",
|
|
"through M39",
|
|
):
|
|
with self.subTest(stale_value=stale_value):
|
|
self.assertNotIn(stale_value, active_release_inventory)
|
|
|
|
def test_local_docker_deployment_documentation_guard_inventory_is_current(self) -> None:
|
|
module_path = Path(__file__)
|
|
module_source = module_path.read_text(encoding="utf-8")
|
|
module_tree = ast.parse(module_source)
|
|
class_nodes = [
|
|
node
|
|
for node in module_tree.body
|
|
if isinstance(node, ast.ClassDef) and node.name == "DocumentationConsistencyTests"
|
|
]
|
|
top_level_names = {
|
|
target.id
|
|
for node in module_tree.body
|
|
if isinstance(node, ast.Assign)
|
|
for target in node.targets
|
|
if isinstance(target, ast.Name)
|
|
}
|
|
required_guard_tests = {
|
|
"test_readmes_describe_single_set_local_docker_deployment_policy",
|
|
"test_readmes_lock_single_set_docker_smoke_command_shape",
|
|
}
|
|
inventory_names = tuple(LOCAL_DOCKER_DOCUMENTATION_GUARD_TEST_INVENTORY)
|
|
|
|
self.assertEqual(len(class_nodes), 1)
|
|
self.assertEqual(len(inventory_names), len(set(inventory_names)))
|
|
self.assertLessEqual(required_guard_tests, set(inventory_names))
|
|
|
|
test_names = {
|
|
item.name
|
|
for item in class_nodes[0].body
|
|
if isinstance(item, ast.FunctionDef) and item.name.startswith("test_")
|
|
}
|
|
for name in inventory_names:
|
|
with self.subTest(name=name):
|
|
loader = unittest.TestLoader()
|
|
suite = loader.loadTestsFromName(
|
|
f"{type(self).__module__}.DocumentationConsistencyTests.{name}"
|
|
)
|
|
|
|
self.assertIn(name, test_names)
|
|
self.assertEqual(loader.errors, [])
|
|
self.assertGreater(suite.countTestCases(), 0)
|
|
|
|
for constant_name in LOCAL_DOCKER_DOCUMENTATION_GUARD_SOURCE_CONSTANTS:
|
|
with self.subTest(constant_name=constant_name):
|
|
self.assertIn(constant_name, top_level_names)
|
|
self.assertIn(f"{constant_name} =", module_source)
|
|
|
|
def test_training_case_acceptance_manifest_modules_are_discoverable(self) -> None:
|
|
manifest_modules = tuple(TRAINING_CASE_ACCEPTANCE_TEST_MANIFEST)
|
|
missing_modules = [
|
|
module
|
|
for module in TRAINING_CASE_REQUIRED_ACCEPTANCE_TEST_MODULES
|
|
if module not in manifest_modules
|
|
]
|
|
|
|
self.assertEqual(missing_modules, [])
|
|
self.assertEqual(len(manifest_modules), len(set(manifest_modules)))
|
|
|
|
for module in manifest_modules:
|
|
with self.subTest(module=module):
|
|
path = ROOT / "tests" / "unit" / f"{module}.py"
|
|
loader = unittest.TestLoader()
|
|
suite = loader.loadTestsFromName(f"tests.unit.{module}")
|
|
|
|
self.assertTrue(path.is_file(), path)
|
|
self.assertEqual(loader.errors, [])
|
|
self.assertGreater(suite.countTestCases(), 0)
|
|
|
|
def test_training_readmes_name_dashboard_privacy_and_offline_registry_coverage(self) -> None:
|
|
expected_doc_snippets = (
|
|
"dashboard and public docs privacy smoke coverage",
|
|
"dashboard_js_syntax",
|
|
"training_case_package",
|
|
)
|
|
for path in (PROJECT_README, TRAINING_PRODUCT_DOC):
|
|
text = path.read_text(encoding="utf-8")
|
|
with self.subTest(path=path.name):
|
|
for snippet in expected_doc_snippets:
|
|
self.assertIn(snippet, text)
|
|
|
|
registry_text = OFFLINE_CHECKS_SCRIPT.read_text(encoding="utf-8")
|
|
for check_name in ("dashboard_js_syntax", "training_case_package"):
|
|
with self.subTest(check_name=check_name):
|
|
self.assertEqual(registry_text.count(f'"{check_name}"'), 1)
|
|
|
|
def test_training_readmes_describe_acceptance_manifest_offline_validation_posture(self) -> None:
|
|
for path in (PROJECT_README, TRAINING_PRODUCT_DOC):
|
|
text = path.read_text(encoding="utf-8")
|
|
with self.subTest(path=path.name):
|
|
for snippet in TRAINING_ACCEPTANCE_VALIDATION_DOC_SNIPPETS:
|
|
self.assertIn(snippet, text)
|
|
|
|
for path in TRAINING_PUBLIC_PRIVACY_DOCS:
|
|
text = path.read_text(encoding="utf-8")
|
|
with self.subTest(path=path.name, surface="manifest_modules"):
|
|
for module in TRAINING_CASE_ACCEPTANCE_TEST_MANIFEST:
|
|
self.assertNotIn(module, text)
|
|
|
|
def test_readmes_describe_single_set_local_docker_deployment_policy(self) -> None:
|
|
for path in LOCAL_DOCKER_POLICY_DOCS:
|
|
text = path.read_text(encoding="utf-8")
|
|
lower_text = text.lower()
|
|
|
|
with self.subTest(path=path.name):
|
|
for snippet in LOCAL_DOCKER_POLICY_REQUIRED_SNIPPETS:
|
|
self.assertIn(snippet, text)
|
|
self.assertLess(
|
|
lower_text.index("down --remove-orphans"),
|
|
lower_text.index("up -d --build"),
|
|
)
|
|
for forbidden in LOCAL_DOCKER_POLICY_FORBIDDEN_ENCOURAGEMENT:
|
|
self.assertNotIn(forbidden, lower_text)
|
|
|
|
def test_readmes_lock_single_set_docker_smoke_command_shape(self) -> None:
|
|
command_lines_by_path = {
|
|
path: _local_docker_command_lines(_local_docker_deployment_section(path))
|
|
for path in LOCAL_DOCKER_POLICY_DOCS
|
|
}
|
|
expected_commands = LOCAL_DOCKER_REBUILD_COMMANDS + LOCAL_DOCKER_SMOKE_COMMANDS
|
|
|
|
self.assertEqual(
|
|
command_lines_by_path[PROJECT_README],
|
|
command_lines_by_path[TRAINING_PRODUCT_DOC],
|
|
)
|
|
for path, command_lines in command_lines_by_path.items():
|
|
with self.subTest(path=path.name):
|
|
for command in expected_commands:
|
|
self.assertIn(command, command_lines)
|
|
self.assertLess(
|
|
command_lines.index(LOCAL_DOCKER_REBUILD_COMMANDS[0]),
|
|
command_lines.index(LOCAL_DOCKER_REBUILD_COMMANDS[1]),
|
|
)
|
|
for command in command_lines:
|
|
if command.startswith("docker compose"):
|
|
self.assertTrue(command.startswith(LOCAL_DOCKER_COMPOSE_PREFIX), command)
|
|
self.assertNotIn("docker compose -p ai-ict down --remove-orphans", command_lines)
|
|
self.assertNotIn("docker compose -p ai-ict up -d --build", command_lines)
|
|
|
|
def test_training_case_product_doc_names_public_response_privacy_contracts(self) -> None:
|
|
text = TRAINING_PRODUCT_DOC.read_text(encoding="utf-8")
|
|
|
|
for snippet in (
|
|
"case list/detail",
|
|
"package export/import",
|
|
"progress",
|
|
"submit",
|
|
"create-attempt",
|
|
"annotation lifecycle",
|
|
"privacy contract tests",
|
|
"scrub private solution material",
|
|
"internal solution details",
|
|
):
|
|
with self.subTest(snippet=snippet):
|
|
self.assertIn(snippet, text)
|
|
|
|
self.assertNotIn("private " + "answer", text.lower())
|
|
self.assertNotIn("answer " + "detail", text.lower())
|
|
|
|
def test_training_case_product_doc_api_routes_match_server_route_request(self) -> None:
|
|
documented_routes = _training_api_routes_from_product_doc()
|
|
server_routes = _supported_training_routes_from_route_request()
|
|
|
|
self.assertEqual(
|
|
len(documented_routes),
|
|
len(set(documented_routes)),
|
|
"Training API docs contain duplicate route entries",
|
|
)
|
|
self.assertEqual(
|
|
sorted(documented_routes),
|
|
sorted(server_routes),
|
|
)
|
|
|
|
def test_training_case_public_route_registry_is_documented_and_supported(self) -> None:
|
|
documented_routes = set(_training_api_routes_from_product_doc())
|
|
server_routes = set(_supported_training_routes_from_route_request())
|
|
|
|
missing_from_docs = [
|
|
route for route in TRAINING_PUBLIC_API_ROUTE_REGISTRY if route not in documented_routes
|
|
]
|
|
missing_from_server = [
|
|
route for route in TRAINING_PUBLIC_API_ROUTE_REGISTRY if route not in server_routes
|
|
]
|
|
|
|
self.assertEqual(missing_from_docs, [])
|
|
self.assertEqual(missing_from_server, [])
|
|
|
|
def test_training_case_product_doc_api_surface_wording_matches_public_routes(self) -> None:
|
|
capabilities = {
|
|
(method, path): capability
|
|
for method, path, capability in _training_api_surface_rows_from_product_doc()
|
|
}
|
|
server_routes = set(_supported_training_routes_from_route_request())
|
|
|
|
self.assertEqual(sorted(capabilities), sorted(TRAINING_PUBLIC_API_ROUTE_REGISTRY))
|
|
for route, snippets in TRAINING_ROUTE_SURFACE_WORDING.items():
|
|
with self.subTest(route=route):
|
|
self.assertIn(route, server_routes)
|
|
for snippet in snippets:
|
|
self.assertIn(snippet, capabilities[route])
|
|
|
|
def test_training_dashboard_routes_are_documented_public_api_routes(self) -> None:
|
|
dashboard_routes = _training_dashboard_routes_from_app()
|
|
dashboard_paths = _training_dashboard_fetch_paths_from_app()
|
|
documented_routes = set(_training_api_routes_from_product_doc())
|
|
server_routes = set(_supported_training_routes_from_route_request())
|
|
|
|
self.assertEqual(dashboard_routes, TRAINING_DASHBOARD_ROUTE_REGISTRY)
|
|
self.assertEqual(dashboard_paths, tuple(path for _method, path in TRAINING_DASHBOARD_ROUTE_REGISTRY))
|
|
for route in dashboard_routes:
|
|
with self.subTest(route=route):
|
|
self.assertIn(route, TRAINING_PUBLIC_API_ROUTE_REGISTRY)
|
|
self.assertIn(route, documented_routes)
|
|
self.assertIn(route, server_routes)
|
|
|
|
def test_training_dashboard_and_public_docs_keep_privacy_wording_exclusionary(self) -> None:
|
|
dashboard_section = _training_product_doc_section("Dashboard Entry").lower()
|
|
dashboard_source = "\n".join(
|
|
path.read_text(encoding="utf-8").lower()
|
|
for path in (TRAINING_DASHBOARD_HTML, TRAINING_DASHBOARD_APP)
|
|
)
|
|
|
|
for snippet in TRAINING_DASHBOARD_PUBLIC_WORDING:
|
|
with self.subTest(snippet=snippet):
|
|
self.assertIn(snippet, dashboard_section)
|
|
|
|
for term in TRAINING_PUBLIC_PRIVACY_FORBIDDEN_TERMS:
|
|
with self.subTest(surface="dashboard", term=term):
|
|
self.assertNotIn(term, dashboard_source)
|
|
|
|
for phrase in TRAINING_PUBLIC_PRIVACY_MATERIAL_PHRASES:
|
|
with self.subTest(surface="dashboard", phrase=phrase):
|
|
self.assertNotIn(phrase, dashboard_source)
|
|
|
|
for path in TRAINING_PUBLIC_PRIVACY_DOCS:
|
|
text = path.read_text(encoding="utf-8")
|
|
lower_text = text.lower()
|
|
privacy_lines = _training_public_privacy_lines(text)
|
|
|
|
with self.subTest(path=path.name):
|
|
self.assertTrue(privacy_lines)
|
|
for term in TRAINING_PUBLIC_PRIVACY_FORBIDDEN_TERMS:
|
|
self.assertNotIn(term, lower_text)
|
|
for line in privacy_lines:
|
|
self.assertTrue(
|
|
any(word in line for word in TRAINING_PUBLIC_PRIVACY_EXCLUSION_WORDS),
|
|
line,
|
|
)
|
|
|
|
def test_training_case_product_doc_names_public_error_semantics(self) -> None:
|
|
section = _training_validation_section()
|
|
|
|
for snippet in (
|
|
"`400` with `invalid_json_body`",
|
|
"`400` with `invalid_path_param:<field>`",
|
|
"`400` with `invalid_limit_query_param:limit`",
|
|
"`404` with `not_found`",
|
|
"`500` with `internal_server_error`",
|
|
"do not echo raw internals",
|
|
):
|
|
with self.subTest(snippet=snippet):
|
|
self.assertIn(snippet, section)
|
|
|
|
self.assertNotIn("answer" + "_key", section)
|
|
|
|
def test_training_readmes_publish_public_error_catalog(self) -> None:
|
|
for path in TRAINING_PUBLIC_ERROR_DOCS:
|
|
text = path.read_text(encoding="utf-8")
|
|
with self.subTest(path=path.name):
|
|
for snippet in TRAINING_PUBLIC_ERROR_CATALOG_SNIPPETS:
|
|
self.assertIn(snippet, text)
|
|
|
|
def test_training_public_error_docs_avoid_raw_stack_and_os_error_wording(self) -> None:
|
|
for path in TRAINING_PUBLIC_ERROR_RAW_WORDING_DOCS:
|
|
text = path.read_text(encoding="utf-8").lower()
|
|
with self.subTest(path=path.name):
|
|
for forbidden in TRAINING_PUBLIC_ERROR_FORBIDDEN_RAW_WORDING:
|
|
self.assertNotIn(forbidden.lower(), text)
|
|
|
|
def test_training_case_product_doc_avoids_private_literal_shapes(self) -> None:
|
|
text = TRAINING_PRODUCT_DOC.read_text(encoding="utf-8").lower()
|
|
|
|
for term in (
|
|
"data" + "base",
|
|
"data" + "base_url",
|
|
"post" + "gresql",
|
|
"psy" + "copg",
|
|
"pass" + "word",
|
|
"pass" + "wd",
|
|
"tok" + "en",
|
|
"sec" + "ret",
|
|
"api" + "_key",
|
|
"answer" + "_key",
|
|
):
|
|
with self.subTest(term=term):
|
|
self.assertNotIn(term, text)
|
|
|
|
self.assertIsNone(re.search(r"\b(?:\d{1,3}\.){3}\d{1,3}\b", text))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|