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

// Flags: --allow-natives-syntax

load("testsrc/assert.js");

function test(f) {
  f();
  f();
  f();
}

test(function TestSetIterator() {
  var s = new Set;
  var iter = s.values();
  //assertEquals('Set Iterator', %_ClassOf(iter));

  var SetIteratorPrototype = iter.__proto__;
  assertFalse(SetIteratorPrototype.hasOwnProperty('constructor'));
  assertEquals(SetIteratorPrototype.__proto__, Object.prototype);

  var propertyNames = Object.getOwnPropertyNames(SetIteratorPrototype);
  assertArrayEquals(['next'], propertyNames);

  assertEquals(new Set().values().__proto__, SetIteratorPrototype);
  assertEquals(new Set().entries().__proto__, SetIteratorPrototype);

  assertEquals("[object Set Iterator]",
      Object.prototype.toString.call(iter));
  assertEquals("Set Iterator", SetIteratorPrototype[Symbol.toStringTag]);
  var desc = Object.getOwnPropertyDescriptor(
      SetIteratorPrototype, Symbol.toStringTag);
  assertTrue(desc.configurable);
  assertFalse(desc.writable);
  assertEquals("Set Iterator", desc.value);
});


test(function TestSetIteratorValues() {
  var s = new Set;
  s.add(1);
  s.add(2);
  s.add(3);
  var iter = s.values();

  assertEquals({value: 1, done: false}, iter.next());
  assertEquals({value: 2, done: false}, iter.next());
  assertEquals({value: 3, done: false}, iter.next());
  assertEquals({value: undefined, done: true}, iter.next());
  assertEquals({value: undefined, done: true}, iter.next());
});

test(function TestSetIteratorKeys() {
  assertEquals(Set.prototype.keys, Set.prototype.values);
});

test(function TestSetIteratorEntries() {
  var s = new Set;
  s.add(1);
  s.add(2);
  s.add(3);
  var iter = s.entries();

  assertEquals({value: [1, 1], done: false}, iter.next());
  assertEquals({value: [2, 2], done: false}, iter.next());
  assertEquals({value: [3, 3], done: false}, iter.next());
  assertEquals({value: undefined, done: true}, iter.next());
  assertEquals({value: undefined, done: true}, iter.next());
});


test(function TestSetIteratorMutations() {
  var s = new Set;
  s.add(1);
  var iter = s.values();
  assertEquals({value: 1, done: false}, iter.next());
  s.add(2);
  s.add(3);
  s.add(4);
  s.add(5);
  assertEquals({value: 2, done: false}, iter.next());
  s.delete(3);
  assertEquals({value: 4, done: false}, iter.next());
  s.delete(5);
  assertEquals({value: undefined, done: true}, iter.next());
  s.add(4);
  assertEquals({value: undefined, done: true}, iter.next());
});


test(function TestSetIteratorMutations2() {
  var s = new Set;
  s.add(1);
  s.add(2);
  var i = s.values();
  assertEquals({value: 1, done: false}, i.next());
  s.delete(2);
  s.delete(1);
  s.add(2);
  assertEquals({value: 2, done: false}, i.next());
  assertEquals({value: undefined, done: true}, i.next());
});


test(function TestSetIteratorMutations3() {
  var s = new Set;
  s.add(1);
  s.add(2);
  var i = s.values();
  assertEquals({value: 1, done: false}, i.next());
  s.delete(2);
  s.delete(1);
  for (var x = 2; x < 500; ++x) s.add(x);
  for (var x = 2; x < 500; ++x) s.delete(x);
  for (var x = 2; x < 1000; ++x) s.add(x);
  assertEquals({value: 2, done: false}, i.next());
  for (var x = 1001; x < 2000; ++x) s.add(x);
  s.delete(3);
  for (var x = 6; x < 2000; ++x) s.delete(x);
  assertEquals({value: 4, done: false}, i.next());
  s.delete(5);
  assertEquals({value: undefined, done: true}, i.next());
  s.add(4);
  assertEquals({value: undefined, done: true}, i.next());
});


test(function TestSetInvalidReceiver() {
  assertThrows(function() {
    Set.prototype.values.call({});
  }, TypeError);
  assertThrows(function() {
    Set.prototype.entries.call({});
  }, TypeError);
});


test(function TestSetIteratorInvalidReceiver() {
  var iter = new Set().values();
  assertThrows(function() {
    iter.next.call({});
  });
});


test(function TestSetIteratorSymbol() {
  assertEquals(Set.prototype[Symbol.iterator], Set.prototype.values);
  assertTrue(Set.prototype.hasOwnProperty(Symbol.iterator));
  assertFalse(Set.prototype.propertyIsEnumerable(Symbol.iterator));

  var iter = new Set().values();
  assertEquals(iter, iter[Symbol.iterator]());
  assertEquals(iter[Symbol.iterator].name, '[Symbol.iterator]');
});


test(function TestMapIterator() {
  var m = new Map;
  var iter = m.values();
  //assertEquals('Map Iterator', %_ClassOf(iter));

  var MapIteratorPrototype = iter.__proto__;
  assertFalse(MapIteratorPrototype.hasOwnProperty('constructor'));
  assertEquals(MapIteratorPrototype.__proto__, Object.prototype);

  var propertyNames = Object.getOwnPropertyNames(MapIteratorPrototype);
  assertArrayEquals(['next'], propertyNames);

  assertEquals(new Map().values().__proto__, MapIteratorPrototype);
  assertEquals(new Map().keys().__proto__, MapIteratorPrototype);
  assertEquals(new Map().entries().__proto__, MapIteratorPrototype);

  assertEquals("[object Map Iterator]",
      Object.prototype.toString.call(iter));
  assertEquals("Map Iterator", MapIteratorPrototype[Symbol.toStringTag]);
  var desc = Object.getOwnPropertyDescriptor(
      MapIteratorPrototype, Symbol.toStringTag);
  assertTrue(desc.configurable);
  assertFalse(desc.writable);
  assertEquals("Map Iterator", desc.value);
});


test(function TestMapIteratorValues() {
  var m = new Map;
  m.set(1, 11);
  m.set(2, 22);
  m.set(3, 33);
  var iter = m.values();

  assertEquals({value: 11, done: false}, iter.next());
  assertEquals({value: 22, done: false}, iter.next());
  assertEquals({value: 33, done: false}, iter.next());
  assertEquals({value: undefined, done: true}, iter.next());
  assertEquals({value: undefined, done: true}, iter.next());
});


test(function TestMapIteratorKeys() {
  var m = new Map;
  m.set(1, 11);
  m.set(2, 22);
  m.set(3, 33);
  var iter = m.keys();

  assertEquals({value: 1, done: false}, iter.next());
  assertEquals({value: 2, done: false}, iter.next());
  assertEquals({value: 3, done: false}, iter.next());
  assertEquals({value: undefined, done: true}, iter.next());
  assertEquals({value: undefined, done: true}, iter.next());
});


test(function TestMapIteratorEntries() {
  var m = new Map;
  m.set(1, 11);
  m.set(2, 22);
  m.set(3, 33);
  var iter = m.entries();

  assertEquals({value: [1, 11], done: false}, iter.next());
  assertEquals({value: [2, 22], done: false}, iter.next());
  assertEquals({value: [3, 33], done: false}, iter.next());
  assertEquals({value: undefined, done: true}, iter.next());
  assertEquals({value: undefined, done: true}, iter.next());
});


test(function TestMapInvalidReceiver() {
  assertThrows(function() {
    Map.prototype.values.call({});
  }, TypeError);
  assertThrows(function() {
    Map.prototype.keys.call({});
  }, TypeError);
  assertThrows(function() {
    Map.prototype.entries.call({});
  }, TypeError);
});


test(function TestMapIteratorInvalidReceiver() {
  var iter = new Map().values();
  assertThrows(function() {
    iter.next.call({});
  }, TypeError);
});


test(function TestMapIteratorSymbol() {
  assertEquals(Map.prototype[Symbol.iterator], Map.prototype.entries);
  assertTrue(Map.prototype.hasOwnProperty(Symbol.iterator));
  assertFalse(Map.prototype.propertyIsEnumerable(Symbol.iterator));

  var iter = new Map().values();
  assertEquals(iter, iter[Symbol.iterator]());
  assertEquals(iter[Symbol.iterator].name, '[Symbol.iterator]');
});

// These were missing from the V8 tests
test(function TestMapFromMap() {
  var m = new Map([['1', 1], ['2', 2]]);
  assertEquals(m.get('1'), 1);
  assertEquals(m.get('2'), 2);
  var n = new Map(m);
  assertEquals(n.get('1'), 1);
  assertEquals(n.get('2'), 2);
});

test(function TestSetFromSet() {
  var m = new Set([1, 2]);
  assertTrue(m.has(1));
  assertTrue(m.has(2));
  var n = new Set(m);
  assertTrue(n.has(1));
  assertTrue(n.has(2));
});

"success";
