/*
 * All content copyright Terracotta, Inc., unless otherwise indicated.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.terracotta.context;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.LinkedList;
import java.util.Queue;
import org.junit.Test;

import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;

/**
 *
 * @author cdennis
 */
public class WeakIdentityHashMapTest {
  
  @Test
  public void testEnqueuedReferenceIsRemoved() {
    
    final Queue<Reference<String>> references = new LinkedList<Reference<String>>();
    WeakIdentityHashMap<String, String> map = new WeakIdentityHashMap<String, String>() {
      @Override
      protected Reference<String> createReference(String key, ReferenceQueue<? super String> queue) {
        if (queue == null) {
          return super.createReference(key, queue);
        } else {
          Reference<String> ref = super.createReference(key, queue);
          references.add(ref);
          return ref;
        }
      }
    };
    
    assertThat(map.putIfAbsent("test", "test"), nullValue());
    assertThat(map.get("test"), is("test"));
    
    references.remove().enqueue();
    
    assertThat(map.get("test"), nullValue());
  }

  @Test
  public void testEnqueuedCleanableReferenceIsRemovedAndCleaned() {
    final Queue<Reference<String>> references = new LinkedList<Reference<String>>();
    WeakIdentityHashMap<String, DummyCleanable> map = new WeakIdentityHashMap<String, DummyCleanable>() {
      @Override
      protected Reference<String> createReference(String key, ReferenceQueue<? super String> queue) {
        if (queue == null) {
          return super.createReference(key, queue);
        } else {
          Reference<String> ref = super.createReference(key, queue);
          references.add(ref);
          return ref;
        }
      }
    };
    
    DummyCleanable value = new DummyCleanable();
    assertThat(map.putIfAbsent("test", value), nullValue());
    assertThat(map.get("test"), is(value));
    
    references.remove().enqueue();
    
    assertThat(map.get("test"), nullValue());
    assertThat(value.isClean(), is(true));
  }
  
  static class DummyCleanable implements WeakIdentityHashMap.Cleanable {

    private boolean cleaned = false;
    
    @Override
    public void clean() {
      cleaned = true;
    }

    public boolean isClean() {
      return cleaned;
    }
  }
}

@@ -1075,27 +1075,16 @@
 ) %7B%0A    
-%0A    final 
 Queue%3CRe
@@ -1188,36 +1188,49 @@
 , String%3E map = 
-new 
+createRefTracking
 WeakIdentityHash
@@ -1236,255 +1236,316 @@
 hMap
-%3CString, String%3E() %7B%0A      @Override%0A      protected Reference%3CString%3E createReference(String key, ReferenceQueue%3C? super String%3E 
+(references);%0A    %0A    assertThat(map.putIfAbsent(%22test%22, %22test%22), nullValue());%0A    assertThat(map.get(%22test%22), is(%22test%22));%0A    %0A    references.remove().en
 queue
-) %7B
+();
 %0A    
+%0A
     
-if (queue == null) %7B%0A          return super.createReference(key, queue);%0A        %7D else %7B%0A          
+assertThat(map.get(%22test%22), nullValue());%0A  %7D%0A%0A  @Test%0A  public void testEnqueuedCleanableReferenceIsRemovedAndCleaned() %7B%0A    Queue%3C
 Refe
@@ -1561,132 +1561,217 @@
 ing%3E
+%3E
  ref
- = super.createReference(key, queue);%0A          references.add(ref);%0A          return ref;%0A        %7D%0A      %7D%0A    %7D;%0A    
+erences = new LinkedList%3CReference%3CString%3E%3E();%0A    WeakIdentityHashMap%3CString, DummyCleanable%3E map = createRefTrackingWeakIdentityHashMap(references);%0A    %0A    DummyCleanable value = new DummyCleanable();
 %0A   
@@ -1798,38 +1798,37 @@
 fAbsent(%22test%22, 
-%22test%22
+value
 ), nullValue());
@@ -1855,38 +1855,37 @@
 get(%22test%22), is(
-%22test%22
+value
 ));%0A    %0A    ref
@@ -1969,225 +1969,191 @@
 ;%0A  
-%7D%0A%0A  @Test%0A  public void testEnqueuedCleanableReferenceIsRemovedAndCleaned() %7B%0A    final Queue%3CReference%3CString%3E%3E references = new LinkedList%3CReference%3CString%3E%3E();%0A    WeakIdentityHashMap%3CString, DummyCleanable%3E map =
+  assertThat(value.isClean(), is(true));%0A  %7D%0A%0A  private %3CT%3E WeakIdentityHashMap%3CString, T%3E createRefTrackingWeakIdentityHashMap(final Queue%3CReference%3CString%3E%3E references) %7B%0A    return
  new
@@ -2181,30 +2181,17 @@
 String, 
-DummyCleanable
+T
 %3E() %7B%0A  
@@ -2555,307 +2555,12 @@
  %7D;%0A
-    %0A    DummyCleanable value = new DummyCleanable();%0A    assertThat(map.putIfAbsent(%22test%22, value), nullValue());%0A    assertThat(map.get(%22test%22), is(value));%0A    %0A    references.remove().enqueue();%0A    %0A    assertThat(map.get(%22test%22), nullValue());%0A    assertThat(value.isClean(), is(true));%0A
   %7D%0A
-  
 %0A  s

Refactor tracking map creation