Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add tests for base64 proposal #3994

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions features.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ promise-with-resolvers
# https://github.com/tc39/proposal-set-methods
set-methods

# Uint8Array Base64
# https://github.com/tc39/proposal-arraybuffer-base64
uint8array-base64

## Standard language features
#
# Language features that have been included in a published version of the
Expand Down
22 changes: 22 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/alphabet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: Conversion of base64 strings to Uint8Arrays exercising the alphabet option
includes: [compareArray.js]
features: [uint8array-base64, TypedArray]
---*/

assert.compareArray(Uint8Array.fromBase64('x+/y'), [199, 239, 242]);
assert.compareArray(Uint8Array.fromBase64('x+/y', { alphabet: 'base64' }), [199, 239, 242]);
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('x+/y', { alphabet: 'base64url' });
});

assert.compareArray(Uint8Array.fromBase64('x-_y', { alphabet: 'base64url' }), [199, 239, 242]);
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('x-_y');
});
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('x-_y', { alphabet: 'base64' });
});
15 changes: 15 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/descriptor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: >
Uint8Array.fromBase64 has default data property attributes.
includes: [propertyHelper.js]
features: [uint8array-base64, TypedArray]
---*/

verifyProperty(Uint8Array, 'fromBase64', {
enumerable: false,
writable: true,
configurable: true
});
19 changes: 19 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/ignores-receiver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: Uint8Array.fromBase64 ignores its receiver
features: [uint8array-base64, TypedArray]
---*/

var fromBase64 = Uint8Array.fromBase64;
var noReceiver = fromBase64("Zg==");
assert.sameValue(Object.getPrototypeOf(noReceiver), Uint8Array.prototype);

class Subclass extends Uint8Array {
constructor() {
throw new Test262Error("subclass constructor called");
}
}
var fromSubclass = Subclass.fromBase64("Zg==");
assert.sameValue(Object.getPrototypeOf(fromSubclass), Uint8Array.prototype);
23 changes: 23 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/illegal-characters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: Uint8Array.fromBase64 throws a SyntaxError when input has non-base64, non-ascii-whitespace characters
features: [uint8array-base64, TypedArray]
---*/

var illegal = [
'Zm.9v',
'Zm9v^',
'Zg==&',
'Z−==', // U+2212 'Minus Sign'
'Z+==', // U+FF0B 'Fullwidth Plus Sign'
'Zg\u00A0==', // nbsp
'Zg\u2009==', // thin space
'Zg\u2028==', // line separator
];
illegal.forEach(function(value) {
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64(value)
});
});
64 changes: 64 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/last-chunk-handling.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: Handling of final chunks in Uint8Array.fromBase64
includes: [compareArray.js]
features: [uint8array-base64, TypedArray]
---*/

// padding
assert.compareArray(Uint8Array.fromBase64('ZXhhZg=='), [101, 120, 97, 102]);
assert.compareArray(Uint8Array.fromBase64('ZXhhZg==', { lastChunkHandling: 'loose' }), [101, 120, 97, 102]);
assert.compareArray(Uint8Array.fromBase64('ZXhhZg==', { lastChunkHandling: 'stop-before-partial' }), [101, 120, 97, 102]);
assert.compareArray(Uint8Array.fromBase64('ZXhhZg==', { lastChunkHandling: 'strict' }), [101, 120, 97, 102]);

// no padding
assert.compareArray(Uint8Array.fromBase64('ZXhhZg'), [101, 120, 97, 102]);
assert.compareArray(Uint8Array.fromBase64('ZXhhZg', { lastChunkHandling: 'loose' }), [101, 120, 97, 102]);
assert.compareArray(Uint8Array.fromBase64('ZXhhZg', { lastChunkHandling: 'stop-before-partial' }), [101, 120, 97]);
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('ZXhhZg', { lastChunkHandling: 'strict' });
});

// non-zero padding bits
assert.compareArray(Uint8Array.fromBase64('ZXhhZh=='), [101, 120, 97, 102]);
assert.compareArray(Uint8Array.fromBase64('ZXhhZh==', { lastChunkHandling: 'loose' }), [101, 120, 97, 102]);
assert.compareArray(Uint8Array.fromBase64('ZXhhZh==', { lastChunkHandling: 'stop-before-partial' }), [101, 120, 97, 102]);
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('ZXhhZh==', { lastChunkHandling: 'strict' });
});

// non-zero padding bits, no padding
assert.compareArray(Uint8Array.fromBase64('ZXhhZh'), [101, 120, 97, 102]);
assert.compareArray(Uint8Array.fromBase64('ZXhhZh', { lastChunkHandling: 'loose' }), [101, 120, 97, 102]);
assert.compareArray(Uint8Array.fromBase64('ZXhhZh', { lastChunkHandling: 'stop-before-partial' }), [101, 120, 97]);
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('ZXhhZh', { lastChunkHandling: 'strict' });
});

// partial padding
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('ZXhhZg=');
});
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('ZXhhZg=', { lastChunkHandling: 'loose' });
});
assert.compareArray(Uint8Array.fromBase64('ZXhhZg=', { lastChunkHandling: 'stop-before-partial' }), [101, 120, 97]);
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('ZXhhZg=', { lastChunkHandling: 'strict' });
});

// excess padding
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('ZXhhZg===');
});
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('ZXhhZg===', { lastChunkHandling: 'loose' });
});
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('ZXhhZg===', { lastChunkHandling: 'stop-before-partial' });
});
assert.throws(SyntaxError, function() {
Uint8Array.fromBase64('ZXhhZg===', { lastChunkHandling: 'strict' });
});
16 changes: 16 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/length.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: >
Uint8Array.fromBase64.length is 1.
includes: [propertyHelper.js]
features: [uint8array-base64, TypedArray]
---*/

verifyProperty(Uint8Array.fromBase64, 'length', {
value: 1,
enumerable: false,
writable: false,
configurable: true
});
16 changes: 16 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: >
Uint8Array.fromBase64.name is "fromBase64".
includes: [propertyHelper.js]
features: [uint8array-base64, TypedArray]
---*/

verifyProperty(Uint8Array.fromBase64, 'name', {
value: 'fromBase64',
enumerable: false,
writable: false,
configurable: true
});
15 changes: 15 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/nonconstructor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: >
Uint8Array.fromBase64 is not a constructor function.
includes: [isConstructor.js]
features: [uint8array-base64, TypedArray, Reflect.construct]
---*/

assert(!isConstructor(Uint8Array.fromBase64), "Uint8Array.fromBase64 is not a constructor");

assert.throws(TypeError, function() {
new Uint8Array.fromBase64('');
});
59 changes: 59 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/option-coercion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: Uint8Array.fromBase64 triggers effects of the "alphabet" and "lastChunkHandling" getters, but does not perform toString on the results
includes: [compareArray.js]
features: [uint8array-base64, TypedArray]
---*/

assert.throws(TypeError, function() {
Uint8Array.fromBase64("Zg==", { alphabet: Object("base64") });
});

assert.throws(TypeError, function() {
Uint8Array.fromBase64("Zg==", { lastChunkHandling: Object("loose") });
});


var toStringCalls = 0;
var throwyToString = {
toString: function() {
toStringCalls += 1;
throw new Test262Error("toString called");
}
};
assert.throws(TypeError, function() {
Uint8Array.fromBase64("Zg==", { alphabet: throwyToString });
});
assert.sameValue(toStringCalls, 0);

assert.throws(TypeError, function() {
Uint8Array.fromBase64("Zg==", { lastChunkHandling: throwyToString });
});
assert.sameValue(toStringCalls, 0);


var alphabetAccesses = 0;
var base64UrlOptions = {};
Object.defineProperty(base64UrlOptions, "alphabet", {
get: function() {
alphabetAccesses += 1;
return "base64url";
}
});
var arr = Uint8Array.fromBase64("x-_y", base64UrlOptions);
assert.compareArray(arr, [199, 239, 242]);
assert.sameValue(alphabetAccesses, 1);

var lastChunkHandlingAccesses = 0;
var strictOptions = {};
Object.defineProperty(strictOptions, "lastChunkHandling", {
get: function() {
lastChunkHandlingAccesses += 1;
return "strict";
}
});
var arr = Uint8Array.fromBase64("Zg==", strictOptions);
assert.compareArray(arr, [102]);
assert.sameValue(lastChunkHandlingAccesses, 1);
27 changes: 27 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/results.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: Conversion of base64 strings to Uint8Arrays
includes: [compareArray.js]
features: [uint8array-base64, TypedArray]
---*/

// standard test vectors from https://datatracker.ietf.org/doc/html/rfc4648#section-10
var standardBase64Vectors = [
["", []],
["Zg==", [102]],
["Zm8=", [102, 111]],
["Zm9v", [102, 111, 111]],
["Zm9vYg==", [102, 111, 111, 98]],
["Zm9vYmE=", [102, 111, 111, 98, 97]],
["Zm9vYmFy", [102, 111, 111, 98, 97, 114]],
];

standardBase64Vectors.forEach(function (pair) {
var arr = Uint8Array.fromBase64(pair[0]);
assert.sameValue(Object.getPrototypeOf(arr), Uint8Array.prototype, "decoding " + pair[0]);
assert.sameValue(arr.length, pair[1].length, "decoding " + pair[0]);
assert.sameValue(arr.buffer.byteLength, pair[1].length, "decoding " + pair[0]);
assert.compareArray(arr, pair[1], "decoding " + pair[0]);
});
41 changes: 41 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/string-coercion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: Uint8Array.fromBase64 throws if its argument is not a string
features: [uint8array-base64, TypedArray]
---*/

var toStringCalls = 0;
var throwyToString = {
toString: function() {
toStringCalls += 1;
throw new Test262Error("toString called");
}
};

assert.throws(TypeError, function() {
Uint8Array.fromBase64(throwyToString);
});
assert.sameValue(toStringCalls, 0);


var optionAccesses = 0;
var touchyOptions = {};
Object.defineProperty(touchyOptions, "alphabet", {
get: function() {
optionAccesses += 1;
throw new Test262Error("alphabet accessed");
}
});
Object.defineProperty(touchyOptions, "lastChunkHandling", {
get: function() {
optionAccesses += 1;
throw new Test262Error("lastChunkHandling accessed");
}
});
assert.throws(TypeError, function() {
Uint8Array.fromBase64(throwyToString, touchyOptions);
});
assert.sameValue(toStringCalls, 0);
assert.sameValue(optionAccesses, 0);
22 changes: 22 additions & 0 deletions test/built-ins/Uint8Array/fromBase64/whitespace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.frombase64
description: Uint8Array.fromBase64 ignores ASCII whitespace in the input
includes: [compareArray.js]
features: [uint8array-base64, TypedArray]
---*/

var whitespaceKinds = [
["Z g==", "space"],
["Z\tg==", "tab"],
["Z\x0Ag==", "LF"],
["Z\x0Cg==", "FF"],
["Z\x0Dg==", "CR"],
];
whitespaceKinds.forEach(function(pair) {
var arr = Uint8Array.fromBase64(pair[0]);
assert.sameValue(arr.length, 1);
assert.sameValue(arr.buffer.byteLength, 1);
assert.compareArray(arr, [102], "ascii whitespace: " + pair[1]);
});
15 changes: 15 additions & 0 deletions test/built-ins/Uint8Array/fromHex/descriptor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.fromhex
description: >
Uint8Array.fromHex has default data property attributes.
includes: [propertyHelper.js]
features: [uint8array-base64, TypedArray]
---*/

verifyProperty(Uint8Array, 'fromHex', {
enumerable: false,
writable: true,
configurable: true
});
19 changes: 19 additions & 0 deletions test/built-ins/Uint8Array/fromHex/ignores-receiver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (C) 2024 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-uint8array.fromhex
description: Uint8Array.fromHex ignores its receiver
features: [uint8array-base64, TypedArray]
---*/

var fromHex = Uint8Array.fromHex;
var noReceiver = fromHex("aa");
assert.sameValue(Object.getPrototypeOf(noReceiver), Uint8Array.prototype);

class Subclass extends Uint8Array {
constructor() {
throw new Test262Error("subclass constructor called");
}
}
var fromSubclass = Subclass.fromHex("aa");
assert.sameValue(Object.getPrototypeOf(fromSubclass), Uint8Array.prototype);