| <!doctype html> |
| <!-- Originally developed by Aryeh Gregor, funded by Google. Copyright belongs |
| to Google. --> |
| <title>atob()/btoa() tests</title> |
| <meta charset=utf-8> |
| <div id=log></div> |
| <script src=/resources/testharness.js></script> |
| <script src=/resources/testharnessreport.js></script> |
| <script> |
| /** |
| * btoa() as defined by the HTML5 spec, which mostly just references RFC4648. |
| */ |
| function mybtoa(s) { |
| // String conversion as required by WebIDL. |
| s = String(s); |
| |
| // "The btoa() method must throw an INVALID_CHARACTER_ERR exception if the |
| // method's first argument contains any character whose code point is |
| // greater than U+00FF." |
| for (var i = 0; i < s.length; i++) { |
| if (s.charCodeAt(i) > 255) { |
| return "INVALID_CHARACTER_ERR"; |
| } |
| } |
| |
| var out = ""; |
| for (var i = 0; i < s.length; i += 3) { |
| var groupsOfSix = [undefined, undefined, undefined, undefined]; |
| groupsOfSix[0] = s.charCodeAt(i) >> 2; |
| groupsOfSix[1] = (s.charCodeAt(i) & 0x03) << 4; |
| if (s.length > i + 1) { |
| groupsOfSix[1] |= s.charCodeAt(i + 1) >> 4; |
| groupsOfSix[2] = (s.charCodeAt(i + 1) & 0x0f) << 2; |
| } |
| if (s.length > i + 2) { |
| groupsOfSix[2] |= s.charCodeAt(i + 2) >> 6; |
| groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f; |
| } |
| for (var j = 0; j < groupsOfSix.length; j++) { |
| if (typeof groupsOfSix[j] == "undefined") { |
| out += "="; |
| } else { |
| out += btoaLookup(groupsOfSix[j]); |
| } |
| } |
| } |
| return out; |
| } |
| |
| /** |
| * Lookup table for mybtoa(), which converts a six-bit number into the |
| * corresponding ASCII character. |
| */ |
| function btoaLookup(idx) { |
| if (idx < 26) { |
| return String.fromCharCode(idx + 'A'.charCodeAt(0)); |
| } |
| if (idx < 52) { |
| return String.fromCharCode(idx - 26 + 'a'.charCodeAt(0)); |
| } |
| if (idx < 62) { |
| return String.fromCharCode(idx - 52 + '0'.charCodeAt(0)); |
| } |
| if (idx == 62) { |
| return '+'; |
| } |
| if (idx == 63) { |
| return '/'; |
| } |
| // Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests. |
| } |
| |
| function btoaException(input) { |
| input = String(input); |
| for (var i = 0; i < input.length; i++) { |
| if (input.charCodeAt(i) > 255) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| function testBtoa(input) { |
| // "The btoa() method must throw an INVALID_CHARACTER_ERR exception if the |
| // method's first argument contains any character whose code point is |
| // greater than U+00FF." |
| var normalizedInput = String(input); |
| for (var i = 0; i < normalizedInput.length; i++) { |
| if (normalizedInput.charCodeAt(i) > 255) { |
| assert_throws("InvalidCharacterError", function() { btoa(input); }, |
| "Code unit " + i + " has value " + normalizedInput.charCodeAt(i) + ", which is greater than 255"); |
| return; |
| } |
| } |
| assert_equals(btoa(input), mybtoa(input)); |
| assert_equals(atob(btoa(input)), String(input), "atob(btoa(input)) must be the same as String(input)"); |
| } |
| |
| var tests = ["עברית", "", "ab", "abc", "abcd", "abcde", |
| // This one is thrown in because IE9 seems to fail atob(btoa()) on it. Or |
| // possibly to fail btoa(). I actually can't tell what's happening here, |
| // but it doesn't hurt. |
| "\xff\xff\xc0", |
| // Is your DOM implementation binary-safe? |
| "\0a", "a\0b", |
| // WebIDL tests. |
| undefined, null, 7, 12, 1.5, true, false, NaN, +Infinity, -Infinity, 0, -0, |
| {toString: function() { return "foo" }}, |
| ]; |
| for (var i = 0; i < 258; i++) { |
| tests.push(String.fromCharCode(i)); |
| } |
| tests.push(String.fromCharCode(10000)); |
| tests.push(String.fromCharCode(65534)); |
| tests.push(String.fromCharCode(65535)); |
| |
| // This is supposed to be U+10000. |
| tests.push(String.fromCharCode(0xd800, 0xdc00)); |
| tests = tests.map( |
| function(elem) { |
| var expected = mybtoa(elem); |
| if (expected === "INVALID_CHARACTER_ERR") { |
| return ["btoa(" + format_value(elem) + ") must raise INVALID_CHARACTER_ERR", elem]; |
| } |
| return ["btoa(" + format_value(elem) + ") == " + format_value(mybtoa(elem)), elem]; |
| } |
| ); |
| |
| var everything = ""; |
| for (var i = 0; i < 256; i++) { |
| everything += String.fromCharCode(i); |
| } |
| tests.push(["btoa(first 256 code points concatenated)", everything]); |
| |
| generate_tests(testBtoa, tests); |
| |
| promise_test(() => fetch("../../../fetch/data-urls/resources/base64.json").then(res => res.json()).then(runAtobTests), "atob() setup."); |
| |
| const idlTests = [ |
| [undefined, null], |
| [null, [158, 233, 101]], |
| [7, null], |
| [12, [215]], |
| [1.5, null], |
| [true, [182, 187]], |
| [false, null], |
| [NaN, [53, 163]], |
| [+Infinity, [34, 119, 226, 158, 43, 114]], |
| [-Infinity, null], |
| [0, null], |
| [-0, null], |
| [{toString: function() { return "foo" }}, [126, 138]], |
| [{toString: function() { return "abcd" }}, [105, 183, 29]] |
| ]; |
| |
| function runAtobTests(tests) { |
| const allTests = tests.concat(idlTests); |
| for(let i = 0; i < allTests.length; i++) { |
| const input = allTests[i][0], |
| output = allTests[i][1]; |
| test(() => { |
| if(output === null) { |
| assert_throws("InvalidCharacterError", () => window.atob(input)); |
| } else { |
| const result = window.atob(input); |
| for(let ii = 0; ii < output.length; ii++) { |
| assert_equals(result.charCodeAt(ii), output[ii]); |
| } |
| } |
| }, "atob(" + format_value(input) + ")"); |
| } |
| } |
| </script> |