Index: trunk/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java	(revision 10580)
+++ trunk/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java	(revision 10588)
@@ -19,4 +19,5 @@
 import org.openstreetmap.josm.io.OsmTransferCanceledException;
 import org.openstreetmap.josm.tools.I18n;
+import org.openstreetmap.josm.tools.MemoryManagerTest;
 import org.openstreetmap.josm.tools.date.DateUtils;
 
@@ -39,4 +40,5 @@
     private boolean platform;
     private boolean useProjection;
+    private boolean allowMemoryManagerLeaks;
 
     /**
@@ -130,4 +132,13 @@
     public JOSMTestRules projection() {
         useProjection = true;
+        return this;
+    }
+
+    /**
+     * Allow the memory manager to contain items after execution of the test cases.
+     * @return this instance, for easy chaining
+     */
+    public JOSMTestRules memoryManagerLeaks() {
+        allowMemoryManagerLeaks = true;
         return this;
     }
@@ -218,4 +229,5 @@
     @SuppressFBWarnings("DM_GC")
     private void cleanUpFromJosmFixture() {
+        MemoryManagerTest.resetState(true);
         Main.getLayerManager().resetState();
         Main.pref = null;
@@ -237,4 +249,5 @@
         // Remove all layers
         Main.getLayerManager().resetState();
+        MemoryManagerTest.resetState(allowMemoryManagerLeaks);
 
         // TODO: Remove global listeners and other global state.
Index: trunk/test/unit/org/openstreetmap/josm/tools/MemoryManagerTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/tools/MemoryManagerTest.java	(revision 10588)
+++ trunk/test/unit/org/openstreetmap/josm/tools/MemoryManagerTest.java	(revision 10588)
@@ -0,0 +1,168 @@
+// 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, () -> new Object());
+        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, () -> new Object());
+        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, () -> new Object());
+        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, () -> new Object());
+        manager.allocateMemory("test2", 10, () -> new Object());
+        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, () -> new Object());
+
+        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());
+        }
+    }
+}
