// Vectors mirror ref/hare/strings/dup.ha where ww can express them. // External strings_test package per the Go foo_test idiom (rule-5/9 // carve-out, task #16); the shared streq helper lives in // helpers_test.ww — same-package test files compose in dir-mode // (the package, not the file, is the unit of testing). package strings_test; import strings; import os; // ref/hare/strings/dup.ha:45. @test fn dup_cases() void = { let e: str = strings.dup(""); assert(!(!streq(e, ""))); assert(!(e.len != 0)); let h: str = strings.dup("hello"); assert(!(!streq(h, "hello"))); defer os.free(h.ptr: *void, h.len: u64); // multi-byte UTF-8: dup must copy raw bytes, not aliased view. let m: str = strings.dup("こんにちは"); assert(!(m.len != 15)); assert(!(!streq(m, "こんにちは"))); assert(!(m.ptr == "こんにちは".ptr)); // fresh alloc defer os.free(m.ptr: *void, m.len: u64); }; // ref/hare/strings/dup.ha:55 (#6). Element reads go through // `&toks.ptr[i]: *str` // per the splitn cases (16B element copy gap, cgen.c:6515). @test fn dupall_cases() void = { // Empty input — empty result, mirrors Hare's `payload = []`. let empty: []str; empty.ptr = nil: *str; empty.len = 0; empty.cap = 0; match (strings.dupall(empty)) { case let r: []str => { assert(!(r.len != 0)); strings.freeall(r); }; case nomem => { abort(); }; }; // Two-element ASCII — each output element is a fresh allocation // independent of the input (ptr differs from the borrowed source). let in2: [2]str; in2[0] = "hello"; in2[1] = "world"; let src2: []str; src2.ptr = &in2[0]; src2.len = 2; src2.cap = 2; match (strings.dupall(src2)) { case let r: []str => { assert(!(r.len != 2)); expect_str(r, 0, "hello"); expect_str(r, 1, "world"); let p0: *str = &r.ptr[0]; assert(!(p0.ptr == in2[0].ptr)); let p1: *str = &r.ptr[1]; assert(!(p1.ptr == in2[1].ptr)); strings.freeall(r); }; case nomem => { abort(); }; }; // Singleton — `only` rune-equivalent of Hare's `["only"]`. let in1: [1]str; in1[0] = "only"; let src1: []str; src1.ptr = &in1[0]; src1.len = 1; src1.cap = 1; match (strings.dupall(src1)) { case let r: []str => { assert(!(r.len != 1)); expect_str(r, 0, "only"); strings.freeall(r); }; case nomem => { abort(); }; }; // Multibyte — UTF-8 bytes (5-byte and 15-byte) round-trip. let inm: [2]str; inm[0] = "héllo"; inm[1] = "こんにちは"; let srcm: []str; srcm.ptr = &inm[0]; srcm.len = 2; srcm.cap = 2; match (strings.dupall(srcm)) { case let r: []str => { assert(!(r.len != 2)); expect_str(r, 0, "héllo"); expect_str(r, 1, "こんにちは"); let p0: *str = &r.ptr[0]; assert(!(p0.len != 6)); // é is 2 bytes assert(!(p0.ptr == inm[0].ptr)); let p1: *str = &r.ptr[1]; assert(!(p1.len != 15)); // each kana is 3 bytes assert(!(p1.ptr == inm[1].ptr)); strings.freeall(r); }; case nomem => { abort(); }; }; };