diff options
Diffstat (limited to 'tests/memory')
| -rw-r--r-- | tests/memory/test_copy_trait.zc | 37 | ||||
| -rw-r--r-- | tests/memory/test_drop.zc | 26 | ||||
| -rw-r--r-- | tests/memory/test_move_double_free.zc | 87 | ||||
| -rw-r--r-- | tests/memory/test_move_semantics.zc | 55 | ||||
| -rw-r--r-- | tests/memory/test_resources.zc | 59 |
5 files changed, 264 insertions, 0 deletions
diff --git a/tests/memory/test_copy_trait.zc b/tests/memory/test_copy_trait.zc new file mode 100644 index 0000000..994ccee --- /dev/null +++ b/tests/memory/test_copy_trait.zc @@ -0,0 +1,37 @@ + +trait Copy {} + +struct Point { + x: int; + y: int; +} + +impl Copy for Point {} + +struct Mover { + val: int; +} + +test "copy_trait" { + var p1 = Point { x: 10, y: 20 }; + var p2 = p1; // Copy, not move + + // Both should be valid + assert(p1.x == 10, "p1 invalid after copy"); + assert(p2.x == 10, "p2 invalid after copy"); + + // Modify p2, p1 should be unchanged + p2.x = 30; + assert(p1.x == 10, "p1 changed after p2 modification"); + assert(p2.x == 30, "p2 modification failed"); + + println "Copy Trait Works!"; +} + +test "move_default" { + var m1 = Mover { val: 1 }; + var m2 = m1; // Moved + + // Uncommenting this should cause compile error + // var m3 = m1; +} diff --git a/tests/memory/test_drop.zc b/tests/memory/test_drop.zc new file mode 100644 index 0000000..8b34efe --- /dev/null +++ b/tests/memory/test_drop.zc @@ -0,0 +1,26 @@ +import "../../std/mem.zc" + +var DROP_CALLED = 0; + +struct MyResource { + id: int; +} + +impl Drop for MyResource { + fn drop(self) { + println "Dropping MyResource {self.id}"; + DROP_CALLED = 1; + } +} + +test "drop_trait" { + { + var res = MyResource { id: 1 }; + // Scope ends here, drop should be called + } + + if (DROP_CALLED != 1) { + println "Error: Drop was not called!"; + exit(1); + } +} diff --git a/tests/memory/test_move_double_free.zc b/tests/memory/test_move_double_free.zc new file mode 100644 index 0000000..b82bd38 --- /dev/null +++ b/tests/memory/test_move_double_free.zc @@ -0,0 +1,87 @@ +import "../../std/mem.zc" + +// Global counters to track drop calls +var DROP_COUNT = 0; +var DROP_NULL_COUNT = 0; + +struct Resource { + data: int*; + id: int; +} + +impl Drop for Resource { + fn drop(self) { + if (self.data != NULL) { + DROP_COUNT = DROP_COUNT + 1; + free(self.data); + self.data = NULL; // Prevent double free logic if called again, though generated code should zero + } else { + DROP_NULL_COUNT = DROP_NULL_COUNT + 1; + } + } +} + +struct Container { + res: Resource; +} + +// No explicit Drop for Container, relies on compiler generating one + +test "move_variable" { + DROP_COUNT = 0; + DROP_NULL_COUNT = 0; + + { + var r1 = Resource { data: malloc(10), id: 1 }; + var r2 = r1; // Move + + // r1 should be nullified + // r2 owns data + } + + assert(DROP_COUNT == 1, "Should drop exactly once (r2)"); + assert(DROP_NULL_COUNT == 1, "Should see one null drop (r1)"); +} + +fn pass_through(r: Resource) -> Resource { + return r; // Move return +} + +test "move_function" { + DROP_COUNT = 0; + DROP_NULL_COUNT = 0; + + { + var r1 = Resource { data: malloc(10), id: 2 }; + var r2 = pass_through(r1); + // r1 moved to arg -> moved to return -> moved to r2 + } + + // r1: null drop + // arg: null drop (moved to return) + // return temp: null drop (moved to r2) + // r2: valid drop + + assert(DROP_COUNT == 1, "Should drop exactly once (final r2)"); + // We expect multiple null drops due to intermediate moves + assert(DROP_NULL_COUNT >= 1, "Should see at least one null drop"); +} + +test "partial_move_member" { + DROP_COUNT = 0; + DROP_NULL_COUNT = 0; + + { + var c = Container { res: Resource { data: malloc(10), id: 3 } }; + var r = c.res; // Partial move + + // c.res should be nullified + // r owns data + } + + // r drops valid + // c drops, checks res -> null drop + + assert(DROP_COUNT == 1, "Should drop exactly once (r)"); + assert(DROP_NULL_COUNT == 1, "Should see null drop (c.res)"); +} diff --git a/tests/memory/test_move_semantics.zc b/tests/memory/test_move_semantics.zc new file mode 100644 index 0000000..bf0d717 --- /dev/null +++ b/tests/memory/test_move_semantics.zc @@ -0,0 +1,55 @@ + +struct Point { + x: int; +} + +struct Mover { + val: int; +} + +test "basic_move" { + var p1 = Mover { val: 10 }; + var p2 = p1; // p1 moved to p2 + + // Valid usage of p2 + assert(p2.val == 10, "p2 should be valid"); + + // Invalid usage of p1 (Uncomment to test compiler error) + // var p3 = p1; +} + +test "primitive_copy" { + var i = 10; + var j = i; // Copy + var k = i; // Copy again - should be valid + assert(k == 10, "Primitive copy failed"); +} + +test "reassignment" { + var m1 = Mover { val: 1 }; + var m2 = m1; // m1 moved + + m1 = Mover { val: 2 }; // Resurrect m1 + var m3 = m1; // Valid now + assert(m3.val == 2, "Resurrection failed"); +} + +fn consume(m: Mover) { + assert(m.val == 10, "Func arg failed"); +} + +test "func_arg" { + var m = Mover { val: 10 }; + consume(m); // m moved + + // 2. Use after move (Call - Negative Test) + // consume(m); // Should fail: Use of moved value 'm' +} + +/* +// 3. Use after return (Negative Test) +fn fail_return(m: Mover) -> Mover { + var m2 = m; + return m; // Should fail: Use of moved value 'm' +} +*/ diff --git a/tests/memory/test_resources.zc b/tests/memory/test_resources.zc new file mode 100644 index 0000000..dc7b9f9 --- /dev/null +++ b/tests/memory/test_resources.zc @@ -0,0 +1,59 @@ + +// Copy Trait +@derive(Copy) +struct Point { x: int; y: int; } + +// Clone Pattern +trait Clone { + fn clone(self) -> Self; +} + +struct Box { val: int; } + +impl Clone for Box { + fn clone(self) -> Box { + return Box{val: self.val}; + } +} + +// Re-initialization +struct Resource { ptr: void*; } + +// Function Param Helper +fn take_point(p: Point) { + if p.x != 10 { + // Error + } +} + +test "Resource Semantics" { + "Testing Resource Semantics..."; + + var p1 = Point{x: 10, y: 20}; + var p2 = p1; // Copied + + var b1 = Box{val: 99}; + var b2 = b1.clone(); + // var b3 = b1; // This would move if uncommented. + + if b2.val != 99 { + !"Clone failed"; + exit(1); + } + + // Re-initialization + // struct Resource (Global) + + var r1 = Resource{ptr: NULL}; + var r2 = r1; // Moved + + r1 = Resource{ptr: NULL}; // Re-init + var r3 = r1; // Valid again + + // Function Param Move (Simulated) + take_point(p1); + take_point(p1); // Still valid because Copy + + "Resource Semantics Passed."; +} + |
