From 7013d58694f581911fbf2434ddc602a87152eff8 Mon Sep 17 00:00:00 2001 From: leventov Date: Wed, 27 May 2015 15:21:31 +0100 Subject: [PATCH] Added BiMapTest --- .../net/openhft/chronicle/map/BiMapTest.java | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/test/java/net/openhft/chronicle/map/BiMapTest.java diff --git a/src/test/java/net/openhft/chronicle/map/BiMapTest.java b/src/test/java/net/openhft/chronicle/map/BiMapTest.java new file mode 100644 index 000000000..b790b15c0 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/BiMapTest.java @@ -0,0 +1,116 @@ +package net.openhft.chronicle.map; + +import net.openhft.chronicle.hash.Value; +import org.jetbrains.annotations.NotNull; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class BiMapTest { + + static class BiMapEntryOperations implements MapEntryOperations { + ChronicleMap reverse; + + public void setReverse(ChronicleMap reverse) { + this.reverse = reverse; + } + + @Override + public Void remove(@NotNull MapEntry entry) { + try (ExternalMapQueryContext rq = reverse.queryContext(entry.value().get())) { + rq.updateLock().lock(); + MapEntry reverseEntry = rq.entry(); + if (reverseEntry != null) { + entry.doRemove(); + reverseEntry.doRemove(); + return null; + } else { + throw new IllegalStateException(entry.key() + " maps to " + entry.value() + + ", but in the reverse map this value is absent"); + } + } + } + + @Override + public Void replaceValue(@NotNull MapEntry entry, Value newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public Void insert(@NotNull MapAbsentEntry absentEntry, Value value) { + try (ExternalMapQueryContext rq = reverse.queryContext(value.get())) { + rq.updateLock().lock(); + MapAbsentEntry reverseAbsentEntry = rq.absentEntry(); + if (reverseAbsentEntry != null) { + absentEntry.doInsert(value); + reverseAbsentEntry.doInsert(absentEntry.absentKey()); + return null; + } else { + Value reverseKey = rq.entry().value(); + if (reverseKey.equals(absentEntry.absentKey())) { + // recover + return null; + } + throw new IllegalArgumentException("Try to associate " + + absentEntry.absentKey() + " with " + value + ", but in the reverse " + + "map this value already maps to " + reverseKey); + } + } + } + } + + @Test + public void biMapTest() { + BiMapEntryOperations biMapOps1 = new BiMapEntryOperations<>(); + ChronicleMap map1 = ChronicleMapBuilder + .of(Integer.class, CharSequence.class) + .entries(100) + .averageValueSize(10) + .entryOperations(biMapOps1) + .create(); + + BiMapEntryOperations biMapOps2 = new BiMapEntryOperations<>(); + ChronicleMap map2 = ChronicleMapBuilder + .of(CharSequence.class, Integer.class) + .entries(100) + .averageKeySize(10) + .entryOperations(biMapOps2) + .create(); + + biMapOps1.setReverse(map2); + biMapOps2.setReverse(map1); + + map1.put(1, "1"); + assertEquals(1, map2.get("1").intValue()); + + map2.remove("1"); + assertTrue(map2.isEmpty()); + assertTrue(map1.isEmpty()); + + map1.put(3, "4"); + map2.put("5", 6); + assertEquals(2, map1.size()); + + try (ExternalMapQueryContext q = map2.queryContext("4")) { + q.updateLock().lock(); + q.entry().doRemove(); + } + + try { + map1.remove(3); + throw new AssertionError("expected IllegalStateException"); + } catch (IllegalStateException e) { + // expected + } + + try { + map2.put("4", 6); + throw new AssertionError("expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + map2.put("4", 3); // recover + } +}