github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/builtin_arrray_test.go (about)

     1  package goja
     2  
     3  import "testing"
     4  
     5  func TestArrayProtoProp(t *testing.T) {
     6  	const SCRIPT = `
     7  	Object.defineProperty(Array.prototype, '0', {value: 42, configurable: true, writable: false})
     8  	var a = []
     9  	a[0] = 1
    10  	a[0]
    11  	`
    12  
    13  	testScript(SCRIPT, valueInt(42), t)
    14  }
    15  
    16  func TestArrayDelete(t *testing.T) {
    17  	const SCRIPT = `
    18  	var a = [1, 2];
    19  	var deleted = delete a[0];
    20  	var undef = a[0] === undefined;
    21  	var len = a.length;
    22  
    23  	deleted && undef && len === 2;
    24  	`
    25  
    26  	testScript(SCRIPT, valueTrue, t)
    27  }
    28  
    29  func TestArrayDeleteNonexisting(t *testing.T) {
    30  	const SCRIPT = `
    31  	Array.prototype[0] = 42;
    32  	var a = [];
    33  	delete a[0] && a[0] === 42;
    34  	`
    35  
    36  	testScript(SCRIPT, valueTrue, t)
    37  }
    38  
    39  func TestArraySetLength(t *testing.T) {
    40  	const SCRIPT = `
    41  	var a = [1, 2];
    42  	var assert0 = a.length == 2;
    43  	a.length = "1";
    44  	a.length = 1.0;
    45  	a.length = 1;
    46  	var assert1 = a.length == 1;
    47  	a.length = 2;
    48  	var assert2 = a.length == 2;
    49  	assert0 && assert1 && assert2 && a[1] === undefined;
    50  
    51  	`
    52  
    53  	testScript(SCRIPT, valueTrue, t)
    54  }
    55  
    56  func TestArrayReverseNonOptimisable(t *testing.T) {
    57  	const SCRIPT = `
    58  	var a = [];
    59  	Object.defineProperty(a, "0", {get: function() {return 42}, set: function(v) {Object.defineProperty(a, "0", {value: v + 1, writable: true, configurable: true})}, configurable: true})
    60  	a[1] = 43;
    61  	a.reverse();
    62  
    63  	a.length === 2 && a[0] === 44 && a[1] === 42;
    64  	`
    65  
    66  	testScript(SCRIPT, valueTrue, t)
    67  }
    68  
    69  func TestArrayPushNonOptimisable(t *testing.T) {
    70  	const SCRIPT = `
    71  	Object.defineProperty(Object.prototype, "0", {value: 42});
    72  	var a = [];
    73  	var thrown = false;
    74  	try {
    75  		a.push(1);
    76  	} catch (e) {
    77  		thrown = e instanceof TypeError;
    78  	}
    79  	thrown;
    80  	`
    81  
    82  	testScript(SCRIPT, valueTrue, t)
    83  }
    84  
    85  func TestArraySetLengthWithPropItems(t *testing.T) {
    86  	const SCRIPT = `
    87  	var a = [1,2,3,4];
    88  	var thrown = false;
    89  
    90  	Object.defineProperty(a, "2", {value: 42, configurable: false, writable: false});
    91  	try {
    92  		Object.defineProperty(a, "length", {value: 0, writable: false});
    93  	} catch (e) {
    94  		thrown = e instanceof TypeError;
    95  	}
    96  	thrown && a.length === 3;
    97  	`
    98  
    99  	testScript(SCRIPT, valueTrue, t)
   100  }
   101  
   102  func TestArrayFrom(t *testing.T) {
   103  	const SCRIPT = `
   104  	function checkDestHoles(dest, prefix) {
   105  		assert(dest !== source, prefix + ": dest !== source");
   106  		assert.sameValue(dest.length, 3, prefix + ": dest.length");
   107  		assert.sameValue(dest[0], 1, prefix + ": [0]");
   108  		assert.sameValue(dest[1], undefined, prefix + ": [1]");
   109  		assert(dest.hasOwnProperty("1"), prefix + ': hasOwnProperty("1")');
   110  		assert.sameValue(dest[2], 3, prefix + ": [2]");
   111  	}
   112  
   113  	function checkDest(dest, prefix) {
   114  		assert(dest !== source, prefix + ": dest !== source");
   115  		assert.sameValue(dest.length, 3, prefix + ": dest.length");
   116  		assert.sameValue(dest[0], 1, prefix + ": [0]");
   117  		assert.sameValue(dest[1], 2, prefix + ": [1]");
   118  		assert.sameValue(dest[2], 3, prefix + ": [2]");
   119  	}
   120  
   121  	var source = [1,2,3];
   122  	var srcHoles = [1,,3];
   123  
   124  	checkDest(Array.from(source), "std source/std dest");
   125  	checkDestHoles(Array.from(srcHoles), "std source (holes)/std dest");
   126  
   127  	function Iter() {
   128  		this.idx = 0;
   129  	}
   130  	Iter.prototype.next = function() {
   131  		if (this.idx < source.length) {
   132  			return {value: source[this.idx++]};
   133  		} else {
   134  			return {done: true};
   135  		}
   136  	}
   137  
   138  	var src = {};
   139  	src[Symbol.iterator] = function() {
   140  		return new Iter();
   141  	}
   142  	checkDest(Array.from(src), "iter src/std dest");
   143  
   144  	src = {0: 1, 2: 3, length: 3};
   145  	checkDestHoles(Array.from(src), "arrayLike src/std dest");
   146  
   147  	function A() {}
   148  	A.from = Array.from;
   149  
   150  	checkDest(A.from(source), "std src/cust dest");
   151  	checkDestHoles(A.from(srcHoles), "std src (holes)/cust dest");
   152  	checkDestHoles(A.from(src), "arrayLike src/cust dest");
   153  
   154  	function T2() {
   155  	  Object.defineProperty(this, 0, {
   156  		configurable: false,
   157  		writable: true,
   158  		enumerable: true
   159  	  });
   160  	}
   161  
   162  	assert.throws(TypeError, function() {
   163  		Array.from.call(T2, source);
   164  	});
   165  
   166  	`
   167  
   168  	testScriptWithTestLib(SCRIPT, _undefined, t)
   169  }
   170  
   171  func TestArrayOf(t *testing.T) {
   172  	const SCRIPT = `
   173  	function T1() {
   174  	  Object.preventExtensions(this);
   175  	}
   176  	
   177  	assert.throws(TypeError, function() {
   178  	  Array.of.call(T1, 'Bob');
   179  	});
   180  
   181  	function T2() {
   182  	  Object.defineProperty(this, 0, {
   183  		configurable: false,
   184  		writable: true,
   185  		enumerable: true
   186  	  });
   187  	}
   188  	
   189  	assert.throws(TypeError, function() {
   190  	  Array.of.call(T2, 'Bob');
   191  	})
   192  
   193  	result = Array.of.call(undefined);
   194  	assert(
   195  	  result instanceof Array,
   196  	  'this is not a constructor'
   197  	);
   198  
   199  	result = Array.of.call(Math.cos);
   200  	assert(
   201  	  result instanceof Array,
   202  	  'this is a builtin function with no [[Construct]] slot'
   203  	);
   204  
   205  	`
   206  
   207  	testScriptWithTestLib(SCRIPT, _undefined, t)
   208  }
   209  
   210  func TestUnscopables(t *testing.T) {
   211  	const SCRIPT = `
   212  	var keys = [];
   213  	var _length;
   214  	with (Array.prototype) {
   215  		_length = length;
   216  		keys.push('something');
   217  	}
   218  	_length === 0 && keys.length === 1 && keys[0] === "something";
   219  	`
   220  	testScript(SCRIPT, valueTrue, t)
   221  }
   222  
   223  func TestArraySort(t *testing.T) {
   224  	const SCRIPT = `
   225  	assert.throws(TypeError, function() {
   226  		[1,2].sort(null);
   227  	}, "null compare function");
   228  	assert.throws(TypeError, function() {
   229  		[1,2].sort({});
   230  	}, "non-callable compare function");
   231  	`
   232  	testScriptWithTestLib(SCRIPT, _undefined, t)
   233  }
   234  
   235  func TestArraySortNonStdArray(t *testing.T) {
   236  	const SCRIPT = `
   237  	const array = [undefined, 'c', /*hole*/, 'b', undefined, /*hole*/, 'a', 'd'];
   238  
   239  	Object.defineProperty(array, '2', {
   240  	  get() {
   241  		array.pop();
   242  		array.pop();
   243  		return this.foo;
   244  	  },
   245  	  set(v) {
   246  		this.foo = v;
   247  	  }
   248  	});
   249  
   250  	array.sort();
   251  
   252  	assert.sameValue(array[0], 'b');
   253  	assert.sameValue(array[1], 'c');
   254  	assert.sameValue(array[3], undefined);
   255  	assert.sameValue(array[4], undefined);
   256  	assert.sameValue('5' in array, false);
   257  	assert.sameValue(array.hasOwnProperty('5'), false);
   258  	assert.sameValue(array.length, 6);
   259  	assert.sameValue(array.foo, undefined);
   260  
   261  	assert.sameValue(array[2], undefined);
   262  	assert.sameValue(array.length, 4);
   263  	`
   264  	testScriptWithTestLib(SCRIPT, _undefined, t)
   265  }
   266  
   267  func TestArrayConcat(t *testing.T) {
   268  	const SCRIPT = `
   269  	var concat = Array.prototype.concat;
   270  	var array = [1, 2];
   271  	var sparseArray = [1, , 2];
   272  	var nonSpreadableArray = [1, 2];
   273  	nonSpreadableArray[Symbol.isConcatSpreadable] = false;
   274  	var arrayLike = { 0: 1, 1: 2, length: 2 };
   275  	var spreadableArrayLike = { 0: 1, 1: 2, length: 2 };
   276  	spreadableArrayLike[Symbol.isConcatSpreadable] = true;
   277  	assert(looksNative(concat));
   278  	assert(deepEqual(array.concat(), [1, 2]), '#1');
   279  	assert(deepEqual(sparseArray.concat(), [1, , 2]), '#2');
   280  	assert(deepEqual(nonSpreadableArray.concat(), [[1, 2]]), '#3');
   281  	assert(deepEqual(concat.call(arrayLike), [{ 0: 1, 1: 2, length: 2 }]), '#4');
   282  	assert(deepEqual(concat.call(spreadableArrayLike), [1, 2]), '#5');
   283  	assert(deepEqual([].concat(array), [1, 2]), '#6');
   284  	assert(deepEqual([].concat(sparseArray), [1, , 2]), '#7');
   285  	assert(deepEqual([].concat(nonSpreadableArray), [[1, 2]]), '#8');
   286  	assert(deepEqual([].concat(arrayLike), [{ 0: 1, 1: 2, length: 2 }]), '#9');
   287  	assert(deepEqual([].concat(spreadableArrayLike), [1, 2]), '#10');
   288  	assert(deepEqual(array.concat(sparseArray, nonSpreadableArray, arrayLike, spreadableArrayLike), [
   289  	1, 2, 1, , 2, [1, 2], { 0: 1, 1: 2, length: 2 }, 1, 2,
   290  	]), '#11');
   291  	array = [];
   292  	array.constructor = {};
   293  	array.constructor[Symbol.species] = function () {
   294  		return { foo: 1 };
   295  	}
   296  	assert.sameValue(array.concat().foo, 1, '@@species');
   297  	`
   298  	testScriptWithTestLibX(SCRIPT, _undefined, t)
   299  }
   300  
   301  func TestArrayFlat(t *testing.T) {
   302  	const SCRIPT = `
   303  	var array = [1, [2,3,[4,5,6]], [[[[7,8,9]]]]];
   304  	assert(deepEqual(array.flat(), [1,2,3,[4,5,6],[[[7,8,9]]]]), '#1');
   305  	assert(deepEqual(array.flat(1), [1,2,3,[4,5,6],[[[7,8,9]]]]), '#2');
   306  	assert(deepEqual(array.flat(3), [1,2,3,4,5,6,[7,8,9]]), '#3');
   307  	assert(deepEqual(array.flat(4), [1,2,3,4,5,6,7,8,9]), '#4');
   308  	assert(deepEqual(array.flat(10), [1,2,3,4,5,6,7,8,9]), '#5');
   309  	`
   310  	testScriptWithTestLibX(SCRIPT, _undefined, t)
   311  }
   312  
   313  func TestArrayFlatMap(t *testing.T) {
   314  	const SCRIPT = `
   315  	var double = function(x) {
   316  		if (isNaN(x)) {
   317  			return x
   318  		}
   319  		return x * 2
   320  	}
   321  	var array = [1, [2,3,[4,5,6]], [[[[7,8,9]]]]];
   322  	assert(deepEqual(array.flatMap(double), [2,2,3,[4,5,6],[[[7,8,9]]]]), '#1');
   323  	`
   324  	testScriptWithTestLibX(SCRIPT, _undefined, t)
   325  }