### ----------------------------------------------------
### -- CBOR::Simple
### -- Licenses: Artistic-2.0
### -- Authors: Geoffrey Broadwell
### -- File: t/06-typed-arrays.rakutest
### ----------------------------------------------------
use Test;
use lib $*PROGRAM.sibling('lib');
use CodecMatches;

use CBOR::Simple;


plan 36;


### Tests for RFC 8746 typed arrays (https://www.rfc-editor.org/rfc/rfc8746.html)


# DECODE BOTH BIG AND LITTLE ENDIAN ON ANY HOST
# diag "Testing bi-endian decoding";

# num32/num64/num
my $num32-empty-be = 'd85140';
my $num32-empty-le = 'd85540';
my $num64-empty-be = 'd85240';
my $num64-empty-le = 'd85640';
decodes-to array[num32].new(), $_ for $num32-empty-be, $num32-empty-le;
decodes-to array[num64].new(), $_ for $num64-empty-be, $num64-empty-le;

my $num32-basic    = array[num32].new(Inf, -Inf, NaN, 0.0e0, -0.0e0, 1.0e0, 100000e0);
my $num32-basic-be = 'd851581c7f800000ff8000007fc00000'
                   ~ '00000000800000003f80000047c35000';
my $num32-basic-le = 'd855581c0000807f000080ff0000c07f'
                   ~ '00000000000000800000803f0050c347';
decodes-to $num32-basic, $_ for $num32-basic-be, $num32-basic-le;

my $num64-basic    = array[num64].new(Inf, -Inf, NaN, 0.0e0, -0.0e0, 1.1e0, 1.0e+300);
my $num-basic      = array[num  ].new(Inf, -Inf, NaN, 0.0e0, -0.0e0, 1.1e0, 1.0e+300);
my $num64-basic-be = 'd85258387ff0000000000000fff0000000000000'
                   ~ '7ff800000000000000000000000000008000000000000000'
                   ~ '3ff199999999999a7e37e43c8800759c';
my $num64-basic-le = 'd8565838000000000000f07f000000000000f0ff'
                   ~ '000000000000f87f00000000000000000000000000000080'
                   ~ '9a9999999999f13f9c7500883ce4377e';
decodes-to $num64-basic, $_ for $num64-basic-be, $num64-basic-le;


# int64/uint64/int/uint
my $int64-basic    = array[int64].new(-9223372036854775808, -9223372036854775807,
                                      -4294967297, -4294967296, -4294967295,
                                      -2147483649, -2147483648, -2147483647,
                                      0, 2147483646, 2147483647, 2147483648,
                                      4294967294, 4294967295, 4294967296,
                                      9223372036854775806, 9223372036854775807);
my $int-basic      = array[int  ].new(-9223372036854775808, -9223372036854775807,
                                      -4294967297, -4294967296, -4294967295,
                                      -2147483649, -2147483648, -2147483647,
                                      0, 2147483646, 2147483647, 2147483648,
                                      4294967294, 4294967295, 4294967296,
                                      9223372036854775806, 9223372036854775807);
my $int64-basic-be = 'd84b588880000000000000008000000000000001fffffffeffffffff'
                   ~ 'ffffffff00000000ffffffff00000001ffffffff7fffffff'
                   ~ 'ffffffff80000000ffffffff800000010000000000000000'
                   ~ '000000007ffffffe000000007fffffff0000000080000000'
                   ~ '00000000fffffffe00000000ffffffff0000000100000000'
                   ~ '7ffffffffffffffe7fffffffffffffff';
my $int64-basic-le = 'd84f588800000000000000800100000000000080fffffffffeffffff'
                   ~ '00000000ffffffff01000000ffffffffffffff7fffffffff'
                   ~ '00000080ffffffff01000080ffffffff0000000000000000'
                   ~ 'feffff7f00000000ffffff7f000000000000008000000000'
                   ~ 'feffffff00000000ffffffff000000000000000001000000'
                   ~ 'feffffffffffff7fffffffffffffff7f';
decodes-to $int64-basic, $_ for $int64-basic-be, $int64-basic-le;

# XXXX: Rakudo only handles 63-bit native uints properly, not full 64-bit natives
my $uint64-basic = array[uint64].new(0, 2147483646, 2147483647, 2147483648,
                                     4294967294, 4294967295, 4294967296,
                                     9223372036854775806, 9223372036854775807);
                                   # 9223372036854775808, 18446744073709551614,
                                   # 18446744073709551615);
my $uint-basic   = array[uint  ].new(0, 2147483646, 2147483647, 2147483648,
                                     4294967294, 4294967295, 4294967296,
                                     9223372036854775806, 9223372036854775807);
                                   # 9223372036854775808, 18446744073709551614,
                                   # 18446744073709551615);
my $uint64-basic-be = 'd84358480000000000000000000000007ffffffe000000007fffffff'
                    ~ '000000008000000000000000fffffffe00000000ffffffff'
                    ~ '00000001000000007ffffffffffffffe7fffffffffffffff';
my $uint64-basic-le = 'd84758480000000000000000feffff7f00000000ffffff7f00000000'
                    ~ '0000008000000000feffffff00000000ffffffff00000000'
                    ~ '0000000001000000feffffffffffff7fffffffffffffff7f';
decodes-to $uint64-basic, $_ for $uint64-basic-be, $uint64-basic-le;


# int32/uint32
my $int32-basic    = array[int32].new(-2147483648, -2147483647, -65537, -65536,
                                      -65535, -32769, -32768, -32767, -256,
                                      -255, -254, -129, -128, -127, -1, 0, 1,
                                      126, 127, 128, 129, 254, 255, 256, 32766,
                                      32767, 32768, 32769, 65534, 65535, 65536,
                                      65537, 2147483646, 2147483647);
my $int32-basic-be = 'd84a58888000000080000001fffeffffffff0000ffff0001ffff7fff'
                   ~ 'ffff8000ffff8001ffffff00ffffff01ffffff02ffffff7fffffff80'
                   ~ 'ffffff81ffffffff00000000000000010000007e0000007f00000080'
                   ~ '00000081000000fe000000ff0000010000007ffe00007fff00008000'
                   ~ '000080010000fffe0000ffff00010000000100017ffffffe7fffffff';
my $int32-basic-le = 'd84e58880000008001000080fffffeff0000ffff0100ffffff7fffff'
                   ~ '0080ffff0180ffff00ffffff01ffffff02ffffff7fffffff80ffffff'
                   ~ '81ffffffffffffff00000000010000007e0000007f00000080000000'
                   ~ '81000000fe000000ff00000000010000fe7f0000ff7f000000800000'
                   ~ '01800000feff0000ffff00000000010001000100feffff7fffffff7f';
decodes-to $int32-basic, $_ for $int32-basic-be, $int32-basic-le;

my $uint32-basic    = array[uint32].new(0, 1, 126, 127, 128, 129, 254, 255,
                                        256, 32766, 32767, 32768, 32769, 65534,
                                        65535, 65536, 65537, 2147483647,
                                        2147483648, 2147483649, 4294967294,
                                        4294967295);
my $uint32-basic-be = 'd842585800000000000000010000007e0000007f0000008000000081'
                    ~ '000000fe000000ff0000010000007ffe00007fff0000800000008001'
                    ~ '0000fffe0000ffff00010000000100017fffffff8000000080000001'
                    ~ 'fffffffeffffffff';
my $uint32-basic-le = 'd846585800000000010000007e0000007f0000008000000081000000'
                    ~ 'fe000000ff00000000010000fe7f0000ff7f00000080000001800000'
                    ~ 'feff0000ffff00000000010001000100ffffff7f0000008001000080'
                    ~ 'feffffffffffffff';
decodes-to $uint32-basic, $_ for $uint32-basic-be, $uint32-basic-le;


# int16/uint16
my $int16-basic    = array[int16].new(-32768, -32767, -256, -255, -254, -129,
                                      -128, -127, -1, 0, 1, 126, 127, 128, 129,
                                      254, 255, 256, 32766, 32767);
my $int16-basic-be = 'd849582880008001ff00ff01ff02ff7fff80ff81ffff00000001007e'
                   ~ '007f0080008100fe00ff01007ffe7fff';
my $int16-basic-le = 'd84d58280080018000ff01ff02ff7fff80ff81ffffff000001007e00'
                   ~ '7f0080008100fe00ff000001fe7fff7f';
decodes-to $int16-basic, $_ for $int16-basic-be, $int16-basic-le;

my $uint16-basic    = array[uint16].new(0, 1, 126, 127, 128, 129, 254, 255,
                                        256, 32766, 32767, 32768, 65534, 65535);
my $uint16-basic-be = 'd841581c00000001007e007f0080008100fe00ff'
                    ~ '01007ffe7fff8000fffeffff';
my $uint16-basic-le = 'd845581c000001007e007f0080008100fe00ff00'
                    ~ '0001fe7fff7f0080feffffff';
decodes-to $uint16-basic, $_ for $uint16-basic-be, $uint16-basic-le;


# TEST 8-BIT ENDIAN-AGNOSTIC ARRAYS

# int8/uint8/byte
my $uint8-basic    = array[uint8].new(0, 1, 126, 127, 128, 129, 254, 255);
my $byte-basic     = array[byte ].new(0, 1, 126, 127, 128, 129, 254, 255);
my $int8-basic     = array[int8 ].new(-128, -127, -1, 0, 1, 42, 126, 127);
my $uint8-basic-ne = 'd8404800017e7f8081feff';
my $int8-basic-ne  = 'd848488081ff00012a7e7f';
matches $uint8-basic, $uint8-basic-ne;
matches $int8-basic,  $int8-basic-ne;

encodes-to $byte-basic, $uint8-basic-ne;


# TEST FOR APPROPRIATE NATIVE ENDIAN ENCODING

if Kernel.endian == BigEndian {
    # diag "Testing BigEndian native encoding";
    encodes-to array[num32].new(), $num32-empty-be;
    encodes-to array[num64].new(), $num64-empty-be;
    encodes-to $num32-basic,       $num32-basic-be;
    encodes-to $num64-basic,       $num64-basic-be;
    encodes-to $num-basic,         $num64-basic-be;

    encodes-to $int16-basic,       $int16-basic-be;
    encodes-to $int32-basic,       $int32-basic-be;
    encodes-to $int64-basic,       $int64-basic-be;
    encodes-to $int-basic,         $int64-basic-be;
    encodes-to $uint16-basic,      $uint16-basic-be;
    encodes-to $uint32-basic,      $uint32-basic-be;
    encodes-to $uint64-basic,      $uint64-basic-be;
    encodes-to $uint-basic,        $uint64-basic-be;
}
# LittleEndian Kernel
else {
    # diag "Testing LittleEndian native encoding";
    encodes-to array[num32].new(), $num32-empty-le;
    encodes-to array[num64].new(), $num64-empty-le;
    encodes-to $num32-basic,       $num32-basic-le;
    encodes-to $num64-basic,       $num64-basic-le;
    encodes-to $num-basic,         $num64-basic-le;

    encodes-to $int16-basic,       $int16-basic-le;
    encodes-to $int32-basic,       $int32-basic-le;
    encodes-to $int64-basic,       $int64-basic-le;
    encodes-to $int-basic,         $int64-basic-le;
    encodes-to $uint16-basic,      $uint16-basic-le;
    encodes-to $uint32-basic,      $uint32-basic-le;
    encodes-to $uint64-basic,      $uint64-basic-le;
    encodes-to $uint-basic,        $uint64-basic-le;
}


done-testing;


