From 2dc5214fd8bb6a1168e2f2b643a36043c36c908a Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Sun, 25 Jan 2026 11:53:53 +0000 Subject: Fix for #121 --- tests/features/test_copy_trait.zc | 37 --------------- tests/features/test_drop.zc | 26 ----------- tests/features/test_move_semantics.zc | 55 ---------------------- tests/features/test_resources.zc | 59 ------------------------ tests/memory/test_copy_trait.zc | 37 +++++++++++++++ tests/memory/test_drop.zc | 26 +++++++++++ tests/memory/test_move_double_free.zc | 87 +++++++++++++++++++++++++++++++++++ tests/memory/test_move_semantics.zc | 55 ++++++++++++++++++++++ tests/memory/test_resources.zc | 59 ++++++++++++++++++++++++ 9 files changed, 264 insertions(+), 177 deletions(-) delete mode 100644 tests/features/test_copy_trait.zc delete mode 100644 tests/features/test_drop.zc delete mode 100644 tests/features/test_move_semantics.zc delete mode 100644 tests/features/test_resources.zc create mode 100644 tests/memory/test_copy_trait.zc create mode 100644 tests/memory/test_drop.zc create mode 100644 tests/memory/test_move_double_free.zc create mode 100644 tests/memory/test_move_semantics.zc create mode 100644 tests/memory/test_resources.zc (limited to 'tests') diff --git a/tests/features/test_copy_trait.zc b/tests/features/test_copy_trait.zc deleted file mode 100644 index 994ccee..0000000 --- a/tests/features/test_copy_trait.zc +++ /dev/null @@ -1,37 +0,0 @@ - -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/features/test_drop.zc b/tests/features/test_drop.zc deleted file mode 100644 index 8b34efe..0000000 --- a/tests/features/test_drop.zc +++ /dev/null @@ -1,26 +0,0 @@ -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/features/test_move_semantics.zc b/tests/features/test_move_semantics.zc deleted file mode 100644 index bf0d717..0000000 --- a/tests/features/test_move_semantics.zc +++ /dev/null @@ -1,55 +0,0 @@ - -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/features/test_resources.zc b/tests/features/test_resources.zc deleted file mode 100644 index dc7b9f9..0000000 --- a/tests/features/test_resources.zc +++ /dev/null @@ -1,59 +0,0 @@ - -// 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."; -} - 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."; +} + -- cgit v1.2.3