View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.util;
23  
24  import java.util.ConcurrentModificationException;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.Map;
28  import java.util.Map.Entry;
29  import java.util.NoSuchElementException;
30  import java.util.Random;
31  import java.util.Set;
32  
33  import org.hipparchus.Field;
34  import org.hipparchus.exception.MathIllegalStateException;
35  import org.hipparchus.fraction.BigFraction;
36  import org.hipparchus.fraction.BigFractionField;
37  import org.hipparchus.fraction.Fraction;
38  import org.hipparchus.fraction.FractionField;
39  import org.junit.Assert;
40  import org.junit.Before;
41  import org.junit.Test;
42  
43  
44  public class OpenIntToFieldHashMapTest {
45  
46      private final Map<Integer, Fraction> javaMap = new HashMap<>();
47      private final FractionField field = FractionField.getInstance();
48  
49      @Before
50      public void setUp() {
51          javaMap.put(50, new Fraction(100.0));
52          javaMap.put(75, new Fraction(75.0));
53          javaMap.put(25, new Fraction(500.0));
54          javaMap.put(Integer.MAX_VALUE, new Fraction(Integer.MAX_VALUE));
55          javaMap.put(0, new Fraction(-1.0));
56          javaMap.put(1, new Fraction(0.0));
57          javaMap.put(33, new Fraction(-0.1));
58          javaMap.put(23234234, new Fraction(-242343.0));
59          javaMap.put(23321, new Fraction (Integer.MIN_VALUE));
60          javaMap.put(-4444, new Fraction(332.0));
61          javaMap.put(-1, new Fraction(-2323.0));
62          javaMap.put(Integer.MIN_VALUE, new Fraction(44.0));
63  
64          /* Add a few more to cause the table to rehash */
65          javaMap.putAll(generate());
66  
67      }
68  
69      private Map<Integer, Fraction> generate() {
70          Map<Integer, Fraction> map = new HashMap<>();
71          Random r = new Random();
72          double dd;
73          for (int i = 0; i < 2000; ++i) {
74              dd = r.nextDouble();
75              try {
76                  map.put(r.nextInt(), new Fraction(dd));
77              } catch (MathIllegalStateException e) {
78                  throw new IllegalStateException("Invalid :" + dd, e);
79              }
80          }
81          return map;
82      }
83  
84      private OpenIntToFieldHashMap<Fraction> createFromJavaMap(Field<Fraction> field) {
85          OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<>(field);
86          for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
87              map.put(mapEntry.getKey(), mapEntry.getValue());
88          }
89          return map;
90      }
91  
92      @Test
93      public void testPutAndGetWith0ExpectedSize() {
94          OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<>(field,0);
95          assertPutAndGet(map);
96      }
97  
98      @Test
99      public void testPutAndGetWithExpectedSize() {
100         OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<>(field,500);
101         assertPutAndGet(map);
102     }
103 
104     @Test
105     public void testPutAndGet() {
106         OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<>(field);
107         assertPutAndGet(map);
108     }
109 
110     private void assertPutAndGet(OpenIntToFieldHashMap<Fraction> map) {
111         assertPutAndGet(map, 0, new HashSet<>());
112     }
113 
114     private void assertPutAndGet(OpenIntToFieldHashMap<Fraction> map, int mapSize,
115             Set<Integer> keysInMap) {
116         Assert.assertEquals(mapSize, map.size());
117         for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
118             map.put(mapEntry.getKey(), mapEntry.getValue());
119             if (!keysInMap.contains(mapEntry.getKey()))
120                 ++mapSize;
121             Assert.assertEquals(mapSize, map.size());
122             Assert.assertEquals(mapEntry.getValue(), map.get(mapEntry.getKey()));
123         }
124     }
125 
126     @Test
127     public void testPutAbsentOnExisting() {
128         OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
129         int size = javaMap.size();
130         for (Map.Entry<Integer, Fraction> mapEntry : generateAbsent().entrySet()) {
131             map.put(mapEntry.getKey(), mapEntry.getValue());
132             Assert.assertEquals(++size, map.size());
133             Assert.assertEquals(mapEntry.getValue(), map.get(mapEntry.getKey()));
134         }
135     }
136 
137     @Test
138     public void testPutOnExisting() {
139         OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
140         for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
141             map.put(mapEntry.getKey(), mapEntry.getValue());
142             Assert.assertEquals(javaMap.size(), map.size());
143             Assert.assertEquals(mapEntry.getValue(), map.get(mapEntry.getKey()));
144         }
145     }
146 
147     @Test
148     public void testGetAbsent() {
149         Map<Integer, Fraction> generated = generateAbsent();
150         OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
151 
152         for (Map.Entry<Integer, Fraction> mapEntry : generated.entrySet())
153             Assert.assertEquals(field.getZero(), map.get(mapEntry.getKey()));
154     }
155 
156     @Test
157     public void testGetFromEmpty() {
158         OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<>(field);
159         Assert.assertEquals(field.getZero(), map.get(5));
160         Assert.assertEquals(field.getZero(), map.get(0));
161         Assert.assertEquals(field.getZero(), map.get(50));
162     }
163 
164     @Test
165     public void testRemove() {
166         OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
167         int mapSize = javaMap.size();
168         Assert.assertEquals(mapSize, map.size());
169         for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
170             map.remove(mapEntry.getKey());
171             Assert.assertEquals(--mapSize, map.size());
172             Assert.assertEquals(field.getZero(), map.get(mapEntry.getKey()));
173         }
174 
175         /* Ensure that put and get still work correctly after removals */
176         assertPutAndGet(map);
177     }
178 
179     /* This time only remove some entries */
180     @Test
181     public void testRemove2() {
182         OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
183         int mapSize = javaMap.size();
184         int count = 0;
185         Set<Integer> keysInMap = new HashSet<>(javaMap.keySet());
186         for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
187             keysInMap.remove(mapEntry.getKey());
188             map.remove(mapEntry.getKey());
189             Assert.assertEquals(--mapSize, map.size());
190             Assert.assertEquals(field.getZero(), map.get(mapEntry.getKey()));
191             if (count++ > 5)
192                 break;
193         }
194 
195         /* Ensure that put and get still work correctly after removals */
196         assertPutAndGet(map, mapSize, keysInMap);
197     }
198 
199     @Test
200     public void testRemoveFromEmpty() {
201         OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<>(field);
202         Assert.assertEquals(field.getZero(), map.remove(50));
203     }
204 
205     @Test
206     public void testRemoveAbsent() {
207         Map<Integer, Fraction> generated = generateAbsent();
208 
209         OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
210         int mapSize = map.size();
211 
212         for (Map.Entry<Integer, Fraction> mapEntry : generated.entrySet()) {
213             map.remove(mapEntry.getKey());
214             Assert.assertEquals(mapSize, map.size());
215             Assert.assertEquals(field.getZero(), map.get(mapEntry.getKey()));
216         }
217     }
218 
219     /**
220      * Returns a map with at least 100 elements where each element is absent from javaMap.
221      */
222     private Map<Integer, Fraction> generateAbsent() {
223         Map<Integer, Fraction> generated = new HashMap<>();
224         do {
225             generated.putAll(generate());
226             for (Integer key : javaMap.keySet())
227                 generated.remove(key);
228         } while (generated.size() < 100);
229         return generated;
230     }
231 
232     @Test
233     public void testCopy() {
234         OpenIntToFieldHashMap<Fraction> copy =
235             new OpenIntToFieldHashMap<>(createFromJavaMap(field));
236         Assert.assertEquals(javaMap.size(), copy.size());
237 
238         for (Map.Entry<Integer, Fraction> mapEntry : javaMap.entrySet())
239             Assert.assertEquals(mapEntry.getValue(), copy.get(mapEntry.getKey()));
240     }
241 
242     @Test
243     public void testContainsKey() {
244         OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
245         for (Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
246             Assert.assertTrue(map.containsKey(mapEntry.getKey()));
247         }
248         for (Map.Entry<Integer, Fraction> mapEntry : generateAbsent().entrySet()) {
249             Assert.assertFalse(map.containsKey(mapEntry.getKey()));
250         }
251         for (Entry<Integer, Fraction> mapEntry : javaMap.entrySet()) {
252             int key = mapEntry.getKey();
253             Assert.assertTrue(map.containsKey(key));
254             map.remove(key);
255             Assert.assertFalse(map.containsKey(key));
256         }
257     }
258 
259     @Test
260     public void testIterator() {
261         OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
262         OpenIntToFieldHashMap<Fraction>.Iterator iterator = map.iterator();
263         for (int i = 0; i < map.size(); ++i) {
264             Assert.assertTrue(iterator.hasNext());
265             iterator.advance();
266             int key = iterator.key();
267             Assert.assertTrue(map.containsKey(key));
268             Assert.assertEquals(javaMap.get(key), map.get(key));
269             Assert.assertEquals(javaMap.get(key), iterator.value());
270             Assert.assertTrue(javaMap.containsKey(key));
271         }
272         Assert.assertFalse(iterator.hasNext());
273         try {
274             iterator.advance();
275             Assert.fail("an exception should have been thrown");
276         } catch (NoSuchElementException nsee) {
277             // expected
278         }
279     }
280 
281     @Test
282     public void testEquals() {
283         OpenIntToFieldHashMap<Fraction> map1 = new OpenIntToFieldHashMap<>(FractionField.getInstance());
284         map1.put(2,   new Fraction( 5, 2));
285         map1.put(17,  new Fraction(-1, 2));
286         map1.put(16,  Fraction.ZERO);
287         Assert.assertEquals(map1, map1);
288         OpenIntToFieldHashMap<Fraction> map2 = new OpenIntToFieldHashMap<>(FractionField.getInstance());
289         map2.put(17, new Fraction(-1, 2));
290         map2.put(2,  new Fraction( 5, 2));
291         map2.put(16, new Fraction(0));
292         Assert.assertEquals(map1, map2);
293         map2.put(16,  new Fraction( 1, 4));
294         Assert.assertNotEquals(map1, map2);
295         map2.put(16,  Fraction.ZERO);
296         Assert.assertEquals(map1, map2);
297         OpenIntToFieldHashMap<BigFraction> map3 = new OpenIntToFieldHashMap<>(BigFractionField.getInstance());
298         map3.put(2,   new BigFraction( 5, 2));
299         map3.put(17,  new BigFraction(-1, 2));
300         map3.put(16,  BigFraction.ZERO);
301         Assert.assertNotEquals(map1, map3);
302         Assert.assertNotEquals(map1, "");
303         Assert.assertNotEquals(map1, null);
304     }
305 
306     @Test
307     public void testHashcode() {
308         OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<>(FractionField.getInstance());
309         map.put(2,   new Fraction( 5, 2));
310         map.put(17,  new Fraction(-1, 2));
311         map.put(16,  Fraction.ZERO);
312         Assert.assertEquals(-528348218, map.hashCode());
313     }
314 
315     @Test
316     public void testConcurrentModification() {
317         OpenIntToFieldHashMap<Fraction> map = createFromJavaMap(field);
318         OpenIntToFieldHashMap<Fraction>.Iterator iterator = map.iterator();
319         map.put(3, new Fraction(3));
320         try {
321             iterator.advance();
322             Assert.fail("an exception should have been thrown");
323         } catch (ConcurrentModificationException cme) {
324             // expected
325         }
326     }
327 
328     /**
329      * Regression test for a bug in findInsertionIndex where the hashing in the second probing
330      * loop was inconsistent with the first causing duplicate keys after the right sequence
331      * of puts and removes.
332      */
333     @Test
334     public void testPutKeysWithCollisions() {
335         OpenIntToFieldHashMap<Fraction> map = new OpenIntToFieldHashMap<>(field);
336         int key1 = -1996012590;
337         Fraction value1 = new Fraction(1);
338         map.put(key1, value1);
339         int key2 = 835099822;
340         map.put(key2, value1);
341         int key3 = 1008859686;
342         map.put(key3, value1);
343         Assert.assertEquals(value1, map.get(key3));
344         Assert.assertEquals(3, map.size());
345 
346         map.remove(key2);
347         Fraction value2 = new Fraction(2);
348         map.put(key3, value2);
349         Assert.assertEquals(value2, map.get(key3));
350         Assert.assertEquals(2, map.size());
351     }
352 
353     /**
354      * Similar to testPutKeysWithCollisions() but exercises the codepaths in a slightly
355      * different manner.
356      */
357     @Test
358     public void testPutKeysWithCollision2() {
359         OpenIntToFieldHashMap<Fraction>map = new OpenIntToFieldHashMap<>(field);
360         int key1 = 837989881;
361         Fraction value1 = new Fraction(1);
362         map.put(key1, value1);
363         int key2 = 476463321;
364         map.put(key2, value1);
365         Assert.assertEquals(2, map.size());
366         Assert.assertEquals(value1, map.get(key2));
367 
368         map.remove(key1);
369         Fraction value2 = new Fraction(2);
370         map.put(key2, value2);
371         Assert.assertEquals(1, map.size());
372         Assert.assertEquals(value2, map.get(key2));
373     }
374 
375 
376 }