package edu.stanford.nlp.util; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import static org.junit.Assert.*; /** * * Basic tests for the FileBackedCache * * @author Gabor Angeli */ @SuppressWarnings("ResultOfMethodCallIgnored") public class FileBackedCacheTest { private static class CustomHash implements Serializable { private int unique; private int hash; private CustomHash(int unique, int hash) { this.unique = unique; this.hash = hash; } public int hashCode() { return hash; } public boolean equals(Object o) { return (o instanceof CustomHash) && ((CustomHash) o).unique == unique; } public String toString() { return "CustomHash(id=" + unique + ", hash=" + hash + ")"; } } private FileBackedCache<String, String> cache; private FileBackedCache<Integer, Map<String, ArrayList<String>>> mapCache; @Before public void setUp() { try { // (regular cache) File cacheDir = File.createTempFile("cache", ".dir"); cacheDir.delete(); cache = new FileBackedCache<String, String>(cacheDir); assertEquals(0, cacheDir.listFiles().length); // (map cache) File mapCacheDir = File.createTempFile("cache", ".dir"); mapCacheDir.delete(); mapCache = new FileBackedCache<Integer, Map<String, ArrayList<String>>>(mapCacheDir); assertEquals(0, mapCacheDir.listFiles().length); } catch (Exception e) { throw new RuntimeException(e); } } @After public void tearDown() { if (cache.cacheDir.listFiles() != null) { for (File c : cache.cacheDir.listFiles()) { assertTrue(c.delete()); } assertTrue(cache.cacheDir.delete()); } if (mapCache.cacheDir.listFiles() != null) { for (File c : mapCache.cacheDir.listFiles()) { assertTrue(c.delete()); } assertTrue(mapCache.cacheDir.delete()); } } @Test public void testContainsLocal() { cache.put("key", "value"); cache.put("key2", "value2"); assertTrue(cache.containsKey("key")); assertTrue(cache.containsKey("key2")); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testGetLocal() { cache.put("key", "value"); cache.put("key2", "value2"); assertEquals("value", cache.get("key")); assertEquals("value2", cache.get("key2")); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testPutLocal() { assertEquals(null, cache.put("key", "value")); assertEquals(null, cache.put("key2", "value2")); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testCacheWritingToDisk() { assertEquals(0, cache.cacheDir.listFiles().length); cache.put("key", "value"); assertEquals(1, cache.cacheDir.listFiles().length); cache.put("key2", "value2"); assertEquals(2, cache.cacheDir.listFiles().length); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testSize() { assertEquals(0, cache.sizeInMemory()); assertEquals(0, cache.size()); cache.put("key", "value"); cache.put("key2", "value2"); assertEquals(2, cache.sizeInMemory()); // assume no GC assertEquals(2, cache.size()); cache.clear(); assertEquals(0, cache.sizeInMemory()); assertEquals(2, cache.cacheDir.listFiles().length); assertEquals(2, cache.size()); assertEquals(2, cache.sizeInMemory()); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testContainsFile() { cache.put("key", "value"); cache.put("key2", "value2"); cache.clear(); assertTrue(cache.containsKey("key")); assertTrue(cache.containsKey("key2")); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testContainsRemoveFromMemory() { cache.put("key", "value"); cache.put("key2", "value2"); cache.removeFromMemory("key"); assertEquals(1, cache.sizeInMemory()); assertTrue(cache.containsKey("key")); assertTrue(cache.containsKey("key2")); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testPutFile() { // Case 1: simple put cache.put("key", "value"); assertEquals("value", cache.put("key", "valueReplaced")); assertEquals("valueReplaced", cache.get("key")); // Case 2: put then clear cache.put("key", "value"); cache.clear(); assertEquals("value", cache.put("key", "valueReplaced")); cache.clear(); assertEquals("valueReplaced", cache.get("key")); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testGetFile() { cache.put("key", "value"); cache.put("key2", "value2"); cache.clear(); assertEquals("value", cache.get("key")); assertEquals("value2", cache.get("key2")); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testIterator() { cache.put("key", "value"); cache.put("key2", "value2"); int count = 0; Iterator<Map.Entry<String,String>> iterator = cache.iterator(); while(iterator.hasNext()) { Map.Entry<String, String> entry = iterator.next(); if (entry.getKey() == "key") assertEquals("value", entry.getValue()); if (entry.getKey() == "key2") assertEquals("value2", entry.getValue()); count += 1; } assertEquals(2, count); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testComprehension() { cache.put("key", "value"); cache.put("key2", "value2"); int count = 0; for (Map.Entry<String, String> entry : cache) { if (entry.getKey() == "key") assertEquals("value", entry.getValue()); if (entry.getKey() == "key2") assertEquals("value2", entry.getValue()); count += 1; } assertEquals(2, count); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testCollision() throws IOException { // Custom Setup File cacheDir = File.createTempFile("cache", ".dir"); cacheDir.delete(); FileBackedCache<CustomHash, String> myCache = new FileBackedCache<CustomHash, String>(cacheDir); assertEquals(0, cacheDir.listFiles().length); // Test myCache.put(new CustomHash(0, 0), "zero"); myCache.put(new CustomHash(1, 0), "one"); myCache.put(new CustomHash(1, 1), "one'"); assertEquals("zero", myCache.get(new CustomHash(0, 0))); assertEquals("one", myCache.get(new CustomHash(1, 0))); assertEquals("one'", myCache.get(new CustomHash(1, 1))); myCache.clear(); assertEquals(0, myCache.sizeInMemory()); assertEquals("zero", myCache.get(new CustomHash(0, 0))); assertEquals("one", myCache.get(new CustomHash(1, 0))); assertEquals("one'", myCache.get(new CustomHash(1, 1))); // Retest FileBackedCache<CustomHash, String> reload = new FileBackedCache<CustomHash, String>(cacheDir); assertEquals("zero", reload.get(new CustomHash(0, 0))); assertEquals("one", reload.get(new CustomHash(1, 0))); assertEquals("one'", reload.get(new CustomHash(1, 1))); reload.put(new CustomHash(2, 0), "two"); assertEquals("two", reload.get(new CustomHash(2, 0))); // Custom Teardown for (File c : cache.cacheDir.listFiles()) { assertTrue(c.delete()); } assertTrue(cache.cacheDir.delete()); assertTrue(FileBackedCache.locksHeld().isEmpty()); } @SuppressWarnings({"unchecked", "ConstantConditions"}) @Test public void testMerge() throws IOException { cache.put("key", "value"); // (create constituents) File constituent1File = File.createTempFile("cache", ".dir"); assertTrue(constituent1File.delete()); FileBackedCache<String, String> constituent1 = new FileBackedCache<String, String>(constituent1File); File constituent2File = File.createTempFile("cache", ".dir"); assertTrue(constituent2File.delete()); FileBackedCache<String, String> constituent2 = new FileBackedCache<String, String>(constituent2File); // (populate constituents) constituent1.put("c1Key1", "constituent1a"); constituent1.put("c1Key2", "constituent1b"); constituent1.put("c1Key3", "overlap"); constituent2.put("c2Key1", "constituent2a"); constituent2.put("c2Key2", "constituent2b"); constituent2.put("c1Key3", "overlapReplaced"); constituent1.clear(); constituent2.clear(); // (merge) FileBackedCache.merge(cache, new FileBackedCache[]{constituent1, constituent2}); assertEquals("value", cache.get("key")); // (checks) cache.clear(); assertEquals("constituent1a", cache.get("c1Key1")); assertEquals("constituent1b", cache.get("c1Key2")); assertEquals("constituent2a", cache.get("c2Key1")); assertEquals("constituent2b", cache.get("c2Key2")); assertEquals("overlapReplaced", cache.get("c1Key3")); // (clean up) if (constituent1File.listFiles() != null) { for (File c : constituent1File.listFiles()) { assertTrue(c.delete()); } assertTrue(constituent1File.delete()); } if (constituent2File.listFiles() != null) { for (File c : constituent2File.listFiles()) { assertTrue(c.delete()); } assertTrue(constituent2File.delete()); } assertTrue(FileBackedCache.locksHeld().isEmpty()); } @Test public void testMapValueGoodPattern() throws IOException { HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>(); map.put("foo", new ArrayList<String>()); mapCache.put(42, map); assertEquals(1, mapCache.get(42).size()); mapCache.clear(); assertEquals(1, mapCache.get(42).size()); } }