blob: 589d8d3a716cfae47e2a93cd7d2e1e60bedbbfe9 [file] [log] [blame]
@safe unittest
{
import std.checkedint;
int[] concatAndAdd(int[] a, int[] b, int offset)
{
// Aborts on overflow on size computation
auto r = new int[(checked(a.length) + b.length).get];
// Aborts on overflow on element computation
foreach (i; 0 .. a.length)
r[i] = (a[i] + checked(offset)).get;
foreach (i; 0 .. b.length)
r[i + a.length] = (b[i] + checked(offset)).get;
return r;
}
assert(concatAndAdd([1, 2, 3], [4, 5], -1) == [0, 1, 2, 3, 4]);
}
@safe unittest
{
import std.checkedint;
auto x = (cast(byte) 127).checked!Saturate;
assert(x == 127);
x++;
assert(x == 127);
}
@safe unittest
{
import std.checkedint;
auto x = 100.checked!WithNaN;
assert(x == 100);
x /= 0;
assert(x.isNaN);
}
@safe unittest
{
import std.checkedint;
uint x = 1;
auto y = x.checked!ProperCompare;
assert(x < -1); // built-in comparison
assert(y > -1); // ProperCompare
}
@safe unittest
{
import std.checkedint;
import std.exception : assertThrown;
auto x = -1.checked!Throw;
assertThrown(x / 0);
assertThrown(x + int.min);
assertThrown(x == uint.max);
}
@safe unittest
{
import std.checkedint;
auto x = checked(ubyte(42));
static assert(is(typeof(x.get()) == ubyte));
assert(x.get == 42);
const y = checked(ubyte(42));
static assert(is(typeof(y.get()) == const ubyte));
assert(y.get == 42);
}
@safe unittest
{
import std.checkedint;
assert(Checked!short.min == -32768);
assert(Checked!(short, WithNaN).min == -32767);
assert(Checked!(uint, WithNaN).max == uint.max - 1);
}
@safe unittest
{
import std.checkedint;
auto a = checked(42L);
assert(a == 42);
auto b = Checked!long(4242); // convert 4242 to long
assert(b == 4242);
}
@safe unittest
{
import std.checkedint;
Checked!long a;
a = 42L;
assert(a == 42);
a = 4242;
assert(a == 4242);
}
@safe unittest
{
import std.checkedint;
Checked!long a, b;
a = b = 3;
assert(a == 3 && b == 3);
}
@system unittest
{
import std.checkedint;
import std.conv : to;
const a = to!long("1234");
const b = to!(Checked!long)("1234");
assert(a == b);
}
@safe unittest
{
import std.checkedint;
assert(cast(uint) checked(42) == 42);
assert(cast(uint) checked!WithNaN(-42) == uint.max);
}
@safe unittest
{
import std.checkedint;
import std.traits : isUnsigned;
static struct MyHook
{
static bool thereWereErrors;
static bool hookOpEquals(L, R)(L lhs, R rhs)
{
if (lhs != rhs) return false;
static if (isUnsigned!L && !isUnsigned!R)
{
if (lhs > 0 && rhs < 0) thereWereErrors = true;
}
else static if (isUnsigned!R && !isUnsigned!L)
if (lhs < 0 && rhs > 0) thereWereErrors = true;
// Preserve built-in behavior.
return true;
}
}
auto a = checked!MyHook(-42);
assert(a == uint(-42));
assert(MyHook.thereWereErrors);
MyHook.thereWereErrors = false;
assert(checked!MyHook(uint(-42)) == -42);
assert(MyHook.thereWereErrors);
static struct MyHook2
{
static bool hookOpEquals(L, R)(L lhs, R rhs)
{
return lhs == rhs;
}
}
MyHook.thereWereErrors = false;
assert(checked!MyHook2(uint(-42)) == a);
// Hook on left hand side takes precedence, so no errors
assert(!MyHook.thereWereErrors);
}
@system unittest
{
import std.checkedint;
import std.format;
assert(format("%04d", checked(15)) == "0015");
assert(format("0x%02x", checked(15)) == "0x0f");
}
@safe unittest
{
import std.checkedint;
import std.traits : isUnsigned;
static struct MyHook
{
static bool thereWereErrors;
static int hookOpCmp(L, R)(L lhs, R rhs)
{
static if (isUnsigned!L && !isUnsigned!R)
{
if (rhs < 0 && rhs >= lhs)
thereWereErrors = true;
}
else static if (isUnsigned!R && !isUnsigned!L)
{
if (lhs < 0 && lhs >= rhs)
thereWereErrors = true;
}
// Preserve built-in behavior.
return lhs < rhs ? -1 : lhs > rhs;
}
}
auto a = checked!MyHook(-42);
assert(a > uint(42));
assert(MyHook.thereWereErrors);
static struct MyHook2
{
static int hookOpCmp(L, R)(L lhs, R rhs)
{
// Default behavior
return lhs < rhs ? -1 : lhs > rhs;
}
}
MyHook.thereWereErrors = false;
assert(Checked!(uint, MyHook2)(uint(-42)) <= a);
//assert(Checked!(uint, MyHook2)(uint(-42)) >= a);
// Hook on left hand side takes precedence, so no errors
assert(!MyHook.thereWereErrors);
assert(a <= Checked!(uint, MyHook2)(uint(-42)));
assert(MyHook.thereWereErrors);
}
@safe unittest
{
import std.checkedint;
static struct MyHook
{
static bool thereWereErrors;
static L hookOpUnary(string x, L)(L lhs)
{
if (x == "-" && lhs == -lhs) thereWereErrors = true;
return -lhs;
}
}
auto a = checked!MyHook(long.min);
assert(a == -a);
assert(MyHook.thereWereErrors);
auto b = checked!void(42);
assert(++b == 43);
}
@safe unittest
{
import std.checkedint;
static struct MyHook
{
static bool thereWereErrors;
static T onLowerBound(Rhs, T)(Rhs rhs, T bound)
{
thereWereErrors = true;
return bound;
}
static T onUpperBound(Rhs, T)(Rhs rhs, T bound)
{
thereWereErrors = true;
return bound;
}
}
auto x = checked!MyHook(byte.min);
x -= 1;
assert(MyHook.thereWereErrors);
MyHook.thereWereErrors = false;
x = byte.max;
x += 1;
assert(MyHook.thereWereErrors);
}
@safe @nogc pure nothrow unittest
{
import std.checkedint;
// Hook that ignores all problems.
static struct Ignore
{
@nogc nothrow pure @safe static:
Dst onBadCast(Dst, Src)(Src src) { return cast(Dst) src; }
Lhs onLowerBound(Rhs, T)(Rhs rhs, T bound) { return cast(T) rhs; }
T onUpperBound(Rhs, T)(Rhs rhs, T bound) { return cast(T) rhs; }
bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs) { return lhs == rhs; }
int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs) { return (lhs > rhs) - (lhs < rhs); }
typeof(~Lhs()) onOverflow(string x, Lhs)(ref Lhs lhs) { return mixin(x ~ "lhs"); }
typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs)
{
static if (x == "/")
return typeof(lhs / rhs).min;
else
return mixin("lhs" ~ x ~ "rhs");
}
}
auto x = Checked!(int, Ignore)(5) + 7;
}
@safe unittest
{
import std.checkedint;
static assert(is(typeof(checked(42)) == Checked!int));
assert(checked(42) == Checked!int(42));
static assert(is(typeof(checked!WithNaN(42)) == Checked!(int, WithNaN)));
assert(checked!WithNaN(42) == Checked!(int, WithNaN)(42));
}
@safe unittest
{
import std.checkedint;
void test(T)()
{
Checked!(int, Abort) x;
x = 42;
auto x1 = cast(T) x;
assert(x1 == 42);
//x1 += long(int.max);
}
test!short;
test!(const short);
test!(immutable short);
}
@safe unittest
{
import std.checkedint;
void test(T)()
{
Checked!(int, Throw) x;
x = 42;
auto x1 = cast(T) x;
assert(x1 == 42);
x = T.max + 1;
import std.exception : assertThrown, assertNotThrown;
assertThrown(cast(T) x);
x = x.max;
assertThrown(x += 42);
assertThrown(x += 42L);
x = x.min;
assertThrown(-x);
assertThrown(x -= 42);
assertThrown(x -= 42L);
x = -1;
assertNotThrown(x == -1);
assertThrown(x == uint(-1));
assertNotThrown(x <= -1);
assertThrown(x <= uint(-1));
}
test!short;
test!(const short);
test!(immutable short);
}
@safe unittest
{
import std.checkedint;
auto x = checked!Warn(-42);
// Passes
assert(x == -42);
// Passes but prints a warning
// assert(x == uint(-42));
}
@safe unittest
{
import std.checkedint;
auto x = checked!Warn(-42);
// Passes
assert(x <= -42);
// Passes but prints a warning
// assert(x <= uint(-42));
}
@safe unittest
{
import std.checkedint;
auto x = checked!Warn(42);
short x1 = cast(short) x;
//x += long(int.max);
auto y = checked!Warn(cast(const int) 42);
short y1 = cast(const byte) y;
}
@safe unittest
{
import std.checkedint;
alias opEqualsProper = ProperCompare.hookOpEquals;
assert(opEqualsProper(42, 42));
assert(opEqualsProper(42.0, 42.0));
assert(opEqualsProper(42u, 42));
assert(opEqualsProper(42, 42u));
assert(-1 == 4294967295u);
assert(!opEqualsProper(-1, 4294967295u));
assert(!opEqualsProper(const uint(-1), -1));
assert(!opEqualsProper(uint(-1), -1.0));
assert(3_000_000_000U == -1_294_967_296);
assert(!opEqualsProper(3_000_000_000U, -1_294_967_296));
}
@safe unittest
{
import std.checkedint;
auto x = checked!WithNaN(422);
assert((cast(ubyte) x) == 255);
x = checked!WithNaN(-422);
assert((cast(byte) x) == -128);
assert(cast(short) x == -422);
assert(cast(bool) x);
x = x.init; // set back to NaN
assert(x != true);
assert(x != false);
}
@safe unittest
{
import std.checkedint;
Checked!(int, WithNaN) x;
assert(!(x < 0) && !(x > 0) && !(x == 0));
x = 1;
assert(x > 0 && !(x < 0) && !(x == 0));
}
@safe unittest
{
import std.checkedint;
Checked!(int, WithNaN) x;
++x;
assert(x.isNaN);
x = 1;
assert(!x.isNaN);
x = -x;
++x;
assert(!x.isNaN);
}
@safe unittest
{
import std.checkedint;
Checked!(int, WithNaN) x;
assert((x + 1).isNaN);
x = 100;
assert(!(x + 1).isNaN);
}
@safe unittest
{
import std.checkedint;
Checked!(int, WithNaN) x;
assert((1 + x).isNaN);
x = 100;
assert(!(1 + x).isNaN);
}
@safe unittest
{
import std.checkedint;
Checked!(int, WithNaN) x;
x += 4;
assert(x.isNaN);
x = 0;
x += 4;
assert(!x.isNaN);
x += int.max;
assert(x.isNaN);
}
@safe unittest
{
import std.checkedint;
auto x1 = Checked!(int, WithNaN)();
assert(x1.isNaN);
assert(x1.get == int.min);
assert(x1 != x1);
assert(!(x1 < x1));
assert(!(x1 > x1));
assert(!(x1 == x1));
++x1;
assert(x1.isNaN);
assert(x1.get == int.min);
--x1;
assert(x1.isNaN);
assert(x1.get == int.min);
x1 = 42;
assert(!x1.isNaN);
assert(x1 == x1);
assert(x1 <= x1);
assert(x1 >= x1);
static assert(x1.min == int.min + 1);
x1 += long(int.max);
}
@safe unittest
{
import std.checkedint;
auto x1 = Checked!(int, WithNaN)();
assert(x1.isNaN);
x1 = 1;
assert(!x1.isNaN);
x1 = x1.init;
assert(x1.isNaN);
}
@safe unittest
{
import std.checkedint;
auto x = checked!Saturate(short(100));
x += 33000;
assert(x == short.max);
x -= 70000;
assert(x == short.min);
}
@safe unittest
{
import std.checkedint;
assert(checked!Saturate(int.max) + 1 == int.max);
assert(checked!Saturate(100) ^^ 10 == int.max);
assert(checked!Saturate(-100) ^^ 10 == int.max);
assert(checked!Saturate(100) / 0 == int.max);
assert(checked!Saturate(100) << -1 == 0);
assert(checked!Saturate(100) << 33 == int.max);
assert(checked!Saturate(100) >> -1 == int.max);
assert(checked!Saturate(100) >> 33 == 0);
}
@safe unittest
{
import std.checkedint;
auto x = checked!Saturate(int.max);
++x;
assert(x == int.max);
--x;
assert(x == int.max - 1);
x = int.min;
assert(-x == int.max);
x -= 42;
assert(x == int.min);
assert(x * -2 == int.max);
}
@safe unittest
{
import std.checkedint;
bool overflow;
assert(opChecked!"+"(const short(1), short(1), overflow) == 2 && !overflow);
assert(opChecked!"+"(1, 1, overflow) == 2 && !overflow);
assert(opChecked!"+"(1, 1u, overflow) == 2 && !overflow);
assert(opChecked!"+"(-1, 1u, overflow) == 0 && !overflow);
assert(opChecked!"+"(1u, -1, overflow) == 0 && !overflow);
}
@safe unittest
{
import std.checkedint;
bool overflow;
assert(opChecked!"-"(1, 1, overflow) == 0 && !overflow);
assert(opChecked!"-"(1, 1u, overflow) == 0 && !overflow);
assert(opChecked!"-"(1u, -1, overflow) == 2 && !overflow);
assert(opChecked!"-"(-1, 1u, overflow) == 0 && overflow);
}
@safe unittest
{
import std.checkedint;
struct MyHook
{
static size_t hookToHash(T)(const T payload) nothrow @trusted
{
return .hashOf(payload);
}
}
int[Checked!(int, MyHook)] aa;
Checked!(int, MyHook) var = 42;
aa[var] = 100;
assert(aa[var] == 100);
int[Checked!(int, Abort)] bb;
Checked!(int, Abort) var2 = 42;
bb[var2] = 100;
assert(bb[var2] == 100);
}