base64: implements rfc4648, the base64 encoding
[ccan] / ccan / base64 / test / run.c
1 /* Start of run.c test */
2 #include "config.h"
3
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7
8 #include <ccan/base64/base64.h>
9 #include <ccan/tap/tap.h>
10
11 #include <ccan/base64/base64.c>
12 #include "moretap.h"
13
14 static void * xmalloc(size_t size);
15
16 /* not defined in terms of test_encode_using_maps so we cross
17    appropriate paths in library */
18 #define test_encode(src,srclen,expected)                        \
19         do {                                                    \
20                 size_t destlen;                                 \
21                 char * dest;                                    \
22                 destlen = base64_encoded_length(srclen);        \
23                 destlen++; /* null termination */               \
24                 dest = xmalloc(destlen);                        \
25                 ok1(base64_encode(dest,destlen,src,srclen) != -1);      \
26                 is_str(dest,expected);                                  \
27                 free(dest);                                             \
28         } while (0)
29
30 #define test_encode_using_alphabet(alphastring,src,srclen,expected)     \
31         do {                                                            \
32                 size_t destlen;                                         \
33                 char * dest;                                            \
34                 base64_maps_t maps;                             \
35                 base64_init_maps(&maps,alphastring);            \
36                 destlen = base64_encoded_length(srclen);                \
37                 destlen++; /* null termination */               \
38                 dest = xmalloc(destlen);                                \
39                 ok1(base64_encode_using_maps(&maps,dest,destlen,src,srclen) != -1); \
40                 is_str(dest,expected);                                  \
41                 free(dest);                                             \
42         } while (0)
43
44 /* not defined in terms of test_decode_using_alphabet so we cross
45    appropriate paths in library */
46 #define test_decode(src,srclen,expected,expectedlen)                    \
47         do {                                                            \
48                 size_t destlen;                                         \
49                 size_t bytes_used;                                      \
50                 char * dest;                                            \
51                 destlen = base64_decoded_length(srclen);                \
52                 dest = xmalloc(destlen);                                \
53                 ok1((bytes_used = base64_decode(dest,destlen,src,srclen)) != -1); \
54                 is_size_t(bytes_used,expectedlen);                      \
55                 is_mem(dest,expected,bytes_used);                       \
56                 free(dest);                                             \
57         } while (0)
58
59 #define test_decode_using_alphabet(alphastring,src,srclen,expected,expectedlen) \
60         do {                                                            \
61                 size_t destlen;                                         \
62                 size_t bytes_used;                                      \
63                 char * dest;                                            \
64                 base64_maps_t maps;                             \
65                                                                         \
66                 base64_init_maps(&maps,alphastring);            \
67                 destlen = base64_decoded_length(srclen);                \
68                 dest = xmalloc(destlen);                                \
69                 ok1((bytes_used = base64_decode_using_maps(&maps,dest,destlen,src,srclen)) != -1); \
70                 is_size_t(bytes_used,expectedlen);                      \
71                 is_mem(dest,expected,bytes_used);                       \
72                 free(dest);                                             \
73         } while (0)
74
75 #define check_bad_range_decode(stuff_to_test,stufflen)  \
76 do {                                                    \
77         char dest[10];                                                  \
78         errno = 0;                                                      \
79         is_size_t(base64_decode(dest,sizeof(dest),stuff_to_test,(size_t)stufflen), \
80                   (size_t)-1);                                          \
81         is_int(errno,EDOM);                                             \
82 } while (0)
83
84 int
85 main(int argc, char *argv[])
86 {
87         plan_tests(131);
88
89         is_size_t(base64_encoded_length(0),(size_t)0);
90         is_size_t(base64_encoded_length(1),(size_t)4);
91         is_size_t(base64_encoded_length(2),(size_t)4);
92         is_size_t(base64_encoded_length(3),(size_t)4);
93         is_size_t(base64_encoded_length(512),(size_t)684);
94
95         /* straight from page 11 of http://tools.ietf.org/html/rfc4648 */
96         test_encode("",0,"");
97         test_encode("f",1,"Zg==");
98         test_encode("fo",2,"Zm8=");
99
100         test_encode("foo",3,"Zm9v");
101         test_encode("foob",4,"Zm9vYg==");
102         test_encode("fooba",5,"Zm9vYmE=");
103         test_encode("foobar",6,"Zm9vYmFy");
104
105         /* a few more */
106         test_encode("foobarb",7,"Zm9vYmFyYg==");
107         test_encode("foobarba",8,"Zm9vYmFyYmE=");
108         test_encode("foobarbaz",9,"Zm9vYmFyYmF6");
109
110         test_encode("foobart",7,"Zm9vYmFydA==");
111
112         test_encode("abcdefghijklmnopqrstuvwxyz",26,"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=");
113         test_encode("\x05\x05\x01\x00\x07",5,"BQUBAAc=");
114
115         test_encode("FOO",3,"Rk9P");
116         test_encode("Z",1,"Wg==");
117
118         /* decode testing */
119
120         test_decode("",0,"",0);
121         test_decode("Zg==",4,"f",1);
122         test_decode("Zm8=",4,"fo",2);
123         test_decode("Zm9v",4,"foo",3);
124         test_decode("Zm9vYg==",8,"foob",4);
125         test_decode("Zm9vYmE=",8,"fooba",5);
126         test_decode("Zm9vYmFy",8,"foobar",6);
127         test_decode("Zm9vYmFyYg==",12,"foobarb",7);
128         test_decode("Zm9vYmFyYmE=",12,"foobarba",8);
129         test_decode("Zm9vYmFyYmF6",12,"foobarbaz",9);
130
131         test_decode("Rk9P",4,"FOO",3);
132
133         test_decode("Wg==",4,"Z",1);
134         test_decode("AA==",4,"\0",1);
135         test_decode("AAA=",4,"\0\0",2);
136
137         {
138                 const char *binary = "\x01\x00\x03";
139                 const size_t binarylen = 3;
140
141                 char * decoded;
142                 char * encoded;
143                 size_t encoded_len;
144                 size_t decoded_len;
145                 size_t decoded_space_required;
146
147                 size_t encoded_space_required = base64_encoded_length(binarylen);
148                 encoded_space_required++; /* null termination */
149                 encoded = xmalloc(encoded_space_required);
150                 encoded_len = base64_encode(encoded,encoded_space_required,binary,binarylen);
151                 is_mem(encoded,"AQAD",encoded_len);
152
153                 decoded_space_required = base64_decoded_length(encoded_len);
154                 decoded = xmalloc(decoded_space_required);
155                 decoded_len = base64_decode(decoded,decoded_space_required,encoded,encoded_len);
156                 is_size_t(decoded_len,binarylen);
157                 is_mem(binary,decoded,decoded_len);
158         }
159
160         /* some expected encode failures: */
161         {
162                 size_t destlen = 1;
163                 char dest[destlen];
164                 errno = 0;
165                 is_size_t(base64_encode(dest,destlen,"A",1),(size_t)-1);
166                 is_int(errno,EOVERFLOW);
167         }
168
169         /* some expected decode failures: */
170         {
171                 base64_maps_t maps;
172                 const char * src = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
173                 base64_init_maps(&maps,src);
174
175                 is_int(sixbit_from_b64(&maps,'\xfe'),(signed char)-1);
176                 is_int(errno,EDOM);
177         }
178         {
179                 size_t destlen = 10;
180                 char dest[destlen];
181                 errno = 0;
182                 is_size_t(base64_decode(dest,destlen,"A",1),(size_t)-1);
183                 is_int(errno,EINVAL);
184         }
185         {
186                 size_t destlen = 1;
187                 char dest[destlen];
188                 errno = 0;
189                 is_size_t(base64_decode(dest,destlen,"A",1),(size_t)-1);
190                 is_int(errno,EOVERFLOW);
191         }
192         {
193                 /* (char)1 is not a valid base64 character: */
194                 check_bad_range_decode("A\x01",2);
195                 /* (char)255 is not a valid base64 character: (char is signed on most platforms, so this is actually < 0 */
196                 check_bad_range_decode("\xff""A",2);
197                 check_bad_range_decode("A\xff",2);
198                 check_bad_range_decode("AA\xff",3);
199                 check_bad_range_decode("A\xff""A",3);
200                 check_bad_range_decode("\xff""AA",3);
201                 check_bad_range_decode("AAA\xff",4);
202                 check_bad_range_decode("\xff\x41\x41\x41\x41",5);
203                 check_bad_range_decode("A\xff\x41\x41\x41\x41",6);
204                 check_bad_range_decode("AA\xff\x41\x41\x41\x41",7);
205                 check_bad_range_decode("AAA\xff\x41\x41\x41\x41",8);
206         }
207         /* trigger some failures in the sixbit-to-b64 encoder: */
208         /* this function now aborts rather than returning -1/setting errno */
209         /* { */
210         /*      is_int(sixbit_to_b64(base64_maps_rfc4648,'\x70'),(char)-1); */
211         /*      is_int(sixbit_to_b64(base64_maps_rfc4648,'\xff'),(char)-1); */
212         /* } */
213         /* following tests all of the mapping from b64 chars to 6-bit values: */
214         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);
215         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=");
216
217
218         /* check the null-padding stuff */
219         {
220                 size_t destlen = 8;
221                 char dest[destlen];
222                 memset(dest,'\1',sizeof(dest));
223                 is_size_t(base64_encode(dest,destlen,"A",1),(size_t)4);
224                 is_mem(&dest[4],"\0\0\0\0",4);
225         }
226         {
227                 size_t destlen = 3;
228                 char dest[destlen];
229                 memset(dest,'\1',sizeof(dest));
230                 is_size_t(base64_decode(dest,destlen,"Wg==",4), 1);
231                 is_mem(&dest[1],"\0",2);
232         }
233
234         /* test encoding using different alphabets */
235         {
236                 char alphabet_fs_safe[64];
237                 memcpy(alphabet_fs_safe,base64_maps_rfc4648.encode_map,sizeof(alphabet_fs_safe));
238                 alphabet_fs_safe[62] = '-';
239                 alphabet_fs_safe[63] = '_';
240                 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=");
241         }
242
243         /* test decoding using different alphabets */
244         {
245                 char alphabet_fs_safe[64];
246                 #define src "__-FwHRSRIsFU2IhAEGD-AMPhOA="
247                 #define expected "\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0"
248
249                 memcpy(alphabet_fs_safe,base64_maps_rfc4648.encode_map,sizeof(alphabet_fs_safe));
250                 alphabet_fs_safe[62] = '-';
251                 alphabet_fs_safe[63] = '_';
252
253                 test_decode_using_alphabet(alphabet_fs_safe,src,strlen(src),expected,20);
254                 #undef src
255                 #undef expected
256         }
257
258         /* explicitly test the non-maps encode_triplet and
259            encode_tail functions */
260         {
261                 size_t destlen = 4;
262                 char dest[destlen];
263                 const char *src = "AB\04";
264                 memset(dest,'\1',sizeof(dest));
265                 base64_encode_triplet(dest,src);
266                 is_mem(dest,"QUIE",sizeof(dest));
267         }
268         {
269                 size_t destlen = 4;
270                 char dest[destlen];
271                 const char *src = "A";
272                 memset(dest,'\1',sizeof(dest));
273                 base64_encode_tail(dest,src,strlen(src));
274                 is_mem(dest,"QQ==",sizeof(dest));
275         }
276
277         /* test the alphabet inversion */
278         {
279                 base64_maps_t dest;
280                 const char expected_inverse[] =
281                         "\xff\xff\xff\xff\xff" /* 0 */
282                         "\xff\xff\xff\xff\xff" /* 5 */
283                         "\xff\xff\xff\xff\xff" /* 10 */
284                         "\xff\xff\xff\xff\xff" /* 15 */
285                         "\xff\xff\xff\xff\xff" /* 20 */
286                         "\xff\xff\xff\xff\xff" /* 25 */
287                         "\xff\xff\xff\xff\xff" /* 30 */
288                         "\xff\xff\xff\xff\xff" /* 35 */
289                         "\xff\xff\xff\x3e\xff" /* 40 */
290                         "\xff\xff\x3f\x34\x35" /* 45 - */
291                         "\x36\x37\x38\x39\x3a" /* 50 */
292                         "\x3b\x3c\x3d\xff\xff" /* 55 */
293                         "\xff\xff\xff\xff\xff" /* 60 */
294                         "\x00\x01\x02\x03\x04" /* 65 A */
295                         "\x05\x06\x07\x08\x09" /* 70 */
296                         "\x0a\x0b\x0c\x0d\x0e" /* 75 */
297                         "\x0f\x10\x11\x12\x13" /* 80 */
298                         "\x14\x15\x16\x17\x18" /* 85 */
299                         "\x19\xff\xff\xff\xff" /* 90 */
300                         "\xff\xff\x1a\x1b\x1c" /* 95 _ */
301                         "\x1d\x1e\x1f\x20\x21" /* 100 */
302                         "\x22\x23\x24\x25\x26" /* 105 */
303                         "\x27\x28\x29\x2a\x2b" /* 110 */
304                         "\x2c\x2d\x2e\x2f\x30" /* 115 */
305                         "\x31\x32\x33\xff\xff" /* 120 */
306                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 125 */
307                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
308                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
309                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 155 */
310                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
311                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
312                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 185 */
313                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
314                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
315                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 215 */
316                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
317                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
318                         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 245 */
319                         ;
320                 const char * src = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
321                 base64_init_maps(&dest, src);
322                 is_mem((const char *)dest.decode_map, expected_inverse, 256);
323                 ok1(base64_char_in_alphabet(&dest,'A'));
324                 ok1(!base64_char_in_alphabet(&dest,'\n'));
325         }
326
327         /* explicitly test the non-alpha decode_tail and decode_quartet */
328         {
329                 char dest[4];
330                 const char *src = "QQ==";
331                 const char * expected = "A";
332                 memset(dest, '%', sizeof(dest));
333                 base64_decode_tail(dest,src,4);
334                 is_mem(dest, expected, 1);
335         }
336         {
337                 char dest[4];
338                 const char *src = "Zm9v";
339                 const char * expected = "foo";
340                 memset(dest, '%', sizeof(dest));
341                 base64_decode_quartet(dest,src);
342                 is_mem(dest, expected, 1);
343         }
344
345         exit(exit_status());
346 }
347
348 static void * xmalloc(size_t size)
349 {
350         char * ret;
351         ret = malloc(size);
352         if (ret == NULL) {
353                 perror("malloc");
354                 abort();
355         }
356         return ret;
357 }
358
359 /* End of run.c test */