mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
180 lines
5 KiB
Zig
180 lines
5 KiB
Zig
//! List refcounting tests - Phase 4: Lists with Refcounted Elements (Strings)
|
|
//!
|
|
//! This phase introduces two-level refcounting:
|
|
//! - List container must be refcounted
|
|
//! - String elements must be refcounted
|
|
//!
|
|
//! This is where list refcounting gets complex. We must verify:
|
|
//! 1. List container refcount is correct
|
|
//! 2. Each string element's refcount is incremented when added to list
|
|
//! 3. String element refcount is decremented when list is freed
|
|
//!
|
|
//! Each test should pass with correct refcounting (no leaks, no corruption)
|
|
|
|
const std = @import("std");
|
|
const helpers = @import("helpers.zig");
|
|
const testing = std.testing;
|
|
|
|
const runExpectStr = helpers.runExpectStr;
|
|
const runExpectInt = helpers.runExpectInt;
|
|
|
|
test "list refcount strings - single string in list" {
|
|
// String refcount should increment when added to list
|
|
try runExpectStr(
|
|
\\{
|
|
\\ x = "hi"
|
|
\\ lst = [x]
|
|
\\ match lst { [s] => s, _ => "" }
|
|
\\}
|
|
, "hi", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - multiple strings in list" {
|
|
// Each string's refcount should increment
|
|
try runExpectStr(
|
|
\\{
|
|
\\ x = "a"
|
|
\\ y = "b"
|
|
\\ lst = [x, y]
|
|
\\ match lst { [first, ..] => first, _ => "" }
|
|
\\}
|
|
, "a", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - return second string" {
|
|
try runExpectStr(
|
|
\\{
|
|
\\ x = "a"
|
|
\\ y = "b"
|
|
\\ lst = [x, y]
|
|
\\ match lst { [_, second] => second, _ => "" }
|
|
\\}
|
|
, "b", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - same string multiple times" {
|
|
// Same string in multiple list slots - refcount incremented per slot
|
|
try runExpectStr(
|
|
\\{
|
|
\\ x = "hi"
|
|
\\ lst = [x, x, x]
|
|
\\ match lst { [first, ..] => first, _ => "" }
|
|
\\}
|
|
, "hi", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - empty string in list" {
|
|
// Empty string edge case
|
|
try runExpectStr(
|
|
\\{
|
|
\\ x = ""
|
|
\\ lst = [x]
|
|
\\ match lst { [s] => s, _ => "fallback" }
|
|
\\}
|
|
, "", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - small vs large strings in list" {
|
|
// Mix of small (inline) and large (heap) strings
|
|
try runExpectStr(
|
|
\\{
|
|
\\ small = "hi"
|
|
\\ large = "This is a very long string that will be heap allocated for sure"
|
|
\\ lst = [small, large]
|
|
\\ match lst { [first, ..] => first, _ => "" }
|
|
\\}
|
|
, "hi", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - return large string" {
|
|
try runExpectStr(
|
|
\\{
|
|
\\ small = "hi"
|
|
\\ large = "This is a very long string that will be heap allocated for sure"
|
|
\\ lst = [small, large]
|
|
\\ match lst { [_, second] => second, _ => "" }
|
|
\\}
|
|
, "This is a very long string that will be heap allocated for sure", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - list of string literals" {
|
|
// Direct string literals in list
|
|
try runExpectStr(
|
|
\\match ["a", "b", "c"] { [first, ..] => first, _ => "" }
|
|
, "a", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - list of string literals return second" {
|
|
try runExpectStr(
|
|
\\match ["a", "b", "c"] { [_, second, ..] => second, _ => "" }
|
|
, "b", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - empty list then string list" {
|
|
// Multiple lists with different types
|
|
try runExpectStr(
|
|
\\{
|
|
\\ empty = []
|
|
\\ strings = ["x", "y"]
|
|
\\ match strings { [first, ..] => first, _ => "" }
|
|
\\}
|
|
, "x", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - string list aliased" {
|
|
// Alias a string list
|
|
try runExpectStr(
|
|
\\{
|
|
\\ lst1 = ["a", "b"]
|
|
\\ lst2 = lst1
|
|
\\ match lst2 { [first, ..] => first, _ => "" }
|
|
\\}
|
|
, "a", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - string list aliased return from original" {
|
|
try runExpectStr(
|
|
\\{
|
|
\\ lst1 = ["a", "b"]
|
|
\\ lst2 = lst1
|
|
\\ match lst1 { [first, ..] => first, _ => "" }
|
|
\\}
|
|
, "a", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - string list shadowed" {
|
|
// Shadow a string list - old list and its strings should be decreffed
|
|
try runExpectStr(
|
|
\\{
|
|
\\ lst = ["old1", "old2"]
|
|
\\ lst = ["new1", "new2"]
|
|
\\ match lst { [first, ..] => first, _ => "" }
|
|
\\}
|
|
, "new1", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - three string lists" {
|
|
try runExpectStr(
|
|
\\{
|
|
\\ a = ["a1", "a2"]
|
|
\\ b = ["b1", "b2"]
|
|
\\ c = ["c1", "c2"]
|
|
\\ match b { [first, ..] => first, _ => "" }
|
|
\\}
|
|
, "b1", .no_trace);
|
|
}
|
|
|
|
test "list refcount strings - extract string from nested match" {
|
|
try runExpectStr(
|
|
\\{
|
|
\\ lst = ["x", "y", "z"]
|
|
\\ match lst {
|
|
\\ [first, .. as rest] => match rest {
|
|
\\ [second, ..] => second,
|
|
\\ _ => ""
|
|
\\ },
|
|
\\ _ => ""
|
|
\\ }
|
|
\\}
|
|
, "y", .no_trace);
|
|
}
|