/*
 * Copyright (C) 2004 Joe Walnes.
 * Copyright (C) 2006, 2007, 2008 XStream Committers.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 * 
 * Created on 30. May 2004 by Joe Walnes
 */
package com.thoughtworks.xstream.core.util;

import junit.framework.TestCase;

import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;


public class ObjectIdDictionaryTest extends TestCase {

    public void testMapsIdsToObjectReferences() {
        ObjectIdDictionary dict = new ObjectIdDictionary();
        Object a = new Object();
        Object b = new Object();
        Object c = new Object();
        dict.associateId(a, "id a");
        dict.associateId(b, "id b");
        dict.associateId(c, "id c");
        assertEquals("id a", dict.lookupId(a));
        assertEquals("id b", dict.lookupId(b));
        assertEquals("id c", dict.lookupId(c));
    }

    public void testTreatsObjectsThatAreEqualButNotSameInstanceAsDifferentReference() {
        ObjectIdDictionary dict = new ObjectIdDictionary();
        Integer a = new Integer(3);
        Integer b = new Integer(3);
        dict.associateId(a, "id a");
        dict.associateId(b, "id b");
        assertEquals("id a", dict.lookupId(a));
        assertEquals("id b", dict.lookupId(b));
    }

    public void testEnforceSameSystemHashCodeForGCedObjects() {
        final StringBuffer memInfo = new StringBuffer("MemoryInfo:\n");
        memInfo.append(memoryInfo());
        memInfo.append('\n');
        System.setProperty("xstream.debug", "true");

        int blocks = forceGCAndGetNumberOfBlocks();
        List softMemory = new ArrayList();
        while (blocks-- > 0) {
            softMemory.add(blocks < 250 ? new SoftReference(new byte[1024*16]) : new byte[1024*16]);
        }

        // create 200000 Strings and call GC after creation of 50000
        final int loop = 4;
        final int elements = 50000;
        final int[] dictSizes = new int[loop * elements];
        ObjectIdDictionary dict = new ObjectIdDictionary();
        for (int i = 0; i < loop; ++i) {
            for (int j = 0; j < elements; ++j) {
                final String s = new String("JUnit ") + j; // enforce new object
                dictSizes[i * elements + j] = dict.size();
                assertFalse("Failed in (" + i + "/" + j + ")", dict.containsId(s));
                dict.associateId(s, "X");
            }
            memInfo.append(memoryInfo());
            memInfo.append('\n');
            forceGCAndGetNumberOfBlocks();
        }

        System.setProperty("xstream.debug", "false");
        assertFalse("Algorithm did not reach last element", 0 == dictSizes[loop * elements - 1]);
        assertFalse("Dictionary did not shrink; " + memInfo,
            loop * elements - 1 == dictSizes[loop * elements - 1]);
    }

    private int forceGCAndGetNumberOfBlocks() {
        int i = 0;
        SoftReference ref = new SoftReference(new Object());
        for (int count = 0; ref.get() != null && count++ < 4; ) {
            List memory = new ArrayList();
            try {
                // fill up memory
                while(ref.get() != null) {
                    memory.add(new byte[1024*16]);
                }
            } catch (OutOfMemoryError error) {
                // expected
            }
            i = memory.size();
            memory.clear();
            memory = null;
            System.gc();
        }

        System.err.println("Force GC, blocks: " + i);
        
        assertNull("This JVM is not releasing memory!", ref.get());
        return i;
    }
    
    private String memoryInfo() {
        Runtime runtime = Runtime.getRuntime();
        StringBuffer buffer = new StringBuffer("Memory: ");
        buffer.append(runtime.freeMemory());
        buffer.append(" free / ");
        buffer.append(runtime.totalMemory());
        buffer.append(" total / ");
        buffer.append(runtime.maxMemory());
        buffer.append(" max / ");
        return buffer.toString();
    }
}

@@ -1888,16 +1888,24 @@
 %3C 250 ? 
+(Object)
 new Soft
@@ -1935,16 +1935,24 @@
 *16%5D) : 
+(Object)
 new byte

Fix compiler problem.