// Copyright 2017 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.

assertThrows(() => {
  Array.prototype.lastIndexOf.call(null, 42);
}, TypeError);
assertThrows(() => {
  Array.prototype.lastIndexOf.call(undefined, 42);
}, TypeError);

/* Tests inspired by test262's
  lastIndexOf/calls-only-has-on-prototype-after-length-zeroed.js */
// Stateful fromIndex that tries to empty the array
(function testFromIndex() {
  var array = [5, undefined, 7];
  var fromIndex = {
    valueOf: function() {
      array.length = 1;
      return 2;
    }
  };
  assertEquals(-1, array.lastIndexOf(undefined, fromIndex));

  array = [5, undefined, 7];
  assertEquals(0, array.lastIndexOf(5, fromIndex));
})();

// Stateful fromIndex and proxy as Prototype
// Must test for [[HasProperty]] before [[Get]]
var testHasProperty = function(value) {
  var array = [5, undefined, 7];
  var fromIndex = {
    valueOf: function() {
      array.length = 0;
      return 2;
    }
  };

  // Install a prototype that only has [[HasProperty]], and throws on [[Get]]
  Object.setPrototypeOf(array,
    new Proxy(Array.prototype, {
                has: function(t, pk) { return pk in t; },
                get: function () { throw new Error('[[Get]] trap called') },
              }));

  assertEquals(-1, Array.prototype.lastIndexOf.call(array, value, fromIndex));
}

testHasProperty(5);
testHasProperty(undefined);

// Test call order: [[HasProperty]] before [[Get]]
var testHasPropertyThenGet = function(value) {
  var array = [5, , 7];
  var log = [];

  // Install a prototype with only [[HasProperty]] and [[Get]]
  Object.setPrototypeOf(array,
    new Proxy(Array.prototype, {
                has: function() { log.push("HasProperty"); return true; },
                get: function() { log.push("Get"); },
              }));
  // The 2nd element (index 1) will trigger the calls to the prototype
  Array.prototype.lastIndexOf.call(array, value);
  assertEquals(["HasProperty", "Get"], log);
}

testHasPropertyThenGet(5);
testHasPropertyThenGet(undefined);

// Test for sparse Arrays
/* This will not enter the fast path for sparse arrays, due to UseSparseVariant
  excluding array elements with accessors */
(function() {
  var array = new Array(10000);
  array[0] = 5; array[9999] = 7;

  var count = 0;
  Object.defineProperty(array.__proto__, 9998, { get: () => ++count });
  Array.prototype.lastIndexOf.call(array, 0);
  assertEquals(1,count);
})();