/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.util;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import java.util.ConcurrentModificationException;
import java.util.logging.Logger;
import org.junit.*;
import static org.junit.Assert.*;
/**
* Tests {@link SoftValueHashMap}.
*
*
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux
*/
public final class SoftValueHashMapTest {
/**
* The size of the test sets to be created.
*/
private static final int SAMPLE_SIZE = 200;
/**
* Tests the {@link SoftValueHashMap} using strong references. The tested
* {@link SoftValueHashMap} should behave like a standard {@link Map} object.
*/
@Test
public void testStrongReferences() {
final Random random = getRandom();
for (int pass=0; pass<4; pass++) {
// make sure we can keep as many strong references as the sample, since there is no guarantee
// the distribution of random.nextBoolean() is uniform in the short term
final SoftValueHashMap<Integer,Integer> softMap = new SoftValueHashMap<Integer,Integer>(SAMPLE_SIZE);
final HashMap<Integer,Integer> strongMap = new HashMap<Integer,Integer>();
for (int i=0; i<SAMPLE_SIZE; i++) {
final Integer key = random.nextInt(SAMPLE_SIZE);
final Integer value = random.nextInt(SAMPLE_SIZE);
assertEquals("containsKey:", strongMap.containsKey(key),
softMap.containsKey(key));
assertEquals("containsValue:", strongMap.containsValue(value),
softMap.containsValue(value));
assertSame ("get:", strongMap.get(key),
softMap.get(key));
assertEquals("equals:", strongMap, softMap);
if (random.nextBoolean()) {
// Test addition.
assertSame("put:", strongMap.put(key, value),
softMap.put(key, value));
} else {
// Test remove
assertSame("remove:", strongMap.remove(key),
softMap.remove(key));
}
assertEquals("equals:", strongMap, softMap);
}
}
}
/**
* Tests the {@link SoftValueHashMap} using soft references.
* In this test, we have to keep in mind than some elements
* in {@code softMap} may disaspear at any time.
*/
@Test
public void testSoftReferences() throws InterruptedException {
final Random random = getRandom();
final SoftValueHashMap<Integer,Integer> softMap = new SoftValueHashMap<Integer,Integer>();
final HashMap<Integer,Integer> strongMap = new HashMap<Integer,Integer>();
for (int pass=0; pass<2; pass++) {
int count = 0;
softMap.clear();
strongMap.clear();
for (int i=0; i<SAMPLE_SIZE; i++) {
// We really want new instances below.
final Integer key = new Integer(random.nextInt(SAMPLE_SIZE));
final Integer value = new Integer(random.nextInt(SAMPLE_SIZE));
if (random.nextBoolean()) {
/*
* Test addition.
*/
final Integer softPrevious = softMap .put(key, value);
final Integer strongPrevious = strongMap.put(key, value);
if (softPrevious == null) {
// If the element was not in the SoftValueHashMap (i.e. if the garbage
// collector has cleared it), then it must not been in HashMap neither
// (otherwise GC should not have cleared it).
assertNull("put:", strongPrevious);
count++; // Count only the new values.
} else {
assertNotSame(value, softPrevious);
}
if (strongPrevious != null) {
// Note: If 'strongPrevious==null', 'softPrevious' may not
// be null if GC has not collected its entry yet.
assertSame("put:", strongPrevious, softPrevious);
}
} else {
/*
* Test remove
*/
final Integer softPrevious = softMap.get(key);
final Integer strongPrevious = strongMap.remove(key);
if (strongPrevious != null) {
assertSame("remove:", strongPrevious, softPrevious);
}
}
assertTrue("containsAll:", softMap.entrySet().containsAll(strongMap.entrySet()));
}
// Do our best to lets GC finish its work.
for (int i=0; i<20; i++) {
Runtime.getRuntime().gc();
Runtime.getRuntime().runFinalization();
}
assertTrue(softMap.isValid());
assertTrue("size:", softMap.size() <= count);
/*
* Make sure that all values are of the correct type. More specifically, we
* want to make sure that we didn't forget to convert some Reference object.
*/
for (final Iterator it=softMap.values().iterator(); it.hasNext();) {
final Object value;
try {
value = it.next();
} catch (ConcurrentModificationException e) {
break;
}
assertTrue(value instanceof Integer);
assertNotNull(value);
}
}
}
private Random getRandom() {
long seed = System.currentTimeMillis() + hashCode();
Random random = new Random(seed);
Logger.getLogger(this.getClass().getName()).info("Using Random Seed: "+seed);
return random;
}
}