diff --git a/gitgalaxy/standards/language_standards.py b/gitgalaxy/standards/language_standards.py index b5d089bb9..2c438964c 100644 --- a/gitgalaxy/standards/language_standards.py +++ b/gitgalaxy/standards/language_standards.py @@ -11613,7 +11613,7 @@ class PrismConfigSchema(TypedDict): # missed the extremely common `` angle-bracket naming # convention for record types (SRFI-9/R6RS idiom, e.g. ``). "class_start": re.compile( - r"^[ \t]*\([ \t]*define-record-type\s+([a-zA-Z0-9_!?*+/<>=.~$%^&:-]+)(?=[ \t)\]\n\r])", + r"^[ \t\n]*\([ \t\n]*define-record-type[ \t\n]+(?:\([ \t\n]*)?([a-zA-Z0-9_!?*+/<>=.~$%^&:-]+)(?=[ \t\n)\]\r])", re.M, ), # --- PHASE 2: RISK & STRUCTURAL INTEGRITY --- diff --git a/tests/extraction/languages/test_scheme.py b/tests/extraction/languages/test_scheme.py new file mode 100644 index 000000000..3fd5ea4f2 --- /dev/null +++ b/tests/extraction/languages/test_scheme.py @@ -0,0 +1,134 @@ +import sys +from pathlib import Path + +import pytest + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from _extraction_harness import ( + assert_invalid_no_match, + assert_pathological_match, + assert_valid_match, +) + +from gitgalaxy.standards.language_standards import LANGUAGE_DEFINITIONS + +scheme_rules = LANGUAGE_DEFINITIONS["scheme"]["rules"] +FUNC_START = scheme_rules.get("func_start") +ARGS = scheme_rules.get("args") +CLASS_START = scheme_rules.get("class_start") + +FUNCTION_CASES = { + "valid": [ + ("(define (TargetFunc x y)", "TargetFunc"), + ("(define (TargetFunc)", "TargetFunc"), + ("(define (string->number str)", "string->number"), + ("(define (foo* x)", "foo*"), + ("(define (1+ x)", "1+"), + ], + "invalid": [ + "(define-record-type TargetFunc", + "(if TargetFunc", + "(let ((TargetFunc 1))", + "(define TargetFunc 42)", + '"(define (TargetFunc x y)"', + "; (define (TargetFunc x y)", + ], + "pathological": [ + ("( \n define \n ( \n TargetFunc \n x \n )", "TargetFunc"), + ("(define \t (TargetFunc\n x\n y)", "TargetFunc"), + ], +} + +ARGS_CASES = { + "valid": [ + ("(define (TargetFunc a b)", "TargetFunc"), + ("(define (TargetFunc)", "TargetFunc"), + ("(define (TargetFunc a b . rest)", "TargetFunc"), + ("(define (TargetFunc a [b 1])", "TargetFunc"), + ], + "invalid": [ + "(TargetFunc a b)", + "(if (> a b)", + "(define TargetFunc 42)", + '"(define (TargetFunc a b)"', + "; (define (TargetFunc a b)", + ], + "pathological": [ + ("( \n define \n ( \n TargetFunc \n a \n b \n )", "TargetFunc"), + ("(define\n\t(TargetFunc\n\ta\n\tb)", "TargetFunc"), + ], +} + +CLASS_CASES = { + "valid": [ + ("(define-record-type TargetFunc (make-Target) Target?)", "TargetFunc"), + ("(define-record-type (make-target))", ""), + ("(define-record-type (TargetFunc x y)", "TargetFunc"), + ], + "invalid": [ + "(define (TargetFunc x y)", + "(let ((TargetFunc 1))", + '"(define-record-type TargetFunc"', + "; (define-record-type TargetFunc", + ], + "pathological": [ + ("( \n define-record-type \n TargetFunc \n (", "TargetFunc"), + ("(define-record-type \n \n (", ""), + ], +} + + +class TestSchemeExtraction: + @pytest.mark.parametrize("payload, expected_name", FUNCTION_CASES.get("valid", [])) + def test_positive_function_extraction(self, payload, expected_name): + if not FUNC_START: + pytest.skip("No pattern") + assert_valid_match(FUNC_START, payload, expected_name, "scheme") + + @pytest.mark.parametrize("payload", FUNCTION_CASES.get("invalid", [])) + def test_negative_function_extraction(self, payload): + if not FUNC_START: + pytest.skip("No pattern") + assert_invalid_no_match(FUNC_START, payload, "scheme") + + @pytest.mark.parametrize("payload, expected_name", FUNCTION_CASES.get("pathological", [])) + def test_pathological_function_extraction(self, payload, expected_name): + if not FUNC_START: + pytest.skip("No pattern") + assert_pathological_match(FUNC_START, payload, expected_name, "scheme") + + @pytest.mark.parametrize("payload, expected_name", ARGS_CASES.get("valid", [])) + def test_positive_args_extraction(self, payload, expected_name): + if not ARGS: + pytest.skip("No pattern") + assert_valid_match(ARGS, payload, expected_name, "scheme") + + @pytest.mark.parametrize("payload", ARGS_CASES.get("invalid", [])) + def test_negative_args_extraction(self, payload): + if not ARGS: + pytest.skip("No pattern") + assert_invalid_no_match(ARGS, payload, "scheme") + + @pytest.mark.parametrize("payload, expected_name", ARGS_CASES.get("pathological", [])) + def test_pathological_args_extraction(self, payload, expected_name): + if not ARGS: + pytest.skip("No pattern") + assert_pathological_match(ARGS, payload, expected_name, "scheme") + + @pytest.mark.parametrize("payload, expected_name", CLASS_CASES.get("valid", [])) + def test_positive_class_extraction(self, payload, expected_name): + if not CLASS_START: + pytest.skip("No pattern") + assert_valid_match(CLASS_START, payload, expected_name, "scheme") + + @pytest.mark.parametrize("payload", CLASS_CASES.get("invalid", [])) + def test_negative_class_extraction(self, payload): + if not CLASS_START: + pytest.skip("No pattern") + assert_invalid_no_match(CLASS_START, payload, "scheme") + + @pytest.mark.parametrize("payload, expected_name", CLASS_CASES.get("pathological", [])) + def test_pathological_class_extraction(self, payload, expected_name): + if not CLASS_START: + pytest.skip("No pattern") + assert_pathological_match(CLASS_START, payload, expected_name, "scheme") diff --git a/tests/extraction/test_args_extraction_strict.py b/tests/extraction/test_args_extraction_strict.py index efe732962..b822ac964 100644 --- a/tests/extraction/test_args_extraction_strict.py +++ b/tests/extraction/test_args_extraction_strict.py @@ -70,17 +70,6 @@ ) ], }, - "scheme": { - "valid": [ - ("(define (TargetFunc a b)", "TargetFunc"), - ("(define (TargetFunc)", "TargetFunc"), - ], - "invalid": ["(TargetFunc a b)", "(if (> a b)"], - "pathological": [ - # Deep vertical S-expressions - ("( \n define \n ( \n TargetFunc \n a \n b \n )", "TargetFunc") - ], - }, } diff --git a/tests/extraction/test_function_extraction_strict.py b/tests/extraction/test_function_extraction_strict.py index fa5f09207..41530098b 100644 --- a/tests/extraction/test_function_extraction_strict.py +++ b/tests/extraction/test_function_extraction_strict.py @@ -128,18 +128,7 @@ "pathological": [("METHOD \n TargetFunc \n .", "TargetFunc")], }, - "scheme": { - "valid": [ - ("(define (TargetFunc x y)", "TargetFunc"), - ("(define (TargetFunc)", "TargetFunc"), - ], - "invalid": [ - "(define-record-type TargetFunc", - "(if TargetFunc", - "(let ((TargetFunc 1))", - ], - "pathological": [("( \n define \n ( \n TargetFunc \n x \n )", "TargetFunc")], - }, + "dockerfile": { "valid": [ ("RUN apt-get update", "RUN"), diff --git a/tests/golden_master_audit.json b/tests/golden_master_audit.json index a1d72587f..ea5067984 100644 --- a/tests/golden_master_audit.json +++ b/tests/golden_master_audit.json @@ -12,8 +12,8 @@ }, "Target Root Name": "data", "Absolute Project Path": "/home/joe/nyx_projects/language-crucible/data", - "Analysis ISO Timestamp": "2026-08-02T21:00:34.380214+00:00", - "Total Scan Duration": "27.12 seconds" + "Analysis ISO Timestamp": "2026-08-02T22:35:36.465352+00:00", + "Total Scan Duration": "28.45 seconds" }, "Source Control Footprint (Immutable Anchor)": { "Active Branch": "main", @@ -4129,7 +4129,7 @@ }, "firewall": { "imports_whitelisted": 0, - "imports_unknown": 8398, + "imports_unknown": 8400, "imports_blacklisted": 0, "threats_found": 139, "threats_allowed": 0 @@ -9238,11 +9238,11 @@ "file_cluster_4": 11.947, "file_cluster_5": 12.007, "file_cluster_6": 11.805, - "file_cluster_7": 11.126, + "file_cluster_7": 11.127, "file_cluster_8": 10.51, "file_cluster_9": 11.766, "file_cluster_10": 12.467, - "file_cluster_11": 11.466, + "file_cluster_11": 11.467, "file_cluster_12": 11.576, "file_cluster_13": 11.512, "file_cluster_14": 15.505, @@ -9292,7 +9292,7 @@ "Sequential Logic Declarations": 488, "Function Parameters": 65, "Function/Method Declarations": 65, - "Class/Entity Declarations": 6, + "Class/Entity Declarations": 7, "Defensive Programming Constructs": 14, "Type/Safety Bypasses": 0, "High-Risk Execution Commands": 0, @@ -246917,26 +246917,26 @@ }, "3. Architectural Profile": { "Repository Archetype": "file_cluster_17", - "Repository Drift (Z-Score)": 14.511, + "Repository Drift (Z-Score)": 14.547, "Repository Fingerprint": { - "file_cluster_0": 14.576, - "file_cluster_1": 15.253, - "file_cluster_2": 15.098, - "file_cluster_3": 15.905, - "file_cluster_4": 14.675, - "file_cluster_5": 15.692, - "file_cluster_6": 14.863, - "file_cluster_7": 14.988, - "file_cluster_8": 14.527, - "file_cluster_9": 14.736, - "file_cluster_10": 15.479, - "file_cluster_11": 14.527, - "file_cluster_12": 15.254, - "file_cluster_13": 14.7, - "file_cluster_14": 17.825, - "file_cluster_15": 15.28, - "file_cluster_16": 15.243, - "file_cluster_17": 14.511 + "file_cluster_0": 14.602, + "file_cluster_1": 15.29, + "file_cluster_2": 15.133, + "file_cluster_3": 15.94, + "file_cluster_4": 14.713, + "file_cluster_5": 15.726, + "file_cluster_6": 14.898, + "file_cluster_7": 15.023, + "file_cluster_8": 14.566, + "file_cluster_9": 14.768, + "file_cluster_10": 15.515, + "file_cluster_11": 14.559, + "file_cluster_12": 15.291, + "file_cluster_13": 14.735, + "file_cluster_14": 17.832, + "file_cluster_15": 15.316, + "file_cluster_16": 15.279, + "file_cluster_17": 14.547 }, "File Archetype": null, "File Drift (Z-Score)": 0.0, @@ -247903,12 +247903,15 @@ "Agentic Rce": 0 }, "8. Dependency Network": { - "Direct Upstream (Fragility)": 0, + "Direct Upstream (Fragility)": 2, "Direct Downstream (Dependency Blast Radius)": 0, "Total Upstream (Absolute Fragility)": 0, "Total Downstream (Absolute Dependency Blast Radius)": 0 }, - "9. Extracted Dependencies": [] + "9. Extracted Dependencies": [ + "$testdir/malloc_common.tcl", + "$testdir/thread_common.tcl" + ] } } }, diff --git a/tests/golden_master_zero_dep_audit.json b/tests/golden_master_zero_dep_audit.json index 04495f47f..3e7254dc0 100644 --- a/tests/golden_master_zero_dep_audit.json +++ b/tests/golden_master_zero_dep_audit.json @@ -12,8 +12,8 @@ }, "Target Root Name": "data", "Absolute Project Path": "/home/joe/nyx_projects/language-crucible/data", - "Analysis ISO Timestamp": "2026-08-02T21:01:06.203842+00:00", - "Total Scan Duration": "24.31 seconds" + "Analysis ISO Timestamp": "2026-08-02T22:36:12.130018+00:00", + "Total Scan Duration": "26.02 seconds" }, "Source Control Footprint (Immutable Anchor)": { "Active Branch": "main", @@ -4129,7 +4129,7 @@ }, "firewall": { "imports_whitelisted": 0, - "imports_unknown": 8398, + "imports_unknown": 8400, "imports_blacklisted": 0, "threats_found": 139, "threats_allowed": 0 @@ -9238,11 +9238,11 @@ "file_cluster_4": 11.947, "file_cluster_5": 12.007, "file_cluster_6": 11.805, - "file_cluster_7": 11.126, + "file_cluster_7": 11.127, "file_cluster_8": 10.51, "file_cluster_9": 11.766, "file_cluster_10": 12.467, - "file_cluster_11": 11.466, + "file_cluster_11": 11.467, "file_cluster_12": 11.576, "file_cluster_13": 11.512, "file_cluster_14": 15.505, @@ -9292,7 +9292,7 @@ "Sequential Logic Declarations": 488, "Function Parameters": 65, "Function/Method Declarations": 65, - "Class/Entity Declarations": 6, + "Class/Entity Declarations": 7, "Defensive Programming Constructs": 14, "Type/Safety Bypasses": 0, "High-Risk Execution Commands": 0, @@ -246917,26 +246917,26 @@ }, "3. Architectural Profile": { "Repository Archetype": "file_cluster_17", - "Repository Drift (Z-Score)": 14.511, + "Repository Drift (Z-Score)": 14.547, "Repository Fingerprint": { - "file_cluster_0": 14.576, - "file_cluster_1": 15.253, - "file_cluster_2": 15.098, - "file_cluster_3": 15.905, - "file_cluster_4": 14.675, - "file_cluster_5": 15.692, - "file_cluster_6": 14.863, - "file_cluster_7": 14.988, - "file_cluster_8": 14.527, - "file_cluster_9": 14.736, - "file_cluster_10": 15.479, - "file_cluster_11": 14.527, - "file_cluster_12": 15.254, - "file_cluster_13": 14.7, - "file_cluster_14": 17.825, - "file_cluster_15": 15.28, - "file_cluster_16": 15.243, - "file_cluster_17": 14.511 + "file_cluster_0": 14.602, + "file_cluster_1": 15.29, + "file_cluster_2": 15.133, + "file_cluster_3": 15.94, + "file_cluster_4": 14.713, + "file_cluster_5": 15.726, + "file_cluster_6": 14.898, + "file_cluster_7": 15.023, + "file_cluster_8": 14.566, + "file_cluster_9": 14.768, + "file_cluster_10": 15.515, + "file_cluster_11": 14.559, + "file_cluster_12": 15.291, + "file_cluster_13": 14.735, + "file_cluster_14": 17.832, + "file_cluster_15": 15.316, + "file_cluster_16": 15.279, + "file_cluster_17": 14.547 }, "File Archetype": null, "File Drift (Z-Score)": 0.0, @@ -247903,12 +247903,15 @@ "Agentic Rce": 0 }, "8. Dependency Network": { - "Direct Upstream (Fragility)": 0, + "Direct Upstream (Fragility)": 2, "Direct Downstream (Dependency Blast Radius)": 0, "Total Upstream (Absolute Fragility)": 0, "Total Downstream (Absolute Dependency Blast Radius)": 0 }, - "9. Extracted Dependencies": [] + "9. Extracted Dependencies": [ + "$testdir/malloc_common.tcl", + "$testdir/thread_common.tcl" + ] } } },