use Test:ver<6.c+>;
plan 7;

use Base64;


subtest 'Encode' => {
    is encode-base64("", :str), '', 'Encoding the empty string';
    is encode-base64("A", :str), 'QQ==', 'Encoding "A"';
    is encode-base64("Ab", :str), 'QWI=', 'Encoding "Ab"';
    is encode-base64("Abc", :str), 'QWJj', 'Encoding "Abc"';
    is encode-base64("Abcd", :str), 'QWJjZA==', 'Encoding "Abcd"';
    is encode-base64("Perl", :str), 'UGVybA==', 'Encoding "Perl"';
    is encode-base64("Perl6", :str), 'UGVybDY=', 'Encoding "Perl6"';
    is encode-base64("Another test!", :str), 'QW5vdGhlciB0ZXN0IQ==', 'Encoding "Another test!"';
    is encode-base64("username:thisisnotmypassword", :str), 'dXNlcm5hbWU6dGhpc2lzbm90bXlwYXNzd29yZA==', 'Encoding "username:thisisnotmypassword"';
    is encode-base64(Buf.new(0), :str), 'AA==', 'encode Test on NULL/0 byte';
    is encode-base64(Buf.new(1), :str), 'AQ==', 'encode Test on byte value 1';
    is encode-base64(Buf.new(255), :str), '/w==', 'encode Test on byte value 255';
    is encode-base64(Buf.new(<1 1>), :str), 'AQE=', 'encode Test on bytes, value 1 1';
    is encode-base64(Blob.new(0), :str), 'AA==', 'encode Test on NULL/0 immutable byte';
    is encode-base64(Blob.new(1), :str), 'AQ==', 'encode Test on immutable byte value 1';
    is encode-base64(Blob.new(255), :str), '/w==', 'encode Test on immutable byte value 255';
    is encode-base64(Blob.new(<1 1>), :str), 'AQE=', 'encode Test on immutable bytes, value 1 1';
}

subtest 'Decode' => {
    is decode-base64("", :bin).decode, "\x0", 'decoding the empty string';
    is decode-base64("QQ==", :bin).decode, 'A', 'decoding "A"';
    is decode-base64("QWI=", :bin).decode, 'Ab', 'decoding "Ab"';
    is decode-base64("QWJj", :bin).decode, "Abc", 'decoding "Abc"';
    is decode-base64("QWJjZA==", :bin).decode, "Abcd", 'decoding "Abcd"';
    is decode-base64("UGVybA==", :bin).decode, "Perl", 'decoding "Perl"';
    is decode-base64("UGVybDY=", :bin).decode, "Perl6", 'decoding "Perl6"';
    is decode-base64("UGVy\nbDY=", :bin).decode, "Perl6", 'decoding "Perl6 with invalid b64 character"';
    is decode-base64("QW5vdGhlciB0ZXN0IQ==", :bin).decode, "Another test!", 'decoding "Another test!"';
    is decode-base64("dXNlcm5hbWU6dGhpc2lzbm90bXlwYXNzd29yZA==", :bin).decode, "username:thisisnotmypassword", 'decoding "username:thisisnotmypassword"';
    is-deeply decode-base64("AA==", :bin), Buf.new(0), 'decode Test on NULL/0 byte';
    is-deeply decode-base64("AQ==", :bin), Buf.new(1), 'decode Test on byte value 1';
    is-deeply decode-base64("/w==", :bin), Buf.new(255), 'decode Test on byte value 255';
    is-deeply decode-base64("AQE=", :bin), Buf.new(<1 1>), 'decode Test on bytes value 1 1';
}

subtest {
    is encode-base64( decode-base64("w0OfABDTw0Of", :bin) , :str ), "w0OfABDTw0Of", "decoded then re-encoded value equals to origianl one, with A in first position of a 4 characters group";
}

subtest {
    is encode-base64("test", :str, :pad), "dGVzdA==";
    is encode-base64("test", :str, :!pad), "dGVzdAAA";
}

subtest 'RFC 3548' => {
    is encode-base64("\x14\xfb\x9c\x03\xd9\x7e", :str), "FPucA9l+";
    is encode-base64("\x14\xfb\x9c\x03\xd9", :str),     "FPucA9k=";
    is encode-base64("\x14\xfb\x9c\x03", :str),         "FPucAw==";
}

subtest 'RFC 4648' => {
    my %from-to = :f<Zg==>, :fo<Zm8=>, :foo<Zm9v>, :foob<Zm9vYg==>, :fooba<Zm9vYmE=>, :foobar<Zm9vYmFy>;
    %from-to.pairs.map: {is encode-base64($_.key, :str), $_.value; }
}

subtest 'Currupt/invalid encodings' => {
    my @invalid = <!!!! ==== =AAA A=AA AA=A AA==A AAA=AAAA AAAAA AAAAAA A= A== AA= AA== AAA= AAAA AAAAAA=>;
    @invalid.map: { is-deeply decode-base64($_, :uri).grep( * > 0 ).elems , 0 }
}
