base64_test.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Copyright 2007 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.crypt.base64Test');
  15. goog.setTestOnly('goog.crypt.base64Test');
  16. goog.require('goog.crypt');
  17. goog.require('goog.crypt.base64');
  18. goog.require('goog.testing.jsunit');
  19. // Static test data
  20. // clang-format off
  21. var tests = [
  22. '', '',
  23. 'f', 'Zg==',
  24. 'fo', 'Zm8=',
  25. 'foo', 'Zm9v',
  26. 'foob', 'Zm9vYg==',
  27. 'fooba', 'Zm9vYmE=',
  28. 'foobar', 'Zm9vYmFy',
  29. // Testing non-ascii characters (1-10 in chinese)
  30. '\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89\xe5\x9b\x9b\xe4\xba\x94\xe5' +
  31. '\x85\xad\xe4\xb8\x83\xe5\x85\xab\xe4\xb9\x9d\xe5\x8d\x81',
  32. '5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5Y2B'];
  33. // clang-format on
  34. /**
  35. * Asserts that `encoded` matches `expected` when base64 decoded as byte array.
  36. * @param {!Array<number>} expected The expected binary decoded content.
  37. * @param {string} encoded The base64 encoded content to check.
  38. * @param {boolean=} opt_webSafe True if we should use the web-safe alphabet.
  39. */
  40. function assertDecodeToByteArrayEquals(expected, encoded, opt_webSafe) {
  41. var dec = goog.crypt.base64.decodeStringToByteArray(encoded, opt_webSafe);
  42. assertArrayEquals(expected, dec);
  43. }
  44. /**
  45. * Asserts that `encoded` matches `expected` when base64 decoded as uint8array,
  46. * if supported on this browser (otherwise this function is a no-op).
  47. * @param {!Array<number>} expected The expected binary decoded content.
  48. * @param {string} encoded The base64 encoded content to check.
  49. */
  50. function assertDecodeToUint8ArrayEquals(expected, encoded) {
  51. if (goog.global.Uint8Array) {
  52. var dec = goog.crypt.base64.decodeStringToUint8Array(encoded);
  53. assertArrayEquals(expected, Array.prototype.slice.call(dec));
  54. }
  55. }
  56. function testByteArrayEncoding() {
  57. // Let's see if it's sane by feeding it some well-known values. Index i
  58. // has the input and index i+1 has the expected value.
  59. for (var i = 0; i < tests.length; i += 2) {
  60. var enc = goog.crypt.base64.encodeByteArray(
  61. goog.crypt.stringToByteArray(tests[i]));
  62. assertEquals(tests[i + 1], enc);
  63. var expected = goog.crypt.stringToByteArray(tests[i]);
  64. assertDecodeToByteArrayEquals(expected, enc);
  65. assertDecodeToUint8ArrayEquals(expected, enc);
  66. // Check that obsolete websafe param has no effect.
  67. assertDecodeToByteArrayEquals(expected, enc, true /* websafe */);
  68. // Re-encode as websafe.
  69. enc = goog.crypt.base64.encodeByteArray(
  70. goog.crypt.stringToByteArray(tests[i], true /* websafe */));
  71. // Check that decoding accepts websafe codes.
  72. assertDecodeToByteArrayEquals(expected, enc);
  73. assertDecodeToUint8ArrayEquals(expected, enc);
  74. // Check that obsolete websafe param has no effect.
  75. assertDecodeToByteArrayEquals(expected, enc, true /* websafe */);
  76. }
  77. }
  78. function testOddLengthByteArrayEncoding() {
  79. var buffer = [0, 0, 0];
  80. var encodedBuffer = goog.crypt.base64.encodeByteArray(buffer);
  81. assertEquals('AAAA', encodedBuffer);
  82. assertDecodeToByteArrayEquals(buffer, encodedBuffer);
  83. assertDecodeToUint8ArrayEquals(buffer, encodedBuffer);
  84. }
  85. // Tests that decoding a string where the length is not a multiple of 4 does
  86. // not produce spurious trailing zeroes. This is a regression test for
  87. // cl/65120705, which fixes a bug that was introduced when support for
  88. // non-padded base64 encoding was added in cl/20209336.
  89. function testOddLengthByteArrayDecoding() {
  90. // The base-64 encoding of the bytes [97, 98, 99, 100], with no padding.
  91. // The padded version would be "YWJjZA==" (length 8), or "YWJjZA.." if
  92. // web-safe.
  93. var encodedBuffer = 'YWJjZA';
  94. var expected = goog.crypt.stringToByteArray('abcd');
  95. assertDecodeToByteArrayEquals(expected, encodedBuffer);
  96. assertDecodeToUint8ArrayEquals(expected, encodedBuffer);
  97. // Repeat the test in web-safe decoding mode.
  98. assertDecodeToByteArrayEquals(expected, encodedBuffer, true /* web-safe */);
  99. }
  100. function testShortcutPathEncoding() {
  101. // Test the higher-level API (tests the btoa/atob shortcut path)
  102. for (var i = 0; i < tests.length; i += 2) {
  103. var enc = goog.crypt.base64.encodeString(tests[i]);
  104. assertEquals(tests[i + 1], enc);
  105. var dec = goog.crypt.base64.decodeString(enc);
  106. assertEquals(tests[i], dec);
  107. }
  108. }
  109. function testMultipleIterations() {
  110. // Now run it through its paces
  111. var numIterations = 100;
  112. for (var i = 0; i < numIterations; i++) {
  113. var input = [];
  114. for (var j = 0; j < i; j++) input[j] = j % 256;
  115. var encoded = goog.crypt.base64.encodeByteArray(input);
  116. assertDecodeToByteArrayEquals(input, encoded);
  117. assertDecodeToUint8ArrayEquals(input, encoded);
  118. }
  119. }
  120. function testWebSafeEncoding() {
  121. // Test non-websafe / websafe difference
  122. var test = '>>>???>>>???=/+';
  123. var testArr = goog.crypt.stringToByteArray(test);
  124. var enc = goog.crypt.base64.encodeByteArray(testArr);
  125. assertEquals('Non-websafe broken?', 'Pj4+Pz8/Pj4+Pz8/PS8r', enc);
  126. enc = goog.crypt.base64.encodeString(test);
  127. assertEquals('Non-websafe broken?', 'Pj4+Pz8/Pj4+Pz8/PS8r', enc);
  128. enc = goog.crypt.base64.encodeByteArray(testArr, true /* websafe */);
  129. assertEquals('Websafe encoding broken', 'Pj4-Pz8_Pj4-Pz8_PS8r', enc);
  130. enc = goog.crypt.base64.encodeString(test, true);
  131. assertEquals('Non-websafe broken?', 'Pj4-Pz8_Pj4-Pz8_PS8r', enc);
  132. assertDecodeToByteArrayEquals(testArr, enc);
  133. assertDecodeToUint8ArrayEquals(testArr, enc);
  134. var dec = goog.crypt.base64.decodeString(enc, true /* websafe */);
  135. assertEquals('Websafe decoding broken', test, dec);
  136. // Test parsing malformed characters
  137. assertThrows('Didn\'t throw on malformed input', function() {
  138. goog.crypt.base64.decodeStringToByteArray('foooooo)oooo');
  139. });
  140. // Test parsing malformed characters
  141. assertThrows('Didn\'t throw on malformed input', function() {
  142. goog.crypt.base64.decodeStringToUint8Array('foooooo)oooo');
  143. });
  144. }
  145. function testDecodeIgnoresSpace() {
  146. var spaceTests = [
  147. // [encoded, expected decoded]
  148. [' \n\t\r', ''], ['Z g =\n=', 'f'], ['Zm 8=', 'fo'], [' Zm 9v', 'foo'],
  149. ['Zm9v Yg ==\t ', 'foob'], ['\nZ m9 vYm\n E=', 'fooba'],
  150. [' \nZ \tm9v YmFy ', 'foobar']
  151. ];
  152. for (var i = 0; i < spaceTests.length; i++) {
  153. var thisTest = spaceTests[i];
  154. var encoded = thisTest[0];
  155. var expectedStr = thisTest[1];
  156. var expected = goog.crypt.stringToByteArray(expectedStr);
  157. assertDecodeToByteArrayEquals(expected, encoded);
  158. assertDecodeToUint8ArrayEquals(expected, encoded);
  159. assertEquals(expectedStr, goog.crypt.base64.decodeString(encoded));
  160. }
  161. }