]> git.ozlabs.org Git - ccan/blobdiff - ccan/base64/test/run.c
base64: implements rfc4648, the base64 encoding
[ccan] / ccan / base64 / test / run.c
diff --git a/ccan/base64/test/run.c b/ccan/base64/test/run.c
new file mode 100644 (file)
index 0000000..11045c8
--- /dev/null
@@ -0,0 +1,359 @@
+/* Start of run.c test */
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <ccan/base64/base64.h>
+#include <ccan/tap/tap.h>
+
+#include <ccan/base64/base64.c>
+#include "moretap.h"
+
+static void * xmalloc(size_t size);
+
+/* not defined in terms of test_encode_using_maps so we cross
+   appropriate paths in library */
+#define test_encode(src,srclen,expected)                       \
+       do {                                                    \
+               size_t destlen;                                 \
+               char * dest;                                    \
+               destlen = base64_encoded_length(srclen);        \
+               destlen++; /* null termination */               \
+               dest = xmalloc(destlen);                        \
+               ok1(base64_encode(dest,destlen,src,srclen) != -1);      \
+               is_str(dest,expected);                                  \
+               free(dest);                                             \
+       } while (0)
+
+#define test_encode_using_alphabet(alphastring,src,srclen,expected)    \
+       do {                                                            \
+               size_t destlen;                                         \
+               char * dest;                                            \
+               base64_maps_t maps;                             \
+               base64_init_maps(&maps,alphastring);            \
+               destlen = base64_encoded_length(srclen);                \
+               destlen++; /* null termination */               \
+               dest = xmalloc(destlen);                                \
+               ok1(base64_encode_using_maps(&maps,dest,destlen,src,srclen) != -1); \
+               is_str(dest,expected);                                  \
+               free(dest);                                             \
+       } while (0)
+
+/* not defined in terms of test_decode_using_alphabet so we cross
+   appropriate paths in library */
+#define test_decode(src,srclen,expected,expectedlen)                   \
+       do {                                                            \
+               size_t destlen;                                         \
+               size_t bytes_used;                                      \
+               char * dest;                                            \
+               destlen = base64_decoded_length(srclen);                \
+               dest = xmalloc(destlen);                                \
+               ok1((bytes_used = base64_decode(dest,destlen,src,srclen)) != -1); \
+               is_size_t(bytes_used,expectedlen);                      \
+               is_mem(dest,expected,bytes_used);                       \
+               free(dest);                                             \
+       } while (0)
+
+#define test_decode_using_alphabet(alphastring,src,srclen,expected,expectedlen) \
+       do {                                                            \
+               size_t destlen;                                         \
+               size_t bytes_used;                                      \
+               char * dest;                                            \
+               base64_maps_t maps;                             \
+                                                                       \
+               base64_init_maps(&maps,alphastring);            \
+               destlen = base64_decoded_length(srclen);                \
+               dest = xmalloc(destlen);                                \
+               ok1((bytes_used = base64_decode_using_maps(&maps,dest,destlen,src,srclen)) != -1); \
+               is_size_t(bytes_used,expectedlen);                      \
+               is_mem(dest,expected,bytes_used);                       \
+               free(dest);                                             \
+       } while (0)
+
+#define check_bad_range_decode(stuff_to_test,stufflen) \
+do {                                                   \
+       char dest[10];                                                  \
+       errno = 0;                                                      \
+       is_size_t(base64_decode(dest,sizeof(dest),stuff_to_test,(size_t)stufflen), \
+                 (size_t)-1);                                          \
+       is_int(errno,EDOM);                                             \
+} while (0)
+
+int
+main(int argc, char *argv[])
+{
+       plan_tests(131);
+
+       is_size_t(base64_encoded_length(0),(size_t)0);
+       is_size_t(base64_encoded_length(1),(size_t)4);
+       is_size_t(base64_encoded_length(2),(size_t)4);
+       is_size_t(base64_encoded_length(3),(size_t)4);
+       is_size_t(base64_encoded_length(512),(size_t)684);
+
+       /* straight from page 11 of http://tools.ietf.org/html/rfc4648 */
+       test_encode("",0,"");
+       test_encode("f",1,"Zg==");
+       test_encode("fo",2,"Zm8=");
+
+       test_encode("foo",3,"Zm9v");
+       test_encode("foob",4,"Zm9vYg==");
+       test_encode("fooba",5,"Zm9vYmE=");
+       test_encode("foobar",6,"Zm9vYmFy");
+
+       /* a few more */
+       test_encode("foobarb",7,"Zm9vYmFyYg==");
+       test_encode("foobarba",8,"Zm9vYmFyYmE=");
+       test_encode("foobarbaz",9,"Zm9vYmFyYmF6");
+
+       test_encode("foobart",7,"Zm9vYmFydA==");
+
+       test_encode("abcdefghijklmnopqrstuvwxyz",26,"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=");
+       test_encode("\x05\x05\x01\x00\x07",5,"BQUBAAc=");
+
+       test_encode("FOO",3,"Rk9P");
+       test_encode("Z",1,"Wg==");
+
+       /* decode testing */
+
+       test_decode("",0,"",0);
+       test_decode("Zg==",4,"f",1);
+       test_decode("Zm8=",4,"fo",2);
+       test_decode("Zm9v",4,"foo",3);
+       test_decode("Zm9vYg==",8,"foob",4);
+       test_decode("Zm9vYmE=",8,"fooba",5);
+       test_decode("Zm9vYmFy",8,"foobar",6);
+       test_decode("Zm9vYmFyYg==",12,"foobarb",7);
+       test_decode("Zm9vYmFyYmE=",12,"foobarba",8);
+       test_decode("Zm9vYmFyYmF6",12,"foobarbaz",9);
+
+       test_decode("Rk9P",4,"FOO",3);
+
+       test_decode("Wg==",4,"Z",1);
+       test_decode("AA==",4,"\0",1);
+       test_decode("AAA=",4,"\0\0",2);
+
+       {
+               const char *binary = "\x01\x00\x03";
+               const size_t binarylen = 3;
+
+               char * decoded;
+               char * encoded;
+               size_t encoded_len;
+               size_t decoded_len;
+               size_t decoded_space_required;
+
+               size_t encoded_space_required = base64_encoded_length(binarylen);
+               encoded_space_required++; /* null termination */
+               encoded = xmalloc(encoded_space_required);
+               encoded_len = base64_encode(encoded,encoded_space_required,binary,binarylen);
+               is_mem(encoded,"AQAD",encoded_len);
+
+               decoded_space_required = base64_decoded_length(encoded_len);
+               decoded = xmalloc(decoded_space_required);
+               decoded_len = base64_decode(decoded,decoded_space_required,encoded,encoded_len);
+               is_size_t(decoded_len,binarylen);
+               is_mem(binary,decoded,decoded_len);
+       }
+
+       /* some expected encode failures: */
+       {
+               size_t destlen = 1;
+               char dest[destlen];
+               errno = 0;
+               is_size_t(base64_encode(dest,destlen,"A",1),(size_t)-1);
+               is_int(errno,EOVERFLOW);
+       }
+
+       /* some expected decode failures: */
+       {
+               base64_maps_t maps;
+               const char * src = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+               base64_init_maps(&maps,src);
+
+               is_int(sixbit_from_b64(&maps,'\xfe'),(signed char)-1);
+               is_int(errno,EDOM);
+       }
+       {
+               size_t destlen = 10;
+               char dest[destlen];
+               errno = 0;
+               is_size_t(base64_decode(dest,destlen,"A",1),(size_t)-1);
+               is_int(errno,EINVAL);
+       }
+       {
+               size_t destlen = 1;
+               char dest[destlen];
+               errno = 0;
+               is_size_t(base64_decode(dest,destlen,"A",1),(size_t)-1);
+               is_int(errno,EOVERFLOW);
+       }
+       {
+               /* (char)1 is not a valid base64 character: */
+               check_bad_range_decode("A\x01",2);
+               /* (char)255 is not a valid base64 character: (char is signed on most platforms, so this is actually < 0 */
+               check_bad_range_decode("\xff""A",2);
+               check_bad_range_decode("A\xff",2);
+               check_bad_range_decode("AA\xff",3);
+               check_bad_range_decode("A\xff""A",3);
+               check_bad_range_decode("\xff""AA",3);
+               check_bad_range_decode("AAA\xff",4);
+               check_bad_range_decode("\xff\x41\x41\x41\x41",5);
+               check_bad_range_decode("A\xff\x41\x41\x41\x41",6);
+               check_bad_range_decode("AA\xff\x41\x41\x41\x41",7);
+               check_bad_range_decode("AAA\xff\x41\x41\x41\x41",8);
+       }
+       /* trigger some failures in the sixbit-to-b64 encoder: */
+       /* this function now aborts rather than returning -1/setting errno */
+       /* { */
+       /*      is_int(sixbit_to_b64(base64_maps_rfc4648,'\x70'),(char)-1); */
+       /*      is_int(sixbit_to_b64(base64_maps_rfc4648,'\xff'),(char)-1); */
+       /* } */
+       /* following tests all of the mapping from b64 chars to 6-bit values: */
+       test_decode("//+FwHRSRIsFU2IhAEGD+AMPhOA=",28,"\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0",20);
+       test_encode("\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0",20,"//+FwHRSRIsFU2IhAEGD+AMPhOA=");
+
+
+       /* check the null-padding stuff */
+       {
+               size_t destlen = 8;
+               char dest[destlen];
+               memset(dest,'\1',sizeof(dest));
+               is_size_t(base64_encode(dest,destlen,"A",1),(size_t)4);
+               is_mem(&dest[4],"\0\0\0\0",4);
+       }
+       {
+               size_t destlen = 3;
+               char dest[destlen];
+               memset(dest,'\1',sizeof(dest));
+               is_size_t(base64_decode(dest,destlen,"Wg==",4), 1);
+               is_mem(&dest[1],"\0",2);
+       }
+
+       /* test encoding using different alphabets */
+       {
+               char alphabet_fs_safe[64];
+               memcpy(alphabet_fs_safe,base64_maps_rfc4648.encode_map,sizeof(alphabet_fs_safe));
+               alphabet_fs_safe[62] = '-';
+               alphabet_fs_safe[63] = '_';
+               test_encode_using_alphabet(alphabet_fs_safe,"\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0",20,"__-FwHRSRIsFU2IhAEGD-AMPhOA=");
+       }
+
+       /* test decoding using different alphabets */
+       {
+               char alphabet_fs_safe[64];
+               #define src "__-FwHRSRIsFU2IhAEGD-AMPhOA="
+               #define expected "\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0"
+
+               memcpy(alphabet_fs_safe,base64_maps_rfc4648.encode_map,sizeof(alphabet_fs_safe));
+               alphabet_fs_safe[62] = '-';
+               alphabet_fs_safe[63] = '_';
+
+               test_decode_using_alphabet(alphabet_fs_safe,src,strlen(src),expected,20);
+               #undef src
+               #undef expected
+       }
+
+       /* explicitly test the non-maps encode_triplet and
+          encode_tail functions */
+       {
+               size_t destlen = 4;
+               char dest[destlen];
+               const char *src = "AB\04";
+               memset(dest,'\1',sizeof(dest));
+               base64_encode_triplet(dest,src);
+               is_mem(dest,"QUIE",sizeof(dest));
+       }
+       {
+               size_t destlen = 4;
+               char dest[destlen];
+               const char *src = "A";
+               memset(dest,'\1',sizeof(dest));
+               base64_encode_tail(dest,src,strlen(src));
+               is_mem(dest,"QQ==",sizeof(dest));
+       }
+
+       /* test the alphabet inversion */
+       {
+               base64_maps_t dest;
+               const char expected_inverse[] =
+                       "\xff\xff\xff\xff\xff" /* 0 */
+                       "\xff\xff\xff\xff\xff" /* 5 */
+                       "\xff\xff\xff\xff\xff" /* 10 */
+                       "\xff\xff\xff\xff\xff" /* 15 */
+                       "\xff\xff\xff\xff\xff" /* 20 */
+                       "\xff\xff\xff\xff\xff" /* 25 */
+                       "\xff\xff\xff\xff\xff" /* 30 */
+                       "\xff\xff\xff\xff\xff" /* 35 */
+                       "\xff\xff\xff\x3e\xff" /* 40 */
+                       "\xff\xff\x3f\x34\x35" /* 45 - */
+                       "\x36\x37\x38\x39\x3a" /* 50 */
+                       "\x3b\x3c\x3d\xff\xff" /* 55 */
+                       "\xff\xff\xff\xff\xff" /* 60 */
+                       "\x00\x01\x02\x03\x04" /* 65 A */
+                       "\x05\x06\x07\x08\x09" /* 70 */
+                       "\x0a\x0b\x0c\x0d\x0e" /* 75 */
+                       "\x0f\x10\x11\x12\x13" /* 80 */
+                       "\x14\x15\x16\x17\x18" /* 85 */
+                       "\x19\xff\xff\xff\xff" /* 90 */
+                       "\xff\xff\x1a\x1b\x1c" /* 95 _ */
+                       "\x1d\x1e\x1f\x20\x21" /* 100 */
+                       "\x22\x23\x24\x25\x26" /* 105 */
+                       "\x27\x28\x29\x2a\x2b" /* 110 */
+                       "\x2c\x2d\x2e\x2f\x30" /* 115 */
+                       "\x31\x32\x33\xff\xff" /* 120 */
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 125 */
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 155 */
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 185 */
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 215 */
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 245 */
+                       ;
+               const char * src = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+               base64_init_maps(&dest, src);
+               is_mem((const char *)dest.decode_map, expected_inverse, 256);
+               ok1(base64_char_in_alphabet(&dest,'A'));
+               ok1(!base64_char_in_alphabet(&dest,'\n'));
+       }
+
+       /* explicitly test the non-alpha decode_tail and decode_quartet */
+       {
+               char dest[4];
+               const char *src = "QQ==";
+               const char * expected = "A";
+               memset(dest, '%', sizeof(dest));
+               base64_decode_tail(dest,src,4);
+               is_mem(dest, expected, 1);
+       }
+       {
+               char dest[4];
+               const char *src = "Zm9v";
+               const char * expected = "foo";
+               memset(dest, '%', sizeof(dest));
+               base64_decode_quartet(dest,src);
+               is_mem(dest, expected, 1);
+       }
+
+       exit(exit_status());
+}
+
+static void * xmalloc(size_t size)
+{
+       char * ret;
+       ret = malloc(size);
+       if (ret == NULL) {
+               perror("malloc");
+               abort();
+       }
+       return ret;
+}
+
+/* End of run.c test */