// 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() {

assertEquals(1, Array.from.length);

function assertArrayLikeEquals(value, expected, type) {
  assertInstanceof(value, type);
  assertEquals(expected.length, value.length);
  for (var i=0; i<value.length; ++i) {
    assertEquals(expected[i], value[i]);
  }
}

// Assert that constructor is called with "length" for array-like objects
var myCollectionCalled = false;
function MyCollection(length) {
  myCollectionCalled = true;
  assertEquals(1, arguments.length);
  assertEquals(5, length);
}

Array.from.call(MyCollection, {length: 5});
assertTrue(myCollectionCalled);

// Assert that calling mapfn with / without thisArg in sloppy and strict modes
// works as expected.
var global = this;
function non_strict(){ assertEquals(global, this); }
function strict(){ "use strict"; assertEquals(void 0, this); }
function strict_null(){ "use strict"; assertEquals(null, this); }
Array.from([1], non_strict);
Array.from([1], non_strict, void 0);
Array.from([1], non_strict, null);
Array.from([1], strict);
Array.from([1], strict, void 0);
Array.from([1], strict_null, null);

function testArrayFrom(thisArg, constructor) {
  assertArrayLikeEquals(Array.from.call(thisArg, [], undefined), [],
      constructor);
  assertArrayLikeEquals(Array.from.call(thisArg, NaN), [], constructor);
  assertArrayLikeEquals(Array.from.call(thisArg, Infinity), [], constructor);
  assertArrayLikeEquals(Array.from.call(thisArg, 10000000), [], constructor);
  assertArrayLikeEquals(Array.from.call(thisArg, 'test'), ['t', 'e', 's', 't'],
      constructor);

  assertArrayLikeEquals(Array.from.call(thisArg,
      { length: 1, '0': { 'foo': 'bar' } }), [{'foo': 'bar'}], constructor);

  assertArrayLikeEquals(Array.from.call(thisArg,
      { length: -1, '0': { 'foo': 'bar' } }), [], constructor);

  assertArrayLikeEquals(Array.from.call(thisArg,
      [ 'foo', 'bar', 'baz' ]), ['foo', 'bar', 'baz'], constructor);

  var kSet = new Set(['foo', 'bar', 'baz']);
  assertArrayLikeEquals(Array.from.call(thisArg, kSet), ['foo', 'bar', 'baz'],
      constructor);

  var kMap = new Map(['foo', 'bar', 'baz'].entries());
  assertArrayLikeEquals(Array.from.call(thisArg, kMap),
      [[0, 'foo'], [1, 'bar'], [2, 'baz']], constructor);


  function* generator() {
    yield 'a';
    yield 'b';
    yield 'c';
  }

  assertArrayLikeEquals(Array.from.call(thisArg, generator()),
                        ['a', 'b', 'c'], constructor);

  // Mozilla:
  // Array.from on a string handles surrogate pairs correctly.
  var gclef = "\uD834\uDD1E"; // U+1D11E MUSICAL SYMBOL G CLEF
  assertArrayLikeEquals(Array.from.call(thisArg, gclef), [gclef], constructor);
  assertArrayLikeEquals(Array.from.call(thisArg, gclef + " G"),
      [gclef, " ", "G"], constructor);

  assertArrayLikeEquals(Array.from.call(thisArg, 'test', function(x) {
    return this.filter(x);
  }, {
    filter: function(x) { return x.toUpperCase(); }
  }), ['T', 'E', 'S', 'T'], constructor);
  assertArrayLikeEquals(Array.from.call(thisArg, 'test', function(x) {
    return x.toUpperCase();
  }), ['T', 'E', 'S', 'T'], constructor);

  assertThrows(function() { Array.from.call(thisArg, null); }, TypeError);
  assertThrows(function() { Array.from.call(thisArg, undefined); }, TypeError);
  assertThrows(function() { Array.from.call(thisArg, [], null); }, TypeError);
  assertThrows(function() { Array.from.call(thisArg, [], "noncallable"); },
               TypeError);

  var nullIterator = {};
  nullIterator[Symbol.iterator] = null;
  assertArrayLikeEquals(Array.from.call(thisArg, nullIterator), [],
                        constructor);

  var nonObjIterator = {};
  nonObjIterator[Symbol.iterator] = function() { return "nonObject"; };
  assertThrows(function() { Array.from.call(thisArg, nonObjIterator); },
               TypeError);

  assertThrows(function() { Array.from.call(thisArg, [], null); }, TypeError);

  // Ensure iterator is only accessed once, and only invoked once
  var called = false;
  var arr = [1, 2, 3];
  var obj = {};

  // Test order --- only get iterator method once
  function testIterator() {
    assertFalse(called, "@@iterator should be called only once");
    called = true;
    assertEquals(obj, this);
    return arr[Symbol.iterator]();
  }
  var getCalled = false;
  Object.defineProperty(obj, Symbol.iterator, {
    get: function() {
      assertFalse(getCalled, "@@iterator should be accessed only once");
      getCalled = true;
      return testIterator;
    },
    set: function() {
      assertUnreachable("@@iterator should not be set");
    }
  });
  assertArrayLikeEquals(Array.from.call(thisArg, obj), [1, 2, 3], constructor);
}

function Other() {}

var boundFn = (function() {}).bind(Array, 27);

testArrayFrom(Array, Array);
testArrayFrom(null, Array);
testArrayFrom({}, Array);
testArrayFrom(Object, Object);
testArrayFrom(Other, Other);
testArrayFrom(Math.cos, Array);
testArrayFrom(Math.cos.bind(Math), Array);
testArrayFrom(boundFn, boundFn);

// Assert that [[DefineOwnProperty]] is used in ArrayFrom, meaning a
// setter isn't called, and a failed [[DefineOwnProperty]] will throw.
var setterCalled = 0;
function exotic() {
  Object.defineProperty(this,  '0', {
    get: function() { return 2; },
    set: function() { setterCalled++; }
  });
}
// Non-configurable properties can't be overwritten with DefineOwnProperty
assertThrows(function () { Array.from.call(exotic, [1]); }, TypeError);
// The setter wasn't called
assertEquals(0, setterCalled);

// Check that array properties defined are writable, enumerable, configurable
function ordinary() { }
var x = Array.from.call(ordinary, [2]);
var xlength = Object.getOwnPropertyDescriptor(x, 'length');
assertEquals(1, xlength.value);
assertEquals(true, xlength.writable);
assertEquals(true, xlength.enumerable);
assertEquals(true, xlength.configurable);
var x0 = Object.getOwnPropertyDescriptor(x, 0);
assertEquals(2, x0.value);
assertEquals(true, xlength.writable);
assertEquals(true, xlength.enumerable);
assertEquals(true, xlength.configurable);

})();
