// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.tools; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.List; import org.junit.Rule; import org.junit.Test; import org.openstreetmap.josm.testutils.JOSMTestRules; import org.openstreetmap.josm.tools.MemoryManager.MemoryHandle; import org.openstreetmap.josm.tools.MemoryManager.NotEnoughMemoryException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** * Tests the {@link MemoryManager} class. * @author Michael Zangl */ public class MemoryManagerTest { /** * Base test environment */ @Rule @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public JOSMTestRules test = new JOSMTestRules().memoryManagerLeaks(); /** * Test {@link MemoryManager#allocateMemory(String, long, java.util.function.Supplier)} * @throws NotEnoughMemoryException if there is not enough memory */ @Test public void testUseMemory() throws NotEnoughMemoryException { MemoryManager manager = MemoryManager.getInstance(); long available = manager.getAvailableMemory(); assertTrue(available < Runtime.getRuntime().maxMemory()); assertEquals(available, manager.getMaxMemory()); Object o1 = new Object(); MemoryHandle<Object> testMemory = manager.allocateMemory("test", 10, () -> o1); assertEquals(available - 10, manager.getAvailableMemory()); assertSame(o1, testMemory.get()); assertEquals(10, testMemory.getSize()); assertTrue(testMemory.toString().startsWith("MemoryHandle")); manager.allocateMemory("test2", 10, Object::new); assertEquals(available - 20, manager.getAvailableMemory()); testMemory.free(); assertEquals(available - 10, manager.getAvailableMemory()); } /** * Test that {@link MemoryHandle#get()} checks for use after free. * @throws NotEnoughMemoryException if there is not enough memory */ @Test(expected = IllegalStateException.class) public void testUseAfterFree() throws NotEnoughMemoryException { MemoryManager manager = MemoryManager.getInstance(); MemoryHandle<Object> testMemory = manager.allocateMemory("test", 10, Object::new); testMemory.free(); testMemory.get(); } /** * Test that {@link MemoryHandle#get()} checks for free after free. * @throws NotEnoughMemoryException if there is not enough memory */ @Test(expected = IllegalStateException.class) public void testFreeAfterFree() throws NotEnoughMemoryException { MemoryManager manager = MemoryManager.getInstance(); MemoryHandle<Object> testMemory = manager.allocateMemory("test", 10, Object::new); testMemory.free(); testMemory.free(); } /** * Test that too big allocations fail * @throws NotEnoughMemoryException always */ @Test(expected = NotEnoughMemoryException.class) public void testAllocationFails() throws NotEnoughMemoryException { MemoryManager manager = MemoryManager.getInstance(); long available = manager.getAvailableMemory(); manager.allocateMemory("test", available + 1, () -> { fail("Should not reach"); return null; }); } /** * Test that allocations with null object fail * @throws NotEnoughMemoryException never */ @Test(expected = IllegalArgumentException.class) public void testSupplierFails() throws NotEnoughMemoryException { MemoryManager manager = MemoryManager.getInstance(); manager.allocateMemory("test", 1, () -> null); } /** * Test {@link MemoryManager#isAvailable(long)} */ @Test public void testIsAvailable() { MemoryManager manager = MemoryManager.getInstance(); assertTrue(manager.isAvailable(10)); assertTrue(manager.isAvailable(100)); assertTrue(manager.isAvailable(10)); } /** * Test {@link MemoryManager#isAvailable(long)} for negative number * @throws NotEnoughMemoryException never */ @Test(expected = IllegalArgumentException.class) public void testIsAvailableFails() throws NotEnoughMemoryException { MemoryManager manager = MemoryManager.getInstance(); manager.isAvailable(-10); } /** * Test {@link MemoryManager#resetState()} * @throws NotEnoughMemoryException if there is not enough memory */ @Test public void testResetState() throws NotEnoughMemoryException { MemoryManager manager = MemoryManager.getInstance(); assertTrue(manager.resetState().isEmpty()); manager.allocateMemory("test", 10, Object::new); manager.allocateMemory("test2", 10, Object::new); assertEquals(2, manager.resetState().size()); assertTrue(manager.resetState().isEmpty()); } /** * Test {@link MemoryManager#resetState()} * @throws NotEnoughMemoryException if there is not enough memory */ @Test(expected = IllegalStateException.class) public void testResetStateUseAfterFree() throws NotEnoughMemoryException { MemoryManager manager = MemoryManager.getInstance(); MemoryHandle<Object> testMemory = manager.allocateMemory("test", 10, Object::new); assertFalse(manager.resetState().isEmpty()); testMemory.get(); } /** * Reset the state of the memory manager * @param allowMemoryManagerLeaks If this is set, no exception is thrown if there were leaking entries. */ public static void resetState(boolean allowMemoryManagerLeaks) { List<MemoryHandle<?>> hadLeaks = MemoryManager.getInstance().resetState(); if (!allowMemoryManagerLeaks) { assertTrue("Memory manager had leaking memory: " + hadLeaks, hadLeaks.isEmpty()); } } }