diff --git a/CHANGELOG.md b/CHANGELOG.md index 16124fa10bc0..aace769e96cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,10 +16,12 @@ - Methods: - `Uint8Array.fromBase64` - `Uint8Array.fromHex` + - `Uint8Array.prototype.setFromBase64` - `Uint8Array.prototype.setFromHex` - `Uint8Array.prototype.toBase64` - `Uint8Array.prototype.toHex` - - Added `Uint8Array.prototype.setFromHex` method + - Added `Uint8Array.prototype.{ setFromBase64, setFromHex }` methods + - Added `Uint8Array.fromBase64` and `Uint8Array.prototype.setFromBase64` `lastChunkHandling` option, [proposal-arraybuffer-base64/33](https://github.com/tc39/proposal-arraybuffer-base64/pull/33) - Added `Uint8Array.prototype.toBase64` `omitPadding` option, [proposal-arraybuffer-base64/60](https://github.com/tc39/proposal-arraybuffer-base64/pull/60) - Added throwing a `TypeError` on arrays backed by detached buffers - Unconditional forced replacement changed to feature detection diff --git a/README.md b/README.md index 4d2ee43a6890..16d4f36a3c91 100644 --- a/README.md +++ b/README.md @@ -2433,9 +2433,10 @@ console.log(view.getFloat16(0)); // => 1.3369140625 Modules [`esnext.uint8-array.from-base64`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.uint8-array.from-base64.js), [`esnext.uint8-array.from-hex`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.uint8-array.from-hex.js), [`esnext.uint8-array.set-from-hex`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.uint8-array.set-from-hex.js), [`esnext.uint8-array.to-base64`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.uint8-array.to-base64.js), [`esnext.uint8-array.to-hex`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.uint8-array.to-hex.js). ```js class Uint8Array { - static fromBase64(string, options?: { alphabet?: 'base64' | 'base64url', strict?: boolean }): Uint8Array; - static fromHex(string): Uint8Array; - setFromHex(string): { read: uint, written: uint }; + static fromBase64(string: string, options?: { alphabet?: 'base64' | 'base64url', lastChunkHandling?: 'loose' | 'strict' | 'stop-before-partial' }): Uint8Array; + static fromHex(string: string): Uint8Array; + setFromBase64(string: string, options?: { alphabet?: 'base64' | 'base64url', lastChunkHandling?: 'loose' | 'strict' | 'stop-before-partial' }): { read: uint, written: uint }; + setFromHex(string: string): { read: uint, written: uint }; toBase64(options?: { alphabet?: 'base64' | 'base64url', omitPadding?: boolean }): string; toHex(): string; } @@ -2446,6 +2447,7 @@ class Uint8Array { core-js/proposals/array-buffer-base64 core-js(-pure)/actual|full/typed-array/from-base64 core-js(-pure)/actual|full/typed-array/from-hex +core-js(-pure)/actual|full/typed-array/set-from-base64 core-js(-pure)/actual|full/typed-array/set-from-hex core-js(-pure)/actual|full/typed-array/to-base64 core-js(-pure)/actual|full/typed-array/to-hex diff --git a/packages/core-js-compat/src/data.mjs b/packages/core-js-compat/src/data.mjs index f63429104bb1..b8273cf0a976 100644 --- a/packages/core-js-compat/src/data.mjs +++ b/packages/core-js-compat/src/data.mjs @@ -2512,6 +2512,8 @@ export const data = { }, 'esnext.uint8-array.from-hex': { }, + 'esnext.uint8-array.set-from-base64': { + }, 'esnext.uint8-array.set-from-hex': { }, 'esnext.uint8-array.to-base64': { diff --git a/packages/core-js-compat/src/modules-by-versions.mjs b/packages/core-js-compat/src/modules-by-versions.mjs index 7143000a2057..9a253814bafc 100644 --- a/packages/core-js-compat/src/modules-by-versions.mjs +++ b/packages/core-js-compat/src/modules-by-versions.mjs @@ -250,6 +250,7 @@ export default { 'web.url.parse', ], 3.38: [ + 'esnext.uint8-array.set-from-base64', 'esnext.uint8-array.set-from-hex', ], }; diff --git a/packages/core-js-pure/override/modules/esnext.uint8-array.set-from-base64.js b/packages/core-js-pure/override/modules/esnext.uint8-array.set-from-base64.js new file mode 100644 index 000000000000..8b1a393741c9 --- /dev/null +++ b/packages/core-js-pure/override/modules/esnext.uint8-array.set-from-base64.js @@ -0,0 +1 @@ +// empty diff --git a/packages/core-js/actual/typed-array/index.js b/packages/core-js/actual/typed-array/index.js index 753688385877..c495f5a5a5d0 100644 --- a/packages/core-js/actual/typed-array/index.js +++ b/packages/core-js/actual/typed-array/index.js @@ -2,6 +2,7 @@ var parent = require('../../stable/typed-array'); require('../../modules/esnext.uint8-array.from-base64'); require('../../modules/esnext.uint8-array.from-hex'); +require('../../modules/esnext.uint8-array.set-from-base64'); require('../../modules/esnext.uint8-array.set-from-hex'); require('../../modules/esnext.uint8-array.to-base64'); require('../../modules/esnext.uint8-array.to-hex'); diff --git a/packages/core-js/actual/typed-array/methods.js b/packages/core-js/actual/typed-array/methods.js index 948e26ca2f11..c9f680c0cc13 100644 --- a/packages/core-js/actual/typed-array/methods.js +++ b/packages/core-js/actual/typed-array/methods.js @@ -2,6 +2,7 @@ var parent = require('../../stable/typed-array/methods'); require('../../modules/esnext.uint8-array.from-base64'); require('../../modules/esnext.uint8-array.from-hex'); +require('../../modules/esnext.uint8-array.set-from-base64'); require('../../modules/esnext.uint8-array.set-from-hex'); require('../../modules/esnext.uint8-array.to-base64'); require('../../modules/esnext.uint8-array.to-hex'); diff --git a/packages/core-js/actual/typed-array/set-from-base64.js b/packages/core-js/actual/typed-array/set-from-base64.js new file mode 100644 index 000000000000..4bdfeb8be835 --- /dev/null +++ b/packages/core-js/actual/typed-array/set-from-base64.js @@ -0,0 +1,2 @@ +'use strict'; +require('../../modules/esnext.uint8-array.set-from-base64'); diff --git a/packages/core-js/full/typed-array/set-from-base64.js b/packages/core-js/full/typed-array/set-from-base64.js new file mode 100644 index 000000000000..78bf569b4fd8 --- /dev/null +++ b/packages/core-js/full/typed-array/set-from-base64.js @@ -0,0 +1,4 @@ +'use strict'; +var parent = require('../../actual/typed-array/set-from-base64'); + +module.exports = parent; diff --git a/packages/core-js/internals/uint8-from-base64.js b/packages/core-js/internals/uint8-from-base64.js new file mode 100644 index 000000000000..6fa6e5a3dbdf --- /dev/null +++ b/packages/core-js/internals/uint8-from-base64.js @@ -0,0 +1,157 @@ +'use strict'; +var globalThis = require('../internals/global-this'); +var uncurryThis = require('../internals/function-uncurry-this'); +var anObjectOrUndefined = require('../internals/an-object-or-undefined'); +var aString = require('../internals/a-string'); +var hasOwn = require('../internals/has-own-property'); +var base64Map = require('../internals/base64-map'); +var getAlphabetOption = require('../internals/get-alphabet-option'); +var notDetached = require('../internals/array-buffer-not-detached'); + +var base64Alphabet = base64Map.c2i; +var base64UrlAlphabet = base64Map.c2iUrl; + +var SyntaxError = globalThis.SyntaxError; +var TypeError = globalThis.TypeError; +var ASCII_WHITESPACE = /[\t\n\f\r ]/; +var exec = uncurryThis(ASCII_WHITESPACE.exec); +var at = uncurryThis(''.charAt); + +var skipAsciiWhitespace = function (string, index) { + var length = string.length; + for (;index < length; index++) { + if (!exec(ASCII_WHITESPACE, at(string, index))) break; + } return index; +}; + +var decodeBase64Chunk = function (chunk, alphabet, throwOnExtraBits) { + var chunkLength = chunk.length; + + if (chunkLength < 4) { + chunk += chunkLength === 2 ? 'AA' : 'A'; + } + + var triplet = (alphabet[at(chunk, 0)] << 18) + + (alphabet[at(chunk, 1)] << 12) + + (alphabet[at(chunk, 2)] << 6) + + alphabet[at(chunk, 3)]; + + var chunkBytes = [ + (triplet >> 16) & 255, + (triplet >> 8) & 255, + triplet & 255 + ]; + + if (chunkLength === 2) { + if (throwOnExtraBits && chunkBytes[1] !== 0) { + throw new SyntaxError('Extra bits'); + } + return [chunkBytes[0]]; + } + + if (chunkLength === 3) { + if (throwOnExtraBits && chunkBytes[2] !== 0) { + throw new SyntaxError('Extra bits'); + } + return [chunkBytes[0], chunkBytes[1]]; + } + + return chunkBytes; +}; + +var writeBytes = function (bytes, elements, written) { + var elementsLength = elements.length; + for (var index = 0; index < elementsLength; index++) { + bytes[written + index] = elements[index]; + } + return written + elementsLength; +}; + +/* eslint-disable max-statements, max-depth -- TODO */ +module.exports = function (string, options, into, maxLength) { + aString(string); + anObjectOrUndefined(options); + var alphabet = getAlphabetOption(options) === 'base64' ? base64Alphabet : base64UrlAlphabet; + var lastChunkHandling = options ? options.lastChunkHandling : undefined; + + if (lastChunkHandling === undefined) lastChunkHandling = 'loose'; + + if (lastChunkHandling !== 'loose' && lastChunkHandling !== 'strict' && lastChunkHandling !== 'stop-before-partial') { + throw new TypeError('Incorrect `lastChunkHandling` option'); + } + + if (into) notDetached(into.buffer); + + var bytes = into || []; + var written = 0; + var read = 0; + var chunk = ''; + var index = 0; + + if (maxLength) while (true) { + index = skipAsciiWhitespace(string, index); + if (index === string.length) { + if (chunk.length > 0) { + if (lastChunkHandling === 'stop-before-partial') { + break; + } + if (lastChunkHandling === 'loose') { + if (chunk.length === 1) { + throw new SyntaxError('Malformed padding: exactly one additional character'); + } + written = writeBytes(bytes, decodeBase64Chunk(chunk, alphabet, false), written); + } else { + throw new SyntaxError('Missing padding'); + } + } + read = string.length; + break; + } + var chr = at(string, index); + ++index; + if (chr === '=') { + if (chunk.length < 2) { + throw new SyntaxError('Padding is too early'); + } + index = skipAsciiWhitespace(string, index); + if (chunk.length === 2) { + if (index === string.length) { + if (lastChunkHandling === 'stop-before-partial') { + break; + } + throw new SyntaxError('Malformed padding: only one ='); + } + if (at(string, index) === '=') { + ++index; + index = skipAsciiWhitespace(string, index); + } + } + if (index < string.length) { + throw new SyntaxError('Unexpected character after padding'); + } + written = writeBytes(bytes, decodeBase64Chunk(chunk, alphabet, lastChunkHandling === 'strict'), written); + read = string.length; + break; + } + if (!hasOwn(alphabet, chr)) { + throw new SyntaxError('Unexpected character'); + } + var remainingBytes = maxLength - written; + if (remainingBytes === 1 && chunk.length === 2 || remainingBytes === 2 && chunk.length === 3) { + // special case: we can fit exactly the number of bytes currently represented by chunk, so we were just checking for `=` + break; + } + + chunk += chr; + if (chunk.length === 4) { + written = writeBytes(bytes, decodeBase64Chunk(chunk, alphabet, false), written); + chunk = ''; + read = index; + if (written === maxLength) { + break; + } + } + } + + return { bytes: bytes, read: read, written: written }; +}; diff --git a/packages/core-js/internals/uint8-from-hex.js b/packages/core-js/internals/uint8-from-hex.js index b9488b1b4c82..fb195c79d3f5 100644 --- a/packages/core-js/internals/uint8-from-hex.js +++ b/packages/core-js/internals/uint8-from-hex.js @@ -16,11 +16,11 @@ module.exports = function (string, into) { var maxLength = into ? min(into.length, stringLength / 2) : stringLength / 2; var bytes = into || new Uint8Array(maxLength); var read = 0; - var index = 0; - while (index < maxLength) { + var written = 0; + while (written < maxLength) { var hexits = stringSlice(string, read, read += 2); if (exec(NOT_HEX, hexits)) throw new SyntaxError('String should only contain hex characters'); - bytes[index++] = parseInt(hexits, 16); + bytes[written++] = parseInt(hexits, 16); } return { bytes: bytes, read: read }; }; diff --git a/packages/core-js/modules/esnext.uint8-array.from-base64.js b/packages/core-js/modules/esnext.uint8-array.from-base64.js index 18689bb926e1..1dfc859730bf 100644 --- a/packages/core-js/modules/esnext.uint8-array.from-base64.js +++ b/packages/core-js/modules/esnext.uint8-array.from-base64.js @@ -1,75 +1,16 @@ 'use strict'; var $ = require('../internals/export'); var globalThis = require('../internals/global-this'); -var uncurryThis = require('../internals/function-uncurry-this'); -var anObjectOrUndefined = require('../internals/an-object-or-undefined'); -var aString = require('../internals/a-string'); -var hasOwn = require('../internals/has-own-property'); var arrayFromConstructorAndList = require('../internals/array-from-constructor-and-list'); -var base64Map = require('../internals/base64-map'); -var getAlphabetOption = require('../internals/get-alphabet-option'); - -var base64Alphabet = base64Map.c2i; -var base64UrlAlphabet = base64Map.c2iUrl; +var $fromBase64 = require('../internals/uint8-from-base64'); var Uint8Array = globalThis.Uint8Array; -var SyntaxError = globalThis.SyntaxError; -var charAt = uncurryThis(''.charAt); -var replace = uncurryThis(''.replace); -var stringSlice = uncurryThis(''.slice); -var push = uncurryThis([].push); -var SPACES = /[\t\n\f\r ]/g; -var EXTRA_BITS = 'Extra bits'; // `Uint8Array.fromBase64` method // https://github.com/tc39/proposal-arraybuffer-base64 if (Uint8Array) $({ target: 'Uint8Array', stat: true }, { fromBase64: function fromBase64(string /* , options */) { - aString(string); - var options = arguments.length > 1 ? anObjectOrUndefined(arguments[1]) : undefined; - var alphabet = getAlphabetOption(options) === 'base64' ? base64Alphabet : base64UrlAlphabet; - var strict = options ? !!options.strict : false; - - var input = strict ? string : replace(string, SPACES, ''); - - if (input.length % 4 === 0) { - if (stringSlice(input, -2) === '==') input = stringSlice(input, 0, -2); - else if (stringSlice(input, -1) === '=') input = stringSlice(input, 0, -1); - } else if (strict) throw new SyntaxError('Input is not correctly padded'); - - var lastChunkSize = input.length % 4; - - switch (lastChunkSize) { - case 1: throw new SyntaxError('Bad input length'); - case 2: input += 'AA'; break; - case 3: input += 'A'; - } - - var bytes = []; - var i = 0; - var inputLength = input.length; - - var at = function (shift) { - var chr = charAt(input, i + shift); - if (!hasOwn(alphabet, chr)) throw new SyntaxError('Bad char in input: "' + chr + '"'); - return alphabet[chr] << (18 - 6 * shift); - }; - - for (; i < inputLength; i += 4) { - var triplet = at(0) + at(1) + at(2) + at(3); - push(bytes, (triplet >> 16) & 255, (triplet >> 8) & 255, triplet & 255); - } - - var byteLength = bytes.length; - - if (lastChunkSize === 2) { - if (strict && bytes[byteLength - 2] !== 0) throw new SyntaxError(EXTRA_BITS); - byteLength -= 2; - } else if (lastChunkSize === 3) { - if (strict && bytes[byteLength - 1] !== 0) throw new SyntaxError(EXTRA_BITS); - byteLength--; - } - - return arrayFromConstructorAndList(Uint8Array, bytes, byteLength); + var result = $fromBase64(string, arguments.length > 1 ? arguments[1] : undefined, null, 0x1FFFFFFFFFFFFF); + return arrayFromConstructorAndList(Uint8Array, result.bytes); } }); diff --git a/packages/core-js/modules/esnext.uint8-array.set-from-base64.js b/packages/core-js/modules/esnext.uint8-array.set-from-base64.js new file mode 100644 index 000000000000..976fcb19d35b --- /dev/null +++ b/packages/core-js/modules/esnext.uint8-array.set-from-base64.js @@ -0,0 +1,19 @@ +'use strict'; +var $ = require('../internals/export'); +var globalThis = require('../internals/global-this'); +var $fromBase64 = require('../internals/uint8-from-base64'); +var anUint8Array = require('../internals/an-uint8-array'); + +var Uint8Array = globalThis.Uint8Array; + +// `Uint8Array.prototype.setFromBase64` method +// https://github.com/tc39/proposal-arraybuffer-base64 +if (Uint8Array) $({ target: 'Uint8Array', proto: true }, { + setFromBase64: function setFromBase64(string /* , options */) { + anUint8Array(this); + + var result = $fromBase64(string, arguments.length > 1 ? arguments[1] : undefined, this, this.length); + + return { read: result.read, written: result.written }; + } +}); diff --git a/packages/core-js/proposals/array-buffer-base64.js b/packages/core-js/proposals/array-buffer-base64.js index 63a0ee16bd82..e4616882a8f3 100644 --- a/packages/core-js/proposals/array-buffer-base64.js +++ b/packages/core-js/proposals/array-buffer-base64.js @@ -2,6 +2,7 @@ // https://github.com/tc39/proposal-arraybuffer-base64 require('../modules/esnext.uint8-array.from-base64'); require('../modules/esnext.uint8-array.from-hex'); +require('../modules/esnext.uint8-array.set-from-base64'); require('../modules/esnext.uint8-array.set-from-hex'); require('../modules/esnext.uint8-array.to-base64'); require('../modules/esnext.uint8-array.to-hex'); diff --git a/tests/compat/tests.js b/tests/compat/tests.js index 66575a6d8853..0b1b1bdf0c6b 100644 --- a/tests/compat/tests.js +++ b/tests/compat/tests.js @@ -1860,6 +1860,9 @@ GLOBAL.tests = { 'esnext.uint8-array.from-hex': function () { return Uint8Array.fromHex; }, + 'esnext.uint8-array.set-from-base64': function () { + return Uint8Array.prototype.setFromBase64; + }, 'esnext.uint8-array.set-from-hex': function () { return Uint8Array.prototype.setFromHex; }, diff --git a/tests/entries/unit.mjs b/tests/entries/unit.mjs index 6666e37f1a87..af3a46dd568a 100644 --- a/tests/entries/unit.mjs +++ b/tests/entries/unit.mjs @@ -1074,6 +1074,7 @@ for (const NS of ['es', 'stable', 'actual', 'full', 'features']) { for (const NS of ['actual', 'full', 'features']) { load(NS, 'typed-array/from-base64'); load(NS, 'typed-array/from-hex'); + load(NS, 'typed-array/set-from-base64'); load(NS, 'typed-array/set-from-hex'); load(NS, 'typed-array/to-base64'); load(NS, 'typed-array/to-hex'); diff --git a/tests/unit-global/esnext.uint8-array.from-base64.js b/tests/unit-global/esnext.uint8-array.from-base64.js index 6de552dc5614..4f99281f5839 100644 --- a/tests/unit-global/esnext.uint8-array.from-base64.js +++ b/tests/unit-global/esnext.uint8-array.from-base64.js @@ -14,11 +14,6 @@ if (DESCRIPTORS) QUnit.test('Uint8Array.fromBase64', assert => { assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ='), array, 'proper result'); - assert.throws(() => fromBase64('1234', null), TypeError, 'incorrect options argument #1'); - assert.throws(() => fromBase64('1234', 1), TypeError, 'incorrect options argument #2'); - - assert.throws(() => fromBase64('1234', { alphabet: 'base32' }), TypeError, 'incorrect encoding'); - assert.deepEqual(fromBase64('12/3'), new Uint8Array([215, 111, 247]), 'encoding #1'); assert.throws(() => fromBase64('12_3'), SyntaxError, 'encoding #2'); assert.deepEqual(fromBase64('12+3'), new Uint8Array([215, 111, 183]), 'encoding #3'); @@ -38,21 +33,34 @@ if (DESCRIPTORS) QUnit.test('Uint8Array.fromBase64', assert => { assert.throws(() => fromBase64(Object('SGVsbG8gV29ybGQ=')), TypeError, "isn't generic #4"); assert.throws(() => fromBase64('SGVsbG8gV29ybG%='), SyntaxError, 'throws on invalid #1'); assert.throws(() => fromBase64('SGVsbG8gV29ybGQ1='), SyntaxError, 'throws on invalid #2'); + assert.throws(() => fromBase64('SGVsbG8gV29ybGQ1=', null), TypeError, 'incorrect options argument #1'); + assert.throws(() => fromBase64('SGVsbG8gV29ybGQ1=', 1), TypeError, 'incorrect options argument #2'); + assert.throws(() => fromBase64('SGVsbG8gV29ybGQ1=', { alphabet: 'base32' }), TypeError, 'incorrect encoding'); + assert.throws(() => fromBase64('SGVsbG8gV29ybGQ1=', { lastChunkHandling: 'fff' }), TypeError, 'incorrect lastChunkHandling'); assert.deepEqual(fromBase64('BBB'), new Uint8Array([4, 16]), 'ending #1'); - assert.deepEqual(fromBase64('BBB', { strict: false }), new Uint8Array([4, 16]), 'ending #2'); - assert.throws(() => fromBase64('BBB', { strict: true }), SyntaxError, 'ending #3'); + assert.deepEqual(fromBase64('BBB', { lastChunkHandling: 'loose' }), new Uint8Array([4, 16]), 'ending #2'); + assert.deepEqual(fromBase64('BBB', { lastChunkHandling: 'stop-before-partial' }), new Uint8Array([]), 'ending #3'); + assert.throws(() => fromBase64('BBB', { lastChunkHandling: 'strict' }), SyntaxError, 'ending #4'); + assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ'), array, 'ending #5'); + assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ', { lastChunkHandling: 'loose' }), array, 'ending #6'); + assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ', { lastChunkHandling: 'stop-before-partial' }), array.slice(0, -2), 'ending #7'); + assert.throws(() => fromBase64('SGVsbG8gV29ybGQ', { lastChunkHandling: 'strict' }), SyntaxError, 'ending #8'); assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ= '), array, 'spaces #1'); assert.deepEqual(fromBase64('SGVsbG8gV2 9ybGQ='), array, 'spaces #2'); assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ=\n'), array, 'spaces #3'); assert.deepEqual(fromBase64('SGVsbG8gV2\n9ybGQ='), array, 'spaces #4'); - assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ= ', { strict: false }), array, 'spaces #5'); - assert.deepEqual(fromBase64('SGVsbG8gV2 9ybGQ=', { strict: false }), array, 'spaces #6'); - assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ=\n', { strict: false }), array, 'spaces #7'); - assert.deepEqual(fromBase64('SGVsbG8gV2\n9ybGQ=', { strict: false }), array, 'spaces #8'); - assert.throws(() => fromBase64('SGVsbG8gV29ybGQ= ', { strict: true }), SyntaxError, 'spaces #9'); - assert.throws(() => fromBase64('SGVsbG8gV2 9ybGQ=', { strict: true }), SyntaxError, 'spaces #10'); - assert.throws(() => fromBase64('SGVsbG8gV29ybGQ=\n', { strict: true }), SyntaxError, 'spaces #11'); - assert.throws(() => fromBase64('SGVsbG8gV2\n9ybGQ=', { strict: true }), SyntaxError, 'spaces #12'); + assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ= ', { lastChunkHandling: 'loose' }), array, 'spaces #5'); + assert.deepEqual(fromBase64('SGVsbG8gV2 9ybGQ=', { lastChunkHandling: 'loose' }), array, 'spaces #6'); + assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ=\n', { lastChunkHandling: 'loose' }), array, 'spaces #7'); + assert.deepEqual(fromBase64('SGVsbG8gV2\n9ybGQ=', { lastChunkHandling: 'loose' }), array, 'spaces #8'); + assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ= ', { lastChunkHandling: 'stop-before-partial' }), array, 'spaces #9'); + assert.deepEqual(fromBase64('SGVsbG8gV2 9ybGQ=', { lastChunkHandling: 'stop-before-partial' }), array, 'spaces #10'); + assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ=\n', { lastChunkHandling: 'stop-before-partial' }), array, 'spaces #11'); + assert.deepEqual(fromBase64('SGVsbG8gV2\n9ybGQ=', { lastChunkHandling: 'stop-before-partial' }), array, 'spaces #12'); + assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ= ', { lastChunkHandling: 'strict' }), array, 'spaces #13'); + assert.deepEqual(fromBase64('SGVsbG8gV2 9ybGQ=', { lastChunkHandling: 'strict' }), array, 'spaces #14'); + assert.deepEqual(fromBase64('SGVsbG8gV29ybGQ=\n', { lastChunkHandling: 'strict' }), array, 'spaces #15'); + assert.deepEqual(fromBase64('SGVsbG8gV2\n9ybGQ=', { lastChunkHandling: 'strict' }), array, 'spaces #16'); }); diff --git a/tests/unit-global/esnext.uint8-array.set-from-base64.js b/tests/unit-global/esnext.uint8-array.set-from-base64.js new file mode 100644 index 000000000000..1c3c31abb2cd --- /dev/null +++ b/tests/unit-global/esnext.uint8-array.set-from-base64.js @@ -0,0 +1,29 @@ +import { DESCRIPTORS } from '../helpers/constants.js'; + +if (DESCRIPTORS) QUnit.test('Uint8Array.prototype.setFromBase64', assert => { + const { setFromBase64 } = Uint8Array.prototype; + assert.isFunction(setFromBase64); + assert.arity(setFromBase64, 1); + assert.name(setFromBase64, 'setFromBase64'); + assert.looksNative(setFromBase64); + + const template = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 0, 0, 0, 0, 0]); + + const array1 = new Uint8Array(16); + const result1 = array1.setFromBase64('SGVsbG8gV29ybGQ='); + + assert.deepEqual(array1, template, 'proper result array #1'); + assert.deepEqual(result1, { read: 16, written: 11 }, 'proper result #1'); + + assert.throws(() => setFromBase64.call(Array(16), 'SGVsbG8gV29ybGQ='), TypeError, "isn't generic, this #1"); + assert.throws(() => setFromBase64.call(new Int8Array(16), 'SGVsbG8gV29ybGQ='), TypeError, "isn't generic, this #2"); + assert.throws(() => new Uint8Array(16).setFromBase64(null), TypeError, "isn't generic, arg #1"); + assert.throws(() => new Uint8Array(16).setFromBase64(undefined), TypeError, "isn't generic, arg #2"); + assert.throws(() => new Uint8Array(16).setFromBase64(1234), TypeError, "isn't generic, arg #3"); + assert.throws(() => new Uint8Array(16).setFromBase64(Object('SGVsbG8gV29ybGQ=')), TypeError, "isn't generic, arg #4"); + assert.throws(() => new Uint8Array(16).setFromBase64('^'), SyntaxError, 'throws on invalid #1'); + assert.throws(() => new Uint8Array(16).setFromBase64('SGVsbG8gV29ybGQ=', null), TypeError, 'incorrect options argument #1'); + assert.throws(() => new Uint8Array(16).setFromBase64('SGVsbG8gV29ybGQ=', 1), TypeError, 'incorrect options argument #2'); + assert.throws(() => new Uint8Array(16).setFromBase64('SGVsbG8gV29ybGQ=', { alphabet: 'base32' }), TypeError, 'incorrect encoding'); + assert.throws(() => new Uint8Array(16).setFromBase64('SGVsbG8gV29ybGQ=', { lastChunkHandling: 'fff' }), TypeError, 'incorrect lastChunkHandling'); +});