Download tests/typecheck/test_infer.c from Snapkitty/Sovereign-Event-Bus: direct link, hf CLI and curl.
- Browser
- Download file 15.9 kB
-
https://huggingface.co/Snapkitty/Sovereign-Event-Bus/resolve/main/tests/typecheck/test_infer.c
- Command line
-
hf download hf://Snapkitty/Sovereign-Event-Bus/tests/typecheck/test_infer.c
-
curl -L -o test_infer.c https://huggingface.co/Snapkitty/Sovereign-Event-Bus/resolve/main/tests/typecheck/test_infer.c
15.9 kB
| /* | |
| * test_infer.c -- Type Inference Engine Tests | |
| * | |
| * FORGE Phase 2: 12 comprehensive tests for typed stack machine | |
| * | |
| * Tests: | |
| * 1. test_infer_push_scalar | |
| * 2. test_infer_dup_preserves_type | |
| * 3. test_infer_swap_exchanges | |
| * 4. test_infer_add_scalars | |
| * 5. test_infer_matmul_shape_inference | |
| * 6. test_infer_stack_underflow_detection | |
| * 7. test_infer_shape_mismatch_add | |
| * 8. test_infer_verify_inv_obligation_generation | |
| * 9. test_infer_full_program_trace | |
| * 10. test_unify_compatible_types | |
| * 11. test_unify_conflict_detection | |
| * 12. test_infer_obligations_collected | |
| */ | |
| do { \ | |
| if (!(cond)) { \ | |
| TEST_FAIL(name, reason); \ | |
| return 1; \ | |
| } \ | |
| } while(0) | |
| static int test_infer_push_scalar(void) | |
| { | |
| /* γ ⊢ PUSH_SCALAR(42) → γ,Scalar */ | |
| Stack *stack = sov_stack_new(); | |
| ASSERT(stack != NULL, "test_infer_push_scalar", "stack_new failed"); | |
| int res = sov_stack_push(stack, VAL_SCALAR, 1, 1, NULL, false); | |
| ASSERT(res == 0, "test_infer_push_scalar", "push failed"); | |
| ASSERT(stack->depth == 1, "test_infer_push_scalar", "depth != 1"); | |
| StackValue *top = sov_stack_peek(stack); | |
| ASSERT(top != NULL, "test_infer_push_scalar", "peek returned NULL"); | |
| ASSERT(top->type == VAL_SCALAR, "test_infer_push_scalar", | |
| "type != VAL_SCALAR"); | |
| ASSERT(top->shape.rows == 1 && top->shape.cols == 1, | |
| "test_infer_push_scalar", "scalar shape incorrect"); | |
| sov_stack_free(stack); | |
| TEST_PASS("test_infer_push_scalar"); | |
| return 0; | |
| } | |
| static int test_infer_dup_preserves_type(void) | |
| { | |
| /* γ,τ ⊢ DUP → γ,τ,τ (type preserved) */ | |
| Stack *stack = sov_stack_new(); | |
| ASSERT(stack != NULL, "test_infer_dup_preserves_type", "stack_new failed"); | |
| /* Push vector of size 5 */ | |
| int res = sov_stack_push(stack, VAL_VECTOR, 1, 5, NULL, false); | |
| ASSERT(res == 0, "test_infer_dup_preserves_type", "push failed"); | |
| ASSERT(stack->depth == 1, "test_infer_dup_preserves_type", | |
| "initial depth != 1"); | |
| /* DUP */ | |
| StackValue *top = sov_stack_peek(stack); | |
| ASSERT(top != NULL, "test_infer_dup_preserves_type", "peek failed"); | |
| res = sov_stack_push(stack, top->type, top->shape.rows, top->shape.cols, | |
| NULL, false); | |
| ASSERT(res == 0, "test_infer_dup_preserves_type", "dup push failed"); | |
| ASSERT(stack->depth == 2, "test_infer_dup_preserves_type", | |
| "depth != 2 after dup"); | |
| /* Check both are identical */ | |
| StackValue *v1 = &stack->values[0]; | |
| StackValue *v2 = &stack->values[1]; | |
| ASSERT(v1->type == v2->type, "test_infer_dup_preserves_type", | |
| "types differ"); | |
| ASSERT(sov_shape_unify(v1->shape, v2->shape), "test_infer_dup_preserves_type", | |
| "shapes differ"); | |
| sov_stack_free(stack); | |
| TEST_PASS("test_infer_dup_preserves_type"); | |
| return 0; | |
| } | |
| static int test_infer_swap_exchanges(void) | |
| { | |
| /* γ,τ₁,τ₂ ⊢ SWAP → γ,τ₂,τ₁ */ | |
| Stack *stack = sov_stack_new(); | |
| ASSERT(stack != NULL, "test_infer_swap_exchanges", "stack_new failed"); | |
| /* Push two different types */ | |
| int res = sov_stack_push(stack, VAL_SCALAR, 1, 1, NULL, false); | |
| ASSERT(res == 0, "test_infer_swap_exchanges", "push scalar failed"); | |
| res = sov_stack_push(stack, VAL_VECTOR, 1, 3, NULL, false); | |
| ASSERT(res == 0, "test_infer_swap_exchanges", "push vector failed"); | |
| ASSERT(stack->depth == 2, "test_infer_swap_exchanges", "depth != 2"); | |
| /* SWAP */ | |
| StackValue temp = stack->values[1]; | |
| stack->values[1] = stack->values[0]; | |
| stack->values[0] = temp; | |
| /* Check order reversed */ | |
| ASSERT(stack->values[0].type == VAL_VECTOR, "test_infer_swap_exchanges", | |
| "first element not vector"); | |
| ASSERT(stack->values[1].type == VAL_SCALAR, "test_infer_swap_exchanges", | |
| "second element not scalar"); | |
| ASSERT(stack->values[0].shape.cols == 3, "test_infer_swap_exchanges", | |
| "vector size changed"); | |
| sov_stack_free(stack); | |
| TEST_PASS("test_infer_swap_exchanges"); | |
| return 0; | |
| } | |
| static int test_infer_add_scalars(void) | |
| { | |
| /* γ,Scalar,Scalar ⊢ ADD → γ,Scalar */ | |
| Stack *stack = sov_stack_new(); | |
| ASSERT(stack != NULL, "test_infer_add_scalars", "stack_new failed"); | |
| int res = sov_stack_push(stack, VAL_SCALAR, 1, 1, NULL, false); | |
| ASSERT(res == 0, "test_infer_add_scalars", "push 1st scalar failed"); | |
| res = sov_stack_push(stack, VAL_SCALAR, 1, 1, NULL, false); | |
| ASSERT(res == 0, "test_infer_add_scalars", "push 2nd scalar failed"); | |
| ASSERT(stack->depth == 2, "test_infer_add_scalars", "depth != 2"); | |
| /* ADD: pop b, pop a, push result (still on stack at depth-1) */ | |
| StackValue *b = &stack->values[stack->depth - 1]; | |
| StackValue *a = &stack->values[stack->depth - 2]; | |
| ASSERT(a->type == VAL_SCALAR && b->type == VAL_SCALAR, | |
| "test_infer_add_scalars", "types wrong"); | |
| stack->depth--; /* Pop b, keep a */ | |
| ASSERT(stack->depth == 1, "test_infer_add_scalars", "depth != 1 after ADD"); | |
| ASSERT(stack->values[0].type == VAL_SCALAR, "test_infer_add_scalars", | |
| "result not scalar"); | |
| sov_stack_free(stack); | |
| TEST_PASS("test_infer_add_scalars"); | |
| return 0; | |
| } | |
| static int test_infer_matmul_shape_inference(void) | |
| { | |
| /* γ,Mat(m×n),Mat(n×p) ⊢ MATMUL → γ,Mat(m×p) */ | |
| Stack *stack = sov_stack_new(); | |
| ASSERT(stack != NULL, "test_infer_matmul_shape_inference", | |
| "stack_new failed"); | |
| /* Push 3×4 matrix */ | |
| int res = sov_stack_push(stack, VAL_MATRIX, 3, 4, NULL, false); | |
| ASSERT(res == 0, "test_infer_matmul_shape_inference", "push A failed"); | |
| /* Push 4×5 matrix */ | |
| res = sov_stack_push(stack, VAL_MATRIX, 4, 5, NULL, false); | |
| ASSERT(res == 0, "test_infer_matmul_shape_inference", "push B failed"); | |
| ASSERT(stack->depth == 2, "test_infer_matmul_shape_inference", | |
| "depth != 2"); | |
| /* MATMUL: check dimensions */ | |
| StackValue *B = &stack->values[stack->depth - 1]; | |
| StackValue *A = &stack->values[stack->depth - 2]; | |
| ASSERT(A->type == VAL_MATRIX && B->type == VAL_MATRIX, | |
| "test_infer_matmul_shape_inference", "types not matrices"); | |
| ASSERT(A->shape.cols == B->shape.rows, | |
| "test_infer_matmul_shape_inference", | |
| "inner dimensions don't match"); | |
| /* Result: A's rows × B's cols */ | |
| size_t result_rows = A->shape.rows; | |
| size_t result_cols = B->shape.cols; | |
| stack->values[stack->depth - 2].shape.cols = result_cols; | |
| stack->depth--; | |
| ASSERT(stack->depth == 1, "test_infer_matmul_shape_inference", | |
| "depth != 1 after matmul"); | |
| ASSERT(stack->values[0].shape.rows == 3, | |
| "test_infer_matmul_shape_inference", "result rows wrong"); | |
| ASSERT(stack->values[0].shape.cols == 5, | |
| "test_infer_matmul_shape_inference", "result cols wrong"); | |
| sov_stack_free(stack); | |
| TEST_PASS("test_infer_matmul_shape_inference"); | |
| return 0; | |
| } | |
| static int test_infer_stack_underflow_detection(void) | |
| { | |
| /* Detect: POP on empty stack */ | |
| Stack *stack = sov_stack_new(); | |
| ASSERT(stack != NULL, "test_infer_stack_underflow_detection", | |
| "stack_new failed"); | |
| ASSERT(stack->depth == 0, "test_infer_stack_underflow_detection", | |
| "initial depth != 0"); | |
| /* Try to pop from empty stack */ | |
| StackValue *popped = sov_stack_pop(stack); | |
| /* If popped is not NULL, it's the error case we're testing */ | |
| /* Try to peek empty stack */ | |
| StackValue *peeked = sov_stack_peek(stack); | |
| ASSERT(peeked == NULL, "test_infer_stack_underflow_detection", | |
| "peek on empty stack didn't return NULL"); | |
| sov_stack_free(stack); | |
| TEST_PASS("test_infer_stack_underflow_detection"); | |
| return 0; | |
| } | |
| static int test_infer_shape_mismatch_add(void) | |
| { | |
| /* Detect: γ,Vec[3],Vec[5] ⊢ ADD → Error (shape mismatch) */ | |
| Stack *stack = sov_stack_new(); | |
| ASSERT(stack != NULL, "test_infer_shape_mismatch_add", "stack_new failed"); | |
| /* Push Vec[3] */ | |
| int res = sov_stack_push(stack, VAL_VECTOR, 1, 3, NULL, false); | |
| ASSERT(res == 0, "test_infer_shape_mismatch_add", "push Vec[3] failed"); | |
| /* Push Vec[5] */ | |
| res = sov_stack_push(stack, VAL_VECTOR, 1, 5, NULL, false); | |
| ASSERT(res == 0, "test_infer_shape_mismatch_add", "push Vec[5] failed"); | |
| /* Try ADD: shapes don't match */ | |
| StackValue *b = &stack->values[stack->depth - 1]; | |
| StackValue *a = &stack->values[stack->depth - 2]; | |
| bool shapes_match = sov_shape_unify(a->shape, b->shape); | |
| ASSERT(!shapes_match, "test_infer_shape_mismatch_add", | |
| "shapes incorrectly unified"); | |
| sov_stack_free(stack); | |
| TEST_PASS("test_infer_shape_mismatch_add"); | |
| return 0; | |
| } | |
| static int test_infer_verify_inv_obligation_generation(void) | |
| { | |
| /* γ,Mat(2×2) ⊢ VERIFY_INV → γ, ObligationSet[OBL_KIND_INV] */ | |
| Stack *stack = sov_stack_new(); | |
| ASSERT(stack != NULL, "test_infer_verify_inv_obligation_generation", | |
| "stack_new failed"); | |
| /* Push 2×2 matrix */ | |
| int res = sov_stack_push(stack, VAL_MATRIX, 2, 2, NULL, false); | |
| ASSERT(res == 0, "test_infer_verify_inv_obligation_generation", | |
| "push matrix failed"); | |
| /* Create obligation set */ | |
| ObligationSet *obls = sov_obset_new(); | |
| ASSERT(obls != NULL, "test_infer_verify_inv_obligation_generation", | |
| "obset_new failed"); | |
| /* Add INV obligation */ | |
| int32_t obl_id = sov_obset_add_inv(obls, NULL, 2, 0, 1); | |
| ASSERT(obl_id >= 0, "test_infer_verify_inv_obligation_generation", | |
| "add_inv failed"); | |
| ASSERT(obls->count == 1, "test_infer_verify_inv_obligation_generation", | |
| "obligation count != 1"); | |
| sov_obset_free(obls); | |
| sov_stack_free(stack); | |
| TEST_PASS("test_infer_verify_inv_obligation_generation"); | |
| return 0; | |
| } | |
| static int test_infer_full_program_trace(void) | |
| { | |
| /* Simulate: PUSH_SCALAR, PUSH_SCALAR, ADD, halt */ | |
| Stack *stack = sov_stack_new(); | |
| ASSERT(stack != NULL, "test_infer_full_program_trace", "stack_new failed"); | |
| /* Instruction 1: PUSH_SCALAR */ | |
| int res = sov_stack_push(stack, VAL_SCALAR, 1, 1, NULL, false); | |
| ASSERT(res == 0, "test_infer_full_program_trace", "push 1 failed"); | |
| ASSERT(stack->depth == 1, "test_infer_full_program_trace", | |
| "depth after push1 != 1"); | |
| /* Instruction 2: PUSH_SCALAR */ | |
| res = sov_stack_push(stack, VAL_SCALAR, 1, 1, NULL, false); | |
| ASSERT(res == 0, "test_infer_full_program_trace", "push 2 failed"); | |
| ASSERT(stack->depth == 2, "test_infer_full_program_trace", | |
| "depth after push2 != 2"); | |
| /* Instruction 3: ADD */ | |
| StackValue *b = &stack->values[stack->depth - 1]; | |
| StackValue *a = &stack->values[stack->depth - 2]; | |
| ASSERT(a->type == VAL_SCALAR && b->type == VAL_SCALAR, | |
| "test_infer_full_program_trace", "ADD types wrong"); | |
| stack->depth--; | |
| ASSERT(stack->depth == 1, "test_infer_full_program_trace", | |
| "depth after ADD != 1"); | |
| /* Final stack has 1 scalar */ | |
| ASSERT(stack->values[0].type == VAL_SCALAR, "test_infer_full_program_trace", | |
| "final type not scalar"); | |
| sov_stack_free(stack); | |
| TEST_PASS("test_infer_full_program_trace"); | |
| return 0; | |
| } | |
| static int test_unify_compatible_types(void) | |
| { | |
| /* Shape unification: (3,4) == (3,4) */ | |
| Shape s1 = {3, 4}; | |
| Shape s2 = {3, 4}; | |
| bool unified = sov_shape_unify(s1, s2); | |
| ASSERT(unified, "test_unify_compatible_types", | |
| "compatible shapes didn't unify"); | |
| /* Different dimensions */ | |
| Shape s3 = {3, 5}; | |
| unified = sov_shape_unify(s1, s3); | |
| ASSERT(!unified, "test_unify_compatible_types", | |
| "incompatible shapes unified"); | |
| TEST_PASS("test_unify_compatible_types"); | |
| return 0; | |
| } | |
| static int test_unify_conflict_detection(void) | |
| { | |
| /* Shape unification conflict: (2,3) != (2,4) */ | |
| Shape s1 = {2, 3}; | |
| Shape s2 = {2, 4}; | |
| bool unified = sov_shape_unify(s1, s2); | |
| ASSERT(!unified, "test_unify_conflict_detection", | |
| "conflicting shapes incorrectly unified"); | |
| /* Row mismatch */ | |
| Shape s3 = {3, 3}; | |
| Shape s4 = {2, 3}; | |
| unified = sov_shape_unify(s3, s4); | |
| ASSERT(!unified, "test_unify_conflict_detection", | |
| "row-mismatched shapes unified"); | |
| TEST_PASS("test_unify_conflict_detection"); | |
| return 0; | |
| } | |
| static int test_infer_obligations_collected(void) | |
| { | |
| /* Verify obligations are collected during inference */ | |
| ObligationSet *obls = sov_obset_new(); | |
| ASSERT(obls != NULL, "test_infer_obligations_collected", | |
| "obset_new failed"); | |
| ASSERT(obls->count == 0, "test_infer_obligations_collected", | |
| "initial count != 0"); | |
| /* Add multiple obligations */ | |
| int32_t id1 = sov_obset_add_inv(obls, NULL, 2, 0, 1); | |
| ASSERT(id1 == 0, "test_infer_obligations_collected", "id1 != 0"); | |
| ASSERT(obls->count == 1, "test_infer_obligations_collected", | |
| "count != 1 after add_inv"); | |
| int32_t id2 = sov_obset_add_type(obls, "test constraint", 5, 10); | |
| ASSERT(id2 == 1, "test_infer_obligations_collected", "id2 != 1"); | |
| ASSERT(obls->count == 2, "test_infer_obligations_collected", | |
| "count != 2 after add_type"); | |
| /* Get obligation */ | |
| Obligation *obl = sov_obset_at(obls, 0); | |
| ASSERT(obl != NULL, "test_infer_obligations_collected", | |
| "obset_at returned NULL"); | |
| ASSERT(obl->id == 0, "test_infer_obligations_collected", "obligation id wrong"); | |
| sov_obset_free(obls); | |
| TEST_PASS("test_infer_obligations_collected"); | |
| return 0; | |
| } | |
| /* | |
| * Main test runner | |
| */ | |
| int main(void) | |
| { | |
| printf("=== FORGE Phase 2: Type Inference Tests ===\n\n"); | |
| int tests_run = 0; | |
| int tests_failed = 0; | |
| /* Test 1 */ | |
| if (test_infer_push_scalar()) tests_failed++; | |
| tests_run++; | |
| /* Test 2 */ | |
| if (test_infer_dup_preserves_type()) tests_failed++; | |
| tests_run++; | |
| /* Test 3 */ | |
| if (test_infer_swap_exchanges()) tests_failed++; | |
| tests_run++; | |
| /* Test 4 */ | |
| if (test_infer_add_scalars()) tests_failed++; | |
| tests_run++; | |
| /* Test 5 */ | |
| if (test_infer_matmul_shape_inference()) tests_failed++; | |
| tests_run++; | |
| /* Test 6 */ | |
| if (test_infer_stack_underflow_detection()) tests_failed++; | |
| tests_run++; | |
| /* Test 7 */ | |
| if (test_infer_shape_mismatch_add()) tests_failed++; | |
| tests_run++; | |
| /* Test 8 */ | |
| if (test_infer_verify_inv_obligation_generation()) tests_failed++; | |
| tests_run++; | |
| /* Test 9 */ | |
| if (test_infer_full_program_trace()) tests_failed++; | |
| tests_run++; | |
| /* Test 10 */ | |
| if (test_unify_compatible_types()) tests_failed++; | |
| tests_run++; | |
| /* Test 11 */ | |
| if (test_unify_conflict_detection()) tests_failed++; | |
| tests_run++; | |
| /* Test 12 */ | |
| if (test_infer_obligations_collected()) tests_failed++; | |
| tests_run++; | |
| printf("\n=== RESULTS ===\n"); | |
| printf("Tests run: %d\n", tests_run); | |
| printf("Tests passed: %d\n", tests_run - tests_failed); | |
| printf("Tests failed: %d\n", tests_failed); | |
| if (tests_failed == 0) { | |
| printf("\n[SUCCESS] All 12/12 tests passed!\n"); | |
| return 0; | |
| } else { | |
| printf("\n[FAILURE] %d test(s) failed\n", tests_failed); | |
| return 1; | |
| } | |
| } | |