From 48182a18d0e65a4211cad52867b2392a7bb58988 Mon Sep 17 00:00:00 2001 From: RBRi Date: Mon, 23 Dec 2024 19:30:42 +0100 Subject: [PATCH] fix border checks for typedarray set * fix border checks for typedarray set (see https://github.com/HtmlUnit/htmlunit-core-js/issues/27) * move error msg to properties file * use messages for typedarray ctor * use messages for typedarray with method --- .../typedarrays/NativeTypedArrayView.java | 43 +++- .../javascript/resources/Messages.properties | 18 ++ .../tests/harmony/TypedArraySetTest.java | 11 + .../tests/harmony/TypedArrayWithTest.java | 11 + .../jstests/harmony/typed-array-ctor.js | 210 ++++++++++++++++++ .../jstests/harmony/typed-array-set.js | 89 ++++++++ .../jstests/harmony/typed-array-with.js | 39 ++++ 7 files changed, 409 insertions(+), 12 deletions(-) create mode 100644 tests/src/test/java/org/mozilla/javascript/tests/harmony/TypedArraySetTest.java create mode 100644 tests/src/test/java/org/mozilla/javascript/tests/harmony/TypedArrayWithTest.java create mode 100644 tests/testsrc/jstests/harmony/typed-array-set.js create mode 100644 tests/testsrc/jstests/harmony/typed-array-with.js diff --git a/rhino/src/main/java/org/mozilla/javascript/typedarrays/NativeTypedArrayView.java b/rhino/src/main/java/org/mozilla/javascript/typedarrays/NativeTypedArrayView.java index 64b39ce1ec..9d35965ba2 100644 --- a/rhino/src/main/java/org/mozilla/javascript/typedarrays/NativeTypedArrayView.java +++ b/rhino/src/main/java/org/mozilla/javascript/typedarrays/NativeTypedArrayView.java @@ -555,17 +555,26 @@ protected static NativeTypedArrayView js_constructor( } if ((byteOff < 0) || (byteOff > na.getLength())) { - throw ScriptRuntime.rangeError("offset out of range"); + String msg = ScriptRuntime.getMessageById("msg.typed.array.bad.offset", byteOff); + throw ScriptRuntime.rangeError(msg); } if ((byteLen < 0) || ((byteOff + byteLen) > na.getLength())) { - throw ScriptRuntime.rangeError("length out of range"); + String msg = ScriptRuntime.getMessageById("msg.typed.array.bad.length", byteLen); + throw ScriptRuntime.rangeError(msg); } if ((byteOff % bytesPerElement) != 0) { - throw ScriptRuntime.rangeError("offset must be a multiple of the byte size"); + String msg = + ScriptRuntime.getMessageById( + "msg.typed.array.bad.offset.byte.size", byteOff, bytesPerElement); + throw ScriptRuntime.rangeError(msg); } if ((byteLen % bytesPerElement) != 0) { - throw ScriptRuntime.rangeError( - "offset and buffer must be a multiple of the byte size"); + String msg = + ScriptRuntime.getMessageById( + "msg.typed.array.bad.buffer.length.byte.size", + byteLen, + bytesPerElement); + throw ScriptRuntime.rangeError(msg); } return constructable.construct(na, byteOff, byteLen / bytesPerElement); @@ -608,12 +617,14 @@ protected static NativeTypedArrayView js_constructor( } private void setRange(NativeTypedArrayView v, int off) { - if (off >= length) { - throw ScriptRuntime.rangeError("offset out of range"); + if (off < 0 || off > length) { + String msg = ScriptRuntime.getMessageById("msg.typed.array.bad.offset", off); + throw ScriptRuntime.rangeError(msg); } if (v.length > (length - off)) { - throw ScriptRuntime.rangeError("source array too long"); + String msg = ScriptRuntime.getMessageById("msg.typed.array.bad.source.array"); + throw ScriptRuntime.rangeError(msg); } if (v.arrayBuffer == arrayBuffer) { @@ -633,11 +644,13 @@ private void setRange(NativeTypedArrayView v, int off) { } private void setRange(NativeArray a, int off) { - if (off > length) { - throw ScriptRuntime.rangeError("offset out of range"); + if (off < 0 || off > length) { + String msg = ScriptRuntime.getMessageById("msg.typed.array.bad.offset", off); + throw ScriptRuntime.rangeError(msg); } if ((off + a.size()) > length) { - throw ScriptRuntime.rangeError("offset + length out of range"); + String msg = ScriptRuntime.getMessageById("msg.typed.array.bad.source.array"); + throw ScriptRuntime.rangeError(msg); } int pos = off; @@ -1118,7 +1131,13 @@ private static Object js_with( Object argsValue = args.length > 1 ? ScriptRuntime.toNumber(args[1]) : 0.0; if (actualIndex < 0 || actualIndex >= self.length) { - throw ScriptRuntime.rangeError("index out of range"); + String msg = + ScriptRuntime.getMessageById( + "msg.typed.array.index.out.of.bounds", + relativeIndex, + self.length * -1, + self.length - 1); + throw ScriptRuntime.rangeError(msg); } NativeArrayBuffer newBuffer = diff --git a/rhino/src/main/resources/org/mozilla/javascript/resources/Messages.properties b/rhino/src/main/resources/org/mozilla/javascript/resources/Messages.properties index c183115283..cde7cb5f50 100644 --- a/rhino/src/main/resources/org/mozilla/javascript/resources/Messages.properties +++ b/rhino/src/main/resources/org/mozilla/javascript/resources/Messages.properties @@ -997,6 +997,24 @@ msg.promise.any.toobig =\ msg.typed.array.ctor.incompatible = \ Method %TypedArray%.prototype.{0} called on incompatible receiver +msg.typed.array.bad.offset = \ + offset {0} out of range + +msg.typed.array.bad.length = \ + length {0} out of range + +msg.typed.array.bad.offset.byte.size = \ + offset {0} must be a multiple of the byte size {1} + +msg.typed.array.bad.buffer.length.byte.size = \ + used buffer length {0} must be a multiple of the byte size {1} + +msg.typed.array.bad.source.array = \ + source array is too long + +msg.typed.array.index.out.of.bounds =\ + index {0} is out of bounds [{1}..{2}] + # Error msg.iterable.expected =\ Expected the first argument to be iterable diff --git a/tests/src/test/java/org/mozilla/javascript/tests/harmony/TypedArraySetTest.java b/tests/src/test/java/org/mozilla/javascript/tests/harmony/TypedArraySetTest.java new file mode 100644 index 0000000000..a9ea93f385 --- /dev/null +++ b/tests/src/test/java/org/mozilla/javascript/tests/harmony/TypedArraySetTest.java @@ -0,0 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.javascript.tests.harmony; + +import org.mozilla.javascript.drivers.RhinoTest; +import org.mozilla.javascript.drivers.ScriptTestsBase; + +@RhinoTest("testsrc/jstests/harmony/typed-array-set.js") +public class TypedArraySetTest extends ScriptTestsBase {} diff --git a/tests/src/test/java/org/mozilla/javascript/tests/harmony/TypedArrayWithTest.java b/tests/src/test/java/org/mozilla/javascript/tests/harmony/TypedArrayWithTest.java new file mode 100644 index 0000000000..32737e74bc --- /dev/null +++ b/tests/src/test/java/org/mozilla/javascript/tests/harmony/TypedArrayWithTest.java @@ -0,0 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.javascript.tests.harmony; + +import org.mozilla.javascript.drivers.RhinoTest; +import org.mozilla.javascript.drivers.ScriptTestsBase; + +@RhinoTest("testsrc/jstests/harmony/typed-array-with.js") +public class TypedArrayWithTest extends ScriptTestsBase {} diff --git a/tests/testsrc/jstests/harmony/typed-array-ctor.js b/tests/testsrc/jstests/harmony/typed-array-ctor.js index 70f8f3e45b..899ec1acf2 100644 --- a/tests/testsrc/jstests/harmony/typed-array-ctor.js +++ b/tests/testsrc/jstests/harmony/typed-array-ctor.js @@ -18,6 +18,28 @@ load("testsrc/assert.js"); try { new Int8Array(-268435457); } catch (e) { msg = e.toString();} assertEquals("RangeError: Negative array length -2.68435457E8", msg); + msg = null; + try { new Int8Array(new ArrayBuffer(), -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset -1 out of range", msg); + + msg = null; + try { new Int8Array(new ArrayBuffer(2), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 out of range", msg); + + msg = null; + try { new Int8Array(new ArrayBuffer(), 0, -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length -1 out of range", msg); + + msg = null; + try { new Int8Array(new ArrayBuffer(2), 0, 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length 3 out of range", msg); + + var ta = new Int8Array(new ArrayBuffer(4), 3); + assertEquals("0", ta.toString()); + + ta = new Int8Array(new ArrayBuffer(5), 2); + assertEquals("0,0,0", ta.toString()); + var one = new Int8Array([7]); assertEquals("7", one.toString()); @@ -63,6 +85,28 @@ load("testsrc/assert.js"); try { new Uint8Array(-268435457); } catch (e) { msg = e.toString();} assertEquals("RangeError: Negative array length -2.68435457E8", msg); + msg = null; + try { new Uint8Array(new ArrayBuffer(), -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset -1 out of range", msg); + + msg = null; + try { new Uint8Array(new ArrayBuffer(2), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 out of range", msg); + + msg = null; + try { new Uint8Array(new ArrayBuffer(), 0, -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length -1 out of range", msg); + + msg = null; + try { new Uint8Array(new ArrayBuffer(2), 0, 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length 3 out of range", msg); + + var ta = new Uint8Array(new ArrayBuffer(4), 3); + assertEquals("0", ta.toString()); + + ta = new Uint8Array(new ArrayBuffer(5), 2); + assertEquals("0,0,0", ta.toString()); + one = new Uint8Array([7]); assertEquals("7", one.toString()); @@ -109,6 +153,30 @@ load("testsrc/assert.js"); try { new Int16Array(-268435457); } catch (e) { msg = e.toString();} assertEquals("RangeError: Negative array length -5.36870914E8", msg); + msg = null; + try { new Int16Array(new ArrayBuffer(), -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset -1 out of range", msg); + + msg = null; + try { new Int16Array(new ArrayBuffer(2), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 out of range", msg); + + msg = null; + try { new Int16Array(new ArrayBuffer(), 0, -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length -2 out of range", msg); + + msg = null; + try { new Int16Array(new ArrayBuffer(2), 0, 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length 6 out of range", msg); + + msg = null; + try { new Int16Array(new ArrayBuffer(4), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 must be a multiple of the byte size 2", msg); + + msg = null; + try { new Int16Array(new ArrayBuffer(5), 2); } catch (e) { msg = e.toString();} + assertEquals("RangeError: used buffer length 3 must be a multiple of the byte size 2", msg); + one = new Int16Array([7]); assertEquals("7", one.toString()); @@ -155,6 +223,30 @@ load("testsrc/assert.js"); try { new Uint16Array(-268435457); } catch (e) { msg = e.toString();} assertEquals("RangeError: Negative array length -5.36870914E8", msg); + msg = null; + try { new Uint16Array(new ArrayBuffer(), -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset -1 out of range", msg); + + msg = null; + try { new Uint16Array(new ArrayBuffer(2), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 out of range", msg); + + msg = null; + try { new Uint16Array(new ArrayBuffer(), 0, -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length -2 out of range", msg); + + msg = null; + try { new Uint16Array(new ArrayBuffer(2), 0, 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length 6 out of range", msg); + + msg = null; + try { new Uint16Array(new ArrayBuffer(4), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 must be a multiple of the byte size 2", msg); + + msg = null; + try { new Uint16Array(new ArrayBuffer(5), 2); } catch (e) { msg = e.toString();} + assertEquals("RangeError: used buffer length 3 must be a multiple of the byte size 2", msg); + one = new Uint16Array([7]); assertEquals("7", one.toString()); @@ -201,6 +293,30 @@ load("testsrc/assert.js"); try { new Int32Array(-268435457); } catch (e) { msg = e.toString();} assertEquals("RangeError: Negative array length -1.073741828E9", msg); + msg = null; + try { new Int32Array(new ArrayBuffer(), -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset -1 out of range", msg); + + msg = null; + try { new Int32Array(new ArrayBuffer(2), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 out of range", msg); + + msg = null; + try { new Int32Array(new ArrayBuffer(), 0, -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length -4 out of range", msg); + + msg = null; + try { new Int32Array(new ArrayBuffer(2), 0, 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length 12 out of range", msg); + + msg = null; + try { new Int32Array(new ArrayBuffer(4), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 must be a multiple of the byte size 4", msg); + + msg = null; + try { new Int32Array(new ArrayBuffer(5), 4); } catch (e) { msg = e.toString();} + assertEquals("RangeError: used buffer length 1 must be a multiple of the byte size 4", msg); + one = new Int32Array([7]); assertEquals("7", one.toString()); @@ -247,6 +363,30 @@ load("testsrc/assert.js"); try { new Uint32Array(-268435457); } catch (e) { msg = e.toString();} assertEquals("RangeError: Negative array length -1.073741828E9", msg); + msg = null; + try { new Uint32Array(new ArrayBuffer(), -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset -1 out of range", msg); + + msg = null; + try { new Uint32Array(new ArrayBuffer(2), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 out of range", msg); + + msg = null; + try { new Uint32Array(new ArrayBuffer(), 0, -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length -4 out of range", msg); + + msg = null; + try { new Uint32Array(new ArrayBuffer(2), 0, 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length 12 out of range", msg); + + msg = null; + try { new Uint32Array(new ArrayBuffer(4), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 must be a multiple of the byte size 4", msg); + + msg = null; + try { new Uint32Array(new ArrayBuffer(5), 4); } catch (e) { msg = e.toString();} + assertEquals("RangeError: used buffer length 1 must be a multiple of the byte size 4", msg); + one = new Uint32Array([7]); assertEquals("7", one.toString()); @@ -293,6 +433,28 @@ load("testsrc/assert.js"); try { new Uint8ClampedArray(-268435457); } catch (e) { msg = e.toString();} assertEquals("RangeError: Negative array length -2.68435457E8", msg); + msg = null; + try { new Uint8ClampedArray(new ArrayBuffer(), -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset -1 out of range", msg); + + msg = null; + try { new Uint8ClampedArray(new ArrayBuffer(2), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 out of range", msg); + + msg = null; + try { new Uint8ClampedArray(new ArrayBuffer(), 0, -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length -1 out of range", msg); + + msg = null; + try { new Uint8ClampedArray(new ArrayBuffer(2), 0, 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length 3 out of range", msg); + + var ta = new Uint8ClampedArray(new ArrayBuffer(4), 3); + assertEquals("0", ta.toString()); + + ta = new Uint8ClampedArray(new ArrayBuffer(5), 2); + assertEquals("0,0,0", ta.toString()); + one = new Uint8ClampedArray([7]); assertEquals("7", one.toString()); @@ -339,6 +501,30 @@ load("testsrc/assert.js"); try { new Float32Array(-268435457); } catch (e) { msg = e.toString();} assertEquals("RangeError: Negative array length -1.073741828E9", msg); + msg = null; + try { new Float32Array(new ArrayBuffer(), -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset -1 out of range", msg); + + msg = null; + try { new Float32Array(new ArrayBuffer(2), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 out of range", msg); + + msg = null; + try { new Float32Array(new ArrayBuffer(), 0, -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length -4 out of range", msg); + + msg = null; + try { new Float32Array(new ArrayBuffer(2), 0, 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length 12 out of range", msg); + + msg = null; + try { new Float32Array(new ArrayBuffer(4), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 must be a multiple of the byte size 4", msg); + + msg = null; + try { new Float32Array(new ArrayBuffer(5), 4); } catch (e) { msg = e.toString();} + assertEquals("RangeError: used buffer length 1 must be a multiple of the byte size 4", msg); + one = new Float32Array([7]); assertEquals("7", one.toString()); @@ -385,6 +571,30 @@ load("testsrc/assert.js"); try { new Float64Array(-268435457); } catch (e) { msg = e.toString();} assertEquals("RangeError: Negative array length -2.147483656E9", msg); + msg = null; + try { new Float64Array(new ArrayBuffer(), -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset -1 out of range", msg); + + msg = null; + try { new Float64Array(new ArrayBuffer(2), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 out of range", msg); + + msg = null; + try { new Float64Array(new ArrayBuffer(), 0, -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length -8 out of range", msg); + + msg = null; + try { new Float64Array(new ArrayBuffer(2), 0, 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: length 24 out of range", msg); + + msg = null; + try { new Float64Array(new ArrayBuffer(4), 3); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 3 must be a multiple of the byte size 8", msg); + + msg = null; + try { new Float64Array(new ArrayBuffer(9), 8); } catch (e) { msg = e.toString();} + assertEquals("RangeError: used buffer length 1 must be a multiple of the byte size 8", msg); + one = new Float64Array([7]); assertEquals("7", one.toString()); diff --git a/tests/testsrc/jstests/harmony/typed-array-set.js b/tests/testsrc/jstests/harmony/typed-array-set.js new file mode 100644 index 0000000000..5097e7f205 --- /dev/null +++ b/tests/testsrc/jstests/harmony/typed-array-set.js @@ -0,0 +1,89 @@ +load("testsrc/assert.js"); + + +var types = [Int8Array, Uint8Array, Int16Array, Uint16Array, + Int32Array, Uint32Array, Uint8ClampedArray, Float32Array, + Float64Array]; + +for (var t = 0; t < types.length; t++) { + var type = types[t]; + + var buffer = new ArrayBuffer(8 * type.BYTES_PER_ELEMENT); + var arr = new type(buffer); + + arr.set([1, 2, 3], 3); + assertEquals("0,0,0,1,2,3,0,0", arr.toString()); + + arr.set([7], 0); + assertEquals("7,0,0,1,2,3,0,0", arr.toString()); + + arr.set([8, 9]); + assertEquals("8,9,0,1,2,3,0,0", arr.toString()); + + var msg = null; + try { arr.set([0], -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset -1 out of range", msg); + + arr.set([], 8); + assertEquals("8,9,0,1,2,3,0,0", arr.toString()); + + msg = null; + try { arr.set([], 9); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 9 out of range", msg); + + arr.set([1], 7); + assertEquals("8,9,0,1,2,3,0,1", arr.toString()); + + msg = null; + try { arr.set([1], 8); } catch (e) { msg = e.toString();} + assertEquals("RangeError: source array is too long", msg); + + arr.set([0, 1, 2, 3, 4, 5, 6, 7]); + assertEquals("0,1,2,3,4,5,6,7", arr.toString()); + + msg = null; + try { arr.set([0, 1, 2, 3, 4, 5, 6, 7, 8]); } catch (e) { msg = e.toString();} + assertEquals("RangeError: source array is too long", msg); +} + +for (var t = 0; t < types.length; t++) { + var type = types[t]; + + var buffer = new ArrayBuffer(8 * type.BYTES_PER_ELEMENT); + var arr = new type(buffer); + + arr.set(new type([1, 2, 3]), 3); + assertEquals("0,0,0,1,2,3,0,0", arr.toString()); + + arr.set(new type([7]), 0); + assertEquals("7,0,0,1,2,3,0,0", arr.toString()); + + arr.set(new type([8, 9])); + assertEquals("8,9,0,1,2,3,0,0", arr.toString()); + + var msg = null; + try { arr.set(new type([0]), -1); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset -1 out of range", msg); + + arr.set(new type([]), 8); + assertEquals("8,9,0,1,2,3,0,0", arr.toString()); + + msg = null; + try { arr.set(new type([]), 9); } catch (e) { msg = e.toString();} + assertEquals("RangeError: offset 9 out of range", msg); + + arr.set(new type([1]), 7); + assertEquals("8,9,0,1,2,3,0,1", arr.toString()); + + msg = null; + try { arr.set(new type([1]), 8); } catch (e) { msg = e.toString();} + assertEquals("RangeError: source array is too long", msg); + + arr.set(new type([0, 1, 2, 3, 4, 5, 6, 7])); + assertEquals("0,1,2,3,4,5,6,7", arr.toString()); + + msg = null; + try { arr.set(new type([0, 1, 2, 3, 4, 5, 6, 7, 8])); } catch (e) { msg = e.toString();} + assertEquals("RangeError: source array is too long", msg);} + +"success"; \ No newline at end of file diff --git a/tests/testsrc/jstests/harmony/typed-array-with.js b/tests/testsrc/jstests/harmony/typed-array-with.js new file mode 100644 index 0000000000..f64c42f2b4 --- /dev/null +++ b/tests/testsrc/jstests/harmony/typed-array-with.js @@ -0,0 +1,39 @@ +load("testsrc/assert.js"); + + +var types = [Int8Array, Uint8Array, Int16Array, Uint16Array, + Int32Array, Uint32Array, Uint8ClampedArray, Float32Array, + Float64Array]; + +for (var t = 0; t < types.length; t++) { + var type = types[t]; + + var buffer = new ArrayBuffer(8 * type.BYTES_PER_ELEMENT); + var arr = new type(buffer); + + var ta = arr.with(0, 11); + assertEquals("0,0,0,0,0,0,0,0", arr.toString()); + assertEquals("11,0,0,0,0,0,0,0", ta.toString()); + + ta = arr.with(7, 4); + assertEquals("0,0,0,0,0,0,0,0", arr.toString()); + assertEquals("0,0,0,0,0,0,0,4", ta.toString()); + + ta = arr.with(-1, 4); + assertEquals("0,0,0,0,0,0,0,0", arr.toString()); + assertEquals("0,0,0,0,0,0,0,4", ta.toString()); + + ta = arr.with(-8, 4); + assertEquals("0,0,0,0,0,0,0,0", arr.toString()); + assertEquals("4,0,0,0,0,0,0,0", ta.toString()); + + var msg = null; + try { arr.with(-9, 42); } catch (e) { msg = e.toString();} + assertEquals("RangeError: index -9 is out of bounds [-8..7]", msg); + + msg = null; + try { arr.with(8, 42); } catch (e) { msg = e.toString();} + assertEquals("RangeError: index 8 is out of bounds [-8..7]", msg); +} + +"success"; \ No newline at end of file