// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import "package:expect/expect.dart";

class FixedHashCode {
  final int _hashCode;
  const FixedHashCode(this._hashCode);
  int get hashCode {
    return _hashCode;
  }
}

class SetIteratorTest {
  static testMain() {
    testSmallSet();
    testLargeSet();
    testEmptySet();
    testSetWithDeletedEntries();
    testBug5116829();
    testDifferentSizes();
    testDifferentHashCodes();
  }

  static void sum(int expected, Iterator<int> it) {
    int count = 0;
    while (it.moveNext()) {
      count += it.current;
    }
    Expect.equals(expected, count);
  }

  static void testSmallSet() {
    Set<int> set = new Set<int>();
    set.add(1);
    set.add(2);
    set.add(3);

    Iterator<int> it = set.iterator;
    sum(6, it);
    Expect.isFalse(it.moveNext());
  }

  static void testLargeSet() {
    Set<int> set = new Set<int>();
    int count = 0;
    for (int i = 0; i < 100; i++) {
      count += i;
      set.add(i);
    }
    Iterator<int> it = set.iterator;
    sum(count, it);
    Expect.isFalse(it.moveNext());
  }

  static void testEmptySet() {
    Set<int> set = new Set<int>();
    Iterator<int> it = set.iterator;
    sum(0, it);
    Expect.isFalse(it.moveNext());
  }

  static void testSetWithDeletedEntries() {
    Set<int> set = new Set<int>();
    for (int i = 0; i < 100; i++) {
      set.add(i);
    }
    for (int i = 0; i < 100; i++) {
      set.remove(i);
    }
    Iterator<int> it = set.iterator;
    Expect.isFalse(it.moveNext());
    it = set.iterator;
    sum(0, it);
    Expect.isFalse(it.moveNext());

    int count = 0;
    for (int i = 0; i < 100; i++) {
      set.add(i);
      if (i % 2 == 0)
        set.remove(i);
      else
        count += i;
    }
    it = set.iterator;
    sum(count, it);
    Expect.isFalse(it.moveNext());
  }

  static void testBug5116829() {
    // During iteration we skipped slot 0 of the hashset's key list. "A" was
    // hashed to slot 0 and therefore triggered the bug.
    Set<String> mystrs = new Set<String>();
    mystrs.add("A");
    int seen = 0;
    for (String elt in mystrs) {
      seen++;
      Expect.equals("A", elt);
    }
    Expect.equals(1, seen);
  }

  static void testDifferentSizes() {
    for (int i = 1; i < 20; i++) {
      Set set = new Set();
      int sum = 0;
      for (int j = 0; j < i; j++) {
        set.add(j);
        sum += j;
      }
      int count = 0;
      int controlSum = 0;
      for (int x in set) {
        controlSum += x;
        count++;
      }
      Expect.equals(i, count);
      Expect.equals(sum, controlSum);
    }
  }

  static void testDifferentHashCodes() {
    for (int i = -20; i < 20; i++) {
      Set set = new Set();
      var element = new FixedHashCode(i);
      set.add(element);
      Expect.equals(1, set.length);
      bool foundIt = false;
      for (var x in set) {
        foundIt = true;
        Expect.equals(true, identical(x, element));
      }
      Expect.equals(true, foundIt);
    }
  }
}

main() {
  SetIteratorTest.testMain();
}
