1: %% -*- coding: utf-8 -*- 2: %% 3: %% %CopyrightBegin% 4: %% 5: %% Copyright Ericsson AB 2007-2012. All Rights Reserved. 6: %% 7: %% The contents of this file are subject to the Erlang Public License, 8: %% Version 1.1, (the "License"); you may not use this file except in 9: %% compliance with the License. You should have received a copy of the 10: %% Erlang Public License along with this software. If not, it can be 11: %% retrieved online at http://www.erlang.org/. 12: %% 13: %% Software distributed under the License is distributed on an "AS IS" 14: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 15: %% the License for the specific language governing rights and limitations 16: %% under the License. 17: %% 18: %% %CopyrightEnd% 19: %% 20: 21: -module(base64_SUITE). 22: 23: -include_lib("common_test/include/ct.hrl"). 24: 25: %% Test server specific exports 26: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 27: init_per_group/2,end_per_group/2, 28: init_per_testcase/2, end_per_testcase/2]). 29: 30: %% Test cases must be exported. 31: -export([base64_encode/1, base64_decode/1, base64_otp_5635/1, 32: base64_otp_6279/1, big/1, illegal/1, mime_decode/1, 33: mime_decode_to_string/1, roundtrip/1]). 34: 35: init_per_testcase(_, Config) -> 36: Dog = test_server:timetrap(?t:minutes(4)), 37: NewConfig = lists:keydelete(watchdog, 1, Config), 38: [{watchdog, Dog} | NewConfig]. 39: 40: end_per_testcase(_, Config) -> 41: Dog = ?config(watchdog, Config), 42: test_server:timetrap_cancel(Dog), 43: ok. 44: 45: %%------------------------------------------------------------------------- 46: %% Test cases starts here. 47: %%------------------------------------------------------------------------- 48: suite() -> [{ct_hooks,[ts_install_cth]}]. 49: 50: all() -> 51: [base64_encode, base64_decode, base64_otp_5635, 52: base64_otp_6279, big, illegal, mime_decode, mime_decode_to_string, 53: roundtrip]. 54: 55: groups() -> 56: []. 57: 58: init_per_suite(Config) -> 59: Config. 60: 61: end_per_suite(_Config) -> 62: ok. 63: 64: init_per_group(_GroupName, Config) -> 65: Config. 66: 67: end_per_group(_GroupName, Config) -> 68: Config. 69: 70: 71: 72: %%------------------------------------------------------------------------- 73: base64_encode(doc) -> 74: ["Test base64:encode/1."]; 75: base64_encode(suite) -> 76: []; 77: base64_encode(Config) when is_list(Config) -> 78: %% Two pads 79: <<"QWxhZGRpbjpvcGVuIHNlc2FtZQ==">> = 80: base64:encode("Aladdin:open sesame"), 81: %% One pad 82: <<"SGVsbG8gV29ybGQ=">> = base64:encode(<<"Hello World">>), 83: %% No pad 84: "QWxhZGRpbjpvcGVuIHNlc2Ft" = 85: base64:encode_to_string("Aladdin:open sesam"), 86: 87: "MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9" = 88: base64:encode_to_string(<<"0123456789!@#0^&*();:<>,. []{}">>), 89: ok. 90: %%------------------------------------------------------------------------- 91: base64_decode(doc) -> 92: ["Test base64:decode/1."]; 93: base64_decode(suite) -> 94: []; 95: base64_decode(Config) when is_list(Config) -> 96: %% Two pads 97: <<"Aladdin:open sesame">> = 98: base64:decode("QWxhZGRpbjpvcGVuIHNlc2FtZQ=="), 99: %% One pad 100: <<"Hello World">> = base64:decode(<<"SGVsbG8gV29ybGQ=">>), 101: %% No pad 102: <<"Aladdin:open sesam">> = 103: base64:decode("QWxhZGRpbjpvcGVuIHNlc2Ft"), 104: 105: Alphabet = list_to_binary(lists:seq(0, 255)), 106: Alphabet = base64:decode(base64:encode(Alphabet)), 107: 108: %% Encoded base 64 strings may be devided by non base 64 chars. 109: %% In this cases whitespaces. 110: "0123456789!@#0^&*();:<>,. []{}" = 111: base64:decode_to_string( 112: "MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9"), 113: "0123456789!@#0^&*();:<>,. []{}" = 114: base64:decode_to_string( 115: <<"MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9">>), 116: ok. 117: %%------------------------------------------------------------------------- 118: base64_otp_5635(doc) -> 119: ["OTP-5635: Some data doesn't pass through base64:decode/1 " 120: "correctly"]; 121: base64_otp_5635(suite) -> 122: []; 123: base64_otp_5635(Config) when is_list(Config) -> 124: <<"===">> = base64:decode(base64:encode("===")), 125: ok. 126: %%------------------------------------------------------------------------- 127: base64_otp_6279(doc) -> 128: ["OTP-6279: Guard needed so that function fails in a correct" 129: "way for faulty input i.e. function_clause"]; 130: base64_otp_6279(suite) -> 131: []; 132: base64_otp_6279(Config) when is_list(Config) -> 133: {'EXIT',{function_clause, _}} = (catch base64:decode("dGVzda==a")), 134: ok. 135: %%------------------------------------------------------------------------- 136: big(doc) -> 137: ["Encode and decode big binaries."]; 138: big(suite) -> 139: []; 140: big(Config) when is_list(Config) -> 141: Big = make_big_binary(300000), 142: B = base64:encode(Big), 143: true = is_binary(B), 144: 400000 = byte_size(B), 145: Big = base64:decode(B), 146: Big = base64:mime_decode(B), 147: ok. 148: %%------------------------------------------------------------------------- 149: illegal(doc) -> 150: ["Make sure illegal characters are rejected when decoding."]; 151: illegal(suite) -> 152: []; 153: illegal(Config) when is_list(Config) -> 154: {'EXIT',{function_clause, _}} = (catch base64:decode("()")), 155: ok. 156: %%------------------------------------------------------------------------- 157: %% mime_decode and mime_decode_to_string have different implementations 158: %% so test both with the same input separately. Both functions have 159: %% the same implementation for binary/string arguments. 160: mime_decode(doc) -> 161: ["Test base64:mime_decode/1."]; 162: mime_decode(suite) -> 163: []; 164: mime_decode(Config) when is_list(Config) -> 165: %% Test correct padding 166: <<"one">> = base64:mime_decode(<<"b25l">>), 167: <<"on">> = base64:mime_decode(<<"b24=">>), 168: <<"o">> = base64:mime_decode(<<"bw==">>), 169: %% Test 1 extra padding 170: <<"one">> = base64:mime_decode(<<"b25l= =">>), 171: <<"on">> = base64:mime_decode(<<"b24== =">>), 172: <<"o">> = base64:mime_decode(<<"bw=== =">>), 173: %% Test 2 extra padding 174: <<"one">> = base64:mime_decode(<<"b25l===">>), 175: <<"on">> = base64:mime_decode(<<"b24====">>), 176: <<"o">> = base64:mime_decode(<<"bw=====">>), 177: %% Test misc embedded padding 178: <<"one">> = base64:mime_decode(<<"b2=5l===">>), 179: <<"on">> = base64:mime_decode(<<"b=24====">>), 180: <<"o">> = base64:mime_decode(<<"b=w=====">>), 181: %% Test misc white space and illegals with embedded padding 182: <<"one">> = base64:mime_decode(<<" b~2=\r\n5()l===">>), 183: <<"on">> = base64:mime_decode(<<"\tb =2\"¤4=¤= ==">>), 184: <<"o">> = base64:mime_decode(<<"\nb=w=====">>), 185: %% Two pads 186: <<"Aladdin:open sesame">> = 187: base64:mime_decode("QWxhZGRpbjpvc()GVuIHNlc2FtZQ=="), 188: %% One pad to ignore, followed by more text 189: <<"Hello World!!">> = base64:mime_decode(<<"SGVsb)(G8gV29ybGQ=h IQ= =">>), 190: %% No pad 191: <<"Aladdin:open sesam">> = 192: base64:mime_decode("QWxhZGRpbjpvcG¤\")(VuIHNlc2Ft"), 193: %% Encoded base 64 strings may be divided by non base 64 chars. 194: %% In this cases whitespaces. 195: <<"0123456789!@#0^&*();:<>,. []{}">> = 196: base64:mime_decode( 197: <<"MDEy MzQ1Njc4 \tOSFAIzBeJ \nio)(oKTs6 PD4sLi \r\nBbXXt9">>), 198: ok. 199: 200: %%------------------------------------------------------------------------- 201: 202: %% Repeat of mime_decode() tests 203: mime_decode_to_string(doc) -> 204: ["Test base64:mime_decode_to_string/1."]; 205: mime_decode_to_string(suite) -> 206: []; 207: mime_decode_to_string(Config) when is_list(Config) -> 208: %% Test correct padding 209: "one" = base64:mime_decode_to_string(<<"b25l">>), 210: "on" = base64:mime_decode_to_string(<<"b24=">>), 211: "o" = base64:mime_decode_to_string(<<"bw==">>), 212: %% Test 1 extra padding 213: "one" = base64:mime_decode_to_string(<<"b25l= =">>), 214: "on" = base64:mime_decode_to_string(<<"b24== =">>), 215: "o" = base64:mime_decode_to_string(<<"bw=== =">>), 216: %% Test 2 extra padding 217: "one" = base64:mime_decode_to_string(<<"b25l===">>), 218: "on" = base64:mime_decode_to_string(<<"b24====">>), 219: "o" = base64:mime_decode_to_string(<<"bw=====">>), 220: %% Test misc embedded padding 221: "one" = base64:mime_decode_to_string(<<"b2=5l===">>), 222: "on" = base64:mime_decode_to_string(<<"b=24====">>), 223: "o" = base64:mime_decode_to_string(<<"b=w=====">>), 224: %% Test misc white space and illegals with embedded padding 225: "one" = base64:mime_decode_to_string(<<" b~2=\r\n5()l===">>), 226: "on" = base64:mime_decode_to_string(<<"\tb =2\"¤4=¤= ==">>), 227: "o" = base64:mime_decode_to_string(<<"\nb=w=====">>), 228: %% Two pads 229: "Aladdin:open sesame" = 230: base64:mime_decode_to_string("QWxhZGRpbjpvc()GVuIHNlc2FtZQ=="), 231: %% One pad to ignore, followed by more text 232: "Hello World!!" = base64:mime_decode_to_string(<<"SGVsb)(G8gV29ybGQ=h IQ= =">>), 233: %% No pad 234: "Aladdin:open sesam" = 235: base64:mime_decode_to_string("QWxhZGRpbjpvcG¤\")(VuIHNlc2Ft"), 236: %% Encoded base 64 strings may be divided by non base 64 chars. 237: %% In this cases whitespaces. 238: "0123456789!@#0^&*();:<>,. []{}" = 239: base64:mime_decode_to_string( 240: <<"MDEy MzQ1Njc4 \tOSFAIzBeJ \nio)(oKTs6 PD4sLi \r\nBbXXt9">>), 241: ok. 242: 243: %%------------------------------------------------------------------------- 244: 245: roundtrip(Config) when is_list(Config) -> 246: Sizes = lists:seq(1, 255) ++ lists:seq(2400-5, 2440), 247: roundtrip_1(Sizes, []). 248: 249: roundtrip_1([NextSize|Sizes], Current) -> 250: Len = length(Current), 251: io:format("~p", [Len]), 252: do_roundtrip(Current), 253: Next = random_byte_list(NextSize - Len, Current), 254: roundtrip_1(Sizes, Next); 255: roundtrip_1([], Last) -> 256: io:format("~p", [length(Last)]), 257: do_roundtrip(Last). 258: 259: do_roundtrip(List) -> 260: Bin = list_to_binary(List), 261: Base64Bin = base64:encode(List), 262: Base64Bin = base64:encode(Bin), 263: Base64List = base64:encode_to_string(List), 264: Base64Bin = list_to_binary(Base64List), 265: Bin = base64:decode(Base64Bin), 266: List = base64:decode_to_string(Base64Bin), 267: Bin = base64:mime_decode(Base64Bin), 268: List = base64:mime_decode_to_string(Base64Bin), 269: append_roundtrip(8, Bin, List, Base64Bin), 270: prepend_roundtrip(8, Bin, List, Base64List), 271: interleaved_ws_roundtrip(Bin, List, Base64List). 272: 273: append_roundtrip(0, _, _, _) -> ok; 274: append_roundtrip(N, Bin, List, Base64Bin0) -> 275: Base64Bin = <<Base64Bin0/binary,"\n">>, 276: Bin = base64:decode(Base64Bin), 277: List = base64:decode_to_string(Base64Bin), 278: Bin = base64:mime_decode(Base64Bin), 279: List = base64:mime_decode_to_string(Base64Bin), 280: 281: Base64List = binary_to_list(Base64Bin), 282: Bin = base64:decode(Base64List), 283: List = base64:decode_to_string(Base64List), 284: Bin = base64:mime_decode(Base64List), 285: List = base64:mime_decode_to_string(Base64List), 286: append_roundtrip(N-1, Bin, List, Base64Bin). 287: 288: prepend_roundtrip(0, _, _, _) -> ok; 289: prepend_roundtrip(N, Bin, List, Base64List0) -> 290: Base64List = [$\s|Base64List0], 291: Bin = base64:decode(Base64List), 292: List = base64:decode_to_string(Base64List), 293: Bin = base64:mime_decode(Base64List), 294: List = base64:mime_decode_to_string(Base64List), 295: 296: Base64Bin = list_to_binary(Base64List), 297: Bin = base64:decode(Base64Bin), 298: List = base64:decode_to_string(Base64Bin), 299: Bin = base64:mime_decode(Base64Bin), 300: List = base64:mime_decode_to_string(Base64Bin), 301: prepend_roundtrip(N-1, Bin, List, Base64List). 302: 303: %% Do an exhaustive test of interleaving whitespace (for short strings). 304: interleaved_ws_roundtrip(Bin, List, Base64List) when byte_size(Bin) =< 6 -> 305: interleaved_ws_roundtrip_1(lists:reverse(Base64List), [], Bin, List); 306: interleaved_ws_roundtrip(_, _, _) -> ok. 307: 308: interleaved_ws_roundtrip_1([H|T], Tail, Bin, List) -> 309: interleaved_ws_roundtrip_1(T, [H|Tail], Bin, List), 310: interleaved_ws_roundtrip_1(T, [H,$\s|Tail], Bin, List), 311: interleaved_ws_roundtrip_1(T, [H,$\s,$\t|Tail], Bin, List), 312: interleaved_ws_roundtrip_1(T, [H,$\n,$\t|Tail], Bin, List); 313: interleaved_ws_roundtrip_1([], Base64List, Bin, List) -> 314: Bin = base64:decode(Base64List), 315: List = base64:decode_to_string(Base64List), 316: Bin = base64:mime_decode(Base64List), 317: List = base64:mime_decode_to_string(Base64List), 318: 319: Base64Bin = list_to_binary(Base64List), 320: Bin = base64:decode(Base64Bin), 321: List = base64:decode_to_string(Base64Bin), 322: Bin = base64:mime_decode(Base64Bin), 323: List = base64:mime_decode_to_string(Base64Bin), 324: ok. 325: 326: random_byte_list(0, Acc) -> 327: Acc; 328: random_byte_list(N, Acc) -> 329: random_byte_list(N-1, [random:uniform(255)|Acc]). 330: 331: make_big_binary(N) -> 332: list_to_binary(mbb(N, [])). 333: 334: mbb(N, Acc) when N > 256 -> 335: B = list_to_binary(lists:seq(0, 255)), 336: mbb(N - 256, [B | Acc]); 337: mbb(N, Acc) -> 338: B = list_to_binary(lists:seq(0, N-1)), 339: lists:reverse(Acc, B).