/* * Copyright (C) 2012, 2016 higherfrequencytrading.com * Copyright (C) 2016 Roman Leventov * * This program 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, either version 3 of the License. * * This program 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. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.chronicle.map; import net.openhft.chronicle.hash.Data; import net.openhft.chronicle.map.impl.NullReturnValue; import org.jetbrains.annotations.NotNull; import org.junit.Test; import java.util.Iterator; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.*; public class ListenersTest { static class CountingEntryOperations<K, V> implements MapEntryOperations<K, V, Void> { AtomicInteger removeCount = new AtomicInteger(); AtomicInteger insertCount = new AtomicInteger(); AtomicInteger replaceValueCount = new AtomicInteger(); @Override public Void remove(@NotNull MapEntry<K, V> entry) { removeCount.incrementAndGet(); return MapEntryOperations.super.remove(entry); } @Override public Void replaceValue(@NotNull MapEntry<K, V> entry, Data<V> newValue) { replaceValueCount.incrementAndGet(); return MapEntryOperations.super.replaceValue(entry, newValue); } @Override public Void insert(@NotNull MapAbsentEntry<K, V> absentEntry, Data<V> value) { insertCount.incrementAndGet(); return MapEntryOperations.super.insert(absentEntry, value); } } @Test public void testAnyRemove() { CountingEntryOperations<Integer, Integer> removeCounting = new CountingEntryOperations<>(); ChronicleMap<Integer, Integer> map = ChronicleMapBuilder.of(Integer.class, Integer.class) .entries(100) .entryOperations(removeCounting) .create(); map.put(1, 1); map.remove(1); // removeCount 1 map.put(1, 1); assertFalse(map.remove(1, 2)); map.remove(1, 1); // removeCount 2 map.put(1, 1); map.merge(1, 1, (v1, v2) -> null); // removeCount 3 map.put(1, 1); Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); it.next(); it.remove(); // removeCount 4 assertEquals(4, removeCounting.removeCount.get()); } @Test public void testAnyPut() { CountingEntryOperations<Integer, Integer> putCounting = new CountingEntryOperations<>(); ChronicleMap<Integer, Integer> map = ChronicleMapBuilder.of(Integer.class, Integer.class) .entries(100) .entryOperations(putCounting) .create(); map.put(1, 1); // insert 1 map.put(1, 2); // replaceValue 1 map.compute(1, (k, v) -> 2); // replaceValue 2 map.entrySet().iterator().next().setValue(1); // replaceValue 3 map.compute(2, (k, v) -> 1); // insert 2 assertEquals(3, putCounting.replaceValueCount.get()); assertEquals(2, putCounting.insertCount.get()); } @Test public void testContainsKey() { AtomicInteger c = new AtomicInteger(); ChronicleMap<Integer, Integer> map = ChronicleMapBuilder.of(Integer.class, Integer.class) .entries(100) .mapMethods(new MapMethods<Integer, Integer, Void>() { @Override public boolean containsKey(MapQueryContext<Integer, Integer, Void> q) { if (q.queriedKey().get() == 2) return false; c.incrementAndGet(); return MapMethods.super.containsKey(q); } }) .create(); assertFalse(map.containsKey(1)); // 1 map.put(1, 1); assertTrue(map.containsKey(1)); // 2 map.put(2, 2); assertFalse(map.containsKey(2)); assertEquals(2, c.get()); } @Test public void testGet() { AtomicInteger c = new AtomicInteger(); ChronicleMap<Integer, Integer> map = ChronicleMapBuilder.of(Integer.class, Integer.class) .entries(100) .mapMethods(new MapMethods<Integer, Integer, Void>() { @Override public void get(MapQueryContext<Integer, Integer, Void> q, ReturnValue<Integer> returnValue) { if (q.queriedKey().get() == 2) { returnValue.returnValue(q.wrapValueAsData(42)); return; } c.incrementAndGet(); MapMethods.super.get(q, returnValue); } }) .create(); assertNull(map.get(1)); // 1 map.put(1, 1); assertEquals(1, map.get(1).intValue()); // 2 map.put(2, 2); assertEquals(42, map.get(2).intValue()); assertEquals(2, c.get()); } @Test public void testPut() { AtomicInteger c = new AtomicInteger(); ChronicleMap<Integer, Integer> map = ChronicleMapBuilder.of(Integer.class, Integer.class) .entries(100) .mapMethods(new MapMethods<Integer, Integer, Void>() { @Override public void put(MapQueryContext<Integer, Integer, Void> q, net.openhft.chronicle.hash.Data<Integer> value, ReturnValue<Integer> returnValue) { if (q.queriedKey().get() == 2) { MapMethods.super.put(q, value, NullReturnValue.get()); return; } if (q.queriedKey().get() == 3) { MapMethods.super.put(q, q.wrapValueAsData(value.get() + 1), returnValue); return; } c.incrementAndGet(); MapMethods.super.put(q, value, returnValue); } }) .create(); assertNull(map.put(1, 1)); // 1 assertEquals(1, map.put(1, 2).intValue()); // 2 assertNull(map.put(2, 1)); assertNull(map.put(2, 2)); assertNull(map.put(3, 1)); assertEquals(2, map.get(3).intValue()); assertEquals(2, c.get()); } }