package set;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.function.Consumer;
import java.util.stream.IntStream;

import org.junit.Test;

@SuppressWarnings("static-method")
public class DynamicHashSetTest {
  @Test
  public void testAddOdd() {
    DynamicHashSet<Integer> set = new DynamicHashSet<>();
    IntStream.range(0, 100).map(i -> i * 2 + 1).forEach(set::add);
  }
  
  @Test
  public void testAddEven() {
    DynamicHashSet<Integer> set = new DynamicHashSet<>();
    IntStream.range(0, 100).map(i -> i * 2).forEach(set::add);
  }
  
  @Test(timeout = 3000)
  public void testAddALot() {
    DynamicHashSet<Integer> set = new DynamicHashSet<>();
    for(int i = 0; i < 1_000_000; i++) {
      set.add(i);
    }
  }
  
  @Test(expected = NullPointerException.class)
  public void testAddNull() {
    DynamicHashSet<Object> set = new DynamicHashSet<>();
    set.add(null);
  }
  
  @Test
  public void testSizeEmpty() {
    DynamicHashSet<Object> set = new DynamicHashSet<>();
    assertEquals(0, set.size());
  }
  
  @Test
  public void testAddAndSize() {
    DynamicHashSet<Integer> set = new DynamicHashSet<>();
    set.add(3);
    assertEquals(1, set.size());
    set.add(-777);
    assertEquals(2, set.size());
    set.add(3);
    assertEquals(2, set.size());
    set.add(-777);
    assertEquals(2, set.size());
  }

  @Test
  public void testForEachEmpy() {
    DynamicHashSet<Object> set = new DynamicHashSet<>();
    set.forEach(__ -> fail());
  }
  
  @Test
  public void testForEachSum() {
    int length = 100;
    DynamicHashSet<Integer> set = new DynamicHashSet<>();
    IntStream.range(0, length).forEach(set::add);
    int[] sum = { 0 };
    set.forEach(value -> sum[0] += value);
    assertEquals(length * (length - 1) / 2, sum[0]);
  }
  
  @Test
  public void testForEachSet() {
    DynamicHashSet<Integer> set = new DynamicHashSet<>();
    IntStream.range(0, 100).forEach(set::add);
    HashSet<Integer> hashSet = new HashSet<>();
    set.forEach(hashSet::add);
    assertEquals(set.size(), hashSet.size());
  }
  
  @Test
  public void testForEachSet2() {
    DynamicHashSet<Integer> set = new DynamicHashSet<>();
    IntStream.range(0, 100).forEach(set::add);
    ArrayList<Integer> list = new ArrayList<>();
    set.forEach(list::add);
    list.sort(null);
    IntStream.range(0, 100).forEach(i -> assertEquals(i, (int)list.get(i)));
  }
  
  @Test
  public void testForEachSuperTypeConsumer() {
    DynamicHashSet<String> set = new DynamicHashSet<>();
    set.add("foo");
    Consumer<Object> consumer = o -> assertTrue(o.equals("foo")); 
    set.forEach(consumer);
  }
  
  @Test
  public void testContains() {
    DynamicHashSet<Integer> set = new DynamicHashSet<>();
    assertFalse(set.contains(4));
    assertFalse(set.contains(7));
    assertFalse(set.contains(1));
    assertFalse(set.contains(0));
  }
  
  @Test
  public void testAddContains() {
    DynamicHashSet<Integer> set = new DynamicHashSet<>();
    for(int i = 0; i < 10; i++) {
      assertFalse(set.contains(i));
      set.add(i);
      assertTrue(set.contains(i));
    }
  }
  
  @Test
  public void testAddTwiceContains() {
    DynamicHashSet<Integer> set = new DynamicHashSet<>();
    assertFalse(set.contains(Integer.MIN_VALUE));
    set.add(Integer.MIN_VALUE);
    assertTrue(set.contains(Integer.MIN_VALUE));
    set.add(Integer.MIN_VALUE);
    assertTrue(set.contains(Integer.MIN_VALUE));
  }
  
  @Test
  public void testContainsOfDifferentType() {
    DynamicHashSet<String> set = new DynamicHashSet<>();
    assertFalse(set.contains("baz"));
  }
  
  @Test(expected = NullPointerException.class)
  public void testContainsNull() {
    DynamicHashSet<Object> set = new DynamicHashSet<>();
    set.contains(null);
  }
  
  @Test
  public void testAddAll() {
    DynamicHashSet<String> set = new DynamicHashSet<>();
    set.addAll(Arrays.asList("hello", "boy"));
    assertEquals(2, set.size());
    set.forEach(s -> assertTrue(s.equals("hello") || s.equals("boy")));
  }
  
  @Test
  public void testAddAll2() {
    DynamicHashSet<String> set = new DynamicHashSet<>();
    set.add("bar");
    ArrayList<String> list = new ArrayList<>();
    list.add("bar");
    set.addAll(list);
    assertEquals(1, set.size());
    set.forEach(s -> assertEquals("bar", s));
  }
  
  @Test
  public void testAddAllSubType() {
    DynamicHashSet<Object> set = new DynamicHashSet<>();
    HashSet<String> hashSet = new HashSet<>();
    set.addAll(hashSet);
  }
}
