We omit type checks for performance reasons in most places currently, so the library grouping is important in showing people what to use for what sort of input. The moved functions make sense to use with floats as well, so we'll move them to the num library. Some of the remaining functions could theoretically be adapted and moved, but aren't for now. Change-Id: Ifdecaa60be594f4438b2a58b9ea6445e2da080e3 Reviewed-on: https://cl.tvl.fyi/c/depot/+/9007 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
455 lines
6.8 KiB
Nix
455 lines
6.8 KiB
Nix
{ depot, lib, ... }:
|
|
|
|
let
|
|
|
|
inherit (depot.nix.runTestsuite)
|
|
runTestsuite
|
|
it
|
|
assertEq
|
|
;
|
|
|
|
inherit (depot.users.sterni.nix)
|
|
int
|
|
string
|
|
fun
|
|
;
|
|
|
|
testBounds = it "checks minBound and maxBound" [
|
|
(assertEq "maxBound is the maxBound" true
|
|
(int.maxBound + 1 < int.maxBound))
|
|
(assertEq "minBound is the minBound" true
|
|
(int.minBound - 1 > int.minBound))
|
|
(assertEq "maxBound overflows to minBound"
|
|
(int.maxBound + 1)
|
|
int.minBound)
|
|
(assertEq "minBound overflows to maxBound"
|
|
(int.minBound - 1)
|
|
int.maxBound)
|
|
];
|
|
|
|
expectedBytes = [
|
|
"00"
|
|
"01"
|
|
"02"
|
|
"03"
|
|
"04"
|
|
"05"
|
|
"06"
|
|
"07"
|
|
"08"
|
|
"09"
|
|
"0A"
|
|
"0B"
|
|
"0C"
|
|
"0D"
|
|
"0E"
|
|
"0F"
|
|
"10"
|
|
"11"
|
|
"12"
|
|
"13"
|
|
"14"
|
|
"15"
|
|
"16"
|
|
"17"
|
|
"18"
|
|
"19"
|
|
"1A"
|
|
"1B"
|
|
"1C"
|
|
"1D"
|
|
"1E"
|
|
"1F"
|
|
"20"
|
|
"21"
|
|
"22"
|
|
"23"
|
|
"24"
|
|
"25"
|
|
"26"
|
|
"27"
|
|
"28"
|
|
"29"
|
|
"2A"
|
|
"2B"
|
|
"2C"
|
|
"2D"
|
|
"2E"
|
|
"2F"
|
|
"30"
|
|
"31"
|
|
"32"
|
|
"33"
|
|
"34"
|
|
"35"
|
|
"36"
|
|
"37"
|
|
"38"
|
|
"39"
|
|
"3A"
|
|
"3B"
|
|
"3C"
|
|
"3D"
|
|
"3E"
|
|
"3F"
|
|
"40"
|
|
"41"
|
|
"42"
|
|
"43"
|
|
"44"
|
|
"45"
|
|
"46"
|
|
"47"
|
|
"48"
|
|
"49"
|
|
"4A"
|
|
"4B"
|
|
"4C"
|
|
"4D"
|
|
"4E"
|
|
"4F"
|
|
"50"
|
|
"51"
|
|
"52"
|
|
"53"
|
|
"54"
|
|
"55"
|
|
"56"
|
|
"57"
|
|
"58"
|
|
"59"
|
|
"5A"
|
|
"5B"
|
|
"5C"
|
|
"5D"
|
|
"5E"
|
|
"5F"
|
|
"60"
|
|
"61"
|
|
"62"
|
|
"63"
|
|
"64"
|
|
"65"
|
|
"66"
|
|
"67"
|
|
"68"
|
|
"69"
|
|
"6A"
|
|
"6B"
|
|
"6C"
|
|
"6D"
|
|
"6E"
|
|
"6F"
|
|
"70"
|
|
"71"
|
|
"72"
|
|
"73"
|
|
"74"
|
|
"75"
|
|
"76"
|
|
"77"
|
|
"78"
|
|
"79"
|
|
"7A"
|
|
"7B"
|
|
"7C"
|
|
"7D"
|
|
"7E"
|
|
"7F"
|
|
"80"
|
|
"81"
|
|
"82"
|
|
"83"
|
|
"84"
|
|
"85"
|
|
"86"
|
|
"87"
|
|
"88"
|
|
"89"
|
|
"8A"
|
|
"8B"
|
|
"8C"
|
|
"8D"
|
|
"8E"
|
|
"8F"
|
|
"90"
|
|
"91"
|
|
"92"
|
|
"93"
|
|
"94"
|
|
"95"
|
|
"96"
|
|
"97"
|
|
"98"
|
|
"99"
|
|
"9A"
|
|
"9B"
|
|
"9C"
|
|
"9D"
|
|
"9E"
|
|
"9F"
|
|
"A0"
|
|
"A1"
|
|
"A2"
|
|
"A3"
|
|
"A4"
|
|
"A5"
|
|
"A6"
|
|
"A7"
|
|
"A8"
|
|
"A9"
|
|
"AA"
|
|
"AB"
|
|
"AC"
|
|
"AD"
|
|
"AE"
|
|
"AF"
|
|
"B0"
|
|
"B1"
|
|
"B2"
|
|
"B3"
|
|
"B4"
|
|
"B5"
|
|
"B6"
|
|
"B7"
|
|
"B8"
|
|
"B9"
|
|
"BA"
|
|
"BB"
|
|
"BC"
|
|
"BD"
|
|
"BE"
|
|
"BF"
|
|
"C0"
|
|
"C1"
|
|
"C2"
|
|
"C3"
|
|
"C4"
|
|
"C5"
|
|
"C6"
|
|
"C7"
|
|
"C8"
|
|
"C9"
|
|
"CA"
|
|
"CB"
|
|
"CC"
|
|
"CD"
|
|
"CE"
|
|
"CF"
|
|
"D0"
|
|
"D1"
|
|
"D2"
|
|
"D3"
|
|
"D4"
|
|
"D5"
|
|
"D6"
|
|
"D7"
|
|
"D8"
|
|
"D9"
|
|
"DA"
|
|
"DB"
|
|
"DC"
|
|
"DD"
|
|
"DE"
|
|
"DF"
|
|
"E0"
|
|
"E1"
|
|
"E2"
|
|
"E3"
|
|
"E4"
|
|
"E5"
|
|
"E6"
|
|
"E7"
|
|
"E8"
|
|
"E9"
|
|
"EA"
|
|
"EB"
|
|
"EC"
|
|
"ED"
|
|
"EE"
|
|
"EF"
|
|
"F0"
|
|
"F1"
|
|
"F2"
|
|
"F3"
|
|
"F4"
|
|
"F5"
|
|
"F6"
|
|
"F7"
|
|
"F8"
|
|
"F9"
|
|
"FA"
|
|
"FB"
|
|
"FC"
|
|
"FD"
|
|
"FE"
|
|
"FF"
|
|
];
|
|
|
|
hexByte = i: string.fit { width = 2; char = "0"; } (int.toHex i);
|
|
|
|
hexInts = [
|
|
{ left = 0; right = "0"; }
|
|
{ left = 1; right = "1"; }
|
|
{ left = 11; right = "B"; }
|
|
{ left = 123; right = "7B"; }
|
|
{ left = 9000; right = "2328"; }
|
|
{ left = 2323; right = "913"; }
|
|
{ left = 4096; right = "1000"; }
|
|
{ left = int.maxBound; right = "7FFFFFFFFFFFFFFF"; }
|
|
{ left = int.minBound; right = "-8000000000000000"; }
|
|
];
|
|
|
|
testHex = it "checks conversion to hex" (lib.flatten [
|
|
(lib.imap0
|
|
(i: hex: [
|
|
(assertEq "hexByte ${toString i} == ${hex}" (hexByte i) hex)
|
|
(assertEq "${toString i} == fromHex ${hex}" i (int.fromHex hex))
|
|
])
|
|
expectedBytes)
|
|
(builtins.map
|
|
({ left, right }: [
|
|
(assertEq "toHex ${toString left} == ${right}" (int.toHex left) right)
|
|
(assertEq "${toString left} == fromHex ${right}" left (int.fromHex right))
|
|
])
|
|
hexInts)
|
|
]);
|
|
|
|
testBasic = it "checks basic int operations" [
|
|
(assertEq "122 is even" (int.even 122 && !(int.odd 122)) true)
|
|
(assertEq "123 is odd" (int.odd 123 && !(int.even 123)) true)
|
|
];
|
|
|
|
expNumbers = [
|
|
{ left = -3; right = 0.125; }
|
|
{ left = -2; right = 0.25; }
|
|
{ left = -1; right = 0.5; }
|
|
{ left = 0; right = 1; }
|
|
{ left = 1; right = 2; }
|
|
{ left = 2; right = 4; }
|
|
{ left = 3; right = 8; }
|
|
{ left = 4; right = 16; }
|
|
{ left = 5; right = 32; }
|
|
{ left = 16; right = 65536; }
|
|
];
|
|
|
|
testExp = it "checks exponentiation"
|
|
(builtins.map
|
|
({ left, right }:
|
|
assertEq
|
|
"2 ^ ${toString left} == ${toString right}"
|
|
(int.exp 2 left)
|
|
right)
|
|
expNumbers);
|
|
|
|
shifts = [
|
|
{ a = 2; b = 5; c = 64; op = "<<"; }
|
|
{ a = -2; b = 5; c = -64; op = "<<"; }
|
|
{ a = 123; b = 4; c = 1968; op = "<<"; }
|
|
{ a = 1; b = 8; c = 256; op = "<<"; }
|
|
{ a = 256; b = 8; c = 1; op = ">>"; }
|
|
{ a = 374; b = 2; c = 93; op = ">>"; }
|
|
{ a = 2; b = 2; c = 0; op = ">>"; }
|
|
{ a = 99; b = 9; c = 0; op = ">>"; }
|
|
];
|
|
|
|
checkShift = { a, b, c, op }@args:
|
|
let
|
|
f = string.match op {
|
|
"<<" = int.bitShiftL;
|
|
">>" = int.bitShiftR;
|
|
};
|
|
in
|
|
assertEq "${toString a} ${op} ${toString b} == ${toString c}" (f a b) c;
|
|
|
|
checkShiftRDivExp = n:
|
|
assertEq "${toString n} >> 5 == ${toString n} / 2 ^ 5"
|
|
(int.bitShiftR n 5)
|
|
(int.div n (int.exp 2 5));
|
|
|
|
checkShiftLMulExp = n:
|
|
assertEq "${toString n} >> 6 == ${toString n} * 2 ^ 6"
|
|
(int.bitShiftL n 5)
|
|
(n * (int.exp 2 5));
|
|
|
|
testBit = it "checks bitwise operations" (lib.flatten [
|
|
(builtins.map checkShift shifts)
|
|
(builtins.map checkShiftRDivExp [
|
|
1
|
|
2
|
|
3
|
|
5
|
|
7
|
|
23
|
|
1623
|
|
238
|
|
34
|
|
348
|
|
2834
|
|
834
|
|
348
|
|
])
|
|
(builtins.map checkShiftLMulExp [
|
|
1
|
|
2
|
|
3
|
|
5
|
|
7
|
|
23
|
|
384
|
|
3
|
|
2
|
|
5991
|
|
85109
|
|
38
|
|
])
|
|
]);
|
|
|
|
divisions = [
|
|
{ a = 2; b = 1; c = 2; mod = 0; }
|
|
{ a = 2; b = 2; c = 1; mod = 0; }
|
|
{ a = 20; b = 10; c = 2; mod = 0; }
|
|
{ a = 12; b = 5; c = 2; mod = 2; }
|
|
{ a = 23; b = 4; c = 5; mod = 3; }
|
|
];
|
|
|
|
checkDiv = n: { a, b, c, mod }: [
|
|
(assertEq "${n}: div result" (int.div a b) c)
|
|
(assertEq "${n}: mod result" (int.mod a b) mod)
|
|
(assertEq "${n}: divMod law" ((int.div a b) * b + (int.mod a b)) a)
|
|
];
|
|
|
|
testDivMod = it "checks integer division and modulo"
|
|
(lib.flatten [
|
|
(builtins.map (checkDiv "+a / +b") divisions)
|
|
(builtins.map
|
|
(fun.rl (checkDiv "-a / +b") (x: x // {
|
|
a = -x.a;
|
|
c = -x.c;
|
|
mod = -x.mod;
|
|
}))
|
|
divisions)
|
|
(builtins.map
|
|
(fun.rl (checkDiv "+a / -b") (x: x // {
|
|
b = -x.b;
|
|
c = -x.c;
|
|
}))
|
|
divisions)
|
|
(builtins.map
|
|
(fun.rl (checkDiv "-a / -b") (x: x // {
|
|
a = -x.a;
|
|
b = -x.b;
|
|
mod = -x.mod;
|
|
}))
|
|
divisions)
|
|
]);
|
|
|
|
in
|
|
runTestsuite "nix.int" [
|
|
testBounds
|
|
testHex
|
|
testBasic
|
|
testExp
|
|
testBit
|
|
testDivMod
|
|
]
|