Files
ww/lib/strings/replace_test.ww

116 lines
3.2 KiB
Plaintext

// Vectors mirror ref/hare/strings/replace.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;
import test;
// ref/hare/strings/replace.ha:46 (#4). Hare rows 1-5 (target found
// once / multiple times / shorter / longer / multibyte) plus ww rows
// (no-match returns fresh copy, empty-replacement, result-shrinks-to-
// empty).
@test fn replace_cases() void = {
// Hare row 1: target found once.
match (strings.replace("Hello world!", "world", "there")) {
case let s: str => {
assert(!(!streq(s, "Hello there!")));
os.free(s.ptr: *void, s.len: u64);
};
case nomem => { abort(); };
};
// Hare row 2: needle found four times (replacement same length).
match (strings.replace("I like dogs, dogs, birds, dogs", "dogs", "cats")) {
case let s: str => {
assert(!(!streq(s, "I like cats, cats, birds, cats")));
os.free(s.ptr: *void, s.len: u64);
};
case nomem => { abort(); };
};
// Hare row 3: replacement shorter than needle, non-overlapping
// matches (Hare advances by needle.len, not 1).
match (strings.replace("aaaaaa", "aa", "a")) {
case let s: str => {
assert(!(!streq(s, "aaa")));
os.free(s.ptr: *void, s.len: u64);
};
case nomem => { abort(); };
};
// Hare row 4: replacement longer than needle.
match (strings.replace("aaa", "a", "aa")) {
case let s: str => {
assert(!(!streq(s, "aaaaaa")));
os.free(s.ptr: *void, s.len: u64);
};
case nomem => { abort(); };
};
// Hare row 5: multibyte UTF-8 (3-byte runes).
match (strings.replace("こんにちは", "にち", "ばん")) {
case let s: str => {
assert(!(!streq(s, "こんばんは")));
os.free(s.ptr: *void, s.len: u64);
};
case nomem => { abort(); };
};
// ww row 1: needle not found — fresh copy (distinct from
// borrowed input ptr).
let src: str = "hello world";
match (strings.replace(src, "xyz", "abc")) {
case let s: str => {
assert(!(!streq(s, "hello world")));
assert(!(s.ptr == src.ptr));
os.free(s.ptr: *void, s.len: u64);
};
case nomem => { abort(); };
};
// ww row 2: empty replacement — needle is removed.
match (strings.replace("foo-bar-baz", "-", "")) {
case let s: str => {
assert(!(!streq(s, "foobarbaz")));
os.free(s.ptr: *void, s.len: u64);
};
case nomem => { abort(); };
};
// ww row 3: result shrinks to empty — total==0 nil-alloc path.
match (strings.replace("aaaa", "aa", "")) {
case let s: str => {
assert(!(!streq(s, "")));
assert(!(s.len != 0));
};
case nomem => { abort(); };
};
// ww row 4: multibyte single-rune replace — every "に" → "X".
match (strings.replace("こんにちは", "に", "X")) {
case let s: str => {
assert(!(!streq(s, "こんXちは")));
os.free(s.ptr: *void, s.len: u64);
};
case nomem => { abort(); };
};
// ww row 5: empty input — returns empty.
match (strings.replace("", "x", "y")) {
case let s: str => {
assert(!(s.len != 0));
};
case nomem => { abort(); };
};
};
@test fn replace_empty_needle_aborts() void = {
test.expectabort();
strings.replace("abc", "", "x");
};