@Test
 public void testGetFromEmpty() {
   OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<Fraction>(field);
   Assert.assertTrue(field.getZero().equals(map.get(5)));
   Assert.assertTrue(field.getZero().equals(map.get(0)));
   Assert.assertTrue(field.getZero().equals(map.get(50)));
 }
  @Test
  public void testGetAbsent() {
    Map<Integer, Fraction> generated = generateAbsent();
    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);

    for (Map.Entry<Integer, Fraction> mapEntry : generated.entrySet())
      Assert.assertTrue(field.getZero().equals(map.get(mapEntry.getKey())));
  }
  @Test
  public void testRemoveAbsent() {
    Map<Integer, Fraction> generated = generateAbsent();

    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
    int mapSize = map.size();

    for (Map.Entry<Integer, Fraction> mapEntry : generated.entrySet()) {
      map.remove(mapEntry.getKey());
      Assert.assertEquals(mapSize, map.size());
      Assert.assertTrue(field.getZero().equals(map.get(mapEntry.getKey())));
    }
  }
  @Test
  public void testRemove() {
    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
    int mapSize = javaMap.size();
    Assert.assertEquals(mapSize, map.size());
    for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
      map.remove(mapEntry.getKey());
      Assert.assertEquals(--mapSize, map.size());
      Assert.assertTrue(field.getZero().equals(map.get(mapEntry.getKey())));
    }

    /* Ensure that put and get still work correctly after removals */
    assertPutAndGet(map);
  }
@SuppressWarnings("boxing")
public class OpenIntToFieldTest {

  private Map<Integer, Fraction> javaMap = new HashMap<Integer, Fraction>();
  private FractionField field = FractionField.getInstance();

  @Before
  public void setUp() throws FractionConversionException {
    javaMap.put(50, new Fraction(100.0));
    javaMap.put(75, new Fraction(75.0));
    javaMap.put(25, new Fraction(500.0));
    javaMap.put(Integer.MAX_VALUE, new Fraction(Integer.MAX_VALUE));
    javaMap.put(0, new Fraction(-1.0));
    javaMap.put(1, new Fraction(0.0));
    javaMap.put(33, new Fraction(-0.1));
    javaMap.put(23234234, new Fraction(-242343.0));
    javaMap.put(23321, new Fraction(Integer.MIN_VALUE));
    javaMap.put(-4444, new Fraction(332.0));
    javaMap.put(-1, new Fraction(-2323.0));
    javaMap.put(Integer.MIN_VALUE, new Fraction(44.0));

    /* Add a few more to cause the table to rehash */
    javaMap.putAll(generate());
  }

  private Map<Integer, Fraction> generate() {
    Map<Integer, Fraction> map = new HashMap<Integer, Fraction>();
    Random r = new Random();
    double dd = 0;
    for (int i = 0; i < 2000; ++i) dd = r.nextDouble();
    try {
      map.put(r.nextInt(), new Fraction(dd));
    } catch (FractionConversionException e) {
      throw new IllegalStateException("Invalid :" + dd, e);
    }
    return map;
  }

  private OpenIntToFieldHashMap<Fraction> createFromJavaMap(Field<Fraction> field) {
    OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<Fraction>(field);
    for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
      map.put(mapEntry.getKey(), mapEntry.getValue());
    }
    return map;
  }

  @Test
  public void testPutAndGetWith0ExpectedSize() {
    OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<Fraction>(field, 0);
    assertPutAndGet(map);
  }

  @Test
  public void testPutAndGetWithExpectedSize() {
    OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<Fraction>(field, 500);
    assertPutAndGet(map);
  }

  @Test
  public void testPutAndGet() {
    OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<Fraction>(field);
    assertPutAndGet(map);
  }

  private void assertPutAndGet(OpenIntToFieldHashMap<Fraction> map) {
    assertPutAndGet(map, 0, new HashSet<Integer>());
  }

  private void assertPutAndGet(
      OpenIntToFieldHashMap<Fraction> map, int mapSize, Set<Integer> keysInMap) {
    Assert.assertEquals(mapSize, map.size());
    for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
      map.put(mapEntry.getKey(), mapEntry.getValue());
      if (!keysInMap.contains(mapEntry.getKey())) ++mapSize;
      Assert.assertEquals(mapSize, map.size());
      Assert.assertEquals(mapEntry.getValue(), map.get(mapEntry.getKey()));
    }
  }

  @Test
  public void testPutAbsentOnExisting() {
    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
    int size = javaMap.size();
    for (Map.Entry<Integer, Fraction> mapEntry : generateAbsent().entrySet()) {
      map.put(mapEntry.getKey(), mapEntry.getValue());
      Assert.assertEquals(++size, map.size());
      Assert.assertEquals(mapEntry.getValue(), map.get(mapEntry.getKey()));
    }
  }

  @Test
  public void testPutOnExisting() {
    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
    for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
      map.put(mapEntry.getKey(), mapEntry.getValue());
      Assert.assertEquals(javaMap.size(), map.size());
      Assert.assertEquals(mapEntry.getValue(), map.get(mapEntry.getKey()));
    }
  }

  @Test
  public void testGetAbsent() {
    Map<Integer, Fraction> generated = generateAbsent();
    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);

    for (Map.Entry<Integer, Fraction> mapEntry : generated.entrySet())
      Assert.assertTrue(field.getZero().equals(map.get(mapEntry.getKey())));
  }

  @Test
  public void testGetFromEmpty() {
    OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<Fraction>(field);
    Assert.assertTrue(field.getZero().equals(map.get(5)));
    Assert.assertTrue(field.getZero().equals(map.get(0)));
    Assert.assertTrue(field.getZero().equals(map.get(50)));
  }

  @Test
  public void testRemove() {
    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
    int mapSize = javaMap.size();
    Assert.assertEquals(mapSize, map.size());
    for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
      map.remove(mapEntry.getKey());
      Assert.assertEquals(--mapSize, map.size());
      Assert.assertTrue(field.getZero().equals(map.get(mapEntry.getKey())));
    }

    /* Ensure that put and get still work correctly after removals */
    assertPutAndGet(map);
  }

  /* This time only remove some entries */
  @Test
  public void testRemove2() {
    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
    int mapSize = javaMap.size();
    int count = 0;
    Set<Integer> keysInMap = new HashSet<Integer>(javaMap.keySet());
    for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
      keysInMap.remove(mapEntry.getKey());
      map.remove(mapEntry.getKey());
      Assert.assertEquals(--mapSize, map.size());
      Assert.assertTrue(field.getZero().equals(map.get(mapEntry.getKey())));
      if (count++ > 5) break;
    }

    /* Ensure that put and get still work correctly after removals */
    assertPutAndGet(map, mapSize, keysInMap);
  }

  @Test
  public void testRemoveFromEmpty() {
    OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<Fraction>(field);
    Assert.assertTrue(field.getZero().equals(map.remove(50)));
  }

  @Test
  public void testRemoveAbsent() {
    Map<Integer, Fraction> generated = generateAbsent();

    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
    int mapSize = map.size();

    for (Map.Entry<Integer, Fraction> mapEntry : generated.entrySet()) {
      map.remove(mapEntry.getKey());
      Assert.assertEquals(mapSize, map.size());
      Assert.assertTrue(field.getZero().equals(map.get(mapEntry.getKey())));
    }
  }

  /** Returns a map with at least 100 elements where each element is absent from javaMap. */
  private Map<Integer, Fraction> generateAbsent() {
    Map<Integer, Fraction> generated = new HashMap<Integer, Fraction>();
    do {
      generated.putAll(generate());
      for (Integer key : javaMap.keySet()) generated.remove(key);
    } while (generated.size() < 100);
    return generated;
  }

  @Test
  public void testCopy() {
    OpenIntToFieldHashMap<Fraction> copy =
        new OpenIntToFieldHashMap<Fraction>(createFromJavaMap(field));
    Assert.assertEquals(javaMap.size(), copy.size());

    for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet())
      Assert.assertEquals(mapEntry.getValue(), copy.get(mapEntry.getKey()));
  }

  @Test
  public void testContainsKey() {
    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
    for (Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
      Assert.assertTrue(map.containsKey(mapEntry.getKey()));
    }
    for (Map.Entry<Integer, Fraction> mapEntry : generateAbsent().entrySet()) {
      Assert.assertFalse(map.containsKey(mapEntry.getKey()));
    }
    for (Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
      int key = mapEntry.getKey();
      Assert.assertTrue(map.containsKey(key));
      map.remove(key);
      Assert.assertFalse(map.containsKey(key));
    }
  }

  @Test
  public void testIterator() {
    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
    OpenIntToFieldHashMap<Fraction>.Iterator iterator = map.iterator();
    for (int i = 0; i < map.size(); ++i) {
      Assert.assertTrue(iterator.hasNext());
      iterator.advance();
      int key = iterator.key();
      Assert.assertTrue(map.containsKey(key));
      Assert.assertEquals(javaMap.get(key), map.get(key));
      Assert.assertEquals(javaMap.get(key), iterator.value());
      Assert.assertTrue(javaMap.containsKey(key));
    }
    Assert.assertFalse(iterator.hasNext());
    try {
      iterator.advance();
      Assert.fail("an exception should have been thrown");
    } catch (NoSuchElementException nsee) {
      // expected
    }
  }

  @Test
  public void testConcurrentModification() {
    OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
    OpenIntToFieldHashMap<Fraction>.Iterator iterator = map.iterator();
    map.put(3, new Fraction(3));
    try {
      iterator.advance();
      Assert.fail("an exception should have been thrown");
    } catch (ConcurrentModificationException cme) {
      // expected
    }
  }

  /**
   * Regression test for a bug in findInsertionIndex where the hashing in the second probing loop
   * was inconsistent with the first causing duplicate keys after the right sequence of puts and
   * removes.
   */
  @Test
  public void testPutKeysWithCollisions() {
    OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<Fraction>(field);
    int key1 = -1996012590;
    Fraction value1 = new Fraction(1);
    map.put(key1, value1);
    int key2 = 835099822;
    map.put(key2, value1);
    int key3 = 1008859686;
    map.put(key3, value1);
    Assert.assertEquals(value1, map.get(key3));
    Assert.assertEquals(3, map.size());

    map.remove(key2);
    Fraction value2 = new Fraction(2);
    map.put(key3, value2);
    Assert.assertEquals(value2, map.get(key3));
    Assert.assertEquals(2, map.size());
  }

  /**
   * Similar to testPutKeysWithCollisions() but exercises the codepaths in a slightly different
   * manner.
   */
  @Test
  public void testPutKeysWithCollision2() {
    OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<Fraction>(field);
    int key1 = 837989881;
    Fraction value1 = new Fraction(1);
    map.put(key1, value1);
    int key2 = 476463321;
    map.put(key2, value1);
    Assert.assertEquals(2, map.size());
    Assert.assertEquals(value1, map.get(key2));

    map.remove(key1);
    Fraction value2 = new Fraction(2);
    map.put(key2, value2);
    Assert.assertEquals(1, map.size());
    Assert.assertEquals(value2, map.get(key2));
  }
}