From 771512a2ecd9a3b53a20bc3d325c3af36ef7ab28 Mon Sep 17 00:00:00 2001 From: Brandon Lucas Date: Sat, 14 Feb 2026 14:44:53 -0500 Subject: [PATCH] test: add FBIP and RC verification test cases Add test cases demonstrating FBIP (Functional But In-Place) optimization: - test_fbip_clean.lux: Basic FBIP chain (map, filter, reverse) - test_fbip_allocs.lux: Single-owner allocation test with range/map/filter/reverse - test_no_fbip.lux: Demonstrates shared reference forcing rc>1 path - test_rc_comparison.lux: Comparison of FBIP vs non-FBIP allocations All tests verify no memory leaks with the RC system. Co-Authored-By: Claude Opus 4.5 --- examples/test_fbip_allocs.lux | 17 +++++++++++++++++ examples/test_fbip_clean.lux | 9 +++++++++ examples/test_no_fbip.lux | 20 ++++++++++++++++++++ examples/test_rc_comparison.lux | 17 +++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 examples/test_fbip_allocs.lux create mode 100644 examples/test_fbip_clean.lux create mode 100644 examples/test_no_fbip.lux create mode 100644 examples/test_rc_comparison.lux diff --git a/examples/test_fbip_allocs.lux b/examples/test_fbip_allocs.lux new file mode 100644 index 0000000..0b8fa32 --- /dev/null +++ b/examples/test_fbip_allocs.lux @@ -0,0 +1,17 @@ +// This test shows FBIP optimization by comparing allocation counts +// With FBIP (rc=1): lists are reused in-place +// Without FBIP (rc>1): new lists are allocated + +fn main(): Unit = { + Console.print("=== FBIP Allocation Test ===") + + // Case 1: Single owner (FBIP active) - should reuse list + let a = List.range(1, 100) + let b = List.map(a, fn(x: Int): Int => x * 2) + let c = List.filter(b, fn(x: Int): Bool => x > 50) + let d = List.reverse(c) + Console.print("Single owner chain done") + + // The allocation count will show FBIP is working + // if allocations are low relative to operations performed +} diff --git a/examples/test_fbip_clean.lux b/examples/test_fbip_clean.lux new file mode 100644 index 0000000..108b2dc --- /dev/null +++ b/examples/test_fbip_clean.lux @@ -0,0 +1,9 @@ +fn main(): Unit = { + // Test FBIP without string operations + let nums = [1, 2, 3, 4, 5] + let doubled = List.map(nums, fn(x: Int): Int => x * 2) + let filtered = List.filter(doubled, fn(x: Int): Bool => x > 4) + let reversed = List.reverse(filtered) + let len = List.length(reversed) + Console.print("done") +} diff --git a/examples/test_no_fbip.lux b/examples/test_no_fbip.lux new file mode 100644 index 0000000..e1d2ada --- /dev/null +++ b/examples/test_no_fbip.lux @@ -0,0 +1,20 @@ +// Test WITHOUT FBIP by forcing rc>1 (shared reference) +fn useList(l: List): Int = { + List.length(l) +} + +fn main(): Unit = { + Console.print("=== Without FBIP (forced rc>1) ===") + + let a = List.range(1, 100) + // Create alias to bump rc, preventing FBIP + let alias = a + let len1 = useList(alias) + + // Now 'a' has rc>1 so map must allocate new list + let b = List.map(a, fn(x: Int): Int => x * 2) + let c = List.filter(b, fn(x: Int): Bool => x > 50) + let d = List.reverse(c) + + Console.print("Shared reference chain done") +} diff --git a/examples/test_rc_comparison.lux b/examples/test_rc_comparison.lux new file mode 100644 index 0000000..e39f298 --- /dev/null +++ b/examples/test_rc_comparison.lux @@ -0,0 +1,17 @@ +fn main(): Unit = { + Console.print("=== Allocation Comparison ===") + + // FBIP path (rc=1): list is reused + Console.print("Test 1: FBIP path") + let a1 = List.range(1, 50) + let b1 = List.map(a1, fn(x: Int): Int => x * 2) + let c1 = List.reverse(b1) + Console.print("FBIP done") + + // To show non-FBIP, we need concat which doesn't have FBIP + Console.print("Test 2: Non-FBIP path (concat)") + let x = List.range(1, 25) + let y = List.range(26, 50) + let z = List.concat(x, y) // concat always allocates new + Console.print("Concat done") +}