Create a unit7 for all unit tests.

This commit is contained in:
Christoffer Lerno
2025-02-24 01:05:45 +01:00
parent 70029cc4b8
commit 87725a3a9e
128 changed files with 9311 additions and 103 deletions

View File

@@ -28,16 +28,6 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic
return n;
}
fn String EnumMap.to_string(&self, Allocator allocator) @dynamic
{
return string::format("%s", *self, allocator: allocator);
}
fn String EnumMap.to_tstring(&self) @dynamic
{
return string::tformat("%s", *self);
}
<*
@return "The total size of this map, which is the same as the number of enum values"
@pure

View File

@@ -156,7 +156,7 @@ fn void Object.init_map_if_needed(&self) @private
if (self.is_empty())
{
self.type = ObjectInternalMap.typeid;
self.map.tinit();
self.map.init(self.allocator);
}
}

View File

@@ -2,10 +2,11 @@
@require Type.kindof == ARRAY : "Required an array type"
*>
module std::collections::ringbuffer(<Type>);
import std::io;
def Element = $typeof((Type){}[0]);
struct RingBuffer
struct RingBuffer (Printable)
{
Type buf;
usz written;
@@ -19,7 +20,7 @@ fn void RingBuffer.init(&self) @inline
fn void RingBuffer.push(&self, Element c)
{
if (self.written < buf.len)
if (self.written < self.buf.len)
{
self.buf[self.written] = c;
self.written++;
@@ -27,14 +28,14 @@ fn void RingBuffer.push(&self, Element c)
else
{
self.buf[self.head] = c;
self.head = (self.head + 1) % buf.len;
self.head = (self.head + 1) % self.buf.len;
}
}
fn Element RingBuffer.get(&self, usz index) @operator([])
{
index %= buf.len;
usz avail = buf.len - self.head;
index %= self.buf.len;
usz avail = self.buf.len - self.head;
if (index < avail)
{
return self.buf[self.head + index];
@@ -48,25 +49,25 @@ fn Element! RingBuffer.pop(&self)
{
case self.written == 0:
return SearchResult.MISSING?;
case self.written < buf.len:
case self.written < self.buf.len:
self.written--;
return self.buf[self.written];
default:
self.head = (self.head - 1) % buf.len;
self.head = (self.head - 1) % self.buf.len;
return self.buf[self.head];
}
}
fn usz! RingBuffer.to_format(&self, Formatter* format)
fn usz! RingBuffer.to_format(&self, Formatter* format) @dynamic
{
// Improve this?
return format.printnf("%s", self.buf);
return format.printf("%s", self.buf);
}
fn usz RingBuffer.read(&self, usz index, Element[] buffer)
{
index %= buf.len;
if (self.written < buf.len)
index %= self.buf.len;
if (self.written < self.buf.len)
{
if (index >= self.written) return 0;
usz end = self.written - index;
@@ -74,7 +75,7 @@ fn usz RingBuffer.read(&self, usz index, Element[] buffer)
buffer[:n] = self.buf[index:n];
return n;
}
usz end = buf.len - self.head;
usz end = self.buf.len - self.head;
if (index >= end)
{
index -= end;
@@ -83,13 +84,13 @@ fn usz RingBuffer.read(&self, usz index, Element[] buffer)
buffer[:n] = self.buf[index:n];
return n;
}
if (buffer.len <= buf.len - index)
if (buffer.len <= self.buf.len - index)
{
usz n = buffer.len;
buffer[:n] = self.buf[self.head + index:n];
return n;
}
usz n1 = buf.len - index;
usz n1 = self.buf.len - index;
buffer[:n1] = self.buf[self.head + index:n1];
buffer = buffer[n1..];
index -= n1;
@@ -101,7 +102,7 @@ fn usz RingBuffer.read(&self, usz index, Element[] buffer)
fn void RingBuffer.write(&self, Element[] buffer)
{
usz i;
while (self.written < buf.len && i < buffer.len)
while (self.written < self.buf.len && i < buffer.len)
{
self.buf[self.written] = buffer[i++];
self.written++;
@@ -109,6 +110,6 @@ fn void RingBuffer.write(&self, Element[] buffer)
foreach (c : buffer[i..])
{
self.buf[self.head] = c;
self.head = (self.head + 1) % buf.len;
self.head = (self.head + 1) % self.buf.len;
}
}

View File

@@ -72,7 +72,7 @@ macro @check(#condition, String format = "", args...)
@stack_mem(512; Allocator allocator)
{
DString s;
s.new_init(allocator: allocator);
s.init(allocator);
s.appendf("check `%s` failed. ", $stringify(#condition));
s.appendf(format, ...args);
print_panicf(s.str_view());

View File

@@ -77,13 +77,13 @@ macro void! CsvReader.@each_row(self, int rows = int.max; @body(String[] row)) @
{
@stack_mem(512; Allocator mem)
{
String! s = io::readline(stream, mem);
String! s = io::readline(mem, stream);
if (catch err = s)
{
if (err == IoError.EOF) return;
return err?;
}
@body(s.split(sep, allocator: mem));
@body(s.split(mem, sep));
};
}
}

View File

@@ -27,9 +27,9 @@ fn Object*! tparse_string(String s)
fn Object*! parse(Allocator allocator, InStream s)
{
@stack_mem(512; Allocator mem)
@stack_mem(512; Allocator smem)
{
JsonContext context = { .last_string = dstring::new_with_capacity(mem, 64), .stream = s, .allocator = allocator };
JsonContext context = { .last_string = dstring::new_with_capacity(smem, 64), .stream = s, .allocator = allocator };
@pool(allocator)
{
return parse_any(&context);

View File

@@ -170,81 +170,81 @@ fn Url! parse(Allocator allocator, String url_string)
return url;
}
<*
Stringify a Url struct.
@param [in] self
@param [inout] allocator
@return "Url as a string"
*>
fn String Url.to_string(&self, Allocator allocator = allocator::heap()) @dynamic => @pool(allocator)
fn usz! Url.to_format(&self, Formatter* f) @dynamic
{
DString builder = dstring::tnew();
usz len;
// Add scheme if it exists
if (self.scheme != "")
{
builder.append_chars(self.scheme);
builder.append_char(':');
if (self.host.len > 0) builder.append_chars("//");
len += f.print(self.scheme)!;
len += f.print(":")!;
if (self.host.len > 0) len += f.print("//")!;
}
// Add username and password if they exist
if (self.username != "")
if (self.username)
{
String username = tencode(self.username, USERPASS);
builder.append_chars(username);
if (self.password != "")
@stack_mem(64; Allocator smem)
{
builder.append_char(':');
String password = tencode(self.password, USERPASS);
builder.append_chars(password);
len += f.print(encode(smem, self.username, USERPASS))!;
};
if (self.password)
{
len += f.print(":")!;
@stack_mem(64; Allocator smem)
{
len += f.print(encode(smem, self.password, USERPASS))!;
};
}
builder.append_char('@');
len += f.print("@")!;
}
// Add host
String host = tencode(self.host, HOST);
builder.append_chars(host);
@stack_mem(128; Allocator smem)
{
len += f.print(encode(smem, self.host, HOST))!;
};
// Add port
if (self.port != 0)
{
builder.append_char(':');
builder.appendf("%d", self.port);
}
if (self.port) len += f.printf(":%d", self.port)!;
// Add path
String path = tencode(self.path, PATH);
builder.append_chars(path);
@stack_mem(256; Allocator smem)
{
len += f.print(encode(smem, self.path, PATH))!;
};
// Add query if it exists (note that `query` is expected to
// be already properly encoded).
if (self.query != "")
if (self.query)
{
builder.append_char('?');
builder.append_chars(self.query);
len += f.print("?")!;
len += f.print(self.query)!;
}
// Add fragment if it exists
if (self.fragment != "")
if (self.fragment)
{
builder.append_char('#');
String fragment = tencode(self.fragment, FRAGMENT);
builder.append_chars(fragment);
@stack_mem(256; Allocator smem)
{
len += f.print("#")!;
len += f.print(encode(smem, self.fragment, FRAGMENT))!;
};
}
return builder.copy_str(allocator);
return len;
}
def UrlQueryValueList = List(<String>);
fn String Url.to_string(&self, Allocator allocator)
{
return string::format(allocator, "%s", *self);
}
def UrlQueryValueList = List{String};
struct UrlQueryValues
{
inline HashMap(<String, UrlQueryValueList>) map;
inline HashMap{String, UrlQueryValueList} map;
UrlQueryValueList key_order;
}
@@ -317,41 +317,35 @@ fn UrlQueryValues* UrlQueryValues.add(&self, String key, String value)
}
<*
Stringify UrlQueryValues into an encoded query string.
@param [in] self
@param [inout] allocator
@return "a percent-encoded query string"
*>
fn String UrlQueryValues.to_string(&self, Allocator allocator = allocator::heap()) @dynamic => @pool(allocator)
fn usz! UrlQueryValues.to_format(&self, Formatter* f) @dynamic
{
DString builder = dstring::tnew();
usz len;
usz i;
foreach (key: self.key_order)
{
String encoded_key = tencode(key, QUERY);
UrlQueryValueList! values = self.map.get(key);
if (catch values) continue;
foreach (value: values)
@stack_mem(128; Allocator mem)
{
if (i > 0) builder.append_char('&');
builder.append_chars(encoded_key);
builder.append_char('=');
String encoded_value = tencode(value, QUERY);
builder.append_chars(encoded_value);
i++;
}
};
return builder.copy_str(allocator);
String encoded_key = encode(mem, key, QUERY);
UrlQueryValueList! values = self.map.get(key);
if (catch values) continue;
foreach (value : values)
{
if (i > 0) len += f.print("&")!;
len += f.print(encoded_key)!;
len += f.print("=")!;
@stack_mem(256; Allocator smem)
{
len += f.print(encode(smem, value, QUERY))!;
};
i++;
}
};
}
return len;
}
fn void UrlQueryValues.free(&self)
{
self.map.@each(;String key, UrlQueryValueList values)

View File

@@ -0,0 +1,25 @@
module any_tests @test;
fn void any_compare()
{
int x;
any a = &x;
any b = &x;
assert(a == b);
assert(a == a);
}
def AnyAlias = any;
fn void test_aliasing()
{
int x;
AnyAlias z = &x;
switch (z)
{
case int:
assert(true);
default:
assert(false);
}
}

View File

@@ -0,0 +1,44 @@
module bitstruct_ops;
import std::io;
bitstruct Foo : int
{
bool a : 0;
bool b : 1;
}
bitstruct Bar : char[13]
{
bool z : 0;
bool w : 1;
bool gh : 25;
}
fn void test_bitops() @test
{
Foo f1 = { true, true };
Foo f2 = { true, false };
Foo f3 = f1 & f2;
assert(f3.a == true);
assert(f3.b == false);
Foo f4 = (f1 | ~f2) ^ f3;
assert(f4.a == false && f4.b == true);
Foo f5 = (Foo) { true, false } | (Foo) { false, true };
assert(f5.a == true && f5.b == true);
f5 &= f2;
assert(f5.a == true && f5.b == false);
Bar b1 = { true, true, true };
Bar b2 = { true, false, false };
Bar b3 = b1 & b2;
assert(b3.z == true && b3.w == false && b3.gh == false);
b3 = ~b3;
assert(b3.z == false && b3.w == true && b3.gh == true);
b3 ^= (Bar) { true, true, false };
assert(b3.z == true && b3.w == false && b3.gh == true);
}

View File

@@ -0,0 +1,65 @@
module bitstruct_ops_bool;
import std::io;
bitstruct Foo : int
{
bool a;
bool b;
}
bitstruct Bar : char[13]
{
bool z;
bool w;
bool gh;
}
fn void test_bitops() @test
{
Foo f1 = { true, true };
Foo f2 = { true, false };
Foo f3 = f1 & f2;
assert(f3.a == true);
assert(f3.b == false);
Foo f4 = (f1 | ~f2) ^ f3;
assert(f4.a == false && f4.b == true);
Foo f5 = (Foo) { true, false } | (Foo) { false, true };
assert(f5.a == true && f5.b == true);
f5 &= f2;
assert(f5.a == true && f5.b == false);
Bar b1 = { true, true, true };
Bar b2 = { true, false, false };
Bar b3 = b1 & b2;
assert(b3.z == true && b3.w == false && b3.gh == false);
b3 = ~b3;
assert(b3.z == false && b3.w == true && b3.gh == true);
b3 ^= (Bar) { true, true, false };
assert(b3.z == true && b3.w == false && b3.gh == true);
}
fn void test_bitops_const() @test
{
const Foo F1 = { true, true };
const Foo F2 = { true, false };
const Foo F3 = F1 & F2;
assert(F3.a == true);
assert(F3.b == false);
const Foo F4 = (F1 | ~F2) ^ F3;
assert(F4.a == false && F4.b == true);
const Foo F5 = (Foo) { true, false } | (Foo) { false, true };
assert(F5.a == true && F5.b == true);
const Bar B1 = { true, true, true };
const Bar B2 = { true, false, false };
const Bar B3 = B1 & B2;
assert(B3.z == true && B3.w == false && B3.gh == false);
}

View File

@@ -0,0 +1,90 @@
module bitstruct_ops_inc @test;
import std::io;
struct Data {
bitstruct : ushort @overlap {
char a : 0..7;
}
bitstruct : ushort @overlap {
ushort ab : 0..15;
}
}
bitstruct Foo : char[10]
{
int a : 10..15;
}
struct NewData {
char a;
ushort ab;
}
fn void test_inc()
{
NewData newdata;
newdata.a = 0x55;
newdata.ab = 0xAABB;
NewData newdata2 = newdata;
newdata.a += 1;
newdata.ab += 1;
newdata2.a++;
newdata2.ab++;
assert(newdata.a == newdata2.a, "Structs: Expected %x, found %x", newdata.a, newdata2.a);
assert(newdata.ab == newdata2.ab, "Structs: Expected %x, found %x", newdata.ab, newdata2.ab);
Data data;
data.a = 0x55;
data.ab = 0xAABB;
Data data2 = data;
data.a += 1;
data.ab += 1;
data2.a++;
data2.ab++;
assert(data.a == data2.a, "BitStructs: Expected %x, found %x", data.a, data2.a);
assert(data.ab == data2.ab, "BitStructs: Expected %x, found %x", data.ab, data2.ab);
data.a -= 1;
data.ab -= 1;
data2.a--;
data2.ab--;
assert(data.a == data2.a, "BitStructs: Expected %x, found %x", data.a, data2.a);
assert(data.ab == data2.ab, "BitStructs: Expected %x, found %x", data.ab, data2.ab);
char a = data.a;
assert(a == data.a++);
assert(a != data.a);
assert(a == --data.a);
}
fn void test_inc_array()
{
Foo x;
x.a = 10;
assert(x.a == 10);
assert(x.a++ == 10);
assert(x.a == 11, "Value was %d", x.a);
assert(--x.a == 10);
}
bitstruct Flags : int
{
bool flag1;
bool flag2;
}
fn void negate()
{
Flags flags;
flags = ~flags;
assert(~0 == (int)flags);
flags = ~(Flags){};
assert(3 == (int)flags);
const Flags FLAGS = {.flag1 };
flags = ~FLAGS;
assert(2 == (int)flags);
}

View File

@@ -0,0 +1,17 @@
module slice_to_arr @test;
fn void to_arr()
{
int[] x = { 1, 2, 3, 4, 5 };
int z = 2;
int[2] y = x[z:2];
assert(y == {3, 4});
}
fn void to_vec()
{
int[] x = { 1, 2, 3, 4, 5 };
int z = 2;
int[<2>] y = x[z:2];
assert(y == { 3, 4 });
}

View File

@@ -0,0 +1,24 @@
module castable @test;
fn void assignable()
{
assert($assignable(12.0, int) == false);
assert($assignable(12, int));
assert(!$assignable("12", int));
assert($assignable("12", String));
assert($assignable("12", char*));
assert($assignable("12", char[?]));
assert($assignable("12", char[2]));
assert($assignable("12", char[3]));
}
fn void castable()
{
assert($defined((int)12.0));
assert($defined((int)12));
assert(!$defined((int)"12"));
assert($defined((String)"12"));
assert($defined((char*)"12"));
assert($defined((char[2])"12"));
assert($defined((char[3])"12"));
}

View File

@@ -0,0 +1,21 @@
module catch_err @test;
fn void test()
{
anyfault a;
int! z = fn int!(anyfault* a) {
const ABC = 4;
int! x = SearchResult.MISSING?;
defer (catch err) *a = err;
return x;
}(&a);
assert(a == SearchResult.MISSING);
anyfault y;
z = fn int!(anyfault* y) {
const ABC = 4;
int! x = 1;
defer (catch err) *y = err;
return x;
}(&y);
assert(!y);
}

View File

@@ -0,0 +1,15 @@
module copysign @test;
import std::math;
fn void copysign_float()
{
float a = 3;
float b = -4;
float c = math::copysign(a, b);
assert(c == -3);
float d = math::copysign(a, 3);
assert(d == 3);
assert(math::copysign(a, -3) == -3);
float e = math::copysign(3, a);
assert(e == 3);
assert(math::copysign(3, b) == -3);
}

View File

@@ -0,0 +1,38 @@
module ct_slice @test;
fn void slice_bytes()
{
char[4] $a = x'aabbccdd';
var $b = $a[1..2];
char[2] y = $b;
assert($b == (char[]){187, 204});
assert(y == {187, 204 });
}
fn void slice_string()
{
String $a = "abcd";
test::eq($a, "abcd");
var $c = $a[1:0];
String c = $c;
assert($c == "");
assert(c == "");
var $d = $a[1:2];
String d = $d;
assert($d == "bc");
assert(d == "bc");
assert($a[..] == "abcd");
}
fn void slice_untyped()
{
var $v = { 1, "hello", 3 };
int[1] v = $v[0:1];
assert(v == { 1 });
int[1] v2 = $v[2:1];
assert(v2 == { 3 });
String[1] v3 = $v[1:1];
assert(v3 == { "hello" });
int[] v4 = $v[0:1];
assert(v4 == { 1 });
}

View File

@@ -0,0 +1,49 @@
module distinct_inline @test;
distinct Foo = inline int;
distinct Bar = inline Foo;
distinct Baz = inline Foo;
distinct Abc = inline Baz;
distinct Def = inline Abc;
distinct Other = inline int;
distinct Other2 = inline Other;
fn void test_binary()
{
assert($typeof((Foo)1 + 1).typeid == Foo.typeid);
assert($typeof((Foo)1 + (Bar)1).typeid == Foo.typeid);
assert($typeof((Baz)1 + (Bar)1).typeid == Foo.typeid);
assert($typeof((Def)1 + (Bar)1).typeid == Foo.typeid);
assert($typeof((Other2)1 + (Def)1).typeid == int.typeid);
}
distinct DistinctInt = inline int;
distinct DistinctUInt = inline uint;
fn void test_comparison()
{
char v_char;
ichar v_ichar;
short v_short;
short v_ushort;
int v_int;
uint v_uint;
long v_long;
ulong v_ulong;
assert((DistinctInt)0 == v_ichar);
assert((DistinctInt)0 == v_char);
assert((DistinctInt)0 == v_short);
assert((DistinctInt)0 == v_ushort);
assert((DistinctInt)0 == v_int);
assert((DistinctInt)0 == v_uint);
assert((DistinctInt)0 == v_long);
assert((DistinctInt)0 == v_ulong);
assert((DistinctUInt)0 == v_ichar);
assert((DistinctUInt)0 == v_char);
assert((DistinctUInt)0 == v_short);
assert((DistinctUInt)0 == v_ushort);
assert((DistinctUInt)0 == v_int);
assert((DistinctUInt)0 == v_uint);
assert((DistinctUInt)0 == v_long);
assert((DistinctUInt)0 == v_ulong);
}

View File

@@ -0,0 +1,21 @@
module faults @test;
fault Foo
{
ABC,
CDE
}
fn void ordinals()
{
Foo z = {};
assert(z.ordinal == 0);
$assert Foo.ABC.ordinal == 1;
$assert Foo.CDE.ordinal == 2;
$assert (Foo){}.ordinal == 0;
Foo x = Foo.CDE;
assert(x.ordinal == 2);
x = Foo.ABC;
assert(x.ordinal == 1);
}

View File

@@ -0,0 +1,22 @@
module test::module_a;
import std::io;
macro line() => $$LINE;
macro func() => $$FUNC;
macro mod() => $$MODULE;
macro line_indirect() => line();
macro func_indirect() => func();
macro mod_indirect() => mod();
module test @test;
fn void test_builtins()
{
assert(module_a::line() == module_a::line_indirect());
assert(module_a::line() == $$LINE);
assert(module_a::func() == module_a::func_indirect());
assert(module_a::func() == $$FUNC);
assert(module_a::mod() == module_a::mod_indirect());
assert(module_a::mod() == $$MODULE);
}

View File

@@ -0,0 +1,16 @@
module gather_scatter;
fn void test_simple() @test
{
int[5] a = { 1, 2, 3, 4, 5 };
void*[<2>] x = { &a[0], &a[4] };
int*[<2>] y = x;
int[<2>] result = mem::@gather_aligned(y, (bool[<2>]) { true, false }, (int[<2>]){ 10, 20 }, 4);
assert(result == { 1, 20});
result = mem::gather(y, (bool[<2>]) { true, false }, (int[<2>]){ 10, 20 });
assert(result == { 1, 20});
mem::@scatter_aligned(y, (int[<2>]){ 66, 77 }, (bool[<2>]) { false, true } , 4);
assert(a == (int[5]){ 1, 2, 3, 4, 77});
mem::scatter(y, (int[<2>]){ 88, 99 }, (bool[<2>]) { true, false });
assert(a == (int[5]){ 88, 2, 3, 4, 77});
}

View File

@@ -0,0 +1,34 @@
fn void vector_inc_dec() @test
{
int[<3>] x;
int[<3>] y;
int z = ++x[0];
int zz = y[0]++;
x[1]++;
++y[2];
int[<3>] g = x--;
assert(x == { 0, 0, -1 });
assert(y == { 1, 0, 1 });
assert(z == 0 && zz == 1);
assert(g == { 1, 1, 0 });
}
fn void int_inc_dec() @test
{
int x;
assert(x++ == 0);
assert(x == 1);
assert(++x == 2);
assert(x-- == 2);
assert(--x == 0);
}
fn void float_inc_dec() @test
{
double x;
assert(x++ == 0);
assert(x == 1.0);
assert(++x == 2.0);
assert(x-- == 2.0);
assert(--x == 0);
}

View File

@@ -0,0 +1,21 @@
module int128_test;
fn void check(uint128 a, uint128 b)
{
uint128 div = a / b;
uint128 mod = a % b;
assert(div * b + mod == a);
}
fn void test_big() @test
{
uint128 a = 12345678901234567890012u128;
uint128 b = 1234567890123456789001u128;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
check(a + i, b + j);
}
}
}

View File

@@ -0,0 +1,9 @@
fn void int_min() @test
{
assert(int.min == -2147483648);
assert((float)int.min == -2147483648.0f);
assert(short.min == -32768);
assert((float)short.min == -32768.0f);
assert(ichar.min == -128);
assert((float)ichar.min == -128.0f);
}

View File

@@ -0,0 +1,22 @@
module liveness;
interface TestProto
{
fn void tesT();
}
fn void Test.tesT(&self) @dynamic
{}
struct Test (TestProto)
{
void* abc;
}
fn void reflect_test() @test
{
TestProto b = mem::alloc(Test);
b.tesT();
defer free(b);
}

View File

@@ -0,0 +1,21 @@
module lvalue_handling;
import std;
struct Foo
{
int a;
}
def IntList = List{Foo};
fn void subscript_overload() @test
{
IntList x;
defer x.free();
x.push({ 3 });
int* a = &x[0].a;
assert(*a == 3);
assert(x[0].a == 3);
*a = 4;
assert(x[0].a == 4);
x[0].a = 5;
assert(x[0].a == 5);
}

View File

@@ -0,0 +1,28 @@
import std;
fn void masked_load() @test
{
long[<4>] val = { 1, 3, 5, 8 };
long[<4>] res = mem::masked_load(&val, { true, false, true, false }, (long[<4>]){ 100, 200, 300, 400 });
assert(res == { 1, 200, 5, 400 });
}
fn void masked_load_aligned() @test
{
long[<4>] val = { 1, 3, 5, 8 };
long[<4>] res = mem::@masked_load_aligned(&val, { true, false, true, false }, (long[<4>]) { 100, 200, 300, 400 }, 8);
assert(res == { 1, 200, 5, 400 });
}
fn void masked_store() @test
{
long[<4>] val = { 1, 3, 5, 8 };
mem::masked_store(&val, (long[<4>]){11, 22, 33, 44}, { true, false, false, true });
assert(val == { 11, 3, 5, 44 });
}
fn void masked_store_aligned() @test
{
long[<4>] val = { 1, 3, 5, 8 };
mem::@masked_store_aligned(&val, (long[<4>]){11, 22, 33, 44}, { true, false, false, true }, 8);
assert(val == { 11, 3, 5, 44 });
}

View File

@@ -0,0 +1,80 @@
module methodsof;
interface IBar
{
fn void fnA();
fn void fnB();
}
struct Bar (IBar)
{
int a;
}
fn void Bar.fnB(&self) @dynamic {}
fn void Bar.fnA(&self) @dynamic {}
struct Foo
{
int i;
bool b;
}
fn void Foo.foo(&self) {}
fn int Foo.bar(&self, int x) { return x * self.i; }
fn bool Foo.xyz(&self) { return self.b; }
struct NoMethods
{
int a;
}
bitstruct BazBits : char
{
int a : 0..2;
int b : 4..6;
bool c : 7;
}
fn void BazBits.fn1(&self) {}
fn void BazBits.fn2(&self) {}
union AUnion {
int y;
double z;
}
fn void AUnion.a(&self) {}
fn void AUnion.b(&self) {}
module methodsof @test;
import std::io;
fn void methodsof()
{
assert(Foo.methodsof.len == 3);
assert(Bar.methodsof.len == 2);
assert(NoMethods.methodsof.len == 0);
assert(Foo.methodsof[0] == "foo");
assert(Foo.methodsof[1] == "bar");
assert(Foo.methodsof[2] == "xyz");
assert(Bar.methodsof[0] == "fnB");
assert(Bar.methodsof[1] == "fnA");
assert(BazBits.methodsof[0] == "fn1");
assert(BazBits.methodsof[1] == "fn2");
assert(AUnion.methodsof[0] == "a");
assert(AUnion.methodsof[1] == "b");
Foo foo = { .i = 4, .b = true };
assert(Foo.$eval(Foo.methodsof[2])(&foo) == true); // Foo.xyz
assert(Foo.$eval(Foo.methodsof[1])(&foo, 2) == 8); // Foo.bar
assert(Foo.$eval(Foo.methodsof[2])(&foo) == true); // Foo.xyz
assert(Foo.$eval(Foo.methodsof[1])(&foo, 2) == 8); // Foo.bar
Foo foo2 = { .i = 2, .b = false };
assert(foo2.$eval(Foo.methodsof[2])() == false); // Foo.xyz
assert(foo2.$eval(Foo.methodsof[1])(10) == 20); // Foo.bar
}

View File

@@ -0,0 +1,20 @@
import std;
struct Foo
{
int a,b,c,d;
}
fn void pointer_diff() @test
{
Foo* foo;
isz offset = &foo[1] - &foo[0];
assert(offset == 1);
}
fn void pointer_add() @test
{
Foo* foo;
Foo* bar = foo + 2;
isz offset = bar - foo;
assert(offset == 2);
}

View File

@@ -0,0 +1,19 @@
module test @test;
fn void pointer_non_decay()
{
int[6] x;
int[3]* y = (int[3]*)&x;
int* z = y;
int[] sub = y;
int[3] y1 = y[1];
int z1 = z[1];
int* xx = y + 1;
int[3]* yy = (int[3]*)(xx);
int* zz = yy - 1;
assert(y == z);
assert(z == zz);
assert(&(*y)[1] == &xx[-2]);
x[1] = 123;
assert(x[1] == z[1]);
}

View File

@@ -0,0 +1,10 @@
import std;
fn long[<4>] process(long[<4>] a, long[<4>] b) @noinline
{
return math::select({ true, true, false, true }, a, b);
}
fn void test_select() @test
{
long[<4>] res = process({ 4, 5, 6, 7 }, { 100, 200, 300, 400 });
assert(res == { 4, 5, 300, 7});
}

View File

@@ -0,0 +1,157 @@
module signed_unsigned_comparisons @test;
fn void test_signed()
{
int a = 0;
int b = 1;
bool ab_gt = a > b;
bool ab_ge = a >= b;
bool ab_le = a <= b;
bool ab_lt = a < b;
bool ab_ne = a != b;
bool ab_eq = a == b;
}
fn void test_unsigned()
{
uint a = 0;
uint b = 1;
bool ab_gt = a > b;
bool ab_ge = a >= b;
bool ab_le = a <= b;
bool ab_lt = a < b;
bool ab_ne = a != b;
bool ab_eq = a == b;
}
fn void test_signedunsigned()
{
ichar a = 0 - 1;
char b = (char)(a);
assert(!(a > b));
assert(!(a >= b));
assert(a < b);
assert(a <= b);
assert(a != b);
assert(!(a == b));
a = 1;
b = 1;
assert(!(a > b));
assert(a >= b);
assert(!(a < b));
assert(a <= b);
assert(!(a != b));
assert(a == b);
a = 1;
b = 4;
assert(!(a > b));
assert(!(a >= b));
assert(a < b);
assert(a <= b);
assert(a != b);
assert(!(a == b));
a = 4;
b = 1;
assert(a > b);
assert(a >= b);
assert(!(a < b));
assert(!(a <= b));
assert(a != b);
assert(!(a == b));
a = 4;
b = 129;
assert(!(a > b));
assert(!(a >= b));
assert(a < b);
assert(a <= b);
assert(a != b);
assert(!(a == b));
a = 0 - 4;
b = 129;
assert(!(a > b));
assert(!(a >= b));
assert(a < b);
assert(a <= b);
assert(a != b);
assert(!(a == b));
}
fn void test_unsignedsigned()
{
int b = -1;
uint a = (uint)(b);
assert(a > b);
assert(a >= b);
assert(!(a < b));
assert(!(a <= b));
assert(a != b);
assert(!(a == b));
a = 1;
b = 1;
assert(!(a > b));
assert(a >= b);
assert(!(a < b));
assert(a <= b);
assert(!(a != b));
assert(a == b);
a = 4;
b = 1;
assert(a > b);
assert(a >= b);
assert(!(a < b));
assert(!(a <= b));
assert(a != b);
assert(!(a == b));
a = 1;
b = 4;
assert(!(a > b));
assert(!(a >= b));
assert(a < b);
assert(a <= b);
assert(a != b);
assert(!(a == b));
a = 0x8000_0001;
b = 4;
assert(a > b);
assert(a >= b);
assert(!(a < b));
assert(!(a <= b));
assert(a != b);
assert(!(a == b));
b = 0 - 4;
a = 0x8000_0001;
assert(a > b);
assert(a >= b);
assert(!(a < b));
assert(!(a <= b));
assert(a != b);
assert(!(a == b));
}

View File

@@ -0,0 +1,9 @@
module slice_assign @test;
fn void assign_slice()
{
int[8] a;
a[2..3] = { 1, 2 };
a[5..7] = 5;
assert(a == (int[8]){ 0, 0, 1, 2, 0, 5, 5, 5});
}

View File

@@ -0,0 +1,18 @@
module struct_alignment @test;
struct Test @align(16) { void* foo; }
struct Test2
{
Test test;
uint a;
}
fn void nested_struct()
{
Test2* array;
assert((uptr)&array[1] - (uptr)array == 32);
assert((uptr)&array[1] - (uptr)array == Test2.sizeof);
assert(Test2.sizeof == 32);
assert(Test.sizeof == 16);
}

View File

@@ -0,0 +1,15 @@
module subscripting_tests @test;
fn void subscript_ct()
{
$if int.nameof[0] == 'i':
assert(true);
$else
assert(false);
$endif
$if int.nameof[^1] == 't':
assert(true);
$else
assert(false);
$endif
}

View File

@@ -0,0 +1,91 @@
module switch_subtype @test;
struct Foo
{
inline Baz g;
int a;
}
struct Bar
{
inline Foo f;
}
struct Baz
{
int z;
}
fn void switch_subtyping()
{
Foo f = {};
f.z = 123;
any x = &f;
switch (x)
{
case int:
assert(false);
case Baz:
assert(true);
default:
assert(false);
}
switch (x)
{
case int:
assert(false);
case Foo:
assert(true);
default:
assert(false);
}
switch (x)
{
case int:
assert(false);
case Bar:
assert(false);
default:
assert(true);
}
switch (Bar.typeid)
{
case int:
assert(false);
case Baz:
assert(true);
case Foo:
assert(false);
case Bar:
assert(false);
default:
assert(false);
}
switch (Bar.typeid)
{
case int:
assert(false);
case Foo:
assert(true);
case Bar:
assert(false);
default:
assert(false);
}
$switch (Bar.typeid)
$case Foo:
assert(true);
$case Bar:
assert(false);
$default:
assert(false);
$endswitch
}
fn void is_subtype()
{
$assert(types::is_subtype_of(Bar, Baz));
$assert(!types::is_subtype_of(Baz, Bar));
typeid baz = Baz.typeid;
typeid bar = Bar.typeid;
assert(bar.is_subtype_of(baz));
assert(!bar.is_subtype_of(double.typeid));
assert(!baz.is_subtype_of(bar));
}

View File

@@ -0,0 +1,18 @@
module swizzletest @test;
fn void test_swizzle()
{
int[<4>] a = { 1, 2, 3, 4 };
int[<4>] b = { 100, 1000, 10000, 100000 };
assert($$swizzle(a, 0, 1, 1, 3) == (int[<4>]) { 1, 2, 2, 4 });
assert($$swizzle2(a, b, 0, 1, 4, 6, 2) == (int[<5>]) { 1, 2, 100, 10000, 3 });
}
fn void swizzle_builtin()
{
int[<4>] abc = { 1, 2, 3, 4 };
assert(abc.rb == { 1, 3 });
assert(abc.xxww == { 1, 1, 4, 4 });
abc = abc.abgr;
assert(abc == { 4, 3, 2, 1 });
}

View File

@@ -0,0 +1,11 @@
module test @test;
fn void const_ternary()
{
int foo = 1;
const int FOO = 1;
assert((foo ?: 2) == 1);
assert((FOO ?: 2) == 1);
int bar = 2;
assert((FOO ?: bar) == 1);
}

View File

@@ -0,0 +1,19 @@
module unwrapping;
fn bool! get_bool()
{
return true;
}
fn void bool_chain_unwrap() @test
{
bool b;
if (try v = get_bool() && b)
{
assert(v == true);
}
if (try v = get_bool() && v)
{
assert(v == true);
}
}

View File

@@ -0,0 +1,35 @@
module vecpointer @test;
fn void pointer_npot2_size()
{
int[<9>][3] a;
assert((usz)&a[1] - (usz)&a[0] == 64);
}
fn void pointer_add_sub_diff()
{
int[5] a;
void*[<2>] x = { &a[0], &a[4] };
int*[<2>] y = x;
assert(x[0] == y[0] && x[1] == y[1]);
int*[2] y2;
y2 = y;
assert(y2[0] == x[0] && y2[1] == x[1]);
y = { null, null };
assert(y[0] == null && y[0] == null);
y = y2;
assert(x[0] == y[0] && x[1] == y[1]);
int[<2>] z = { 1, -1 };
y = y + z;
assert(y[0] == &a[1] && y[1] == &a[3]);
y = y - z;
assert(y[0] == &a[0] && y[1] == &a[4]);
int*[<2>] yy = { &a[1], &a[2] };
isz[<2>] w;
w = y - yy;
assert(w == { -1, 2 });
int*[<2>] zz = y - (y - yy);
assert(zz[0] == &a[1] && zz[1] == &a[2]);
int[?]*[<2>] g = (int[2]*[<2>]) { null, null };
int[?]*[<?>] g2 = (int[2]*[<2>]) { null, null };
}

View File

@@ -0,0 +1,31 @@
module test @test;
fn void vector_array_inferred()
{
int[<2>] x = { 4, 7 };
int[2] y = x;
int[?] y1 = y;
int[?] y2 = x;
int[<?>] z = x;
int[<?>] w = y;
double[<2>] ww = x;
assert((int[<2>])y == { 4, 7});
assert((int[<2>])y1 == { 4, 7 });
assert((int[<2>])y2 == { 4, 7 });
assert(z == { 4, 7 });
assert(w == { 4, 7 });
}
fn void vector_convert_slice()
{
int[<2>] x = { 1, 2 };
int[2] y = { 4, 4 };
x *= y[:2];
assert(x == { 4, 8 });
}
fn void vector_convert_bool()
{
bool[<2>] a = { true, false };
assert({ -1, 0 } == (int[<2>])a);
assert({ 1.0, 0 } == (float[<2>])a);
}

View File

@@ -0,0 +1,18 @@
import std::math;
fn void vector_method_reduce() @test
{
float[<3>] x = { 1, 2.0, 4.0 };
int[<?>] y = { -23, 1, 4 };
assert(y.sum() == -18);
assert(y.product() == -92);
assert(y.max() == 4);
assert(y.and() == 0);
assert(y.xor() == -20);
assert(y.min() == -23);
assert(y.or() == -19);
assert(x.sum(1.2) - 8.2 < 0.000001);
assert(x.product(1.2) - 9.6 < 0.000001);
assert(x.min() == 1.0);
assert(x.max() == 4.0);
}

View File

@@ -0,0 +1,114 @@
import std::io;
fn void test_int_mod() @test
{
int[<2>] y = { 10, 99 };
int[<2>] z = { 3, 5 };
assert(y % z == { 1, 4 });
assert(y / z == { 3, 19 });
assert((int[<2>]){ 10, 99 } % { 3, 5 } == { 1, 4 });
assert((int[<2>]){ 10, 99 } / { 3, 5 } == { 3, 19 });
}
fn void test_conv() @test
{
float[<4>] y = { 1, 2, 3, 4 };
float[<4>] z = { 0, 2, 2, -100 };
int[<4>] w = { -1, 2, 3, 4 };
float[<4>] yy = w;
assert(yy == { -1.0, 2.0, 3.0, 4.0 });
ulong[<4>] ww = w;
assert(ww == { (ulong)-1, 2, 3, 4 });
int[<4>] g = (int[<4>])ww;
assert(g == w);
ww = (long[<4>])y;
assert(ww == { 1, 2, 3, 4 });
bool[<2>] b = { true, false };
int[<2>] gh = b;
assert(gh == { -1, 0 });
var $k = (bool[<2>]){ true, false };
var $gh = (int[<2>])$k;
$assert $gh[0] == -1;
var $gh2 = (char[<2>])$gh;
$assert $gh2[0] == 255;
b = (bool[<2>])gh;
assert(b == { true, false });
}
fn void testf() @test
{
float[<4>] x = { 4, 0, -1, 33 };
assert({ true, false, true, true} == (bool[<4>])x);
float[<4>] y = { 1, 2, 3, 4 };
float[<4>] z = { 2, 2, 2, -100 };
float[<4>] w = y + z;
assert(w == { 3, 4, 5, -96 });
w = y * z;
assert(w == { 2, 4, 6, -400 });
w = y / z;
assert(w == { 0.5, 1.0, 1.5, -0.04 });
w = y - z;
assert(w == { -1, 0, 1, 104 });
int[<4>] ww = $$veccomplt(y, z);
assert(ww == { -1, 0, 0, 0 });
ww = $$veccomple(y, z);
assert(ww == { -1, -1, 0, 0 });
ww = $$veccompgt(y, z);
assert(ww == { 0, 0, -1, -1 });
ww = $$veccompge(y, z);
assert(ww == { 0, -1, -1, -1 });
ww = $$veccompeq(y, z);
assert(ww == { 0, -1, 0, 0 });
ww = $$veccompne(y, z);
assert(ww == { -1, 0, -1, -1 });
}
fn void testb() @test
{
bool[<4>] y = { true, false, true, true };
bool[<4>] z = { false, false, true, true };
ichar[<4>] ww = $$veccomplt(y, z);
assert(ww == { 0, 0, 0, 0 });
ww = $$veccomple(y, z);
assert(ww == { 0, -1, -1, -1 });
ww = $$veccompgt(y, z);
assert(ww == { -1, 0, 0, 0 });
ww = $$veccompge(y, z);
assert(ww == { -1, -1, -1, -1 });
ww = $$veccompeq(y, z);
assert(ww == { 0, -1, -1, -1 });
ww = $$veccompne(y, z);
assert(ww == { -1, 0, 0, 0 });
}
fn void testi() @test
{
int[<4>] x = { 4, 0, -1, 33 };
assert({ true, false, true, true} == (bool[<4>])x);
int[<4>] y = { 1, 2, 3, 4 };
int[<4>] z = { 2, 2, 2, -100 };
int[<4>] w = y + z;
assert(w == { 3, 4, 5, -96 });
w = y * z;
assert(w == { 2, 4, 6, -400 });
w = y / z;
assert(w == { 0, 1, 1, 0 });
w = y - z;
assert(w == { -1, 0, 1, 104 });
w = z >> y;
assert(w == { 1, 0, 0, -7});
w = z << y;
assert(w == { 4, 8, 16, -1600 });
w = $$veccompgt(z, y);
assert(w == { -1, 0, 0, 0});
w = $$veccompge(z, y);
assert(w == { -1, -1, 0, 0 });
w = $$veccomplt(z, y);
assert(w == { 0, 0, -1, -1 });
w = $$veccomple(z, y);
assert(w == { 0, -1, -1, -1 });
w = $$veccompeq(z, y);
assert(w == { 0, -1, 0, 0 });
w = $$veccompne(z, y);
assert(w == { -1, 0, -1, -1 });
}

245
test/unit7/stdlib/atomic.c3 Normal file
View File

@@ -0,0 +1,245 @@
import std::thread;
import std::io;
import std::atomic;
uint a;
float fa;
fn void add() @test
{
Thread[100] ts;
a = 0;
foreach (&t : ts)
{
t.create(fn int(void* arg) {
thread::sleep_ms(5);
atomic::fetch_add(&a, 5);
thread::sleep_ms(5);
atomic::fetch_add(&a, 5);
thread::sleep_ms(5);
atomic::fetch_add(&a, 5);
thread::sleep_ms(5);
atomic::fetch_add(&a, 5);
thread::sleep_ms(5);
atomic::fetch_add(&a, 5);
thread::sleep_ms(5);
atomic::fetch_add(&a, 5);
thread::sleep_ms(5);
atomic::fetch_add(&a, 5);
thread::sleep_ms(5);
atomic::fetch_add(&a, 5);
thread::sleep_ms(5);
atomic::fetch_add(&a, 5);
thread::sleep_ms(5);
atomic::fetch_add(&a, 5);
return 0;
}, null)!!;
}
foreach (&t : ts)
{
assert(t.join()!! == 0);
}
assert(a == ts.len * 10 * 5, "Threads returned %d, expected %d", a, ts.len * 10 * 5);
}
fn void sub() @test
{
Thread[100] ts;
a = ts.len * 10 * 5;
foreach (&t : ts)
{
t.create(fn int(void* arg) {
thread::sleep_ms(5);
atomic::fetch_sub(&a, 5);
thread::sleep_ms(5);
atomic::fetch_sub(&a, 5);
thread::sleep_ms(5);
atomic::fetch_sub(&a, 5);
thread::sleep_ms(5);
atomic::fetch_sub(&a, 5);
thread::sleep_ms(5);
atomic::fetch_sub(&a, 5);
thread::sleep_ms(5);
atomic::fetch_sub(&a, 5);
thread::sleep_ms(5);
atomic::fetch_sub(&a, 5);
thread::sleep_ms(5);
atomic::fetch_sub(&a, 5);
thread::sleep_ms(5);
atomic::fetch_sub(&a, 5);
thread::sleep_ms(5);
atomic::fetch_sub(&a, 5);
return 0;
}, null)!!;
}
foreach (&t : ts)
{
assert(t.join()!! == 0);
}
assert(a == 0, "Threads returned %d, expected %d", a, 0);
}
fn void div() @test
{
Thread[8] ts;
a = 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8;
foreach (&t : ts)
{
t.create(fn int(void* arg) {
thread::sleep_ms(5);
atomic::fetch_div(&a, 8);
return 0;
}, null)!!;
}
foreach (&t : ts)
{
assert(t.join()!! == 0);
}
assert(a == 8, "Threads returned %d, expected %d", a, 8);
}
fn void max() @test
{
Thread[100] ts;
a = 0;
foreach (&t : ts)
{
t.create(fn int(void* arg) {
uint la = 0;
thread::sleep_ms(5);
atomic::fetch_max(&a, la);
la++;
thread::sleep_ms(5);
atomic::fetch_max(&a, la);
la++;
thread::sleep_ms(5);
atomic::fetch_max(&a, la);
la++;
thread::sleep_ms(5);
atomic::fetch_max(&a, la);
la++;
thread::sleep_ms(5);
atomic::fetch_max(&a, la);
la++;
thread::sleep_ms(5);
atomic::fetch_max(&a, la);
la++;
return 0;
}, null)!!;
}
foreach (&t : ts)
{
assert(t.join()!! == 0);
}
assert(a == 5, "Threads returned %d, expected %d", a, 5);
}
fn void min() @test
{
Thread[100] ts;
a = 10;
foreach (&t : ts)
{
t.create(fn int(void* arg) {
uint la = 5;
thread::sleep_ms(5);
atomic::fetch_min(&a, la);
la--;
thread::sleep_ms(5);
atomic::fetch_min(&a, la);
la--;
thread::sleep_ms(5);
atomic::fetch_min(&a, la);
la--;
thread::sleep_ms(5);
atomic::fetch_min(&a, la);
la--;
thread::sleep_ms(5);
atomic::fetch_min(&a, la);
la--;
thread::sleep_ms(5);
atomic::fetch_min(&a, la);
la--;
return 0;
}, null)!!;
}
foreach (&t : ts)
{
assert(t.join()!! == 0);
}
assert(a == 0, "Threads returned %d, expected %d", a, 0);
}
fn void fadd() @test
{
Thread[100] ts;
fa = 0;
foreach (&t : ts)
{
t.create(fn int(void* arg) {
thread::sleep_ms(5);
atomic::fetch_add(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_add(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_add(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_add(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_add(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_add(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_add(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_add(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_add(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_add(&fa, 0.5f);
return 0;
}, null)!!;
}
foreach (&t : ts)
{
assert(t.join()!! == 0);
}
assert(fa == ts.len * 10 * 0.5, "Threads returned %f, expected %f", fa, ts.len * 10 * 0.5);
}
fn void fsub() @test
{
Thread[100] ts;
fa = ts.len * 10 * 0.5;
foreach (&t : ts)
{
t.create(fn int(void* arg) {
thread::sleep_ms(5);
atomic::fetch_sub(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_sub(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_sub(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_sub(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_sub(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_sub(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_sub(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_sub(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_sub(&fa, 0.5f);
thread::sleep_ms(5);
atomic::fetch_sub(&fa, 0.5f);
return 0;
}, null)!!;
}
foreach (&t : ts)
{
assert(t.join()!! == 0);
}
assert(fa == 0, "Threads returned %f, expected %f", fa, 0);
}

View File

@@ -0,0 +1,156 @@
import std::thread;
import std::io;
import std::atomic::types;
def AtomicUint = Atomic{uint};
def AtomicFloat = Atomic{float};
AtomicUint a;
AtomicFloat fa;
fn void add() @test
{
Thread[100] ts;
a.store(0);
foreach (&t : ts)
{
t.create(fn int(void* arg) {
thread::sleep_ms(5);
a.add(5);
thread::sleep_ms(5);
a.add(5);
thread::sleep_ms(5);
a.add(5);
thread::sleep_ms(5);
a.add(5);
thread::sleep_ms(5);
a.add(5);
thread::sleep_ms(5);
a.add(5);
thread::sleep_ms(5);
a.add(5);
thread::sleep_ms(5);
a.add(5);
thread::sleep_ms(5);
a.add(5);
thread::sleep_ms(5);
a.add(5);
return 0;
}, null)!!;
}
foreach (&t : ts)
{
assert(t.join()!! == 0);
}
assert(a.load() == ts.len * 10 * 5, "Threads returned %d, expected %d", a.load(), ts.len * 10 * 5);
}
fn void sub() @test
{
Thread[100] ts;
a.store(ts.len * 10 * 5);
foreach (&t : ts)
{
t.create(fn int(void* arg) {
thread::sleep_ms(5);
a.sub(5);
thread::sleep_ms(5);
a.sub(5);
thread::sleep_ms(5);
a.sub(5);
thread::sleep_ms(5);
a.sub(5);
thread::sleep_ms(5);
a.sub(5);
thread::sleep_ms(5);
a.sub(5);
thread::sleep_ms(5);
a.sub(5);
thread::sleep_ms(5);
a.sub(5);
thread::sleep_ms(5);
a.sub(5);
thread::sleep_ms(5);
a.sub(5);
return 0;
}, null)!!;
}
foreach (&t : ts)
{
assert(t.join()!! == 0);
}
assert(a.load() == 0, "Threads returned %d, expected %d", a.load(), 0);
}
fn void fadd() @test
{
Thread[100] ts;
fa.store(0);
foreach (&t : ts)
{
t.create(fn int(void* arg) {
thread::sleep_ms(5);
fa.add(0.5);
thread::sleep_ms(5);
fa.add(0.5);
thread::sleep_ms(5);
fa.add(0.5);
thread::sleep_ms(5);
fa.add(0.5);
thread::sleep_ms(5);
fa.add(0.5);
thread::sleep_ms(5);
fa.add(0.5);
thread::sleep_ms(5);
fa.add(0.5);
thread::sleep_ms(5);
fa.add(0.5);
thread::sleep_ms(5);
fa.add(0.5);
thread::sleep_ms(5);
fa.add(0.5);
return 0;
}, null)!!;
}
foreach (&t : ts)
{
assert(t.join()!! == 0);
}
assert(fa.load() == ts.len * 10 * 0.5, "Threads returned %f, expected %f", fa.load(), ts.len * 10 * 0.5);
}
fn void fsub() @test
{
Thread[100] ts;
fa.store(ts.len * 10 * 0.5);
foreach (&t : ts)
{
t.create(fn int(void* arg) {
thread::sleep_ms(5);
fa.sub(0.5);
thread::sleep_ms(5);
fa.sub(0.5);
thread::sleep_ms(5);
fa.sub(0.5);
thread::sleep_ms(5);
fa.sub(0.5);
thread::sleep_ms(5);
fa.sub(0.5);
thread::sleep_ms(5);
fa.sub(0.5);
thread::sleep_ms(5);
fa.sub(0.5);
thread::sleep_ms(5);
fa.sub(0.5);
thread::sleep_ms(5);
fa.sub(0.5);
thread::sleep_ms(5);
fa.sub(0.5);
return 0;
}, null)!!;
}
foreach (&t : ts)
{
assert(t.join()!! == 0);
}
assert(fa.load() == 0, "Threads returned %f, expected %f", fa.load(), 0);
}

View File

@@ -0,0 +1,89 @@
module bitset_test @test;
import std::collections::bitset;
import std::collections::growablebitset;
import std::collections::list;
import std::io;
def List = List{usz};
def BitSet = BitSet{2048};
fn void set_get()
{
BitSet bs;
assert(bs.cardinality() == 0);
assert(!bs.get(0));
bs.set(0);
assert(bs.get(0));
assert(bs.cardinality() == 1);
assert(!bs.get(2000));
bs[2000] = true;
assert(bs.get(2000));
assert(bs.cardinality() == 2);
List found;
foreach (i, x : bs)
{
switch (i)
{
case 0:
case 2000:
assert(x);
found.push(i);
default:
assert(!x);
}
}
assert(found.array_view() == (usz[]){0, 2000});
bs.unset(0);
assert(!bs.get(0));
bs[2000] = false;
assert(!bs.get(2000));
assert(bs.cardinality() == 0);
}
def GrowableBitSet = GrowableBitSet{char};
fn void growable_set_get()
{
GrowableBitSet bs;
bs.tinit();
assert(bs.cardinality() == 0, "Invalid cardinality");
assert(!bs.get(0), "Get was true");
bs.set(0);
assert(bs.get(0), "Get should be true");
assert(bs.cardinality() == 1, "Cardinality should be 1");
assert(bs.len() == 1, "Len should be 1");
assert(!bs.get(2000), "Get 2000 should be false");
bs[2000] = true;
assert(bs.get(2000), "Get 2000 should be true");
assert(bs.cardinality() == 2, "Cardinality should be 2");
assert(bs.data.len() == 251, "Len should be 251");
assert(bs.len() == 2001, "Len should be 2001");
List found;
foreach (i, x : bs)
{
switch (i)
{
case 0:
case 2000:
assert(x);
found.push(i);
default:
assert(!x, "Should not get here");
}
}
assert(found.array_view() == (usz[]){0, 2000}, "Array view should hold 2");
bs.unset(0);
assert(!bs.get(0), "Get should be false");
bs[2000] = false;
assert(!bs.get(2000), "Get should be false");
assert(bs.cardinality() == 0, "Cardinality should be 0");
}

View File

@@ -0,0 +1,53 @@
module test;
import std::io;
import std::collections::map;
def IntMap = HashMap{String, int};
fn void copy_map() @test
{
TrackingAllocator alloc;
alloc.init(allocator::heap());
defer alloc.free();
assert(alloc.allocated() == 0);
mem::@scoped(&alloc)
{
IntMap x;
x.init(mem);
DString y;
y.append("hello");
x.set(y.str_view(), 123);
y.append("bye");
x.set(y.str_view(), 333);
y.clear();
y.append("bye");
x.set(y.str_view(), 444);
assert(x.get("hello")!! == 123);
assert(x.get("hellobye")!! == 333);
assert(x.get("bye")!! == 444);
assert(alloc.allocated() > 0);
x.free();
y.free();
assert(alloc.allocated() == 0);
};
}
/*
Some Keys (including Strings) are deep_copied into the hashmap on insertion.
When copying keys out, the keys themselves must also be deep-copied out.
Otherwise when the map is freed, the copied-in keys will also be freed,
resulting in use-after-free.
*/
fn void copy_keys() @test
{
String[] y;
@pool()
{
IntMap x;
x.set("hello", 0); // keys copied into temp hashmap
y = x.keys(mem); // keys copied out
// end of pool: hashmap and its copied-in keys dropped
};
assert(y == {"hello"});
foreach(key : y) free(key);
free(y);
}

View File

@@ -0,0 +1,143 @@
module elastic_array_test @test;
import std::collections::elastic_array;
def IntList = ElasticArray{int, 10};
def PtrList = ElasticArray{void*, 10};
fn void delete_contains_index()
{
IntList test;
test.add_array({ 1, 2 });
assert(test.contains(1));
assert(test.contains(2));
assert(!test.contains(0));
assert(!test.contains(3));
assert(test.array_view() == (int[]){ 1, 2 });
test.push(3);
assert(test.array_view() == (int[]){ 1, 2, 3 });
assert(test.contains(3));
test[0] = 10;
assert(test.contains(10));
test.remove_item(10);
assert(test.array_view() == (int[]){ 2, 3 });
assert(!test.contains(1));
assert(test.contains(2));
assert(test.len() == 2);
test.push(0);
test.insert_at(0, 0);
assert(test.array_view() == (int[]){ 0, 2, 3, 0 });
assert(test.index_of(0)!! == 0);
assert(test.rindex_of(0)!! == 3);
test.remove_item(0);
assert(test.len() == 2);
assert(test.array_view() == (int[]){ 2, 3 });
}
fn void compact()
{
PtrList test;
test.add_array({ null, &test });
assert(test.compact_count() == 1);
test.push(null);
assert(test.compact_count() == 1);
assert(test.len() == 3);
assert(test.compact() == 2);
assert(test.len() == 1);
assert(test.compact() == 0);
}
fn void reverse()
{
IntList test;
test.reverse();
test.add_array({ 1, 2 });
test.push(3);
assert(test.array_view() == (int[]) { 1, 2, 3});
test.reverse();
assert(test.array_view() == (int[]) { 3, 2, 1 });
test.push(10);
assert(test.array_view() == (int[]) { 3, 2, 1, 10 });
test.reverse();
assert(test.array_view() == (int[]) { 10, 1, 2, 3 });
}
fn void remove_if()
{
IntList test;
usz removed;
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_if(&filter);
assert(removed == 3);
assert(test.array_view() == (int[]){1, 2});
test.clear();
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_if(&select);
assert(removed == 2);
assert(test.array_view() == (int[]){11, 10, 20});
}
fn void remove_using_test()
{
IntList test;
usz removed;
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_using_test(fn bool(i, ctx) => *i >= *(int*)ctx, &&10);
assert(removed == 3);
assert(test.array_view() == (int[]){1, 2});
test.clear();
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_using_test(fn bool(i, ctx) => *i < *(int*)ctx, &&10);
assert(removed == 2);
assert(test.array_view() == (int[]){11, 10, 20});
}
fn void retain_if()
{
IntList test;
usz removed;
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.retain_if(&select);
assert(removed == 3);
assert(test.array_view() == (int[]){1, 2});
test.clear();
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.retain_if(&filter);
assert(removed == 2);
assert(test.array_view() == (int[]){11, 10, 20});
}
fn void retain_using_test()
{
IntList test;
usz removed;
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_using_test(fn bool(i, ctx) => *i >= *(int*)ctx, &&10);
assert(removed == 3);
assert(test.array_view() == (int[]){1, 2});
test.clear();
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_using_test(fn bool(i, ctx) => *i < *(int*)ctx, &&10);
assert(removed == 2);
assert(test.array_view() == (int[]){11, 10, 20});
}
module elastic_array_test;
fn bool filter(int* i)
{
return *i >= 10;
}
fn bool select(int* i)
{
return *i < 10;
}

View File

@@ -0,0 +1,29 @@
module enummap_test @test;
import std::collections::enummap;
enum FooEnum
{
ONE,
TWO,
THREE,
}
def FooEnumMap = EnumMap{FooEnum, uint};
fn void enums()
{
FooEnumMap nm;
nm.set(ONE, 1);
nm.set(TWO, 2);
nm.set(THREE, 3);
assert(nm[FooEnum.ONE] == 1);
assert(nm[FooEnum.TWO] == 2);
assert(nm[FooEnum.THREE] == 3);
nm.init(0);
assert(nm[FooEnum.ONE] == 0);
assert(nm[FooEnum.TWO] == 0);
assert(nm[FooEnum.THREE] == 0);
}

View File

@@ -0,0 +1,15 @@
module glist @test;
import std::collections;
fn void simple_use()
{
AnyList l;
l.push(1);
l.push("Hello");
assert(l.get(1, String)!! == "Hello");
assert(l.get(0, int)!! == 1);
assert(l.pop(String)!! == "Hello");
assert(l.pop(int)!! == 1);
assert(l.len() == 0);
l.free();
}

View File

@@ -0,0 +1,237 @@
module linkedlist_test @test;
import std::collections::linkedlist;
def IntList = LinkedList{int};
fn void test_push_front()
{
IntList list;
defer list.free();
list.push_front(23);
assert(list.len() == 1);
assert(list.first()!! == 23);
assert(list.last()!! == 23);
list.push_front(55);
assert(list.len() == 2);
assert(list.last()!! == 23);
assert(list.first()!! == 55);
}
fn void test_push()
{
IntList list;
defer list.free();
list.push(23);
assert(list.len() == 1);
assert(list.first()!! == 23);
assert(list.last()!! == 23);
list.push(55);
assert(list.len() == 2);
assert(list.last()!! == 55);
assert(list.first()!! == 23);
}
fn void test_get()
{
IntList list;
defer list.free();
list.push(23);
list.push(55);
list.push(-3);
assert(list.get(2) == -3);
assert(list.get(1) == 55);
assert(list.get(0) == 23);
}
fn void test_insert()
{
IntList list;
defer list.free();
list.push(-3);
list.push(55);
list.push(23);
list.insert_at(0, 1);
list.insert_at(2, 11);
list.insert_at(4, 111);
list.insert_at(6, 1111);
assert(list.get(0) == 1);
assert(list.get(1) == -3);
assert(list.get(2) == 11);
assert(list.get(3) == 55);
assert(list.get(4) == 111);
assert(list.get(5) == 23);
assert(list.get(6) == 1111);
}
fn void test_set()
{
IntList list;
defer list.free();
list.push(-3);
list.push(55);
list.push(23);
for (int i = 0; i < 3; i++) list.set(i, list.get(i) + 1);
assert(list.get(0) == -2);
assert(list.get(1) == 56);
assert(list.get(2) == 24);
}
fn void test_remove_at()
{
IntList list;
defer list.free();
for (int i = 0; i < 10; i++) list.push(i);
list.remove_at(0);
list.remove_at(1);
list.remove_at(7);
list.remove_at(5);
assert(list.get(0) == 1);
assert(list.get(1) == 3);
assert(list.get(5) == 8);
assert(list.get(4) == 6);
}
fn void test_remove()
{
IntList list;
defer list.free();
list.push(2);
for (int i = 0; i < 10; i++) list.push(5);
list.push(2);
list.remove(5);
assert(list.len() == 2);
}
fn void test_remove_first_match()
{
IntList list;
defer list.free();
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_first_match(23));
assert(list.pop()!! == -3);
assert(list.pop()!! == 55);
assert(!list.len());
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_first_match(55));
assert(list.pop()!! == -3);
assert(list.pop()!! == 23);
assert(!list.len());
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_first_match(-3));
assert(list.pop()!! == 55);
assert(list.pop()!! == 23);
assert(!list.len());
}
fn void test_remove_last_match()
{
IntList list;
defer list.free();
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_last_match(23));
assert(list.pop()!! == -3);
assert(list.pop()!! == 55);
assert(!list.len());
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_last_match(55));
assert(list.pop()!! == -3);
assert(list.pop()!! == 23);
assert(!list.len());
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_last_match(-3));
assert(list.pop()!! == 55);
assert(list.pop()!! == 23);
assert(!list.len());
}
fn void test_pop()
{
IntList list;
defer list.free();
list.push(23);
list.push(55);
list.push(-3);
assert(list.len() == 3);
assert(list.first()!! == 23);
assert(list.last()!! == -3);
assert(list.pop()!! == -3);
assert(list.len() == 2);
assert(list.first()!! == 23);
assert(list.last()!! == 55);
assert(list.pop()!! == 55);
assert(list.first()!! == 23);
assert(list.last()!! == 23);
assert(list.pop()!! == 23);
assert(list.len() == 0);
assert(@catch(list.pop()));
assert(list.len() == 0);
list.push(55);
assert(list.len() == 1);
}
fn void test_remove_last()
{
IntList list;
defer list.free();
list.push(23);
list.push(55);
list.push(-3);
assert(list.len() == 3);
assert(list.first()!! == 23);
assert(list.last()!! == -3);
assert(@ok(list.remove_last()));
assert(list.len() == 2);
assert(list.first()!! == 23);
assert(list.last()!! == 55);
assert(@ok(list.remove_last()));
assert(list.first()!! == 23);
assert(list.last()!! == 23);
assert(@ok(list.remove_last()));
assert(list.len() == 0);
assert(@catch(list.pop()));
assert(list.len() == 0);
list.push(55);
assert(list.len() == 1);
}
fn void test_remove_first()
{
IntList list;
defer list.free();
list.push(23);
list.push(55);
list.push(-3);
assert(list.len() == 3);
assert(list.first()!! == 23);
assert(list.last()!! == -3);
assert(@ok(list.remove_first()));
assert(list.len() == 2);
assert(list.last()!! == -3);
assert(list.first()!! == 55);
assert(@ok(list.remove_first()));
assert(list.last()!! == -3);
assert(list.first()!! == -3);
assert(@ok(list.remove_first()));
assert(list.len() == 0);
assert(@catch(list.remove_first()));
assert(list.len() == 0);
list.push(55);
assert(list.len() == 1);
}

View File

@@ -0,0 +1,178 @@
module list_test @test;
import std::collections::list;
def IntList = List{int};
def PtrList = List{void*};
struct Overalign
{
float[<4>] x @align(128);
}
def OveralignList = List{Overalign};
fn void overaligned_type()
{
OveralignList l;
defer l.free();
Overalign y;
for (int i = 0; i < 1000; i++) l.push(y);
assert((usz)l.get_ref(2) - (usz)l.get_ref(1) == Overalign.sizeof);
}
fn void delete_contains_index()
{
IntList test;
test.add_array({ 1, 2 });
assert(test.contains(1));
assert(test.contains(2));
assert(!test.contains(0));
assert(!test.contains(3));
assert(test.array_view() == { 1, 2 });
test.push(3);
assert(test.array_view() == { 1, 2, 3 });
assert(test.contains(3));
test[0] = 10;
assert(test.contains(10));
test.remove_item(10);
assert(test.array_view() == { 2, 3 });
assert(!test.contains(1));
assert(test.contains(2));
assert(test.len() == 2);
test.push(0);
test.insert_at(0, 0);
assert(test.array_view() == { 0, 2, 3, 0 });
assert(test.index_of(0)!! == 0);
assert(test.rindex_of(0)!! == 3);
test.remove_item(0);
assert(test.len() == 2);
assert(test.array_view() == { 2, 3 });
}
fn void compact()
{
PtrList test;
test.add_array({ null, &test });
assert(test.compact_count() == 1);
test.push(null);
assert(test.compact_count() == 1);
assert(test.len() == 3);
assert(test.compact() == 2);
assert(test.len() == 1);
assert(test.compact() == 0);
}
fn void reverse()
{
IntList test;
test.reverse();
test.add_array({ 1, 2 });
test.push(3);
assert(test.array_view() == { 1, 2, 3});
test.reverse();
assert(test.array_view() == { 3, 2, 1 });
test.push(10);
assert(test.array_view() == { 3, 2, 1, 10 });
test.reverse();
assert(test.array_view() == { 10, 1, 2, 3 });
}
fn void remove_if()
{
IntList test;
usz removed;
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_if(&filter);
assert(removed == 3);
assert(test.array_view() == {1, 2});
test.clear();
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_if(&select);
assert(removed == 2);
assert(test.array_view() == {11, 10, 20});
}
fn void init_with_array()
{
IntList foo;
foo.init_with_array(mem, { 1, 2, 3});
defer foo.free();
assert(foo.len() == 3);
assert(foo[2] == 3);
}
fn void init_with_temp_array()
{
IntList foo;
foo.tinit_with_array({ 1, 2, 3});
assert(foo.len() == 3);
assert(foo[2] == 3);
}
fn void remove_using_test()
{
IntList test;
usz removed;
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_using_test(fn bool(i, ctx) => *i >= *(int*)ctx, &&10);
assert(removed == 3);
assert(test.array_view() == {1, 2});
test.clear();
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_using_test(fn bool(i, ctx) => *i < *(int*)ctx, &&10);
assert(removed == 2);
assert(test.array_view() == {11, 10, 20});
}
fn void retain_if()
{
IntList test;
usz removed;
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.retain_if(&select);
assert(removed == 3);
assert(test.array_view() == {1, 2});
test.clear();
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.retain_if(&filter);
assert(removed == 2);
assert(test.array_view() == {11, 10, 20});
}
fn void retain_using_test()
{
IntList test;
usz removed;
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_using_test(fn bool(i, ctx) => *i >= *(int*)ctx, &&10);
assert(removed == 3);
assert(test.array_view() == {1, 2});
test.clear();
test.add_array({ 1, 11, 2, 10, 20 });
removed = test.remove_using_test(fn bool(i, ctx) => *i < *(int*)ctx, &&10);
assert(removed == 2);
assert(test.array_view() == {11, 10, 20});
}
module list_test;
fn bool filter(int* i)
{
return *i >= 10;
}
fn bool select(int* i)
{
return *i < 10;
}

View File

@@ -0,0 +1,105 @@
module map_test @test;
import std::collections::list;
import std::collections::map;
import std::sort;
import std::io;
def TestHashMap = HashMap{String, usz};
struct MapTest
{
String key;
usz value;
}
def List = List{MapTest};
fn void map()
{
TestHashMap m;
assert(!m.is_initialized());
m.tinit();
assert(m.is_initialized());
assert(m.is_empty());
assert(m.len() == 0);
m.set("a", 1);
assert(!m.is_empty());
assert(m.len() == 1);
m.remove("a");
assert(m.is_empty());
MapTest[] tcases = { {"key1", 0}, {"key2", 1}, {"key3", 2} };
foreach (tc : tcases)
{
m.set(tc.key, tc.value);
}
assert(m.len() == tcases.len);
foreach (tc : tcases)
{
usz v = m.get(tc.key)!!;
assert(tc.value == v);
}
List list;
list.tinit();
m.@each(;String key, usz value)
{
list.push({key, value});
};
assert(list.len() == tcases.len);
quicksort(list, fn int (MapTest a, MapTest b) => (int)(a.value - b.value));
foreach (i, tc : tcases)
{
assert(tc.key == list[i].key);
assert(tc.value == list[i].value);
}
}
def FooMap = HashMap{char, Foobar};
enum Foobar : inline char
{
FOO,
BAR,
BAZ
}
enum Foobar2 : int (inline char y)
{
ABC = 3,
DEF = 5,
}
fn void map_inline_enum()
{
FooMap x;
x[Foobar.BAZ] = FOO;
x[Foobar2.ABC] = BAR;
test::eq(string::tformat("%s", x), "{ 2: FOO, 3: BAR }");
x.free();
}
fn void map_remove()
{
TestHashMap m;
assert(!@ok(m.remove("A")));
m.tinit();
assert(!@ok(m.remove("A")));
m.set("A", 0);
assert(@ok(m.remove("A")));
}
fn void map_copy()
{
TestHashMap hash_map;
hash_map.tinit();
hash_map.set("aa", 1);
hash_map.set("b", 2);
hash_map.set("bb", 1);
TestHashMap hash_map_copy;
hash_map_copy.tinit_from_map(&hash_map);
assert(hash_map_copy.len() == hash_map.len());
}

View File

@@ -0,0 +1,43 @@
module object_test @test;
import std::collections::object;
fn void test_general()
{
Object* root = object::new_obj(allocator::heap());
defer root.free();
root.set("foo", 1);
root.set("bar", "baz");
assert(root.get_int("foo")!! == 1);
assert(root.get_string("bar")!! == "baz");
Object* goo = root.set("goo", object::new_obj(allocator::heap()));
goo.push("hello");
goo.push(132);
assert(root.get("goo").get_int_at(1)!! == 132);
assert(root.get("goo").get_string_at(0)!! == "hello");
Object* abc = root.get_or_create_obj("abc80");
abc.set("cool", 1.3);
assert(root.get("abc80").get_int("cool")!! == 1);
assert(root.get("abc80").get_float("cool")!! == 1.3);
assert((root.get_int("yyy") ?? -1) == -1);
root.set("yyy", true);
assert(root.get_bool("yyy") ?? false);
}
fn void test_to_format_int()
{
{
Object* int_object = object::new_int(16, allocator::heap());
defer int_object.free();
String s = string::format(mem, "%s", int_object);
defer free(s);
assert(s == "16");
}
{
Object* int_object = object::new_int(-16, allocator::heap());
defer int_object.free();
String s = string::format(mem, "%s", int_object);
defer free(s);
assert(s == "-16");
}
}

View File

@@ -0,0 +1,62 @@
module priorityqueue_test @test;
import std::collections;
import std::collections::priorityqueue;
def Queue = PriorityQueue{int};
fn void priorityqueue()
{
Queue q;
defer q.free();
assert(q.is_empty());
q.push(1);
q.push(2);
assert(q.len() == 2);
int x;
x = q.pop()!!;
assert(x == 1, "got %d; want %d", x, 1);
x = q.pop()!!;
assert(x == 2, "got %d; want %d", x, 2);
q.push(3);
q.push(2);
q.push(1);
x = q.pop()!!;
assert(x == 1, "got %d; want %d", x, 1);
x = q.pop()!!;
assert(x == 2, "got %d; want %d", x, 2);
x = q.pop()!!;
assert(x == 3, "got %d; want %d", x, 3);
}
def QueueMax = PriorityQueueMax{int};
fn void priorityqueue_max()
{
QueueMax q;
defer q.free();
assert(q.is_empty());
q.push(1);
q.push(2);
assert(q.len() == 2);
int x;
x = q.pop()!!;
assert(x == 2, "got %d; want %d", x, 2);
x = q.pop()!!;
assert(x == 1, "got %d; want %d", x, 1);
q.push(3);
q.push(2);
q.push(1);
x = q.pop()!!;
assert(x == 3, "got %d; want %d", x, 3);
x = q.pop()!!;
assert(x == 2, "got %d; want %d", x, 2);
x = q.pop()!!;
assert(x == 1, "got %d; want %d", x, 1);
}

View File

@@ -0,0 +1,36 @@
module range_test @test;
import std::collections::range;
def IntRange = Range{int};
def IntExRange = ExclusiveRange{int};
fn void test_range()
{
IntRange range = { -4, 2 };
int sum = 0;
foreach (int z : range)
{
assert(z >= -4 && z < 3);
sum += z * z;
}
assert(sum == 35);
assert(range.contains(-4));
assert(range.contains(2));
assert(!range.contains(3));
}
fn void test_exrange()
{
IntExRange range = { -4, 2 };
int sum = 0;
foreach (int z : range)
{
assert(z >= -4 && z < 2);
sum += z * z;
}
assert(sum == 31);
assert(range.contains(-4));
assert(range.contains(1));
assert(!range.contains(2));
}

View File

@@ -0,0 +1,29 @@
module ringbuffer_test @test;
import std::collections::ringbuffer;
import std::io;
def Buffer = RingBuffer{char[4]};
fn void push_get()
{
Buffer rb;
rb.init();
rb.push(1);
rb.push(2);
rb.push(3);
rb.push(4);
assert(rb.get(0) == 1);
assert(rb.get(1) == 2);
assert(rb.get(2) == 3);
assert(rb.get(3) == 4);
rb.push(5);
assert(rb.get(0) == 2);
assert(rb.get(1) == 3);
assert(rb.get(2) == 4);
assert(rb.get(3) == 5);
char c = rb.pop()!!;
assert(c == 5);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,79 @@
module conv_tests;
import std::io;
fn void! comparison_helper_32_to_8(Char32 c32, String expected_output)
{
char[8] out;
usz len = conv::char32_to_utf8(c32, &out)!;
assert(len == expected_output.len, "Len should be 1");
foreach (i, c : expected_output)
{
assert(out[i] == c, "Expected other value");
}
}
fn void! comparison_helper_8_to_32(String in, Char32 c32)
{
usz len = in.len;
Char32 res = conv::utf8_to_char32(in.ptr, &len)!;
assert(len == in.len, "All len should be used.");
assert(res == c32, "Expected character match.");
}
fn void assert_utf8_is_error(String in)
{
usz len = in.len;
assert(@catch(conv::utf8_to_char32(in.ptr, &len)), "Expected error");
}
fn void test_char32_ut8_boundary() @test
{
// First sequence per len
comparison_helper_32_to_8(0x00000000, { 0 })!!;
comparison_helper_32_to_8(0x00000080, { 0xc2, 0x80 })!!;
comparison_helper_32_to_8(0x00000800, { 0xe0, 0xa0, 0x80 })!!;
comparison_helper_32_to_8(0x00010000, { 0xf0, 0x90, 0x80, 0x80 })!!;
assert(@catch(comparison_helper_32_to_8(0x10ffff + 1, { 0 })), "Expected error");
// Last seq per len
comparison_helper_32_to_8(0x0000007f, { 0x7f })!!;
comparison_helper_32_to_8(0x000007ff, { 0xdf, 0xbf })!!;
comparison_helper_32_to_8(0x0000ffff, { 0xef, 0xbf, 0xbf })!!;
comparison_helper_32_to_8(0x0010ffff, { 0xf4, 0x8f, 0xbf, 0xbf })!!;
// Other boundaries
comparison_helper_32_to_8(0x0000d7ff, { 0xed, 0x9f, 0xbf})!!;
comparison_helper_32_to_8(0x0000e000, { 0xee, 0x80, 0x80 })!!;
comparison_helper_32_to_8(0x0000fffd, { 0xef, 0xbf, 0xbd })!!;
}
fn void test_utf8_to_char32_boundary() @test
{
// First sequence per len
comparison_helper_8_to_32("\0", 0x0 )!!;
comparison_helper_8_to_32({ 0xc2, 0x80 }, 0x80)!!;
comparison_helper_8_to_32({ 0xe0, 0xa0, 0x80 }, 0x800 )!!;
comparison_helper_8_to_32({ 0xf0, 0x90, 0x80, 0x80 }, 0x10000)!!;
// Last seq per len
comparison_helper_8_to_32({ 0x7f }, 0x7f)!!;
comparison_helper_8_to_32({ 0xdf, 0xbf }, 0x7ff )!!;
comparison_helper_8_to_32({ 0xef, 0xbf, 0xbf }, 0xffff)!!;
comparison_helper_8_to_32({ 0xf4, 0x8f, 0xbf, 0xbf }, 0x10ffff)!!;
// Other boundaries
comparison_helper_8_to_32({ 0xed, 0x9f, 0xbf }, 0xd7ff)!!;
comparison_helper_8_to_32({ 0xee, 0x80, 0x80 }, 0xe000)!!;
comparison_helper_8_to_32({ 0xef, 0xbf, 0xbd }, 0xfffd)!!;
assert_utf8_is_error({ 0x80 });
assert_utf8_is_error({ 0xbf });
assert_utf8_is_error({ 0xfe });
assert_utf8_is_error({ 0xff });
assert_utf8_is_error({ 0xfe, 0xfe, 0xff, 0xff });
// Overlong
assert_utf8_is_error({ 0xc0, 0xaf });
assert_utf8_is_error({ 0xe0, 0x80, 0xaf });
assert_utf8_is_error({ 0xf0, 0x80, 0x80, 0xaf });
assert_utf8_is_error({ 0xf8, 0x80, 0x80, 0xaf });
assert_utf8_is_error({ 0xfc, 0x80, 0x80, 0x80, 0xaf });
}

View File

@@ -0,0 +1,32 @@
module arraytests @test;
fn void find()
{
int[3] a = { 1, 2, 3 };
assert(array::index_of(a, 2)!! == 1);
assert(array::index_of(a, 1)!! == 0);
assert(array::index_of(a, 3)!! == 2);
assert(@catch(array::index_of(a, 4)) == SearchResult.MISSING);
}
fn void find_subarray()
{
int[] a = { 1, 2, 3 };
assert(array::index_of(a, 2)!! == 1);
assert(array::index_of(a, 1)!! == 0);
assert(array::index_of(a, 3)!! == 2);
assert(@catch(array::index_of(a, 4)) == SearchResult.MISSING);
}
fn void concat()
{
int[3] a = { 1, 2, 3 };
free(array::concat_new(a, a));
free(array::concat_new(a[..], a[..]));
free(array::concat_new(a[:0], a[:0]));
free(array::concat_new((int[2]) { 1, 2 }, a[:0]));
free(array::concat_new(a[:0], (int[2]) { 1, 2 }));
int[] c = array::concat_new(a[1..2], a);
defer free(c);
assert (c == (int[]){ 2, 3, 1, 2, 3 });
}

View File

@@ -0,0 +1,45 @@
module std::core::bitorder @test;
fn void test_read()
{
char[?] bytes = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
assert(bitorder::read(bytes, UShortBE) == 0x0102);
assert(bitorder::read(bytes, UShortLE) == 0x0201);
assert(bitorder::read(bytes, UIntBE) == 0x01020304);
assert(bitorder::read(bytes, UIntLE) == 0x04030201);
assert(bitorder::read(bytes, ULongBE) == 0x0102030405060708);
assert(bitorder::read(bytes, ULongLE) == 0x0807060504030201);
assert(bitorder::read(&bytes, UShortBE) == 0x0102);
assert(bitorder::read(&bytes, UShortLE) == 0x0201);
assert(bitorder::read(&bytes, UIntBE) == 0x01020304);
assert(bitorder::read(&bytes, UIntLE) == 0x04030201);
assert(bitorder::read(&bytes, ULongBE) == 0x0102030405060708);
assert(bitorder::read(&bytes, ULongLE) == 0x0807060504030201);
assert(bitorder::read(bytes[..], UShortBE) == 0x0102);
assert(bitorder::read(bytes[..], UShortLE) == 0x0201);
assert(bitorder::read(bytes[..], UIntBE) == 0x01020304);
assert(bitorder::read(bytes[..], UIntLE) == 0x04030201);
assert(bitorder::read(bytes[..], ULongBE) == 0x0102030405060708);
assert(bitorder::read(bytes[..], ULongLE) == 0x0807060504030201);
}
fn void test_write()
{
char[?] bytes = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
char[8] buf;
ushort x1 = bitorder::read(bytes, UShortBE);
bitorder::write(x1, &buf, UShortBE);
assert(bitorder::read(buf, UShortBE) == x1);
uint x2 = bitorder::read(bytes, UIntBE);
bitorder::write(x2, buf[..], UIntBE);
assert(bitorder::read(buf, UIntBE) == x2);
ulong x3 = bitorder::read(bytes, ULongBE);
bitorder::write(x3, buf[..], ULongBE);
assert(bitorder::read(buf, ULongBE) == x3);
}

View File

@@ -0,0 +1,79 @@
module std::core::builtins @test;
fn void test_anycast()
{
int a;
any b = &a;
assert(anycast(b, int)!! == &a);
assert(@catch(anycast(b, double)) == CastResult.TYPE_MISMATCH);
}
fn void test_bitcast()
{
int a = 123;
float z = bitcast(a, float);
assert(bitcast(z, int) == a);
}
enum Tester
{
ABC,
DEF,
}
fn void test_enum_by_name()
{
assert(enum_by_name(Tester, "ABC")!! == Tester.ABC);
assert(enum_by_name(Tester, "DEF")!! == Tester.DEF);
assert(@catch(enum_by_name(Tester, "GHI")) == SearchResult.MISSING);
}
fn void test_likely()
{
int a = 2;
int b = 43;
if (@likely(a > b, 0.5)) a++;
if (@likely(a < b)) b++;
}
fn void test_unlikely()
{
int a = 2;
int b = 43;
if (@unlikely(a > b, 0.5)) a++;
if (@unlikely(a < b)) b++;
}
fn void test_expect()
{
int a = 2;
int b = 43;
int c = @expect(a, 2, 0.5);
int d = @expect(b, 2u8);
}
int abc;
fn void test_prefetch()
{
@prefetch(&abc);
}
fn void test_hash()
{
(char){}.hash();
(ichar){}.hash();
(short){}.hash();
(ushort){}.hash();
(int){}.hash();
(uint){}.hash();
(long){}.hash();
(ulong){}.hash();
(int128){}.hash();
(uint128){}.hash();
String x = "abc";
char[] y = "abc";
assert(x.hash() == y.hash());
assert(int.typeid.hash());
}

View File

@@ -0,0 +1,22 @@
module comparison @test;
fn void compare_long()
{
assert(compare_to(long.max, long.min) == 1);
assert(compare_to(long.min, long.max) == -1);
assert(compare_to(long.min, long.min) == 0);
}
fn void compare_ulong()
{
assert(compare_to(ulong.max, ulong.min) == 1);
assert(compare_to(ulong.min, ulong.max) == -1);
assert(compare_to(ulong.min, ulong.min) == 0);
}
fn void compare_int128()
{
assert(compare_to(int128.max, int128.min) == 1);
assert(compare_to(int128.min, int128.max) == -1);
assert(compare_to(int128.min, int128.min) == 0);
}

View File

@@ -0,0 +1,277 @@
module std::core::dstring2 @test;
const TEST_STRING = "hello world";
fn void test_replace()
{
DString hello = dstring::new(mem, "Hello world where are you? Are you here too?");
defer hello.free();
hello.replace("u", "ooo");
assert(hello.str_view() == "Hello world where are yoooo? Are yoooo here too?");
}
fn void test_reverse()
{
DString a;
a.append("abcd");
a.reverse();
assert(a.str_view() == "dcba");
a.reverse();
assert(a.str_view() == "abcd");
a.append("e");
assert(a.str_view() == "abcde");
a.reverse();
assert(a.str_view() == "edcba");
a.free();
}
fn void test_delete()
{
{
DString d;
d.append("Hello cruel world.");
d.delete_range(5, 10);
assert(d.str_view() == "Hello world.");
d.free();
}
DString d;
d.append("Hello cruel world.");
d.delete(0, 2);
assert(d.str_view() == "llo cruel world.");
d.delete(14, 2);
assert(d.str_view() == "llo cruel worl");
d.delete(7);
assert(d.str_view() == "llo crul worl");
d.delete(2, 0);
assert(d.str_view() == "llo crul worl");
d.delete(0, 1);
assert(d.str_view() == "lo crul worl");
d.free();
}
fn void test_append()
{
DString str = dstring::new(mem, TEST_STRING);
defer str.free();
String s;
assert(str.len() == TEST_STRING.len);
assert(str.capacity() == 16);
s = str.str_view();
assert(s == TEST_STRING, "got '%s'; want '%s'", s, TEST_STRING);
ZString zs;
zs = str.zstr_view();
assert(s.ptr[s.len] == 0, "got '%c'; want 0", s.ptr[s.len]);
str.chop(5);
s = str.str_view();
assert(s == TEST_STRING[:5], "got '%s'; want '%s'", s, TEST_STRING[:5]);
str.append(TEST_STRING[5..]);
s = str.str_view();
assert(s == TEST_STRING, "got '%s'; want '%s'", s, TEST_STRING);
str.append_char('x');
s = str.str_view();
assert(s[^1] == 'x', "got '%c'; want 'x'", s[^1]);
str.append('y');
s = str.str_view();
assert(s[^1] == 'y', "got '%c'; want 'y'", s[^1]);
str.set(0, 'z');
s = str.str_view();
assert(s[0] == 'z', "got '%c'; want 'z'", s[0]);
str.clear();
assert(str.len() == 0);
str.append_char32('é');
s = str.str_view();
assert(s == "é", "got '%s'; want 'é'", s);
str.append_utf32({ 'è', 'à' });
s = str.str_view();
assert(s == "éèà", "got '%s'; want 'éèà'", s);
str.clear();
str.append_chars("foo");
s = str.str_view();
assert(s == "foo", "got '%s'; want 'foo'", s);
str.clear();
str.append_repeat('x', 3);
s = str.str_view();
assert(s == "xxx", "got '%s'; want 'xxx'", s);
DString str2 = dstring::new(mem, "yyy");
defer str2.free();
DString str3 = str.concat(mem, str2);
defer str3.free();
s = str3.str_view();
assert(s == "xxxyyy", "got '%s'; want 'xxxyyy'", s);
str3.clear();
str3.append_string(str2);
s = str3.str_view();
assert(s == "yyy", "got '%s'; want 'yyy'", s);
}
fn void test_print()
{
DString str = dstring::new(mem, "");
defer str.free();
String s;
str.appendf("_%s_", "foo");
s = str.str_view();
assert(s == "_foo_", "got '%s'; want '_foo_'", s);
str.clear();
str.appendfn("_%s_", "foo");
s = str.str_view();
assert(s == "_foo_\n", "got '%s'; want '_foo_\n'", s);
}
fn void test_copy()
{
DString str = dstring::new(mem, TEST_STRING);
defer str.free();
String s;
DString str2 = str.copy(mem);
defer str2.free();
s = str2.str_view();
assert(s == TEST_STRING, "got '%s'; want '%s'", s, TEST_STRING);
}
fn void test_cmp()
{
DString str = dstring::new(mem, TEST_STRING);
defer str.free();
DString str2 = dstring::new(mem, TEST_STRING);
defer str2.free();
assert(str.equals(str2));
str2.clear();
str2.append("hello you..");
assert(str.len() == str2.len());
assert(!str.less(str2));
}
fn void test_join()
{
DString str = dstring::join(mem, {"hello", "world"}, " ");
defer str.free();
String s = str.str_view();
assert(s == TEST_STRING, "got '%s'; want '%s'", s, TEST_STRING);
}
fn void test_insert_at()
{
DString str = dstring::tnew(" world");
String s;
str.insert_at(0, "");
s = str.str_view();
assert(s == " world", "got '%s'; want ' world'", s);
str.insert_at(0, "hello");
s = str.str_view();
assert(s == "hello world", "got '%s'; want 'hello world'", s);
str.insert_at(5, " shiny");
s = str.str_view();
assert(s == "hello shiny world", "got '%s'; want 'hello shiny world'", s);
str.insert_at(0, '[');
s = str.str_view();
assert(s == "[hello shiny world", "got '%s'; want '[hello shiny world'", s);
str.insert_at(18, ']');
s = str.str_view();
assert(s == "[hello shiny world]", "got '%s'; want 'hello shiny world]'", s);
str.insert_at(0, 'ꫩ');
s = str.str_view();
assert(s == "ꫩ[hello shiny world]", "got '%s'; want 'ꫩ[hello shiny world]'", s);
// ꫩ is 3 bytes long
str.insert_utf32_at(4, {'寃', 't', 'e', 'x', 't', '¥'});
s = str.str_view();
assert(s == "ꫩ[寃text¥hello shiny world]", "got '%s'; want 'ꫩ[寃text¥hello shiny world]'", s);
}
fn void test_insert_at_overlaps()
{
DString str = dstring::tnew("abc");
String s;
String v;
str.insert_at(0, "bc");
s = str.str_view();
assert(s == "bcabc", "got '%s'; want 'bcabc'", s);
// Inserted string is unchanged.
str.chop(0);
str.append("abc");
v = str.str_view();
str.insert_at(0, v);
s = str.str_view();
assert(s == "abc", "got '%s'; want 'abc'", s);
// Inserted string is part of the tail.
str.chop(0);
str.append("abc");
v = str.str_view()[1..];
assert(v == "bc");
str.insert_at(0, v);
s = str.str_view();
assert(s == "bcabc", "got '%s'; want 'bcabc'", s);
// Inserted string is part of the head.
str.chop(0);
str.append("abc");
v = str.str_view()[1..];
str.insert_at(2, v);
s = str.str_view();
assert(s == "abbcc", "got '%s'; want 'abbcc'", s);
str.chop(0);
str.append("abcdef");
v = str.str_view()[3..];
assert(v == "def");
str.insert_at(0, v);
str.chop(3);
s = str.str_view();
assert(s == "def", "got '%s'; want 'def'", s);
}
fn void test_char_at()
{
DString str = dstring::new(mem, "hello");
defer str.free();
char c = str.char_at(1);
assert(c == 'e');
char c_with_operator = str[4];
assert(c_with_operator == 'o');
}
fn void test_operators()
{
DString str = dstring::new(mem, "hello");
defer str.free();
str[0] = 'p';
assert(str.str_view() == "pello");
char* c = &str[1];
assert(*c == 'e');
}

View File

@@ -0,0 +1,20 @@
module std::core::formatter_test;
import std;
struct Foo (Printable) { int a; }
fn usz! Foo.to_format(&self, Formatter *f) @dynamic
{
return f.printf("Foo[%d]", self.a);
}
fn void test_ref() @test
{
Foo* f = &&(Foo){ 8 };
Foo* f0 = null;
int* a = (void*)(uptr)0x40;
int* b = null;
String s = string::format(mem, "%s %s %s %s %s", a, b, f0, f, *f);
defer free(s);
assert(s == "0x40 0x0 (null) Foo[8] Foo[8]");
}

View File

@@ -0,0 +1,25 @@
module std::core::allocator_test;
import std;
struct Foo
{
int x;
int y;
}
struct Bar
{
int x;
int y;
List{Foo} foos;
}
fn void test_new_aligned_compiles() @test
{
Bar* bar2 = allocator::new_aligned(allocator::heap(), Bar)!!;
allocator::free_aligned(allocator::heap(), bar2);
Bar* bar = allocator::new_aligned(allocator::heap(), Bar, {.x = 1, .y = 2, .foos = {}})!!;
allocator::free_aligned(allocator::heap(), bar);
}

View File

@@ -0,0 +1,37 @@
module std::core::runtime_test;
import std::sort;
fn void cmp_unit() @test
{
TestUnit[] list = {
{ .name = "http::url_test::url_query" },
{ .name = "http::url_test::url_init" },
{ .name = "http::url_test::url_decode" },
{ .name = "text_test::test_render_notag" },
{ .name = "text_test::test_render_tag1" },
{ .name = "text_test::test_render_template_iter" },
{ .name = "http::header_test::header_scan" },
{ .name = "http::header_test::header" },
{ .name = "stringmap_test::test_map" },
{ .name = "text_test::test_render_template" },
};
quicksort(list, &runtime::cmp_test_unit);
String[] want = {
"http::header_test::header",
"http::header_test::header_scan",
"http::url_test::url_decode",
"http::url_test::url_init",
"http::url_test::url_query",
"stringmap_test::test_map",
"text_test::test_render_notag",
"text_test::test_render_tag1",
"text_test::test_render_template",
"text_test::test_render_template_iter",
};
assert(list.len == want.len);
foreach (i, l : list)
{
assert(l.name == want[i], "got %s; want %s", l.name, want[i]);
}
}

View File

@@ -0,0 +1,208 @@
module std::core::string::tests @test;
fn void test_starts_with()
{
String s = "ofke";
assert(s.starts_with("of"));
assert(s.starts_with("ofke"));
assert(!s.starts_with("ofkes"));
assert(!s.starts_with("ofkf"));
s = "";
assert(s.starts_with(""));
assert(!s.starts_with("o"));
}
fn void test_print_null()
{
ZString z;
int* y;
ZString w = "hello";
String s = string::format(mem, "%s %s %s", z, w, y);
defer free(s);
assert(s == "(null) hello 0x0");
}
fn void test_strip()
{
String s = "ofke";
assert(s.strip("of") == "ke");
assert(s.strip("ofke") == "");
assert(s.strip("ofkes") == "ofke");
assert(s.strip("ofkf") == "ofke");
assert(s.strip("") == "ofke");
s = "";
assert(s.strip("") == "");
assert(s.strip("o") == "");
}
fn void test_strip_end()
{
String s = "ofke";
assert(s.strip_end("ke") == "of");
assert(s.strip_end("ofke") == "");
assert(s.strip_end("ofkes") == "ofke");
assert(s.strip_end("ofkf") == "ofke");
assert(s.strip_end("") == "ofke");
s = "";
assert(s.strip_end("") == "");
assert(s.strip_end("o") == "");
}
fn void test_ends_with()
{
String s = "ofke";
assert(s.ends_with("ke"));
assert(s.ends_with("ofke"));
assert(!s.ends_with("ofkes"));
assert(!s.ends_with("ofkf"));
s = "";
assert(s.ends_with(""));
assert(!s.ends_with("e"));
}
fn void test_trim()
{
String s = " \t\nabc ";
assert(s.trim() == "abc");
assert("\n\t".trim() == "");
assert(" \n\tok".trim() == "ok");
assert("!! \n\t ".trim() == "!!");
assert(s.trim("c \t") == "\nab");
assert("".trim() == "");
}
fn void test_trim_left()
{
String s = " \t\nabc ";
assert(s.trim_left() == "abc ");
assert("\n\t".trim_left() == "");
assert(" \n\tok".trim_left() == "ok");
assert("!! \n\t ".trim_left() == "!! \n\t ");
assert("".trim_left() == "");
}
fn void test_trim_right()
{
String s = " \t\nabc ";
assert(s.trim_right() == " \t\nabc");
assert("\n\t".trim_right() == "");
assert(" \n\tok".trim_right() == " \n\tok");
assert("!! \n\t ".trim_right() == "!!");
assert("".trim_right() == "");
}
fn void test_split()
{
String test = "abc|b||c|";
String[] strings = test.split(mem, "|");
assert(strings.len == 5);
assert(strings[0] == "abc");
assert(strings[1] == "b");
assert(strings[2] == "");
assert(strings[3] == "c");
assert(strings[4] == "");
free(strings);
strings = test.split(mem, "|", 2);
assert(strings.len == 2);
assert(strings[0] == "abc");
assert(strings[1] == "b||c|");
free(strings);
}
fn void test_split_skip_empty()
{
String test = "abc|b||c|";
String[] strings = test.split(mem, "|", skip_empty: true);
assert(strings.len == 3);
assert(strings[0] == "abc");
assert(strings[1] == "b");
assert(strings[2] == "c");
free(strings);
strings = test.split(mem, "|", 2, skip_empty: true);
assert(strings.len == 2);
assert(strings[0] == "abc");
assert(strings[1] == "b||c|");
free(strings);
}
fn void test_split_to_buffer_skip_empty()
{
String[10] buffer;
String test = "abc|b||c|";
String[] strings = test.split_to_buffer("|", &buffer, skip_empty: true)!!;
assert(strings.len == 3);
assert(strings[0] == "abc");
assert(strings[1] == "b");
assert(strings[2] == "c");
strings = test.split(mem, "|", 2, skip_empty: true);
assert(strings.len == 2);
assert(strings[0] == "abc");
assert(strings[1] == "b||c|");
free(strings);
}
fn void test_split_to_buffer()
{
String[5] b;
String test = "abc|b||c|";
String[] strings = test.split_to_buffer("|", &b)!!;
assert(strings.len == 5);
assert(strings[0] == "abc");
assert(strings[1] == "b");
assert(strings[2] == "");
assert(strings[3] == "c");
assert(strings[4] == "");
String[4] c;
assert(@catch(test.split_to_buffer("|", &c)) == SplitResult.BUFFER_EXCEEDED);
strings = test.split(mem, "|", 2);
assert(strings.len == 2);
assert(strings[0] == "abc");
assert(strings[1] == "b||c|");
free(strings);
}
fn void test_index_of()
{
String test = "hello world hello";
assert(test.index_of("o")!! == 4);
assert(test.index_of("ll")!! == 2);
assert(test.index_of(" hello")!! == 11);
assert(@catch(test.index_of("wi")));
}
fn void test_rindex_of()
{
String test = "hello world hello";
assert(test.rindex_of("o")!! == 16);
assert(test.rindex_of("ll")!! == 14);
assert(test.rindex_of("he")!! == 12);
assert(test.rindex_of("world")!! == 6);
assert(test.rindex_of("hello ")!! == 0);
assert(@catch(test.rindex_of("wi")));
}
fn void test_index_of_char()
{
String test = "hello world hello";
assert(test.index_of_char('o')!! == 4);
assert(test.index_of_char('l')!! == 2);
assert(test.index_of_char('h')!! == 0);
assert(@catch(test.index_of_char('x')));
}
fn void test_rindex_of_char()
{
String test = "hello world hello";
assert(test.rindex_of_char('o')!! == 16);
assert(test.rindex_of_char('l')!! == 15);
assert(test.rindex_of_char('h')!! == 12);
assert(@catch(test.index_of_char('x')));
}
fn void test_hex_conversion()
{
assert("0x123aCd".to_long()!! == 0x123acd);
assert("123acD".to_long(16)!! == 0x123acd);
}

View File

@@ -0,0 +1,35 @@
module std::core::test::string_iterator::tests @test;
fn void test_at_start()
{
String test = "abcd";
StringIterator iterator = test.iterator();
assert(iterator.get()!! == 'a');
assert(iterator.peek()!! == 'a');
iterator.next()!!;
assert(iterator.next()!! == 'b');
assert(iterator.has_next());
}
fn void test_general()
{
String test = "åƦs1";
StringIterator iterator = test.iterator();
assert(iterator.get()!! == 'å');
iterator.next()!!;
assert(iterator.peek()!! == 'Ʀ');
assert(iterator.next()!! == 'Ʀ');
iterator.reset();
assert(iterator.current == 0);
}
fn void test_end()
{
String test = "åƦ";
StringIterator iterator = test.iterator();
assert(@ok(iterator.next()));
assert(iterator.peek()!! == 'Ʀ');
assert(@ok(iterator.next()));
assert(@catch(iterator.next()));
}

View File

@@ -0,0 +1,332 @@
module test::std::core::test @test;
import std::core::runtime @public;
import std::core::builtin;
import std::io;
struct TestState
{
int n_runs;
int n_fails;
bool expected_fail;
// NOTE: we must wrap setup/teardown functions to hide them from module @test runner
TestFn setup_fn;
TestFn teardown_fn;
PanicFn old_panic; // original test panic, use it when it's really fails
PanicFn panic_mock_fn; // mock panic, for testing the test:: failed
void* buf;
}
TestState state =
{
.setup_fn = fn void()
{
state.n_runs++;
state.n_fails = 0;
assert (runtime::test_context.assert_print_backtrace);
assert (builtin::panic != state.panic_mock_fn, "missing finalization of panic");
state.buf = mem::alloc(int);
state.old_panic = builtin::panic;
builtin::panic = state.panic_mock_fn;
},
.teardown_fn = fn void()
{
builtin::panic = state.old_panic;
assert(state.n_runs > 0);
if (state.expected_fail)
{
assert(state.n_fails > 0, "test case expected to fail, but it's not");
}
state.n_fails = 0;
state.expected_fail = false;
state.n_runs = 0;
mem::free(state.buf);
},
.panic_mock_fn = fn void (String message, String file, String function, uint line)
{
if (runtime::test_context.is_in_panic) return;
if (runtime::test_context.assert_print_backtrace)
{
$if env::NATIVE_STACKTRACE:
builtin::print_backtrace(message, 0);
$else
io::printfn("No print_backtrace() supported by this platform");
$endif
}
runtime::test_context.assert_print_backtrace = true;
if (state.expected_fail)
{
state.n_fails++;
}
else
{
builtin::panic = state.old_panic;
state.old_panic(message, file, function, line);
}
runtime::test_context.is_in_panic = false;
}
};
fn void test_eq()
{
test::eq(1, 1);
test::eq(true, true);
test::eq(1.31, 1.31);
test::eq("foo", "foo");
}
fn void test_almost_equal()
{
test::eq_approx(1, 1);
test::eq_approx(1.31, 1.31);
test::eq_approx(1.31f, 1.31f);
test::eq_approx(double.nan, double.nan);
test::eq_approx(float.nan, float.nan);
test::eq_approx(1.31, 1.31, delta: 0.01);
test::eq_approx(1.311, 1.312, delta: 0.01);
test::eq_approx(1.311, 1.312, places: 2);
// 7 decimal places are default
test::eq_approx(1.00000001, 1.00000000);
}
fn void test_almost_equal_fails()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
// 7 decimal places are default
test::eq_approx(1.0000001, 1.00000000);
}
fn void test_almost_equal_fails_nan()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::eq_approx(1.0000001, double.nan);
}
fn void test_almost_equal_fails_nan2()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::eq_approx(double.nan, 1);
}
fn void test_almost_equal_fails_equal_nan_false()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::eq_approx(double.nan, double.nan, equal_nan: false);
}
fn void setup_teardown()
{
state.n_runs = 0; // just in case of previous test failed
test::@setup(state.setup_fn, state.teardown_fn);
test::eq(state.n_runs, 1);
test::eq(state.n_fails, 0);
test::eq(state.expected_fail, false);
}
fn void setup_no_teardown()
{
test::@setup(state.setup_fn);
test::eq(state.n_runs, 1);
test::eq(state.n_fails, 0);
test::eq(state.expected_fail, false);
mem::free(state.buf);
// WARNING: reverting back original panic func
builtin::panic = state.old_panic;
}
fn void expected_fail()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::eq(state.n_fails, 0);
test::eq(2, 1); // this fails, and we test it
test::eq(state.n_fails, 1);
}
fn void test_neq()
{
test::ne(2, 1);
test::ne(false, true);
test::ne(1.32, 1.31);
test::ne("foo", "bar");
}
fn void test_neq_fails()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::ne(1, 1);
}
fn void test_gt()
{
test::gt(2, 1);
test::gt(true, false);
test::gt(1.32, 1.31);
}
fn void test_gt_fails_when_equal()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::gt(2, 2);
}
fn void test_gt_fails_when_less()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::gt(1, 2);
}
fn void test_gte()
{
test::ge(2, 1);
test::ge(true, false);
test::ge(1.32, 1.31);
test::ge(2, 2);
test::ge(true, true);
test::ge(1.32, 1.32);
}
fn void test_gte_fails_when_less()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::ge(1, 2);
}
fn void test_lt()
{
test::lt(1, 2);
test::lt(false, true);
test::lt(1.31, 1.32);
}
fn void test_lt_fails_when_equal()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::lt(2, 2);
}
fn void test_lt_fails_when_greater()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::lt(2, 1);
}
fn void test_lte()
{
test::le(1, 2);
test::le(false, true);
test::le(1.31, 1.32);
test::le(2, 2);
test::le(true, true);
test::le(1.32, 1.32);
}
fn void test_lte_fails_when_greater()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::le(2, 1);
}
fn void test_check(){
test::@check(1 == 1);
test::@check(1.2 == 1.2, "1 == 1");
test::@check(true == true, "1 == 1");
test::@check("foo" == "foo", "2 == %d", 1 );
}
fn void test_check_fails()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::@check(2 == 1, "2 == %d", 1 );
}
fn void test_check_fails_no_info()
{
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::@check(2 == 1);
}
def TestIntFn = fn int! (int a, int b);
def TestFailFn = fn void! (bool to_fail);
fault MyFault
{
FOO,
}
fn void test_error()
{
TestFailFn ffail_void = fn void!(bool to_fail)
{
if (to_fail) return IoError.FILE_NOT_FOUND?;
};
TestIntFn ffail_int = fn int! (int a, int b)
{
if (b == 0) return IoError.FILE_NOT_FOUND?;
return a / b;
};
test::@setup(state.setup_fn, state.teardown_fn);
test::@error(ffail_void(true), IoError.FILE_NOT_FOUND);
test::@error(ffail_int(1, 0), IoError.FILE_NOT_FOUND);
}
fn void test_error_not_raised()
{
TestIntFn ffail_int = fn int! (int a, int b) {
if (b == 0) return IoError.FILE_NOT_FOUND?;
return a / b;
};
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::@error(ffail_int(1, 1), IoError.FILE_NOT_FOUND);
}
fn void test_error_wrong_error_expected()
{
TestIntFn ffail_int = fn int! (int a, int b) {
if (b == 0) return IoError.BUSY?;
return a / b;
};
test::@setup(state.setup_fn, state.teardown_fn);
state.expected_fail = true;
test::@error(ffail_int(1, 0), IoError.FILE_NOT_FOUND);
}
fn void test_std_out_hijack()
{
io::print("print: aldsjalsdjlasjdlja\n");
io::printf("printf: aldsjalsdjlasjdlja\n");
io::eprint("eprint: aldsjalsdjlasjdlja\n");
io::eprintfn("eprintfn: aldsjalsdjlasjdlja\n");
io::fprint(io::stdout(), "fprint: stdout aldsjalsdjlasjdlja\n")!!;
io::fprint(io::stderr(), "fprint: stderr aldsjalsdjlasjdlja\n")!!;
io::fprintf(io::stderr(), "fprintf: stderr aldsjalsdjlasjdlja\n")!!;
io::fprintf(io::stderr(), "fprintfn: stderr aldsjalsdjlasjdlja\n")!!;
test::eq(true, true);
}

View File

@@ -0,0 +1,9 @@
module std::core::values @test;
fn void test_select()
{
const int X = @select(true, 1, "Hello");
const String Y = @select(false, 1, "Hello");
test::eq(X, 1);
test::eq(Y, "Hello");
}

View File

@@ -0,0 +1,16 @@
import std::crypto;
import std::io;
fn void rc_crypt() @test
{
Rc4 rc;
rc.init(&&x"63727970746969");
char[200] x;
String text = "The quick brown fox jumps over the lazy dog.";
rc.crypt(text, &x);
char[?] res = x'2ac2fecdd8fbb84638e3a4
820eb205cc8e29c28b9d5d
6b2ef974f311964971c90e
8b9ca16467ef2dc6fc3520';
assert(res[:text.len] == x[:text.len]);
}

View File

@@ -0,0 +1,108 @@
module encoding::base32 @test;
import std::encoding::base32;
// https://www.rfc-editor.org/rfc/rfc4648#section-10
struct TestCase
{
char[] dec;
char[] enc;
}
TestCase[?] std_tests = {
{ "", "" },
{ "f", "MY======" },
{ "fo", "MZXQ====" },
{ "foo", "MZXW6===" },
{ "foob", "MZXW6YQ=" },
{ "fooba", "MZXW6YTB" },
{ "foobar", "MZXW6YTBOI======" },
};
TestCase[?] hex_tests = {
{ "", "" },
{ "f", "CO======" },
{ "fo", "CPNG====" },
{ "foo", "CPNMU===" },
{ "foob", "CPNMUOG=" },
{ "fooba", "CPNMUOJ1" },
{ "foobar", "CPNMUOJ1E8======" },
};
macro encode_tests(tests, alphabet, padding)
{
foreach (t : tests)
{
char[64] buf;
usz n = base32::encode_len(t.dec.len, padding);
base32::encode_buffer(t.dec, buf[:n], padding, alphabet);
char[] want = t.enc;
usz! pad_idx = array::index_of(want, '=');
if (try pad_idx && !padding)
{
want = want[:pad_idx];
}
assert(buf[:n] == want, "got: %s, want: %s",
(String)buf[:n], (String)want);
}
}
fn void encode()
{
encode_tests(std_tests, &base32::STANDARD, '=');
encode_tests(hex_tests, &base32::HEX, '=');
}
fn void encode_nopadding()
{
encode_tests(std_tests, &base32::STANDARD, base32::NO_PAD);
encode_tests(hex_tests, &base32::HEX, base32::NO_PAD);
}
macro decode_tests(tests, alphabet, padding)
{
foreach (t : tests)
{
char[] input = t.enc[..];
usz! pad_idx = array::index_of(input, '=');
if (try pad_idx && !padding)
{
input = input[:pad_idx];
}
char[64] buf;
usz n = base32::decode_len(input.len, padding);
char[] buf2 = base32::decode_buffer(input, buf[:n], padding, alphabet)!!;
assert(buf2 == t.dec, "got: %s, want: %s", buf2, (String)t.dec);
}
}
fn void decode()
{
decode_tests(std_tests, &base32::STANDARD, '=');
decode_tests(hex_tests, &base32::HEX, '=');
}
fn void decode_nopadding()
{
decode_tests(std_tests, &base32::STANDARD, base32::NO_PAD);
decode_tests(hex_tests, &base32::HEX, base32::NO_PAD);
}
fn void base32_api()
{
@pool()
{
foreach (t : std_tests)
{
String got = base32::encode_temp(t.dec)!!;
assert(got == t.enc, "got: %s, want: %s", got, t.enc);
char[] got_chars = base32::decode_temp(t.enc)!!;
assert(got_chars == t.dec, "got: %s, want: %s", got_chars, t.dec);
}
};
}

View File

@@ -0,0 +1,122 @@
module encoding::base64_test @test;
import std::encoding::base64;
// https://www.rfc-editor.org/rfc/rfc4648#section-10
struct TestCase
{
char[] in;
char[] out;
}
import std;
fn void encode()
{
TestCase[] tcases = {
{ "", "" },
{ "f", "Zg==" },
{ "fo", "Zm8=" },
{ "foo", "Zm9v" },
{ "foob", "Zm9vYg==" },
{ "fooba", "Zm9vYmE=" },
{ "foobar", "Zm9vYmFy" },
{ "test", "dGVzdA==" },
};
foreach (tc : tcases)
{
@pool()
{
usz n = base64::encode_len(tc.in.len, base64::DEFAULT_PAD);
char[64] buf;
char[] res = base64::encode_buffer(tc.in, buf[:n]);
assert(res == tc.out);
};
}
}
fn void encode_nopadding()
{
TestCase[] tcases = {
{ "", "" },
{ "f", "Zg" },
{ "fo", "Zm8" },
{ "foo", "Zm9v" },
{ "foob", "Zm9vYg" },
{ "fooba", "Zm9vYmE" },
{ "foobar", "Zm9vYmFy" },
{ "test", "dGVzdA" },
};
foreach (tc : tcases)
{
usz n = base64::encode_len(tc.in.len, base64::NO_PAD);
char[64] buf;
base64::encode_buffer(tc.in, buf[:n], padding: base64::NO_PAD);
assert(buf[:n] == tc.out);
}
}
fn void decode()
{
TestCase[] tcases = {
{ "", "" },
{ "Zg==", "f" },
{ "Zm8=", "fo" },
{ "Zm9v", "foo" },
{ "Zm9vYg==", "foob" },
{ "Zm9vYmE=", "fooba" },
{ "Zm9vYmFy", "foobar" },
{ "Zm9vYmFy", "foobar" },
{ "dGVzdA==", "test" },
};
foreach (tc : tcases)
{
usz n = base64::decode_len(tc.in.len, base64::DEFAULT_PAD)!!;
char[64] buf;
char[] res = base64::decode_buffer(tc.in, buf[:n])!!;
assert(res == tc.out);
}
}
fn void decode_nopadding()
{
TestCase[] tcases = {
{ "", "" },
{ "Zg", "f" },
{ "Zm8", "fo" },
{ "Zm9v", "foo" },
{ "Zm9vYg", "foob" },
{ "Zm9vYmE", "fooba" },
{ "Zm9vYmFy", "foobar" },
{ "dGVzdA", "test" },
};
foreach (tc : tcases)
{
usz n = base64::decode_len(tc.in.len, base64::NO_PAD)!!;
char[64] buf;
char[] res = base64::decode_buffer(tc.in, buf[:n], base64::NO_PAD)!!;
assert(res == tc.out);
}
}
fn void urlencode() {
TestCase[] tcases = {
{ x"14fb9c03d97e", "FPucA9l-"},
};
@pool()
{
usz n;
char[] got;
char[64] buf;
foreach (t : tcases)
{
char[] res = base64::encode_buffer(t.in, buf[..], alphabet: &base64::URL);
assert (res == t.out, "got: %s, want: %s", (String)res, (String)t.out);
res = base64::decode_buffer(t.out, buf[..], alphabet: &base64::URL)!!;
assert (res == t.in, "got: %s, want: %s", (String)res, (String)t.in);
}
};
}

View File

@@ -0,0 +1,68 @@
module csv_test @test;
import std::encoding::csv;
import std::io;
struct TestCase {
String input;
String[] want;
String sep;
}
fn void csv_each_row()
{
TestCase[] tests = {
{
"aaa,bbb,ccc",
{"aaa","bbb","ccc"},
","
},
{
"aaa;bbb;ccc",
{"aaa", "bbb", "ccc"},
";"
},
{
"aaa,bbb,ccc\n111,222,333",
{"aaa", "bbb", "ccc", "111", "222", "333"},
","
},
{
"aaa , bbb\t ,ccc\r\n 111,222,333\r\n",
{"aaa ", " bbb\t ", "ccc", " 111", "222", "333"},
","
},
};
foreach (t : tests) {
String[] want = t.want;
CsvReader r;
r.init((ByteReader){}.init(t.input), t.sep);
r.@each_row(; String[] row) {
foreach (i, s : row) {
assert(want.len > 0,
"more records than we want");
assert(s == want[0], "columns do not match; "
"got: '%s', want: '%s'", s, want[0]);
want = want[1..];
}
};
assert(want.len == 0, "not enough records found");
}
}
fn void csv_row()
{
TestCase t = {
"aaa,bbb,ccc",
{"aaa", "bbb", "ccc"},
","
};
CsvReader r;
r.init((ByteReader){}.init(t.input), t.sep);
CsvRow row = r.tread_row()!!;
assert(row.list.len == t.want.len, "not enough records found");
for (int i = 0; i < row.list.len; i++) {
assert(row.list[i] == t.want[i],"columns do not match; "
"got: '%s', want: '%s'", row.list[i], t.want[i]);
}
}

View File

@@ -0,0 +1,49 @@
module encoding::hex @test;
import std::encoding::hex;
struct TestCase
{
char[] dec;
char[] enc;
}
TestCase[] tests = {
{"", ""},
{{'g'}, "67"},
{{0,1,2,3,4,5,6,7}, "0001020304050607"},
{{8,9,10,11,12,13,14,15}, "08090a0b0c0d0e0f"},
{{0xf0, 0xf1, 0xf2, 0xf3}, "f0f1f2f3"},
{{0xe3, 0xa1}, "e3a1"},
{{0xe3, 0xa1}, "E3A1"},
};
fn void encode()
{
usz n;
char[64] buf;
foreach (t : tests)
{
n = hex::encode_bytes(t.dec, buf[..]);
String want = ((String)t.enc).to_lower_tcopy();
assert(want == buf[:n], "encode failed: got: %s, want: %s", buf[:n], want);
@pool()
{
assert(want == hex::tencode(t.dec));
};
}
}
fn void decode()
{
usz n;
char[64] buf;
foreach (t : tests)
{
n = hex::decode_bytes(t.enc, buf[..])!!;
assert(t.dec == buf[:n], "decode failed: got: %s, want: %s", buf[:n], t.dec);
@pool()
{
assert(t.dec == hex::tdecode(t.enc)!!);
};
}
}

View File

@@ -0,0 +1,53 @@
module json_test @test;
import std::collections::object;
import std::io;
import std::encoding::json;
fn void simple_test()
{
ByteReader reader;
reader.init(`{ "b": 123, "c": [ { "d": 66 }, null, "hello\tworld", false, { "id": "xyz" } ] }`);
Object* o = json::parse(mem, &reader)!!;
defer o.free();
assert(o.get_int("b")!! == 123);
assert(o.get("c").get_len()!! == 5);
assert(o.get("c").get_at(0).get_int("d")!! == 66);
assert(o.get("c").get_at(1).is_null()!!);
assert(o.get("c").get_string_at(2)!! == "hello\tworld");
assert(o.get("c").get_bool_at(3)!! == false);
assert(o.get("c").get_at(4).get_string("id")!! == "xyz");
}
fn void simple_test2()
{
ByteReader reader;
reader.init(`{"jsonrpc":"2.0","id":null,"method":"initialize"}`);
Object* o = json::parse(mem, &reader)!!;
defer o.free();
}
fn void test_string()
{
Object* o = json::parse_string(mem, `{"jsonrpc":"2","id":null,"method":"initialize"}`)!!;
defer o.free();
String s = string::tformat("%s", *o);
Object* o2 = json::parse_string(mem, s)!!;
defer o2.free();
String s2 = string::tformat("%s", *o2);
assert(s2 == s, "Unexpectedly got %s and not %s", s2, s);
}
fn void test_temp_string()
{
@pool()
{
Object* o = json::tparse_string(`{"jsonrpc":"2","id":null,"method":"initialize"}`)!!;
defer o.free();
String s = string::tformat("%s", *o);
Object* o2 = json::tparse_string(s)!!;
defer o2.free();
String s2 = string::tformat("%s", *o2);
assert(s2 == s, "Unexpectedly got %s and not %s", s2, s);
};
}

View File

@@ -0,0 +1,24 @@
module std::hash::fnv32a_test @test;
import std::hash::fnv32a;
fn void test_fnv32a()
{
Fnv32a hash;
char[] input = "Hello world";
uint want = 0x594d29c7;
// update
hash.init();
hash.update(input);
assert ((uint)hash == want, "got: %d, want: %d", hash, want);
// update_char
hash.init();
foreach (c : input) hash.update_char(c);
assert ((uint)hash == want, "got: %d, want: %d", hash, want);
// encode
uint encoded = fnv32a::encode(input);
assert (encoded == want, "got: %d, want: %d", encoded, want);
}

View File

@@ -0,0 +1,24 @@
module std::hash::fnv64a_test @test;
import std::hash::fnv64a;
fn void test_fnv64a()
{
Fnv64a hash;
char[] input = "Hello world";
ulong want = 0x2713f785a33764c7;
// update
hash.init();
hash.update(input);
assert ((ulong)hash == want, "got: %d, want: %d", hash, want);
// update_char
hash.init();
foreach (c : input) hash.update_char(c);
assert ((ulong)hash == want, "got: %d, want: %d", hash, want);
// encode
ulong encoded = fnv64a::encode(input);
assert (encoded == want, "got: %d, want: %d", encoded, want);
}

View File

@@ -0,0 +1,41 @@
module std::hash::md5_test @test;
import std::hash::md5;
fn void test_md5_rfc()
{
Md5 md5;
md5.init();
assert (md5.final() == x'd41d8cd98f00b204e9800998ecf8427e');
md5.init();
md5.update("a");
assert (md5.final() == x'0cc175b9c0f1b6a831c399e269772661');
md5.init();
md5.update("abc");
assert (md5.final() == x'900150983cd24fb0d6963f7d28e17f72');
md5.init();
md5.update("message ");
md5.update("digest");
assert(md5.final() == x'f96b697d7cb7938d525a2f31aaf161d0');
md5.init();
md5.update("abcdefghijklmnopqrstuvwxyz");
assert(md5.final() == x'c3fcd3d76192e4007dfb496cca67e13b');
md5.init();
md5.update("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
assert(md5.final() == x'd174ab98d277d9f5a5611c2c9f419d9f');
md5.init();
md5.update("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
assert(md5.final() == x'57edf4a22be3c955ac49da2e2107b67a');
}
fn void test_md5_hash()
{
assert(md5::hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890") == x'57edf4a22be3c955ac49da2e2107b67a');
}

View File

@@ -0,0 +1,70 @@
module std::hash::sha1_test @test;
import std::hash::sha1;
fn void test_sha1_abc()
{
Sha1 sha;
sha.init();
sha.update("abc");
assert(sha.final() == x"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D");
}
fn void test_sha1_even_longer()
{
char[] content = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce viverra nulla nec neque convallis feugiat. Vestibulum sodales at.";
Sha1 sha1;
sha1.init();
sha1.update(content);
assert(sha1.final() == x"7ba51bc42c21e6159556537c2134d1c2028799ef");
}
fn void test_sha1_longer()
{
Sha1 sha;
sha.init();
sha.update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
assert(sha.final() == x"84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1");
}
fn void test_pbkdf2()
{
char[] pw = "password";
char[] s = "salt";
char[20] out;
sha1::pbkdf2(pw, s, 1, &out);
assert(out == x'0c60c80f961f0e71f3a9b524af6012062fe037a6');
sha1::pbkdf2(pw, s, 2, &out);
assert(out == x'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957');
sha1::pbkdf2(pw, s, 4096, &out);
assert(out == x'4b007901b765489abead49d926f721d065a429c1');
}
fn void test_pbkdf2_2()
{
char[] pw = "passwordPASSWORDpassword";
char[] s = "saltSALTsaltSALTsaltSALTsaltSALTsalt";
char[25] out;
sha1::pbkdf2(pw, s, 4096, &out);
assert(out == x'3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038');
}
fn void test_pbkdf2_3()
{
char[] pw = "pass\0word";
char[] salt = "sa\0lt";
char[16] out;
sha1::pbkdf2(pw, salt, 4096, &out);
assert(out == x'56fa6aa75548099dcc37d7f03425e0c3');
}
fn void test_sha1_million_a()
{
Sha1 sha;
sha.init();
const int COUNT = 1_000_000;
for (int i = 0; i < COUNT / 10; i++)
{
sha.update("aaaaaaaaaa");
}
assert(sha.final() == x"34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F");
}

View File

@@ -0,0 +1,74 @@
module std::hash::sha256_test @test;
import std::hash::sha256;
fn void test_sha256_empty()
{
Sha256 sha;
sha.init();
sha.update("");
assert(sha.final() == x"E3B0C442 98FC1C14 9AFBF4C8 996FB924 27AE41E4 649B934C A495991B 7852B855");
}
fn void test_sha256_abc()
{
Sha256 sha;
sha.init();
sha.update("abc");
assert(sha.final() == x"BA7816BF 8F01CFEA 414140DE 5DAE2223 B00361A3 96177A9C B410FF61 F20015AD");
}
fn void test_sha256_longer()
{
Sha256 sha;
sha.init();
sha.update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopqabcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
assert(sha.final() == x"59F109D9 533B2B70 E7C3B814 A2BD218F 78EA5D37 14455BC6 7987CF0D 664399CF");
}
fn void test_pbkdf2()
{
char[] pw = "password";
char[] s = "salt";
char[32] out;
sha256::pbkdf2(pw, s, 1, &out);
assert(out == x'120FB6CF FCF8B32C 43E72252 56C4F837 A86548C9 2CCC3548 0805987C B70BE17B');
sha256::pbkdf2(pw, s, 2, &out);
assert(out == x'AE4D0C95 AF6B46D3 2D0ADFF9 28F06DD0 2A303F8E F3C251DF D6E2D85A 95474C43');
sha256::pbkdf2(pw, s, 4096, &out);
assert(out == x'C5E478D5 9288C841 AA530DB6 845C4C8D 962893A0 01CE4E11 A4963873 AA98134A');
}
fn void test_pbkdf2_2()
{
char[] pw = "passwordPASSWORDpassword";
char[] s = "saltSALTsaltSALTsaltSALTsaltSALTsalt";
char[32] out;
sha256::pbkdf2(pw, s, 4096, &out);
assert(out == x'348C89DB CBD32B2F 32D814B8 116E84CF 2B17347E BC180018 1C4E2A1F B8DD53E1');
}
fn void test_pbkdf2_3()
{
char[] pw = "pass\0word";
char[] salt = "sa\0lt";
char[32] out;
sha256::pbkdf2(pw, salt, 4096, &out);
assert(out == x'89B69D05 16F82989 3C696226 650A8687 8C029AC1 3EE27650 9D5AE58B 6466A724');
}
fn void test_sha256_million_a()
{
Sha256 sha;
sha.init();
const int COUNT = 1_000_000;
for (int i = 0; i < COUNT / 10; i++)
{
sha.update("aaaaaaaaaa");
}
assert(sha.final() == x"CDC76E5C 9914FB92 81A1C7E2 84D73E67 F1809A48 A497200E 046D39CC C7112CD0");
}

View File

@@ -0,0 +1,249 @@
module std::io::bits @test;
import std::io;
fn void test_write_0b1() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0b11111111, 1)!!;
bw.flush()!!;
assert(w.str_view() == x"80"); // 0b1000 0000
}
fn void test_write_0b1111() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0b11111111, 4)!!;
bw.flush()!!;
assert(w.str_view() == x"f0"); // 0b1111 0000
}
fn void test_write_0b1111_1111() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0b11111111, 8)!!;
bw.flush()!!;
assert(w.str_view() == x"ff");
}
fn void test_write_0b1000() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0b0001000, 4)!!;
bw.flush()!!;
assert(w.str_view() == x"80"); // 0b1000 0000
}
fn void test_write_0b01000() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0b0001000, 5)!!;
bw.flush()!!;
assert(w.str_view() == x"40"); // 0b0100 0000
}
fn void test_write_0b0001() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0b0000001, 4)!!;
bw.flush()!!;
assert(w.str_view() == x"10"); // 0b0001 0000
}
fn void test_write_0b0000_0001() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0b0000001, 8)!!;
bw.flush()!!;
assert(w.str_view() == x"01"); // 0b0000 0001
}
fn void test_write_10_bits() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0x789, 10)!!; // 01|11 1000 1001
bw.flush()!!;
// e 2 4 0
assert(w.str_view() == x"e2 40"); // 0b1110 0010 0100 0000
}
fn void test_write_16_bits() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0xfafb, 16)!!;
bw.flush()!!;
assert(w.str_view() == x"fa fb");
}
fn void test_write_24_bits() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0xfafbfc, 24)!!;
bw.flush()!!;
assert(w.str_view() == x"fa fb fc");
}
fn void test_write_30_bits() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0xf0f1f2f3, 30)!!; // 11 | 110000111100011111001011110011
bw.flush()!!;
// c 3 c 7 c b c c
assert(w.str_view() == x"c3 c7 cb cc"); // 1100 0011 1100 0111 1100 1011 1100 1100
}
fn void test_write_32_bits() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0xfafbfcfd, 32)!!;
bw.flush()!!;
assert(w.str_view() == x"fa fb fc fd");
}
fn void test_write_2_bits_multiple() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0b11111111, 2)!!;
bw.write_bits(0b00000001, 2)!!;
bw.write_bits(0b11111111, 2)!!;
bw.flush()!!;
assert(w.str_view() == x"dc"); // 0b1101 1100
}
fn void test_write_10_bits_multiple() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0x789, 10)!!; // 01 | 11 1000 1001
bw.write_bits(0xabc, 10)!!; // 10 | 10 1011 1100
bw.write_bits(0xdef, 10)!!; // 11 | 01 1110 1111
bw.flush()!!;
// e 2 6 b c 7 b c
assert(w.str_view() == x"e2 6b c7 bc"); // 0b1110 0010 0110 1011 1100 0111 1011 1100
}
fn void test_write_24_bits_multiple() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0xfafbfc, 24)!!;
bw.write_bits(0xfdfeff, 24)!!;
bw.flush()!!;
assert(w.str_view() == x"fa fb fc fd fe ff");
}
fn void test_write_30_bits_multiple() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0xf0f1f2f3, 30)!!; // 11 | 110000111100011111001011110011
bw.write_bits(0xfafbfcfd, 30)!!; // 11 | 111010111110111111110011111101
bw.flush()!!;
assert(w.str_view() == x"c3 c7 cb cf af bf cf d0");
}
fn void test_write_32_bits_multiple() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0xf0f1f2f3, 32)!!;
bw.write_bits(0xfafbfcfd, 32)!!;
bw.flush()!!;
assert(w.str_view() == x"f0 f1 f2 f3 fa fb fc fd");
}
fn void test_write_mixed_multiple() {
ByteWriter w;
w.temp_init();
BitWriter bw;
bw.init(&w);
bw.write_bits(0xf0f1f2f3, 8)!!;
bw.write_bits(0xf0f1f2f3, 32)!!;
bw.write_bits(0xfafbfcfd, 30)!!;
bw.write_bits(0xf4f5f6f7, 10)!!;
bw.flush()!!;
assert(w.str_view() == x"f3 f0 f1 f2 f3 eb ef f3 f6 f7");
}

View File

@@ -0,0 +1,94 @@
module std::io @test;
const DATA = "Lorem ipsum blandit.";
fn void readbuffer_large()
{
ByteReader src;
src.init(DATA);
char[DATA.len] buf;
ReadBuffer reader_buf;
reader_buf.init(&src, buf[..]);
char[DATA.len] bytes;
usz n = reader_buf.read(bytes[..])!!;
assert(n == DATA.len, "large read failed: got %d; want %d", n, DATA.len);
String got = (String)bytes[..];
assert(got == DATA, "large read failed: got %s; want %s", got, DATA);
}
fn void readbuffer()
{
ByteReader src;
src.init(DATA);
char[3] buf;
ReadBuffer reader_buf;
reader_buf.init(&src, buf[..]);
ByteWriter bw;
bw.temp_init();
usz n = io::copy_to(&reader_buf, &bw)!!;
assert(n == DATA.len, "got %d; want %d", n, DATA.len);
String got = bw.str_view();
assert(got == DATA, "got %s; want %s", got, DATA);
}
fn void writebuffer_large()
{
ByteWriter out;
out.temp_init();
char[16] buf;
WriteBuffer write_buf;
write_buf.init(&out, buf[..]);
usz n = write_buf.write(DATA)!!;
assert(n == DATA.len, "large write failed: got %d; want %d", n, DATA.len);
String got = out.str_view();
assert(got == DATA, "large write failed: got %s; want %s", got, DATA);
}
fn void writebuffer()
{
ByteReader br;
br.init(DATA);
ByteWriter out;
out.temp_init();
char[3] buf;
WriteBuffer write_buf;
write_buf.init(&out, buf[..]);
usz n = io::copy_to(&br, &write_buf)!!;
assert(n == DATA.len, "got %d; want %d", n, DATA.len);
String got = out.str_view();
assert(got == DATA, "got %s; want %s", got, DATA);
}
fn void writebuffer_write_byte()
{
ByteWriter out;
out.temp_init();
char[2] buf;
WriteBuffer write_buf;
write_buf.init(&out, buf[..]);
write_buf.write_byte('a')!!;
assert(write_buf.str_view() == "a");
assert(out.str_view() == "");
write_buf.write_byte('b')!!;
assert(write_buf.str_view() == "ab");
assert(out.str_view() == "");
write_buf.write_byte('c')!!;
assert(write_buf.str_view() == "c");
assert(out.str_view() == "ab");
write_buf.flush()!!;
assert(write_buf.str_view() == "");
assert(out.str_view() == "abc");
}

View File

@@ -0,0 +1,29 @@
module std::io::bytebuffer @test;
import std::io;
fn void write_read()
{
ByteBuffer buffer;
buffer.new_init(0);
defer buffer.free();
buffer.write("hello")!!;
char[8] bytes;
usz n = buffer.read(bytes[..])!!;
assert(n == 5);
assert((String)bytes[:n] == "hello");
buffer.write("hello world")!!;
n = buffer.read(bytes[..])!!;
assert(n == bytes.len);
assert((String)bytes[:n] == "hello wo");
assert(buffer.read_idx == 1);
char c = buffer.read_byte()!!;
assert(c == 'r');
buffer.pushback_byte()!!;
n = buffer.read(bytes[..])!!;
assert((String)bytes[:n] == "rld");
assert(buffer.read_idx == 1);
}

View File

@@ -0,0 +1,72 @@
module std::io @test;
fn void bytestream()
{
ByteReader r;
r.init("abc");
InStream s = &r;
assert(s.len() == 3);
char[5] buffer;
assert('a' == s.read_byte()!!);
s.pushback_byte()!!;
usz len = s.read(&buffer)!!;
assert((String)buffer[:len] == "abc");
ByteWriter w;
w.new_init();
defer (void)w.destroy();
OutStream ws = &w;
ws.write("helloworld")!!;
assert(w.str_view() == "helloworld");
s.seek(0, SET)!!;
io::copy_to(s, ws)!!;
s.seek(1, SET)!!;
s.write_to(ws)!!;
assert(w.str_view() == "helloworldabcbc");
}
fn void bytewriter_buffer()
{
ByteWriter writer;
char[8] z;
writer.init_with_buffer(&z);
OutStream s = &writer;
s.write("hello")!!;
s.write_byte(0)!!;
String o = ((ZString)&z).str_view();
assert(o == "hello");
assert(@catch(s.write("xxxx")));
}
fn void bytewriter_read_from()
{
char[] data = "Lorem ipsum dolor sit amet biam.";
TestReader r = { .bytes = data };
InStream s = &r;
ByteWriter bw;
bw.temp_init();
bw.read_from(s)!!;
assert(bw.str_view() == data);
}
module std::io;
// TestReader only has the read method to trigger the path
// in ByteWriter.read_from that does not rely on the available method.
struct TestReader (InStream)
{
char[] bytes;
usz index;
}
fn usz! TestReader.read(&self, char[] bytes) @dynamic
{
usz left = self.bytes.len - self.index;
if (left == 0) return 0;
usz n = min(left, bytes.len);
mem::copy(bytes.ptr, &self.bytes[self.index], n);
self.index += n;
return n;
}
fn char! TestReader.read_byte(&self) @dynamic => io::read_byte_using_read(self);

View File

@@ -0,0 +1,18 @@
module std::io @test;
fn void test_writing()
{
DString foo;
foo.init(mem);
defer foo.free();
OutStream s = &foo;
s.write("hello")!!;
s.write_byte('-')!!;
s.write("what?-------------------------------------------------------")!!;
ByteReader r;
String test_str = "2134";
io::copy_to(r.init(test_str), s)!!;
String o = foo.str_view();
assert(o == "hello-what?-------------------------------------------------------2134");
}

View File

@@ -0,0 +1,94 @@
module std::io::file @test;
import std::io;
struct Data
{
bool boolean;
char byte;
ichar s_byte;
ushort word;
short s_word;
uint dword;
int s_dword;
ulong qword;
long s_qword;
uint128 dqword;
int128 s_dqword;
char[128] data;
bool[57] flags;
bitstruct : ushort
{
char upper : 8..15;
char lower : 0..7;
}
bitstruct : ushort @overlap
{
ushort total : 0..15;
char t_lower : 0..7;
char t_upper : 8..15;
bool t_rand : 12;
bool t_other : 4;
}
union
{
char hello;
short hallo;
uint byebye;
}
}
fn void read_write_any()
{
Data data;
data.boolean = false;
data.byte = 0xAF;
data.s_byte = -56;
data.word = 0xBEAF;
data.s_word = -547;
data.qword = 0xCAFEAFBC;
data.s_qword = -2000000000;
data.dqword = 0xCAFEADDEAFBEFF;
data.s_dqword = -45600000000000000;
for (int i = 0; i < 128; ++i) data.data[i] = (char)(255 - i);
for (int i = 0; i < 57; ++i) data.flags[i] = (i % 4) == 0;
data.upper = 0x56;
data.lower = 0x44;
data.total = 0xA55A;
data.hello = 0xCC;
File file = file::open("tmp/__file_read_write_any_test_file", "wb")!!;
io::write_any(&file, &data)!!;
file.flush()!!;
file.close()!!;
file = file::open("tmp/__file_read_write_any_test_file", "rb")!!;
Data rdata;
io::read_any(&file, &rdata)!!;
file.close()!!;
assert(rdata.boolean == data.boolean);
assert(rdata.byte == data.byte);
assert(rdata.s_byte == data.s_byte);
assert(rdata.word == data.word);
assert(rdata.s_word == data.s_word);
assert(rdata.dword == data.dword);
assert(rdata.s_dword == data.s_dword);
assert(rdata.qword == data.qword);
assert(rdata.s_qword == data.s_qword);
assert(rdata.dqword == data.dqword);
assert(rdata.data == data.data);
assert(rdata.flags == data.flags);
assert(rdata.upper == data.upper);
assert(rdata.lower == data.lower);
assert(rdata.t_lower == data.t_lower);
assert(rdata.t_upper == data.t_upper);
assert(rdata.t_rand == data.t_rand);
assert(rdata.t_other == data.t_other);
assert(rdata.total == data.total);
assert(rdata.hello == data.hello);
assert(rdata.hallo == data.hallo);
assert(rdata.byebye == data.byebye);
}

View File

@@ -0,0 +1,16 @@
module std::io::fileinfo @test;
import std::io::os;
fn void test_native_is_file() @if(env::LINUX || env::DARWIN)
{
assert(!os::native_is_file("/dev/loop0"));
assert(!os::native_is_file("/dev/null"));
}
fn void test_native_is_dir() @if(env::LINUX || env::DARWIN)
{
assert(os::native_is_dir("/"));
assert(!os::native_is_file("/"));
assert(!os::native_is_dir("/dev/loop0"));
assert(!os::native_is_dir("/dev/null"));
}

View File

@@ -0,0 +1,20 @@
module std::io @test;
fn void limitreader()
{
const DATA = "Hello World!";
ByteReader src;
src.init(DATA);
const LIMIT = 5;
LimitReader lmr;
lmr.init(&src, LIMIT);
char[DATA.len] bytes;
usz n = lmr.read(bytes[..])!!;
assert(n == LIMIT, "got %d; want %d", n, LIMIT);
String got = (String)bytes[:n];
String want = DATA[:LIMIT];
assert(got == want, "got %d; want %d", got, want);
}

View File

@@ -0,0 +1,21 @@
module std::io @test;
fn void test_multireader()
{
MultiReader mr;
mr.temp_init(
&&wrap_bytes("foo"),
&&wrap_bytes(" "),
&&wrap_bytes("bar"),
&&wrap_bytes("!"),
);
defer mr.free();
ByteWriter w;
io::copy_to(&mr, w.temp_init())!!;
String want = "foo bar!";
assert(w.str_view() == want,
"invalid data read; got: %s, want: %s", w.str_view(), want);
}

View File

@@ -0,0 +1,17 @@
module std::io @test;
fn void test_multiwriter()
{
ByteWriter w1, w2;
MultiWriter mw;
mw.temp_init(w1.temp_init(), w2.temp_init());
defer mw.free();
String want = "foobar";
io::copy_to((ByteReader){}.init(want), &mw)!!;
assert(w1.str_view() == want,
"invalid write; got: %s, want: %s", w1.str_view(), want);
assert(w2.str_view() == want,
"invalid write; got: %s, want: %s", w2.str_view(), want);
}

View File

@@ -0,0 +1,378 @@
module std::io::path @test;
fn void test_dot()
{
Path p = path::new(mem, ".")!!;
defer p.free();
assert(@catch(p.parent()));
// It must be possible to form the absolute version.
Path p2 = p.absolute(mem)!!;
p2.free();
p2 = p.append(mem, "/hello/world")!!;
if (p2.env == POSIX)
{
assert(p2.str_view() == "hello/world");
}
else
{
assert(p2.str_view() == `hello\world`);
}
p2.free();
}
fn void test_parent()
{
Path p = path::new(mem, "")!!;
assert(@catch(p.parent()));
p.free();
p = path::new(mem, "/", path_env: PathEnv.POSIX)!!;
assert(@catch(p.parent()));
p.free();
p = path::new(mem, "/a/b/c", path_env: PathEnv.POSIX)!!;
assert(p.parent().str_view()!! == "/a/b");
p.free();
p = path::new(mem, "/a/b/c", path_env: PathEnv.WIN32)!!;
assert(p.parent().str_view()!! == `\a\b`);
p.free();
}
fn void test_path_normalized() => mem::@scoped(allocator::temp())
{
assert(path::new(mem, "", path_env: PathEnv.WIN32).str_view()!! == "");
assert(@catch(path::new(mem, "1:\\a\\b\\c.txt", path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, ":", path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, "1:", path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, "1:a", path_env: PathEnv.WIN32)));
// assert(@catch(path::new(mem, `\\\a\b\c.txt`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, `\\server\a\b\..\..\..\c`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, `\\a`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, `/a/b/../../../c`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, `/a/b/../../../c`, path_env: PathEnv.POSIX)));
assert(@catch(path::new(mem, `/a/b/../../..`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, `/a/b/../../..`, path_env: PathEnv.POSIX)));
assert(@catch(path::new(mem, `/../a`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, `/../a`, path_env: PathEnv.POSIX)));
assert(@catch(path::new(mem, `/..`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, `/..`, path_env: PathEnv.POSIX)));
assert(@catch(path::new(mem, `C:/a/b/../../../c`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, `C:/../a`, path_env: PathEnv.WIN32)));
assert(@catch(path::new(mem, `C:/..`, path_env: PathEnv.WIN32)));
assert(path::new(mem, "/", path_env: PathEnv.POSIX).str_view()!! == "/");
assert(path::new(mem, "/./", path_env: PathEnv.POSIX).str_view()!! == "/");
assert(path::new(mem, "/foo/../", path_env: PathEnv.POSIX).str_view()!! == "/");
assert(path::new(mem, "/foo/bar/../", path_env: PathEnv.POSIX).str_view()!! == "/foo");
assert(path::new(mem, "/foo//bar", path_env: PathEnv.POSIX).str_view()!! == "/foo/bar");
assert(path::new(mem, "/foo//bar/../", path_env: PathEnv.POSIX).str_view()!! == "/foo");
assert(path::new(mem, "/foo/.bar", path_env: PathEnv.POSIX).str_view()!! == "/foo/.bar");
assert(path::new(mem, `\foo\.bar`, path_env: PathEnv.WIN32).str_view()!! == `\foo\.bar`);
assert(path::new(mem, "a\\b/c.txt", path_env: PathEnv.WIN32).str_view()!! == `a\b\c.txt`);
assert(path::new(mem, "a\\b/c.txt", path_env: PathEnv.POSIX).str_view()!! == "a\\b/c.txt");
assert(path::new(mem, "C:\\a\\b/c.txt", path_env: PathEnv.WIN32).str_view()!! == `C:\a\b\c.txt`);
assert(path::new(mem, "C:\\a\\b/c.txt", path_env: PathEnv.POSIX).str_view()!! == "C:\\a\\b/c.txt");
assert(path::new(mem, `\\server\a\b/c.txt`, path_env: PathEnv.WIN32).str_view()!! == `\\server\a\b\c.txt`);
assert(path::new(mem, `\\server\a\b/c.txt`, path_env: PathEnv.POSIX).str_view()!! == `\\server\a\b/c.txt`);
assert(path::new(mem, `c:\hello//bar\\\\foo.txt`, path_env: PathEnv.WIN32).str_view()!! == `c:\hello\bar\foo.txt`);
assert(path::new(mem, `~\a\b/c.txt`, path_env: PathEnv.WIN32).str_view()!! == `~\a\b\c.txt`);
assert(path::new(mem, `~\a\b/c.txt`, path_env: PathEnv.POSIX).str_view()!! == `~\a\b/c.txt`);
assert(path::new(mem, `a/b/../../../c`, path_env: PathEnv.WIN32).str_view()!! == `..\c`);
assert(path::new(mem, `a/b/../../../c`, path_env: PathEnv.POSIX).str_view()!! == `../c`);
assert(path::new(mem, `a/b/../../..`, path_env: PathEnv.WIN32).str_view()!! == `..`);
assert(path::new(mem, `a/b/../../..`, path_env: PathEnv.POSIX).str_view()!! == `..`);
assert(path::new(mem, `../a`, path_env: PathEnv.WIN32).str_view()!! == `..\a`);
assert(path::new(mem, `../a`, path_env: PathEnv.POSIX).str_view()!! == `../a`);
assert(path::new(mem, `..`, path_env: PathEnv.WIN32).str_view()!! == `..`);
assert(path::new(mem, `..`, path_env: PathEnv.POSIX).str_view()!! == `..`);
assert(path::new(mem, `a/b/../c`, path_env: PathEnv.WIN32).str_view()!! == `a\c`);
assert(path::new(mem, `a/b/../c`, path_env: PathEnv.POSIX).str_view()!! == `a/c`);
assert(path::new(mem, `a/b/../../c`, path_env: PathEnv.WIN32).str_view()!! == `c`);
assert(path::new(mem, `a/b/../../c`, path_env: PathEnv.POSIX).str_view()!! == `c`);
assert(path::new(mem, `a/b/..`, path_env: PathEnv.WIN32).str_view()!! == `a`);
assert(path::new(mem, `a/b/..`, path_env: PathEnv.POSIX).str_view()!! == `a`);
assert(path::new(mem, `a/b/../`, path_env: PathEnv.WIN32).str_view()!! == `a`);
assert(path::new(mem, `a/b/../`, path_env: PathEnv.POSIX).str_view()!! == `a`);
assert(path::new(mem, `a/b/../..`, path_env: PathEnv.WIN32).str_view()!! == ".");
assert(path::new(mem, `a/b/../..`, path_env: PathEnv.POSIX).str_view()!! == ".");
assert(path::new(mem, `a/b/../../`, path_env: PathEnv.WIN32).str_view()!! == ".");
assert(path::new(mem, `a/b/../../`, path_env: PathEnv.POSIX).str_view()!! == ".");
assert(path::new(mem, `a/b/../c/../d`, path_env: PathEnv.WIN32).str_view()!! == `a\d`);
assert(path::new(mem, `a/b/../c/../d`, path_env: PathEnv.POSIX).str_view()!! == `a/d`);
assert(path::new(mem, `a/b/../c/../d/`, path_env: PathEnv.WIN32).str_view()!! == `a\d`);
assert(path::new(mem, `a/b/../c/../d/`, path_env: PathEnv.POSIX).str_view()!! == `a/d`);
assert(path::new(mem, `a/b//d`, path_env: PathEnv.WIN32).str_view()!! == `a\b\d`);
assert(path::new(mem, `a/b//d`, path_env: PathEnv.POSIX).str_view()!! == `a/b/d`);
assert(path::new(mem, `a/b/././.`, path_env: PathEnv.WIN32).str_view()!! == `a\b`);
assert(path::new(mem, `a/b/././.`, path_env: PathEnv.POSIX).str_view()!! == `a/b`);
assert(path::new(mem, `a/b/./././`, path_env: PathEnv.WIN32).str_view()!! == `a\b`);
assert(path::new(mem, `a/b/./././`, path_env: PathEnv.POSIX).str_view()!! == `a/b`);
assert(path::new(mem, `./a/`, path_env: PathEnv.WIN32).str_view()!! == `a`);
assert(path::new(mem, `./a/`, path_env: PathEnv.POSIX).str_view()!! == `a`);
assert(path::new(mem, `./`, path_env: PathEnv.WIN32).str_view()!! == `.`);
assert(path::new(mem, `./`, path_env: PathEnv.POSIX).str_view()!! == `.`);
assert(path::new(mem, `.`, path_env: PathEnv.WIN32).str_view()!! == `.`);
assert(path::new(mem, `.`, path_env: PathEnv.POSIX).str_view()!! == `.`);
assert(path::new(mem, ``, path_env: PathEnv.WIN32).str_view()!! == ``);
assert(path::new(mem, ``, path_env: PathEnv.POSIX).str_view()!! == ``);
assert(path::new(mem, `/a`, path_env: PathEnv.WIN32).str_view()!! == `\a`);
assert(path::new(mem, `/a`, path_env: PathEnv.POSIX).str_view()!! == `/a`);
assert(path::new(mem, `/a/`, path_env: PathEnv.WIN32).str_view()!! == `\a`);
assert(path::new(mem, `/a/`, path_env: PathEnv.POSIX).str_view()!! == `/a`);
assert(path::new(mem, `/a/b/../c`, path_env: PathEnv.WIN32).str_view()!! == `\a\c`);
assert(path::new(mem, `/a/b/../c`, path_env: PathEnv.POSIX).str_view()!! == `/a/c`);
assert(path::new(mem, `/a/b/../../c`, path_env: PathEnv.WIN32).str_view()!! == `\c`);
assert(path::new(mem, `/a/b/../../c`, path_env: PathEnv.POSIX).str_view()!! == `/c`);
assert(path::new(mem, `/a/b/..`, path_env: PathEnv.WIN32).str_view()!! == `\a`);
assert(path::new(mem, `/a/b/..`, path_env: PathEnv.POSIX).str_view()!! == `/a`);
assert(path::new(mem, `/a/b/../..`, path_env: PathEnv.WIN32).str_view()!! == `\`);
assert(path::new(mem, `/a/b/../..`, path_env: PathEnv.POSIX).str_view()!! == `/`);
assert(path::new(mem, `/a/b/../c/../d`, path_env: PathEnv.WIN32).str_view()!! == `\a\d`);
assert(path::new(mem, `/a/b/../c/../d`, path_env: PathEnv.POSIX).str_view()!! == `/a/d`);
assert(path::new(mem, `/a/b//d`, path_env: PathEnv.WIN32).str_view()!! == `\a\b\d`);
assert(path::new(mem, `/a/b//d`, path_env: PathEnv.POSIX).str_view()!! == `/a/b/d`);
assert(path::new(mem, `/./a/`, path_env: PathEnv.WIN32).str_view()!! == `\a`);
assert(path::new(mem, `/./a/`, path_env: PathEnv.POSIX).str_view()!! == `/a`);
assert(path::new(mem, `/./`, path_env: PathEnv.WIN32).str_view()!! == `\`);
assert(path::new(mem, `/./`, path_env: PathEnv.POSIX).str_view()!! == `/`);
assert(path::new(mem, `/.`, path_env: PathEnv.WIN32).str_view()!! == `\`);
assert(path::new(mem, `/.`, path_env: PathEnv.POSIX).str_view()!! == `/`);
assert(path::new(mem, `/`, path_env: PathEnv.WIN32).str_view()!! == `\`);
assert(path::new(mem, `/`, path_env: PathEnv.POSIX).str_view()!! == `/`);
assert(path::new(mem, `C:/a`, path_env: PathEnv.WIN32).str_view()!! == `C:\a`);
assert(path::new(mem, `C:/a`, path_env: PathEnv.POSIX).str_view()!! == `C:/a`);
assert(path::new(mem, `C:/a/b/../c`, path_env: PathEnv.WIN32).str_view()!! == `C:\a\c`);
assert(path::new(mem, `C:/a/b/../c`, path_env: PathEnv.POSIX).str_view()!! == `C:/a/c`);
assert(path::new(mem, `C:/a/b/../../c`, path_env: PathEnv.WIN32).str_view()!! == `C:\c`);
assert(path::new(mem, `C:/a/b/../../c`, path_env: PathEnv.POSIX).str_view()!! == `C:/c`);
assert(path::new(mem, `C:/a/b/../../../c`, path_env: PathEnv.POSIX).str_view()!! == `c`);
assert(path::new(mem, `C:/a/b/..`, path_env: PathEnv.WIN32).str_view()!! == `C:\a`);
assert(path::new(mem, `C:/a/b/..`, path_env: PathEnv.POSIX).str_view()!! == `C:/a`);
assert(path::new(mem, `C:/a/b/../..`, path_env: PathEnv.WIN32).str_view()!! == `C:\`);
assert(path::new(mem, `C:/a/b/../..`, path_env: PathEnv.POSIX).str_view()!! == `C:`);
assert(path::new(mem, `C:/a/b/../c/../d`, path_env: PathEnv.WIN32).str_view()!! == `C:\a\d`);
assert(path::new(mem, `C:/a/b/../c/../d`, path_env: PathEnv.POSIX).str_view()!! == `C:/a/d`);
assert(path::new(mem, `C:/a/b//d`, path_env: PathEnv.WIN32).str_view()!! == `C:\a\b\d`);
assert(path::new(mem, `C:/a/b//d`, path_env: PathEnv.POSIX).str_view()!! == `C:/a/b/d`);
assert(path::new(mem, `C:/a/b/././.`, path_env: PathEnv.WIN32).str_view()!! == `C:\a\b`);
assert(path::new(mem, `C:/a/b/././.`, path_env: PathEnv.POSIX).str_view()!! == `C:/a/b`);
assert(path::new(mem, `C:/./a`, path_env: PathEnv.WIN32).str_view()!! == `C:\a`);
assert(path::new(mem, `C:/./a`, path_env: PathEnv.POSIX).str_view()!! == `C:/a`);
assert(path::new(mem, `C:/./`, path_env: PathEnv.WIN32).str_view()!! == `C:\`);
assert(path::new(mem, `C:/./`, path_env: PathEnv.POSIX).str_view()!! == `C:`);
assert(path::new(mem, `C:/../a`, path_env: PathEnv.POSIX).str_view()!! == `a`);
assert(path::new(mem, `C:/..`, path_env: PathEnv.POSIX).str_view()!! == `.`);
assert(path::new(mem, `C:/`, path_env: PathEnv.WIN32).str_view()!! == `C:\`);
assert(path::new(mem, `C:/`, path_env: PathEnv.POSIX).str_view()!! == `C:`);
assert(path::new(mem, `C:a`, path_env: PathEnv.WIN32).str_view()!! == `C:a`);
assert(path::new(mem, `C:a`, path_env: PathEnv.POSIX).str_view()!! == `C:a`);
assert(path::new(mem, `C:a/`, path_env: PathEnv.WIN32).str_view()!! == `C:a`);
assert(path::new(mem, `C:a/`, path_env: PathEnv.POSIX).str_view()!! == `C:a`);
assert(path::new(mem, `C:a/b/../c`, path_env: PathEnv.WIN32).str_view()!! == `C:a\c`);
assert(path::new(mem, `C:a/b/../c`, path_env: PathEnv.POSIX).str_view()!! == `C:a/c`);
assert(path::new(mem, `C:a/b/../../c`, path_env: PathEnv.WIN32).str_view()!! == `C:c`);
assert(path::new(mem, `C:a/b/../../c`, path_env: PathEnv.POSIX).str_view()!! == `c`);
assert(path::new(mem, `C:a/b/..`, path_env: PathEnv.WIN32).str_view()!! == `C:a`);
assert(path::new(mem, `C:a/b/..`, path_env: PathEnv.POSIX).str_view()!! == `C:a`);
assert(path::new(mem, `C:a/b/../..`, path_env: PathEnv.WIN32).str_view()!! == `C:`);
assert(path::new(mem, `C:a/b/../..`, path_env: PathEnv.POSIX).str_view()!! == `.`);
assert(path::new(mem, `C:a/b/../c/../d`, path_env: PathEnv.WIN32).str_view()!! == `C:a\d`);
assert(path::new(mem, `C:a/b/../c/../d`, path_env: PathEnv.POSIX).str_view()!! == `C:a/d`);
assert(path::new(mem, `C:a/b//d`, path_env: PathEnv.WIN32).str_view()!! == `C:a\b\d`);
assert(path::new(mem, `C:a/b//d`, path_env: PathEnv.POSIX).str_view()!! == `C:a/b/d`);
assert(path::new(mem, `C:a/b/././.`, path_env: PathEnv.WIN32).str_view()!! == `C:a\b`);
assert(path::new(mem, `C:a/b/././.`, path_env: PathEnv.POSIX).str_view()!! == `C:a/b`);
assert(path::new(mem, `C:a/b/../../../c`, path_env: PathEnv.WIN32).str_view()!! == `C:..\c`);
assert(path::new(mem, `C:./a`, path_env: PathEnv.WIN32).str_view()!! == `C:a`);
assert(path::new(mem, `C:./a`, path_env: PathEnv.POSIX).str_view()!! == `C:./a`);
assert(path::new(mem, `C:./`, path_env: PathEnv.WIN32).str_view()!! == `C:`);
assert(path::new(mem, `C:./`, path_env: PathEnv.POSIX).str_view()!! == `C:.`);
assert(path::new(mem, `C:../a`, path_env: PathEnv.POSIX).str_view()!! == `C:../a`);
assert(path::new(mem, `C:../a`, path_env: PathEnv.WIN32).str_view()!! == `C:..\a`);
assert(path::new(mem, `C:..`, path_env: PathEnv.POSIX).str_view()!! == `C:..`);
assert(path::new(mem, `C:..`, path_env: PathEnv.WIN32).str_view()!! == `C:..`);
assert(path::new(mem, `C:`, path_env: PathEnv.WIN32).str_view()!! == `C:`);
assert(path::new(mem, `C:`, path_env: PathEnv.POSIX).str_view()!! == `C:`);
assert(path::new(mem, `\\server\foo/a`, path_env: PathEnv.WIN32).str_view()!! == `\\server\foo\a`);
assert(path::new(mem, `\\server\foo/a`, path_env: PathEnv.POSIX).str_view()!! == `\\server\foo/a`);
assert(path::new(mem, `\\server\foo\a\b\..\c`, path_env: PathEnv.WIN32).str_view()!! == `\\server\foo\a\c`);
assert(path::new(mem, `\\server\foo\a\b\..\..\c`, path_env: PathEnv.WIN32).str_view()!! == `\\server\foo\c`);
assert(path::new(mem, `\\server\foo\a\b\..`, path_env: PathEnv.WIN32).str_view()!! == `\\server\foo\a`);
assert(path::new(mem, `\\server\foo\a\..`, path_env: PathEnv.WIN32).str_view()!! == `\\server\foo\`);
assert(path::new(mem, `\\server\foo\a\b\..\c\..\d`, path_env: PathEnv.WIN32).str_view()!! == `\\server\foo\a\d`);
assert(path::new(mem, `\\server\foo\a\b\\d`, path_env: PathEnv.WIN32).str_view()!! == `\\server\foo\a\b\d`);
assert(path::new(mem, `\\server\foo\a\b\.\.\.`, path_env: PathEnv.WIN32).str_view()!! == `\\server\foo\a\b`);
assert(path::new(mem, `\\server\foo\.\a`, path_env: PathEnv.WIN32).str_view()!! == `\\server\foo\a`);
assert(path::new(mem, `\\server\foo\.`, path_env: PathEnv.WIN32).str_view()!! == `\\server\foo\`);
assert(path::new(mem, `\\server\foo\`, path_env: PathEnv.WIN32).str_view()!! == `\\server\foo\`);
}
fn void test_extension() => mem::@scoped(allocator::temp())
{
assert(@catch(path::new(mem, `C:`, path_env: PathEnv.WIN32).extension()));
assert(@catch(path::new(mem, `C:`, path_env: PathEnv.POSIX).extension()));
assert(@catch(path::new(mem, `file`, path_env: PathEnv.WIN32).extension()));
assert(@catch(path::new(mem, `file`, path_env: PathEnv.POSIX).extension()));
assert(@catch(path::new(mem, `C:\temp\foo.bar\README`, path_env: PathEnv.WIN32).extension()));
assert(path::for_windows(mem, "file.txt").extension()!! == "txt");
assert(path::for_posix(mem, "file.txt").extension()!! == "txt");
assert(path::for_windows(mem, "a/b/file.txt").extension()!! == "txt");
assert(path::for_posix(mem, "a/b/file.txt").extension()!! == "txt");
assert(path::for_windows(mem, "a\\b\\file.txt").extension()!! == "txt");
assert(path::for_windows(mem, "a.b/file.txt").extension()!! == "txt");
assert(path::for_posix(mem, "a.b/file.txt").extension()!! == "txt");
assert(path::for_windows(mem, "a.b/file.txt").extension()!! == "txt");
assert(path::for_posix(mem, "a.b/file.txt").extension()!! == "txt");
assert(path::for_windows(mem, "a.b\\file.txt").extension()!! == "txt");
assert(path::for_windows(mem, "domain.dot.com").extension()!! == "com");
assert(path::for_posix(mem, "domain.dot.com").extension()!! == "com");
assert(path::for_windows(mem, "image.jpeg").extension()!! == "jpeg");
assert(path::for_posix(mem, "image.jpeg").extension()!! == "jpeg");
assert(path::for_windows(mem, "../filename.ext").extension()!! == "ext");
assert(path::for_posix(mem, "../filename.ext").extension()!! == "ext");
}
fn void test_has_extension() => mem::@scoped(allocator::temp())
{
assert(!path::new(mem, `C:\temp\foo.bar\README`, path_env: PathEnv.WIN32)!!.has_extension(`bar\README`));
assert(path::for_windows(mem, "file.txt")!!.has_extension("txt"));
assert(path::for_posix(mem, "file.txt")!!.has_extension("txt"));
assert(path::for_windows(mem, "a/b/file.txt")!!.has_extension("txt"));
assert(path::for_posix(mem, "a/b/file.txt")!!.has_extension("txt"));
assert(path::for_windows(mem, "a\\b\\file.txt")!!.has_extension("txt"));
assert(path::for_windows(mem, "a.b/file.txt")!!.has_extension("txt"));
assert(path::for_posix(mem, "a.b/file.txt")!!.has_extension("txt"));
assert(path::for_windows(mem, "a.b/file.txt")!!.has_extension("txt"));
assert(path::for_posix(mem, "a.b/file.txt")!!.has_extension("txt"));
assert(path::for_windows(mem, "a.b\\file.txt")!!.has_extension("txt"));
assert(path::for_windows(mem, "domain.dot.com")!!.has_extension("com"));
assert(path::for_posix(mem, "domain.dot.com")!!.has_extension("com"));
assert(path::for_windows(mem, "image.jpeg")!!.has_extension("jpeg"));
assert(path::for_posix(mem, "image.jpeg")!!.has_extension("jpeg"));
assert(path::for_windows(mem, "../filename.ext")!!.has_extension("ext"));
assert(path::for_posix(mem, "../filename.ext")!!.has_extension("ext"));
}
fn void test_basename() => mem::@scoped(allocator::temp())
{
assert(path::for_windows(mem, "file.txt").basename()!! == "file.txt");
assert(path::for_posix(mem, "file.txt").basename()!! == "file.txt");
assert(path::for_windows(mem, "a/b/file.txt").basename()!! == "file.txt");
assert(path::for_posix(mem, "a/b/file.txt").basename()!! == "file.txt");
assert(path::for_windows(mem, "a.b/file.txt").basename()!! == "file.txt");
assert(path::for_posix(mem, "a.b/file.txt").basename()!! == "file.txt");
assert(path::for_windows(mem, "a.b/file.txt").basename()!! == "file.txt");
assert(path::for_posix(mem, "a.b/file.txt").basename()!! == "file.txt");
assert(path::for_windows(mem, "../filename.ext").basename()!! == "filename.ext");
assert(path::for_posix(mem, "../filename.ext").basename()!! == "filename.ext");
assert(path::for_windows(mem, "C:").basename()!! == "");
assert(path::for_posix(mem, "C:").basename()!! == "C:");
assert(path::for_windows(mem, "../..").basename()!! == "..");
assert(path::for_posix(mem, "../..").basename()!! == "..");
assert(path::for_windows(mem, `\\server\abc`).basename()!! == "");
assert(path::for_posix(mem, `\\server\abc`).basename()!! == `\\server\abc`);
}
fn void test_dirname() => mem::@scoped(allocator::temp())
{
assert(path::for_posix(mem, "").dirname()!! == ".");
assert(path::for_posix(mem, "/file").dirname()!! == "/");
assert(path::for_posix(mem, "///").dirname()!! == "/");
assert(path::for_windows(mem, "d:").dirname()!! == "d:");
assert(path::for_windows(mem, "d:file").dirname()!! == "d:");
assert(path::for_windows(mem, `d:\file`).dirname()!! == `d:\`);
assert(path::for_windows(mem, "file.txt").dirname()!! == ".");
assert(path::for_posix(mem, "file.txt").dirname()!! == ".");
assert(path::for_windows(mem, "a/b/file.txt").dirname()!! == `a\b`);
assert(path::for_posix(mem, "a/b/file.txt").dirname()!! == "a/b");
assert(path::for_windows(mem, "a.b/file.txt").dirname()!! == "a.b");
assert(path::for_posix(mem, "a.b/file.txt").dirname()!! == "a.b");
assert(path::for_windows(mem, "../filename.ext").dirname()!! == "..");
assert(path::for_posix(mem, "../filename.ext").dirname()!! == "..");
assert(path::for_windows(mem, "C:").dirname()!! == "C:");
assert(path::for_posix(mem, "C:").dirname()!! == ".");
assert(path::for_windows(mem, "C:/").dirname()!! == "C:\\");
assert(path::for_posix(mem, "C:/").dirname()!! == ".");
assert(path::for_windows(mem, "C:/a").dirname()!! == "C:\\");
assert(path::for_posix(mem, "C:/a").dirname()!! == "C:");
assert(path::for_windows(mem, "../..").dirname()!! == "..");
assert(path::for_posix(mem, "../..").dirname()!! == "..");
assert(path::for_windows(mem, `\\server\share\dir\file`).dirname()!! == `\\server\share\dir`);
assert(path::for_windows(mem, `\\server\share\file`).dirname()!! == `\\server\share`);
assert(path::for_windows(mem, `\\server\share\`).dirname()!! == `\\server\share`);
assert(path::for_windows(mem, `\\server\share`).dirname()!! == `\\server\share`);
assert(path::for_posix(mem, `\\server\`).dirname()!! == `.`);
}
fn void test_path_volume() => mem::@scoped(allocator::temp())
{
assert(path::for_windows(mem, `C:\abs`).volume_name()!! == `C:`);
assert(path::for_windows(mem, `C:abs`).volume_name()!! == `C:`);
assert(path::for_posix(mem, `C:/abs`).volume_name()!! == ``);
assert(path::for_posix(mem, `C:abs`).volume_name()!! == ``);
assert(path::for_windows(mem, `\\server\foo`).volume_name()!! == `\\server\foo`);
assert(path::for_windows(mem, `\\server\foo\abc`).volume_name()!! == `\\server\foo`);
}
fn void test_path_is_absolute() => mem::@scoped(allocator::temp())
{
assert(!path::for_posix(mem, "").is_absolute()!!);
assert(path::for_posix(mem, "/").is_absolute()!!);
assert(path::for_posix(mem, "/a/b").is_absolute()!!);
assert(!path::for_posix(mem, "a/b").is_absolute()!!);
assert(!path::for_windows(mem, `C:`).is_absolute()!!);
assert(path::for_windows(mem, `C:\abs`).is_absolute()!!);
assert(!path::for_windows(mem, `C:abs`).is_absolute()!!);
assert(path::for_windows(mem, `\\server\foo`).is_absolute()!!);
assert(path::for_windows(mem, `\\server\foo\abc`).is_absolute()!!);
}
fn void test_path_absolute() => mem::@scoped(allocator::temp())
{
$if env::WIN32:
assert(path::for_windows(mem, `C:\abs`).absolute(mem, )!!.str_view() == `C:\abs`);
$else
assert(path::for_posix(mem, "/").absolute(mem, )!!.str_view() == "/");
assert(path::for_posix(mem, ".").absolute(mem, )!!.str_view() == path::tcwd()!!.str_view());
$endif
}

View File

@@ -0,0 +1,116 @@
module std::io @test;
fn void printf_int()
{
String s;
s = string::format(mem, "[%-10d]", 78);
assert(s == "[78 ]");
free(s);
s = string::format(mem, "[%10d]", 78);
assert(s == "[ 78]");
free(s);
s = string::format(mem, "[%010d]", 78);
assert(s == "[0000000078]");
free(s);
s = string::format(mem, "[%+10d]", 78);
assert(s == "[ +78]");
free(s);
s = string::format(mem, "[%-+10d]", 78);
assert(s == "[+78 ]");
free(s);
}
fn void printf_a()
{
String s;
s = string::format(mem, "%08.2a", 234.125);
assert(s == "0x1.d4p+7", "got '%s'; want '0x1.d4p+7'", s);
free(s);
s = string::format(mem, "%a", 234.125);
assert(s == "0x1.d44p+7", "got '%s'; want '0x1.d44p+7'", s);
free(s);
s = string::format(mem, "%A", 234.125);
assert(s == "0X1.D44P+7", "got '%s'; want '0X1.D44P+7'", s);
free(s);
s = string::format(mem, "%20a", 234.125);
assert(s == " 0x1.d44p+7", "got '%s'; want ' 0x1.d44p+7'", s);
free(s);
s = string::format(mem, "%-20a", 234.125);
assert(s == "0x1.d44p+7 ", "got '%s'; want '0x1.d44p+7 '", s);
free(s);
s = string::format(mem, "%-20s", "hello world");
assert(s == "hello world ", "got '%s'; want 'hello world '", s);
free(s);
s = string::format(mem, "%20s", "hello world");
assert(s == " hello world", "got '%s'; want ' hello world'", s);
free(s);
String str = "hello!";
s = string::format(mem, "%-20s", str);
assert(s == "hello! ", "got '%s'; want 'hello! '", s);
free(s);
s = string::format(mem, "%20s", str);
assert(s == " hello!", "got '%s'; want ' hello!'", s);
free(s);
int[2] a = { 12, 23 };
s = string::format(mem, "%-20s", a);
assert(s == "[12, 23] ", "got '%s'; want '[12, 23] '", s);
free(s);
s = string::format(mem, "%20s", a);
assert(s == " [12, 23]", "got '%s'; want ' [12, 23]'", s);
free(s);
s = string::format(mem, "%-20s", a[..]);
assert(s == "[12, 23] ", "got '%s'; want '[12, 23] '", s);
free(s);
s = string::format(mem, "%20s", a[..]);
assert(s == " [12, 23]", "got '%s'; want ' [12, 23]'", s);
free(s);
float[2] f = { 12.0, 23.0 };
s = string::format(mem, "%-24s", f);
assert(s == "[12.000000, 23.000000] ", "got '%s'; want '[12.000000, 23.000000] '", s);
free(s);
s = string::format(mem, "%24s", f);
assert(s == " [12.000000, 23.000000]", "got '%s'; want ' [12.000000, 23.000000]'", s);
free(s);
int[<2>] vec = { 12, 23 };
s = string::format(mem, "%-20s", vec);
assert(s == "[<12, 23>] ", "got '%s'; want '[<12, 23>] '", s);
free(s);
s = string::format(mem, "%20s", vec);
assert(s == " [<12, 23>]", "got '%s'; want ' [<12, 23>]'", s);
free(s);
String ss = "hello world";
s = string::format(mem, "%.4s %.5s", ss, ss);
assert(s == "hell hello", "got '%s'; want 'hell hello'", s);
free(s);
}
enum PrintfTest : ushort
{
ENUMA,
ENUMB,
}
fn void printf_enum()
{
String s;
s = string::format(mem, "%s", PrintfTest.ENUMA);
assert(s == "ENUMA", "got '%s'; want 'ENUMA'", s);
free(s);
s = string::format(mem, "%s", PrintfTest.ENUMB);
assert(s == "ENUMB", "got '%s'; want 'ENUMB'", s);
free(s);
s = string::format(mem, "%d", PrintfTest.ENUMA);
assert(s == "0", "got '%s'; want '0'", s);
free(s);
s = string::format(mem, "%d", PrintfTest.ENUMB);
assert(s == "1", "got '%s'; want '1'", s);
free(s);
}

View File

@@ -0,0 +1,68 @@
module std::io @test;
import std::collections::list;
def Results = List{String};
struct ScanTest
{
String in;
String[] out;
String left_over;
}
fn void scanner()
{
ScanTest[] tcases = {
{"aa,,bb", {"aa"}, "bb"},
{"a,,b,,", {"a", "b"}, ""},
{"ab,,c", {"ab"}, "c"},
{"ab,,cd,,e", {"ab", "cd"}, "e"},
};
foreach (tc : tcases)
{
ByteReader br;
br.init(tc.in);
Scanner sc;
char[4] buffer; // max match (2) + pattern length (2)
sc.init(&br, buffer[..]);
Results results;
defer results.free();
while LOOP: (true)
{
char[]! res = sc.scan(",,");
if (catch err = res)
{
case SearchResult.MISSING:
break LOOP;
default:
return err?!!;
}
String str = (String)res;
results.push(str.tconcat(""));
}
String[] got = results.array_view();
assert(got == tc.out, "got %s; want %s", got, tc.out);
char[] fl = sc.flush();
String left_over = (String)fl;
assert(left_over == tc.left_over, "%s -> %s", tc.in, left_over);
}
}
fn void scanner_as_reader()
{
ByteReader br;
br.init("Lorem ipsum sit.");
Scanner sc;
char[8] buffer;
sc.init(&br, buffer[..]);
sc.scan(" ")!!;
char[16] res;
usz n = sc.read(&res)!!;
String str = (String)res[:n];
assert(str == "ipsum sit.", "got '%s'; want 'ipsum sit.'", str);
}

View File

@@ -0,0 +1,89 @@
module std::io @test;
fn void read_ushort_test()
{
ByteReader reader = io::wrap_bytes({0x34, 0x8a});
assert(io::read_be_ushort(&reader)!! == 0x348a);
}
fn void read_uint_test()
{
ByteReader reader = io::wrap_bytes({0x34, 0x8a, 0xef, 0xcc});
assert(io::read_be_uint(&reader)!! == 0x348aefcc);
}
fn void read_ulong_test()
{
ByteReader reader = io::wrap_bytes({0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc});
assert(io::read_be_ulong(&reader)!! == 0x348aefcc348aefcc);
}
fn void read_uint128_test()
{
ByteReader reader = io::wrap_bytes({0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc, 0x34, 0x8a, 0xef, 0xcc});
assert(io::read_be_uint128(&reader)!! == 0x348aefcc348aefcc348aefcc348aefcc);
}
fn void write_ushort_test()
{
ByteWriter bw;
bw.temp_init();
io::write_be_short(&bw, 0x348a)!!;
assert(bw.str_view() == &&x'348a');
}
fn void write_uint_test()
{
ByteWriter bw;
bw.temp_init();
io::write_be_int(&bw, 0x3421348a)!!;
assert(bw.str_view() == &&x'3421348a');
}
fn void write_ulong_test()
{
ByteWriter bw;
bw.temp_init();
io::write_be_long(&bw, 0xaabbccdd3421348a)!!;
assert(bw.str_view() == &&x'aabbccdd3421348a');
}
fn void write_uint128_test()
{
ByteWriter bw;
bw.temp_init();
io::write_be_int128(&bw, 0xaabbccdd3421348aaabbccdd3421348a)!!;
assert(bw.str_view() == &&x'aabbccdd3421348aaabbccdd3421348a');
}
fn void write_tiny_bytearray_test()
{
ByteWriter bw;
bw.temp_init();
io::write_tiny_bytearray(&bw, &&x"aabbcc00112233")!!;
assert(bw.str_view() == &&x'07aabbcc00112233');
}
fn void write_short_bytearray_test()
{
ByteWriter bw;
bw.temp_init();
io::write_short_bytearray(&bw, &&x"aabbcc00112233")!!;
assert(bw.str_view() == &&x'0007aabbcc00112233');
}
fn void read_tiny_bytearray_test()
{
ByteReader reader = io::wrap_bytes(&&x'07aabbcc00112233');
char[] read = io::read_tiny_bytearray(&reader, allocator: allocator::heap())!!;
assert(read == &&x'aabbcc00112233');
free(read);
}
fn void read_short_bytearray_test()
{
ByteReader reader = io::wrap_bytes(&&x'0007aabbcc00112233');
char[] read = io::read_short_bytearray(&reader, allocator: allocator::heap())!!;
assert(read == &&x'aabbcc00112233');
free(read);
}

View File

@@ -0,0 +1,17 @@
module std::io @test;
fn void test_teereader()
{
String want = "foobar";
ByteWriter w;
TeeReader r = tee_reader((ByteReader){}.init(want), w.temp_init());
char[16] buf;
usz n = r.read(buf[..])!!;
String got = w.str_view();
assert(n == want.len, "teereader: invalid length");
assert(got == want, "teereader: got: %s, want: %s", got, want);
assert(got == (String)buf[:n], "teereader: got: %s, want: %s", got, (String)buf[:n]);
}

View File

@@ -0,0 +1,54 @@
module std::io::varint @test;
import std::io;
fn void write_read()
{
ByteBuffer buf;
buf.temp_init(16);
usz n;
uint x;
uint y;
n = io::write_varint(&buf, 123)!!;
assert(n == 1, "got %d; want 1", n);
io::read_varint(&buf, &y)!!;
assert(y == 123, "got %d; want 123", y);
n = io::write_varint(&buf, 123456789)!!;
assert(n == 4, "got %d; want 4", n);
io::read_varint(&buf, &y)!!;
assert(y == 123456789, "got %d; want 123456789", y);
}
struct VarIntTest
{
uint in;
char[] bytes;
}
fn void samples()
{
VarIntTest[] tcases = {
{ 0, { 0x00 } },
{ 100, { 0x64 } },
{ 127, { 0x7F } },
{ 128, { 0x80, 0x01 } },
{ 16271, { 0x8F, 0x7F } },
{ 16383, { 0xFF, 0x7F } },
{ 16384, { 0x80, 0x80, 0x01 } },
{ 1048576, { 0x80, 0x80, 0x40 } },
{ 2097151, { 0xFF, 0xFF, 0x7F } },
{ 2097152, { 0x80, 0x80, 0x80, 0x01 } },
{ 2147483648, { 0x80, 0x80, 0x80, 0x80, 0x08 } },
{ 4294967295, { 0xFF, 0xFF, 0xFF, 0xFF, 0x0F } },
};
foreach (tc : tcases)
{
ByteWriter bw;
bw.temp_init();
usz n = io::write_varint(&bw, tc.in)!!;
assert(n == tc.bytes.len, "got %d; want %d", n, tc.bytes.len);
char[] bytes = bw.bytes[:bw.index];
assert(bytes == tc.bytes, "got %d; want %d", bytes, tc.bytes);
}
}

View File

@@ -0,0 +1,23 @@
module core_builtin_tests;
fn void test_likely() @test
{
assert(@likely(2 > 1));
assert(@likely(2 > 1, 0.5));
}
fn void test_unlikely() @test
{
assert(!@unlikely(2 < 1));
assert(!@unlikely(2 < 1, 0.5));
}
fn void test_expect() @test
{
assert(@expect(2 > 1, true));
assert(!@expect(2 < 1, false));
assert(@expect(2 > 1, true, 0.5));
assert(!@expect(2 < 1, false, 0.5));
}

View File

@@ -0,0 +1,75 @@
module std::math::bigint @test;
fn void test_parse16()
{
BigInt bi @noinit;
assert(bi.init_string_radix("c", 16)!!.equals(bigint::from_int(12)));
}
fn void test_zero()
{
assert(bigint::from_int(0).to_string(allocator::temp()) == "0");
BigInt bi;
bi.init_string_radix("00", 16)!!;
assert(bi.to_string(allocator::temp()) == "0");
}
fn void test_plus()
{
BigInt a = bigint::from_int(123);
BigInt b = bigint::from_int(234);
assert(a.add(b).equals(bigint::from_int(234 + 123)));
a = bigint::from_int(12323400012311213314141414i128);
b = bigint::from_int(23400012311213314141414i128);
assert(a.add(b).equals(bigint::from_int(12323400012311213314141414i128 + 23400012311213314141414i128)));
}
fn void test_mult()
{
BigInt a = bigint::from_int(123);
BigInt b = bigint::from_int(234);
assert(a.mult(b).equals(bigint::from_int(234 * 123)));
a = bigint::from_int(1232311213314141414i128);
b = bigint::from_int(234000123112414i128);
assert(a.mult(b).equals(bigint::from_int(1232311213314141414i128 * 234000123112414i128)));
}
fn void test_minus()
{
BigInt a = bigint::from_int(123);
BigInt b = bigint::from_int(234);
assert(a.sub(b).equals(bigint::from_int(123 - 234)));
a = bigint::from_int(12323400012311213314141414i128);
b = bigint::from_int(23400012311213314141414i128);
assert(a.sub(b).equals(bigint::from_int(12323400012311213314141414i128 - 23400012311213314141414i128)));
}
fn void test_init_string_radix()
{
BigInt a;
a.init_string_radix("123", 10)!!;
assert(a.equals(bigint::from_int(123)));
a.init_string_radix("123", 8)!!;
assert(a.equals(bigint::from_int(0o123)));
a.init_string_radix("123", 16)!!;
assert(a.equals(bigint::from_int(0x123)));
}
fn void test_gcd()
{
BigInt a = bigint::from_int(15);
BigInt b = bigint::from_int(20);
assert(a.gcd(b).equals(bigint::from_int(5)));
assert(math::gcd(a,b).equals(bigint::from_int(5)));
}
fn void test_lcm()
{
BigInt a = bigint::from_int(11);
BigInt b = bigint::from_int(17);
assert(a.lcm(b).equals(bigint::from_int(11*17)));
assert(math::lcm(a,b).equals(bigint::from_int(11*17)));
}

View File

@@ -0,0 +1,18 @@
module std::math @test;
fn void test_frexp()
{
int a;
double z = math::frexp(231.23, &a);
assert((z - 0.903242187) < 0.0000001 && a == 8);
float z2 = math::frexp(231.23f, &a);
assert((z2 - 0.903242187) < 0.0000001 && a == 8);
}
fn void test_signbit()
{
assert(math::signbit(-231.3) == 1);
assert(math::signbit(231.3) == 0);
assert(math::signbit(float.inf) == 0);
assert(math::signbit(-float.inf) == 1);
}

Some files were not shown because too many files have changed in this diff Show More