tvl-depot/users/sterni/nix/int/tests/default.nix
sterni 81fc87e29e refactor(nix/sterni/int): rename div & mod to quot & rem
This mirrors the terminology Haskell uses: quot and rem truncate towards
zero which is also the case for builtins.div. We can give us the option
to introduce Haskell-style int.div and int.mod (to complete the
confusion) which would truncate towards negative infinity.

Change-Id: Ibebb0a01a73c9718cd62121b2fc2a19c3a4be0de
Reviewed-on: https://cl.tvl.fyi/c/depot/+/9009
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
2023-08-09 12:12:47 +00:00

455 lines
6.9 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)
(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; rem = 0; }
{ a = 2; b = 2; c = 1; rem = 0; }
{ a = 20; b = 10; c = 2; rem = 0; }
{ a = 12; b = 5; c = 2; rem = 2; }
{ a = 23; b = 4; c = 5; rem = 3; }
];
checkQuot = n: { a, b, c, rem }: [
(assertEq "${n}: quot result" (int.quot a b) c)
(assertEq "${n}: rem result" (int.rem a b) rem)
(assertEq "${n}: quotRem law" ((int.quot a b) * b + (int.rem a b)) a)
];
testQuotRem = it "checks integer quotient and remainder"
(lib.flatten [
(builtins.map (checkQuot "+a / +b") divisions)
(builtins.map
(fun.rl (checkQuot "-a / +b") (x: x // {
a = -x.a;
c = -x.c;
rem = -x.rem;
}))
divisions)
(builtins.map
(fun.rl (checkQuot "+a / -b") (x: x // {
b = -x.b;
c = -x.c;
}))
divisions)
(builtins.map
(fun.rl (checkQuot "-a / -b") (x: x // {
a = -x.a;
b = -x.b;
rem = -x.rem;
}))
divisions)
]);
in
runTestsuite "nix.int" [
testBounds
testHex
testBasic
testExp
testBit
testQuotRem
]