mirror of
				https://github.com/tc39/test262.git
				synced 2025-11-03 21:24:30 +01:00 
			
		
		
		
	sourceRevisionAtLastExport: 33f2fb0e53d135f0ee17cfccd9d993eb2a6f47de targetRevisionAtLastExport: 31340cbd9add103f586d501b0c3354b7b182abc0
		
			
				
	
	
		
			897 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			897 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// Copyright 2014 the V8 project authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style license that can be
 | 
						|
// found in the LICENSE file.
 | 
						|
(function testArrayConcatArity() {
 | 
						|
  "use strict";
 | 
						|
  assertEquals(1, Array.prototype.concat.length);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testArrayConcatNoPrototype() {
 | 
						|
  "use strict";
 | 
						|
  assertEquals(void 0, Array.prototype.concat.prototype);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testArrayConcatDescriptor() {
 | 
						|
  "use strict";
 | 
						|
  var desc = Object.getOwnPropertyDescriptor(Array.prototype, 'concat');
 | 
						|
  assertEquals(false, desc.enumerable);
 | 
						|
})();
 | 
						|
 | 
						|
(function testNonConcatSpreadableArray() {
 | 
						|
  "use strict"
 | 
						|
  var array = [1, 2, 3];
 | 
						|
  assertEquals(array, [].concat(array));
 | 
						|
  assertEquals(array, array.concat([]));
 | 
						|
  array[Symbol.isConcatSpreadable] = false;
 | 
						|
  assertEquals([[1,2,3]], [].concat(array));
 | 
						|
  assertEquals([[1,2,3]], array.concat([]));
 | 
						|
})();
 | 
						|
 | 
						|
(function testConcatArrayLike() {
 | 
						|
  "use strict";
 | 
						|
  var obj = {
 | 
						|
    "length": 6,
 | 
						|
    "1": "A",
 | 
						|
    "3": "B",
 | 
						|
    "5": "C"
 | 
						|
  };
 | 
						|
  obj[Symbol.isConcatSpreadable] = true;
 | 
						|
  var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" };
 | 
						|
  var arr = ["X", "Y", "Z"];
 | 
						|
  assertEquals([void 0, "A", void 0, "B", void 0, "C",
 | 
						|
               { "length": 3, "0": "0", "1": "1", "2": "2" },
 | 
						|
               "X", "Y", "Z"], Array.prototype.concat.call(obj, obj2, arr));
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatArrayLikeStringLength() {
 | 
						|
  "use strict";
 | 
						|
  var obj = {
 | 
						|
    "length": "6",
 | 
						|
    "1": "A",
 | 
						|
    "3": "B",
 | 
						|
    "5": "C"
 | 
						|
  };
 | 
						|
  obj[Symbol.isConcatSpreadable] = true;
 | 
						|
  var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" };
 | 
						|
  var arr = ["X", "Y", "Z"];
 | 
						|
  assertEquals([void 0, "A", void 0, "B", void 0, "C",
 | 
						|
               { "length": 3, "0": "0", "1": "1", "2": "2" },
 | 
						|
               "X", "Y", "Z"], Array.prototype.concat.call(obj, obj2, arr));
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatArrayLikeNegativeLength() {
 | 
						|
  "use strict";
 | 
						|
  var obj = {
 | 
						|
    "length": -6,
 | 
						|
    "1": "A",
 | 
						|
    "3": "B",
 | 
						|
    "5": "C"
 | 
						|
  };
 | 
						|
  obj[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertEquals([], [].concat(obj));
 | 
						|
  obj.length = -6.7;
 | 
						|
  assertEquals([], [].concat(obj));
 | 
						|
  obj.length = "-6";
 | 
						|
  assertEquals([], [].concat(obj));
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatArrayLikeToLengthThrows() {
 | 
						|
  "use strict";
 | 
						|
  var obj = {
 | 
						|
    "length": {valueOf: null, toString: null},
 | 
						|
    "1": "A",
 | 
						|
    "3": "B",
 | 
						|
    "5": "C"
 | 
						|
  };
 | 
						|
  obj[Symbol.isConcatSpreadable] = true;
 | 
						|
  var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" };
 | 
						|
  var arr = ["X", "Y", "Z"];
 | 
						|
  assertThrows(function() {
 | 
						|
    Array.prototype.concat.call(obj, obj2, arr);
 | 
						|
  }, TypeError);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatArrayLikePrimitiveNonNumberLength() {
 | 
						|
  "use strict";
 | 
						|
  var obj = {
 | 
						|
    "1": "A",
 | 
						|
    "3": "B",
 | 
						|
    "5": "C"
 | 
						|
  };
 | 
						|
  obj[Symbol.isConcatSpreadable] = true;
 | 
						|
  obj.length = {toString: function() { return "SIX"; }, valueOf: null };
 | 
						|
  assertEquals([], [].concat(obj));
 | 
						|
  obj.length = {toString: null, valueOf: function() { return "SIX"; } };
 | 
						|
  assertEquals([], [].concat(obj));
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatArrayLikeLengthToStringThrows() {
 | 
						|
  "use strict";
 | 
						|
  function MyError() {}
 | 
						|
  var obj = {
 | 
						|
    "length": { toString: function() {
 | 
						|
        throw new MyError();
 | 
						|
      }, valueOf: null
 | 
						|
    },
 | 
						|
    "1": "A",
 | 
						|
    "3": "B",
 | 
						|
    "5": "C"
 | 
						|
  };
 | 
						|
  obj[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertThrows(function() {
 | 
						|
    [].concat(obj);
 | 
						|
  }, MyError);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatArrayLikeLengthValueOfThrows() {
 | 
						|
  "use strict";
 | 
						|
  function MyError() {}
 | 
						|
  var obj = {
 | 
						|
    "length": { valueOf: function() {
 | 
						|
      throw new MyError();
 | 
						|
    }, toString: null
 | 
						|
  },
 | 
						|
  "1": "A",
 | 
						|
  "3": "B",
 | 
						|
  "5": "C"
 | 
						|
};
 | 
						|
obj[Symbol.isConcatSpreadable] = true;
 | 
						|
assertThrows(function() {
 | 
						|
  [].concat(obj);
 | 
						|
}, MyError);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatHoleyArray() {
 | 
						|
  "use strict";
 | 
						|
  var arr = [];
 | 
						|
  arr[4] = "Item 4";
 | 
						|
  arr[8] = "Item 8";
 | 
						|
  var arr2 = [".", "!", "?"];
 | 
						|
  assertEquals([void 0, void 0, void 0, void 0, "Item 4", void 0, void 0,
 | 
						|
                void 0, "Item 8", ".", "!", "?"], arr.concat(arr2));
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testIsConcatSpreadableGetterThrows() {
 | 
						|
  "use strict";
 | 
						|
  function MyError() {}
 | 
						|
  var obj = {};
 | 
						|
  Object.defineProperty(obj, Symbol.isConcatSpreadable, {
 | 
						|
    get: function() { throw new MyError(); }
 | 
						|
  });
 | 
						|
 | 
						|
  assertThrows(function() {
 | 
						|
    [].concat(obj);
 | 
						|
  }, MyError);
 | 
						|
 | 
						|
  assertThrows(function() {
 | 
						|
    Array.prototype.concat.call(obj, 1, 2, 3);
 | 
						|
  }, MyError);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatLengthThrows() {
 | 
						|
  "use strict";
 | 
						|
  function MyError() {}
 | 
						|
  var obj = {};
 | 
						|
  obj[Symbol.isConcatSpreadable] = true;
 | 
						|
  Object.defineProperty(obj, "length", {
 | 
						|
    get: function() { throw new MyError(); }
 | 
						|
  });
 | 
						|
 | 
						|
  assertThrows(function() {
 | 
						|
    [].concat(obj);
 | 
						|
  }, MyError);
 | 
						|
 | 
						|
  assertThrows(function() {
 | 
						|
    Array.prototype.concat.call(obj, 1, 2, 3);
 | 
						|
  }, MyError);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatArraySubclass() {
 | 
						|
  "use strict";
 | 
						|
  // If @@isConcatSpreadable is not used, the value of IsArray(O)
 | 
						|
  // is used to determine the spreadable property.
 | 
						|
  class A extends Array {}
 | 
						|
  var obj = [].concat(new A(1, 2, 3), new A(4, 5, 6), new A(7, 8, 9));
 | 
						|
  assertEquals(9, obj.length);
 | 
						|
  for (var i = 0; i < obj.length; ++i) {
 | 
						|
    assertEquals(i + 1, obj[i]);
 | 
						|
  }
 | 
						|
 | 
						|
  // TODO(caitp): when concat is called on instances of classes which extend
 | 
						|
  // Array, they should:
 | 
						|
  //
 | 
						|
  // - return an instance of the class, rather than an Array instance (if from
 | 
						|
  //   same Realm)
 | 
						|
  // - always treat such classes as concat-spreadable
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatArraySubclassOptOut() {
 | 
						|
  "use strict";
 | 
						|
  class A extends Array {
 | 
						|
    get [Symbol.isConcatSpreadable]() { return false; }
 | 
						|
  }
 | 
						|
  var obj = [].concat(new A(1, 2, 3), new A(4, 5, 6), new A(7, 8, 9));
 | 
						|
  assertEquals(3, obj.length);
 | 
						|
  assertEquals(3, obj[0].length);
 | 
						|
  assertEquals(3, obj[1].length);
 | 
						|
  assertEquals(3, obj[2].length);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatNonArray() {
 | 
						|
  "use strict";
 | 
						|
  class NonArray {
 | 
						|
    constructor() { Array.apply(this, arguments); }
 | 
						|
  };
 | 
						|
 | 
						|
  var obj = new NonArray(1,2,3);
 | 
						|
  var result = Array.prototype.concat.call(obj, 4, 5, 6);
 | 
						|
  assertEquals(Array, result.constructor);
 | 
						|
  assertEquals([obj,4,5,6], result);
 | 
						|
  assertFalse(result instanceof NonArray);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
function testConcatTypedArray(type, elems, modulo) {
 | 
						|
  "use strict";
 | 
						|
  var items = new Array(elems);
 | 
						|
  var ta_by_len = new type(elems);
 | 
						|
  for (var i = 0; i < elems; ++i) {
 | 
						|
    ta_by_len[i] = items[i] = modulo === false ? i : elems % modulo;
 | 
						|
  }
 | 
						|
  var ta = new type(items);
 | 
						|
  assertEquals([ta, ta], [].concat(ta, ta));
 | 
						|
  ta[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertEquals(items, [].concat(ta));
 | 
						|
 | 
						|
  assertEquals([ta_by_len, ta_by_len], [].concat(ta_by_len, ta_by_len));
 | 
						|
  ta_by_len[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertEquals(items, [].concat(ta_by_len));
 | 
						|
 | 
						|
  // TypedArray with fake `length`.
 | 
						|
  ta = new type(1);
 | 
						|
  var defValue = ta[0];
 | 
						|
  var expected = new Array(4000);
 | 
						|
  expected[0] = defValue;
 | 
						|
 | 
						|
  Object.defineProperty(ta, "length", { value: 4000 });
 | 
						|
  ta[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertEquals(expected, [].concat(ta));
 | 
						|
}
 | 
						|
 | 
						|
(function testConcatSmallTypedArray() {
 | 
						|
  var length = 1;
 | 
						|
  testConcatTypedArray(Uint8Array, length, Math.pow(2, 8));
 | 
						|
  testConcatTypedArray(Uint16Array, length, Math.pow(2, 16));
 | 
						|
  testConcatTypedArray(Uint32Array, length,  Math.pow(2, 32));
 | 
						|
  testConcatTypedArray(Float32Array, length, false);
 | 
						|
  testConcatTypedArray(Float64Array, length, false);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatLargeTypedArray() {
 | 
						|
  var length = 4000;
 | 
						|
  testConcatTypedArray(Uint8Array, length, Math.pow(2, 8));
 | 
						|
  testConcatTypedArray(Uint16Array, length, Math.pow(2, 16));
 | 
						|
  testConcatTypedArray(Uint32Array, length,  Math.pow(2, 32));
 | 
						|
  testConcatTypedArray(Float32Array, length, false);
 | 
						|
  testConcatTypedArray(Float64Array, length, false);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatStrictArguments() {
 | 
						|
  var args = (function(a, b, c) { "use strict"; return arguments; })(1,2,3);
 | 
						|
  args[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
 | 
						|
 | 
						|
  Object.defineProperty(args, "length", { value: 6 });
 | 
						|
  assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatSloppyArguments() {
 | 
						|
  var args = (function(a, b, c) { return arguments; })(1,2,3);
 | 
						|
  args[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
 | 
						|
 | 
						|
  Object.defineProperty(args, "length", { value: 6 });
 | 
						|
  assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatSloppyArgumentsWithDupes() {
 | 
						|
  var args = (function(a, a, a) { return arguments; })(1,2,3);
 | 
						|
  args[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
 | 
						|
 | 
						|
  Object.defineProperty(args, "length", { value: 6 });
 | 
						|
  assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatSloppyArgumentsThrows() {
 | 
						|
  function MyError() {}
 | 
						|
  var args = (function(a) { return arguments; })(1,2,3);
 | 
						|
  Object.defineProperty(args, 0, {
 | 
						|
    get: function() { throw new MyError(); }
 | 
						|
  });
 | 
						|
  args[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertThrows(function() {
 | 
						|
    return [].concat(args, args);
 | 
						|
  }, MyError);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatHoleySloppyArguments() {
 | 
						|
  var args = (function(a) { return arguments; })(1,2,3);
 | 
						|
  delete args[1];
 | 
						|
  args[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertEquals([1, void 0, 3, 1, void 0, 3], [].concat(args, args));
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatSpreadableStringWrapper() {
 | 
						|
  "use strict";
 | 
						|
  var str1 = new String("yuck\uD83D\uDCA9")
 | 
						|
  // String wrapper objects are not concat-spreadable by default
 | 
						|
  assertEquals([str1], [].concat(str1));
 | 
						|
 | 
						|
  // String wrapper objects may be individually concat-spreadable
 | 
						|
  str1[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertEquals(["y", "u", "c", "k", "\uD83D", "\uDCA9"],
 | 
						|
               [].concat(str1));
 | 
						|
 | 
						|
  String.prototype[Symbol.isConcatSpreadable] = true;
 | 
						|
  // String wrapper objects may be concat-spreadable
 | 
						|
  assertEquals(["y", "u", "c", "k", "\uD83D", "\uDCA9"],
 | 
						|
               [].concat(new String("yuck\uD83D\uDCA9")));
 | 
						|
 | 
						|
  // String values are never concat-spreadable
 | 
						|
  assertEquals(["yuck\uD83D\uDCA9"], [].concat("yuck\uD83D\uDCA9"));
 | 
						|
  delete String.prototype[Symbol.isConcatSpreadable];
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatSpreadableBooleanWrapper() {
 | 
						|
  "use strict";
 | 
						|
  var bool = new Boolean(true)
 | 
						|
  // Boolean wrapper objects are not concat-spreadable by default
 | 
						|
  assertEquals([bool], [].concat(bool));
 | 
						|
 | 
						|
  // Boolean wrapper objects may be individually concat-spreadable
 | 
						|
  bool[Symbol.isConcatSpreadable] = true;
 | 
						|
  bool.length = 3;
 | 
						|
  bool[0] = 1, bool[1] = 2, bool[2] = 3;
 | 
						|
  assertEquals([1, 2, 3], [].concat(bool));
 | 
						|
 | 
						|
  Boolean.prototype[Symbol.isConcatSpreadable] = true;
 | 
						|
  // Boolean wrapper objects may be concat-spreadable
 | 
						|
  assertEquals([], [].concat(new Boolean(true)));
 | 
						|
  Boolean.prototype[0] = 1;
 | 
						|
  Boolean.prototype[1] = 2;
 | 
						|
  Boolean.prototype[2] = 3;
 | 
						|
  Boolean.prototype.length = 3;
 | 
						|
  assertEquals([1,2,3], [].concat(new Boolean(true)));
 | 
						|
 | 
						|
  // Boolean values are never concat-spreadable
 | 
						|
  assertEquals([true], [].concat(true));
 | 
						|
  delete Boolean.prototype[Symbol.isConcatSpreadable];
 | 
						|
  delete Boolean.prototype[0];
 | 
						|
  delete Boolean.prototype[1];
 | 
						|
  delete Boolean.prototype[2];
 | 
						|
  delete Boolean.prototype.length;
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatSpreadableNumberWrapper() {
 | 
						|
  "use strict";
 | 
						|
  var num = new Number(true)
 | 
						|
  // Number wrapper objects are not concat-spreadable by default
 | 
						|
  assertEquals([num], [].concat(num));
 | 
						|
 | 
						|
  // Number wrapper objects may be individually concat-spreadable
 | 
						|
  num[Symbol.isConcatSpreadable] = true;
 | 
						|
  num.length = 3;
 | 
						|
  num[0] = 1, num[1] = 2, num[2] = 3;
 | 
						|
  assertEquals([1, 2, 3], [].concat(num));
 | 
						|
 | 
						|
  Number.prototype[Symbol.isConcatSpreadable] = true;
 | 
						|
  // Number wrapper objects may be concat-spreadable
 | 
						|
  assertEquals([], [].concat(new Number(123)));
 | 
						|
  Number.prototype[0] = 1;
 | 
						|
  Number.prototype[1] = 2;
 | 
						|
  Number.prototype[2] = 3;
 | 
						|
  Number.prototype.length = 3;
 | 
						|
  assertEquals([1,2,3], [].concat(new Number(123)));
 | 
						|
 | 
						|
  // Number values are never concat-spreadable
 | 
						|
  assertEquals([true], [].concat(true));
 | 
						|
  delete Number.prototype[Symbol.isConcatSpreadable];
 | 
						|
  delete Number.prototype[0];
 | 
						|
  delete Number.prototype[1];
 | 
						|
  delete Number.prototype[2];
 | 
						|
  delete Number.prototype.length;
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatSpreadableFunction() {
 | 
						|
  "use strict";
 | 
						|
  var fn = function(a, b, c) {}
 | 
						|
  // Functions are not concat-spreadable by default
 | 
						|
  assertEquals([fn], [].concat(fn));
 | 
						|
 | 
						|
  // Functions may be individually concat-spreadable
 | 
						|
  fn[Symbol.isConcatSpreadable] = true;
 | 
						|
  fn[0] = 1, fn[1] = 2, fn[2] = 3;
 | 
						|
  assertEquals([1, 2, 3], [].concat(fn));
 | 
						|
 | 
						|
  Function.prototype[Symbol.isConcatSpreadable] = true;
 | 
						|
  // Functions may be concat-spreadable
 | 
						|
  assertEquals([void 0, void 0, void 0], [].concat(function(a,b,c) {}));
 | 
						|
  Function.prototype[0] = 1;
 | 
						|
  Function.prototype[1] = 2;
 | 
						|
  Function.prototype[2] = 3;
 | 
						|
  assertEquals([1,2,3], [].concat(function(a, b, c) {}));
 | 
						|
 | 
						|
  delete Function.prototype[Symbol.isConcatSpreadable];
 | 
						|
  delete Function.prototype[0];
 | 
						|
  delete Function.prototype[1];
 | 
						|
  delete Function.prototype[2];
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testConcatSpreadableRegExp() {
 | 
						|
  "use strict";
 | 
						|
  var re = /abc/;
 | 
						|
  // RegExps are not concat-spreadable by default
 | 
						|
  assertEquals([re], [].concat(re));
 | 
						|
 | 
						|
  // RegExps may be individually concat-spreadable
 | 
						|
  re[Symbol.isConcatSpreadable] = true;
 | 
						|
  re[0] = 1, re[1] = 2, re[2] = 3, re.length = 3;
 | 
						|
  assertEquals([1, 2, 3], [].concat(re));
 | 
						|
 | 
						|
  // RegExps may be concat-spreadable
 | 
						|
  RegExp.prototype[Symbol.isConcatSpreadable] = true;
 | 
						|
  RegExp.prototype.length = 3;
 | 
						|
 | 
						|
  assertEquals([void 0, void 0, void 0], [].concat(/abc/));
 | 
						|
  RegExp.prototype[0] = 1;
 | 
						|
  RegExp.prototype[1] = 2;
 | 
						|
  RegExp.prototype[2] = 3;
 | 
						|
  assertEquals([1,2,3], [].concat(/abc/));
 | 
						|
 | 
						|
  delete RegExp.prototype[Symbol.isConcatSpreadable];
 | 
						|
  delete RegExp.prototype[0];
 | 
						|
  delete RegExp.prototype[1];
 | 
						|
  delete RegExp.prototype[2];
 | 
						|
  delete RegExp.prototype.length;
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testArrayConcatSpreadableSparseObject() {
 | 
						|
  "use strict";
 | 
						|
  var obj = { length: 5 };
 | 
						|
  obj[Symbol.isConcatSpreadable] = true;
 | 
						|
  assertEquals([void 0, void 0, void 0, void 0, void 0], [].concat(obj));
 | 
						|
 | 
						|
  obj.length = 4000;
 | 
						|
  assertEquals(new Array(4000), [].concat(obj));
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
// ES5 tests
 | 
						|
(function testArrayConcatES5() {
 | 
						|
  "use strict";
 | 
						|
  var poses;
 | 
						|
  var pos;
 | 
						|
 | 
						|
  poses = [140, 4000000000];
 | 
						|
  while (pos = poses.shift()) {
 | 
						|
    var a = new Array(pos);
 | 
						|
    var array_proto = [];
 | 
						|
    a.__proto__ = array_proto;
 | 
						|
    assertEquals(pos, a.length);
 | 
						|
    a.push('foo');
 | 
						|
    assertEquals(pos + 1, a.length);
 | 
						|
    var b = ['bar'];
 | 
						|
    var c = a.concat(b);
 | 
						|
    assertEquals(pos + 2, c.length);
 | 
						|
    assertEquals("undefined", typeof(c[pos - 1]));
 | 
						|
    assertEquals("foo", c[pos]);
 | 
						|
    assertEquals("bar", c[pos + 1]);
 | 
						|
 | 
						|
    // Can we fool the system by putting a number in a string?
 | 
						|
    var onetwofour = "124";
 | 
						|
    a[onetwofour] = 'doo';
 | 
						|
    assertEquals(a[124], 'doo');
 | 
						|
    c = a.concat(b);
 | 
						|
    assertEquals(c[124], 'doo');
 | 
						|
 | 
						|
    // If we put a number in the prototype, then the spec says it should be
 | 
						|
    // copied on concat.
 | 
						|
    array_proto["123"] = 'baz';
 | 
						|
    assertEquals(a[123], 'baz');
 | 
						|
 | 
						|
    c = a.concat(b);
 | 
						|
    assertEquals(pos + 2, c.length);
 | 
						|
    assertEquals("baz", c[123]);
 | 
						|
    assertEquals("undefined", typeof(c[pos - 1]));
 | 
						|
    assertEquals("foo", c[pos]);
 | 
						|
    assertEquals("bar", c[pos + 1]);
 | 
						|
 | 
						|
    // When we take the number off the prototype it disappears from a, but
 | 
						|
    // the concat put it in c itself.
 | 
						|
    array_proto["123"] = undefined;
 | 
						|
    assertEquals("undefined", typeof(a[123]));
 | 
						|
    assertEquals("baz", c[123]);
 | 
						|
 | 
						|
    // If the element of prototype is shadowed, the element on the instance
 | 
						|
    // should be copied, but not the one on the prototype.
 | 
						|
    array_proto[123] = 'baz';
 | 
						|
    a[123] = 'xyz';
 | 
						|
    assertEquals('xyz', a[123]);
 | 
						|
    c = a.concat(b);
 | 
						|
    assertEquals('xyz', c[123]);
 | 
						|
 | 
						|
    // Non-numeric properties on the prototype or the array shouldn't get
 | 
						|
    // copied.
 | 
						|
    array_proto.moe = 'joe';
 | 
						|
    a.ben = 'jerry';
 | 
						|
    assertEquals(a["moe"], 'joe');
 | 
						|
    assertEquals(a["ben"], 'jerry');
 | 
						|
    c = a.concat(b);
 | 
						|
    // ben was not copied
 | 
						|
    assertEquals("undefined", typeof(c.ben));
 | 
						|
 | 
						|
    // When we take moe off the prototype it disappears from all arrays.
 | 
						|
    array_proto.moe = undefined;
 | 
						|
    assertEquals("undefined", typeof(c.moe));
 | 
						|
 | 
						|
    // Negative indices don't get concated.
 | 
						|
    a[-1] = 'minus1';
 | 
						|
    assertEquals("minus1", a[-1]);
 | 
						|
    assertEquals("undefined", typeof(a[0xffffffff]));
 | 
						|
    c = a.concat(b);
 | 
						|
    assertEquals("undefined", typeof(c[-1]));
 | 
						|
    assertEquals("undefined", typeof(c[0xffffffff]));
 | 
						|
    assertEquals(c.length, a.length + 1);
 | 
						|
  }
 | 
						|
 | 
						|
  poses = [140, 4000000000];
 | 
						|
  while (pos = poses.shift()) {
 | 
						|
    var a = new Array(pos);
 | 
						|
    assertEquals(pos, a.length);
 | 
						|
    a.push('foo');
 | 
						|
    assertEquals(pos + 1, a.length);
 | 
						|
    var b = ['bar'];
 | 
						|
    var c = a.concat(b);
 | 
						|
    assertEquals(pos + 2, c.length);
 | 
						|
    assertEquals("undefined", typeof(c[pos - 1]));
 | 
						|
    assertEquals("foo", c[pos]);
 | 
						|
    assertEquals("bar", c[pos + 1]);
 | 
						|
 | 
						|
    // Can we fool the system by putting a number in a string?
 | 
						|
    var onetwofour = "124";
 | 
						|
    a[onetwofour] = 'doo';
 | 
						|
    assertEquals(a[124], 'doo');
 | 
						|
    c = a.concat(b);
 | 
						|
    assertEquals(c[124], 'doo');
 | 
						|
 | 
						|
    // If we put a number in the prototype, then the spec says it should be
 | 
						|
    // copied on concat.
 | 
						|
    Array.prototype["123"] = 'baz';
 | 
						|
    assertEquals(a[123], 'baz');
 | 
						|
 | 
						|
    c = a.concat(b);
 | 
						|
    assertEquals(pos + 2, c.length);
 | 
						|
    assertEquals("baz", c[123]);
 | 
						|
    assertEquals("undefined", typeof(c[pos - 1]));
 | 
						|
    assertEquals("foo", c[pos]);
 | 
						|
    assertEquals("bar", c[pos + 1]);
 | 
						|
 | 
						|
    // When we take the number off the prototype it disappears from a, but
 | 
						|
    // the concat put it in c itself.
 | 
						|
    Array.prototype["123"] = undefined;
 | 
						|
    assertEquals("undefined", typeof(a[123]));
 | 
						|
    assertEquals("baz", c[123]);
 | 
						|
 | 
						|
    // If the element of prototype is shadowed, the element on the instance
 | 
						|
    // should be copied, but not the one on the prototype.
 | 
						|
    Array.prototype[123] = 'baz';
 | 
						|
    a[123] = 'xyz';
 | 
						|
    assertEquals('xyz', a[123]);
 | 
						|
    c = a.concat(b);
 | 
						|
    assertEquals('xyz', c[123]);
 | 
						|
 | 
						|
    // Non-numeric properties on the prototype or the array shouldn't get
 | 
						|
    // copied.
 | 
						|
    Array.prototype.moe = 'joe';
 | 
						|
    a.ben = 'jerry';
 | 
						|
    assertEquals(a["moe"], 'joe');
 | 
						|
    assertEquals(a["ben"], 'jerry');
 | 
						|
    c = a.concat(b);
 | 
						|
    // ben was not copied
 | 
						|
    assertEquals("undefined", typeof(c.ben));
 | 
						|
    // moe was not copied, but we can see it through the prototype
 | 
						|
    assertEquals("joe", c.moe);
 | 
						|
 | 
						|
    // When we take moe off the prototype it disappears from all arrays.
 | 
						|
    Array.prototype.moe = undefined;
 | 
						|
    assertEquals("undefined", typeof(c.moe));
 | 
						|
 | 
						|
    // Negative indices don't get concated.
 | 
						|
    a[-1] = 'minus1';
 | 
						|
    assertEquals("minus1", a[-1]);
 | 
						|
    assertEquals("undefined", typeof(a[0xffffffff]));
 | 
						|
    c = a.concat(b);
 | 
						|
    assertEquals("undefined", typeof(c[-1]));
 | 
						|
    assertEquals("undefined", typeof(c[0xffffffff]));
 | 
						|
    assertEquals(c.length, a.length + 1);
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  a = [];
 | 
						|
  c = a.concat('Hello');
 | 
						|
  assertEquals(1, c.length);
 | 
						|
  assertEquals("Hello", c[0]);
 | 
						|
  assertEquals("Hello", c.toString());
 | 
						|
 | 
						|
  // Check that concat preserves holes.
 | 
						|
  var holey = [void 0,'a',,'c'].concat(['d',,'f',[0,,2],void 0])
 | 
						|
  assertEquals(9, holey.length);  // hole in embedded array is ignored
 | 
						|
  for (var i = 0; i < holey.length; i++) {
 | 
						|
    if (i == 2 || i == 5) {
 | 
						|
      assertFalse(i in holey);
 | 
						|
    } else {
 | 
						|
      assertTrue(i in holey);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Polluted prototype from prior tests.
 | 
						|
  delete Array.prototype[123];
 | 
						|
 | 
						|
  // Check that concat reads getters in the correct order.
 | 
						|
  var arr1 = [,2];
 | 
						|
  var arr2 = [1,3];
 | 
						|
  var r1 = [].concat(arr1, arr2);  // [,2,1,3]
 | 
						|
  assertEquals([,2,1,3], r1);
 | 
						|
 | 
						|
  // Make first array change length of second array.
 | 
						|
  Object.defineProperty(arr1, 0, {get: function() {
 | 
						|
        arr2.push("X");
 | 
						|
        return undefined;
 | 
						|
      }, configurable: true})
 | 
						|
  var r2 = [].concat(arr1, arr2);  // [undefined,2,1,3,"X"]
 | 
						|
  assertEquals([undefined,2,1,3,"X"], r2);
 | 
						|
 | 
						|
  // Make first array change length of second array massively.
 | 
						|
  arr2.length = 2;
 | 
						|
  Object.defineProperty(arr1, 0, {get: function() {
 | 
						|
        arr2[500000] = "X";
 | 
						|
        return undefined;
 | 
						|
      }, configurable: true})
 | 
						|
  var r3 = [].concat(arr1, arr2);  // [undefined,2,1,3,"X"]
 | 
						|
  var expected = [undefined,2,1,3];
 | 
						|
  expected[500000 + 2] = "X";
 | 
						|
 | 
						|
  assertEquals(expected, r3);
 | 
						|
 | 
						|
  var arr3 = [];
 | 
						|
  var trace = [];
 | 
						|
  var expectedTrace = []
 | 
						|
  function mkGetter(i) { return function() { trace.push(i); }; }
 | 
						|
  arr3.length = 10000;
 | 
						|
  for (var i = 0; i < 100; i++) {
 | 
						|
    Object.defineProperty(arr3, i * i, {get: mkGetter(i)});
 | 
						|
    expectedTrace[i] = i;
 | 
						|
    expectedTrace[100 + i] = i;
 | 
						|
  }
 | 
						|
  var r4 = [0].concat(arr3, arr3);
 | 
						|
  assertEquals(1 + arr3.length * 2, r4.length);
 | 
						|
  assertEquals(expectedTrace, trace);
 | 
						|
 | 
						|
  // Clean up.
 | 
						|
  delete Array.prototype[123];
 | 
						|
  delete Array.prototype["123"];
 | 
						|
  delete Array.prototype["moe"];
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// Tests with proxies
 | 
						|
 | 
						|
// Note: concat does not currently support species so there is no difference
 | 
						|
// between [].concat(foo) and Array.prototype.concat.apply(foo).
 | 
						|
 | 
						|
 | 
						|
var log = [];
 | 
						|
var logger = {};
 | 
						|
var handler = new Proxy({}, logger);
 | 
						|
 | 
						|
logger.get = function(t, trap, r) {
 | 
						|
  return function(...args) {
 | 
						|
    log.push([trap, ...args]);
 | 
						|
    return Reflect[trap](...args);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
(function testUnspreadableNonArrayLikeProxy() {
 | 
						|
  var target = {0: "a", 1: "b"};
 | 
						|
  var obj = new Proxy(target, handler);
 | 
						|
 | 
						|
  log.length = 0;
 | 
						|
  assertEquals([obj], [].concat(obj));
 | 
						|
  assertEquals(1, log.length);
 | 
						|
  for (var i in log) assertSame(target, log[i][1]);
 | 
						|
  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);
 | 
						|
 | 
						|
  log.length = 0;
 | 
						|
  assertEquals([obj], Array.prototype.concat.apply(obj));
 | 
						|
  assertEquals(1, log.length);
 | 
						|
  for (var i in log) assertSame(target, log[i][1]);
 | 
						|
  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testSpreadableNonArrayLikeProxy() {
 | 
						|
  var target = {0: "a", 1: "b", [Symbol.isConcatSpreadable]: "truish"};
 | 
						|
  var obj = new Proxy(target, handler);
 | 
						|
 | 
						|
  log.length = 0;
 | 
						|
  assertEquals([], [].concat(obj));
 | 
						|
  assertEquals(2, log.length);
 | 
						|
  for (var i in log) assertSame(target, log[i][1]);
 | 
						|
  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);
 | 
						|
  assertEquals(["get", target, "length", obj], log[1]);
 | 
						|
 | 
						|
  log.length = 0;
 | 
						|
  assertEquals([], Array.prototype.concat.apply(obj));
 | 
						|
  assertEquals(2, log.length);
 | 
						|
  for (var i in log) assertSame(target, log[i][1]);
 | 
						|
  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);
 | 
						|
  assertEquals(["get", target, "length", obj], log[1]);
 | 
						|
 | 
						|
  target.length = 3;
 | 
						|
 | 
						|
  log.length = 0;
 | 
						|
  assertEquals(["a", "b", undefined], [].concat(obj));
 | 
						|
  assertEquals(7, log.length);
 | 
						|
  for (var i in log) assertSame(target, log[i][1]);
 | 
						|
  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);
 | 
						|
  assertEquals(["get", target, "length", obj], log[1]);
 | 
						|
  assertEquals(["has", target, "0"], log[2]);
 | 
						|
  assertEquals(["get", target, "0", obj], log[3]);
 | 
						|
  assertEquals(["has", target, "1"], log[4]);
 | 
						|
  assertEquals(["get", target, "1", obj], log[5]);
 | 
						|
  assertEquals(["has", target, "2"], log[6]);
 | 
						|
 | 
						|
  log.length = 0;
 | 
						|
  assertEquals(["a", "b", undefined], Array.prototype.concat.apply(obj));
 | 
						|
  assertEquals(7, log.length);
 | 
						|
  for (var i in log) assertSame(target, log[i][1]);
 | 
						|
  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);
 | 
						|
  assertEquals(["get", target, "length", obj], log[1]);
 | 
						|
  assertEquals(["has", target, "0"], log[2]);
 | 
						|
  assertEquals(["get", target, "0", obj], log[3]);
 | 
						|
  assertEquals(["has", target, "1"], log[4]);
 | 
						|
  assertEquals(["get", target, "1", obj], log[5]);
 | 
						|
  assertEquals(["has", target, "2"], log[6]);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testUnspreadableArrayLikeProxy() {
 | 
						|
  var target = ["a", "b"];
 | 
						|
  target[Symbol.isConcatSpreadable] = "";
 | 
						|
  var obj = new Proxy(target, handler);
 | 
						|
 | 
						|
  log.length = 0;
 | 
						|
  assertEquals([obj], [].concat(obj));
 | 
						|
  assertEquals(1, log.length);
 | 
						|
  for (var i in log) assertSame(target, log[i][1]);
 | 
						|
  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);
 | 
						|
 | 
						|
  log.length = 0;
 | 
						|
  assertEquals([obj], Array.prototype.concat.apply(obj));
 | 
						|
  assertEquals(2, log.length);  // An extra read for the constructor
 | 
						|
  for (var i in log) assertSame(target, log[i][1]);
 | 
						|
  assertEquals(["get", target, "constructor", obj], log[0]);
 | 
						|
  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[1]);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testSpreadableArrayLikeProxy() {
 | 
						|
  var target = ["a", "b"];
 | 
						|
  target[Symbol.isConcatSpreadable] = undefined;
 | 
						|
  var obj = new Proxy(target, handler);
 | 
						|
 | 
						|
  log.length = 0;
 | 
						|
  assertEquals(["a", "b"], [].concat(obj));
 | 
						|
  assertEquals(6, log.length);
 | 
						|
  for (var i in log) assertSame(target, log[i][1]);
 | 
						|
  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);
 | 
						|
  assertEquals(["get", target, "length", obj], log[1]);
 | 
						|
  assertEquals(["has", target, "0"], log[2]);
 | 
						|
  assertEquals(["get", target, "0", obj], log[3]);
 | 
						|
  assertEquals(["has", target, "1"], log[4]);
 | 
						|
  assertEquals(["get", target, "1", obj], log[5]);
 | 
						|
 | 
						|
  log.length = 0;
 | 
						|
  assertEquals(["a", "b"], Array.prototype.concat.apply(obj));
 | 
						|
  assertEquals(7, log.length);
 | 
						|
  for (var i in log) assertSame(target, log[i][1]);
 | 
						|
  assertEquals(["get", target, "constructor", obj], log[0]);
 | 
						|
  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[1]);
 | 
						|
  assertEquals(["get", target, "length", obj], log[2]);
 | 
						|
  assertEquals(["has", target, "0"], log[3]);
 | 
						|
  assertEquals(["get", target, "0", obj], log[4]);
 | 
						|
  assertEquals(["has", target, "1"], log[5]);
 | 
						|
  assertEquals(["get", target, "1", obj], log[6]);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testSpreadableArrayLikeProxyWithNontrivialLength() {
 | 
						|
  var getTrap = function(t, key) {
 | 
						|
    if (key === "length") return {[Symbol.toPrimitive]() {return 3}};
 | 
						|
    if (key === "2") return "baz";
 | 
						|
    if (key === "3") return "bar";
 | 
						|
  };
 | 
						|
  var target = [];
 | 
						|
  var obj = new Proxy(target, {get: getTrap, has: () => true});
 | 
						|
 | 
						|
  assertEquals([undefined, undefined, "baz"], [].concat(obj));
 | 
						|
  assertEquals([undefined, undefined, "baz"], Array.prototype.concat.apply(obj))
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
(function testSpreadableArrayLikeProxyWithBogusLength() {
 | 
						|
  var getTrap = function(t, key) {
 | 
						|
    if (key === "length") return Symbol();
 | 
						|
    if (key === "2") return "baz";
 | 
						|
    if (key === "3") return "bar";
 | 
						|
  };
 | 
						|
  var target = [];
 | 
						|
  var obj = new Proxy(target, {get: getTrap, has: () => true});
 | 
						|
 | 
						|
  assertThrows(() => [].concat(obj), TypeError);
 | 
						|
  assertThrows(() => Array.prototype.concat.apply(obj), TypeError);
 | 
						|
})();
 | 
						|
 | 
						|
(function testConcatRevokedProxy() {
 | 
						|
  "use strict";
 | 
						|
  var target = [];
 | 
						|
  var handler = {
 | 
						|
    get(_, name) {
 | 
						|
      if (name === Symbol.isConcatSpreadable) {
 | 
						|
        p.revoke();
 | 
						|
      }
 | 
						|
      return target[name];
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  p = Proxy.revocable(target, handler);
 | 
						|
  target = {};
 | 
						|
  target.__proto__ = p.proxy;
 | 
						|
  assertThrows(function() { [].concat({ __proto__: p.proxy }); }, TypeError);
 | 
						|
 | 
						|
  target = [];
 | 
						|
  var p = Proxy.revocable(target, handler);
 | 
						|
  assertThrows(function() { [].concat(p.proxy); }, TypeError);
 | 
						|
})();
 |