/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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.apache.geode.internal.offheap;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.nio.ByteBuffer;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import org.apache.geode.compression.Compressor;
import org.apache.geode.internal.cache.CachePerfStats;
import org.apache.geode.internal.cache.DiskId;
import org.apache.geode.internal.cache.EntryEventImpl;
import org.apache.geode.internal.cache.RegionEntryContext;
import org.apache.geode.internal.cache.Token;
import org.apache.geode.internal.cache.VMCachedDeserializable;
import org.apache.geode.internal.cache.entries.DiskEntry;
import org.apache.geode.internal.cache.entries.OffHeapRegionEntry;
import org.apache.geode.internal.cache.entries.VersionedStatsDiskRegionEntryOffHeap;
import org.apache.geode.internal.serialization.DSCODE;

@RunWith(PowerMockRunner.class)
@PowerMockIgnore("*.UnitTest")
@PrepareForTest({OffHeapStoredObject.class, OffHeapRegionEntryHelper.class})
public class OffHeapRegionEntryHelperJUnitTest {

  private static final Long VALUE_IS_NOT_ENCODABLE = 0L;

  private MemoryAllocator ma;

  @Before
  public void setUp() {
    OutOfOffHeapMemoryListener ooohml = mock(OutOfOffHeapMemoryListener.class);
    OffHeapMemoryStats stats = mock(OffHeapMemoryStats.class);

    ma = MemoryAllocatorImpl.create(ooohml, stats, 1, OffHeapStorage.MIN_SLAB_SIZE * 1,
        OffHeapStorage.MIN_SLAB_SIZE);
  }

  @After
  public void tearDown() {
    MemoryAllocatorImpl.freeOffHeapMemory();
  }

  private OffHeapStoredObject createChunk(Object value) {
    byte[] v = EntryEventImpl.serialize(value);

    boolean isSerialized = true;
    boolean isCompressed = false;

    OffHeapStoredObject chunk =
        (OffHeapStoredObject) ma.allocateAndInitialize(v, isSerialized, isCompressed);

    return chunk;
  }

  @Test
  public void encodeDataAsAddressShouldReturnZeroIfValueIsGreaterThanSevenBytes() {
    Long value = Long.MAX_VALUE;

    byte[] valueInBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(value).array();
    boolean isSerialized = false;
    boolean isCompressed = false;

    assertThat(valueInBytes.length)
        .isGreaterThanOrEqualTo(OffHeapRegionEntryHelper.MAX_LENGTH_FOR_DATA_AS_ADDRESS);

    long encodedAddress =
        OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);

    assertThat(encodedAddress).isEqualTo(VALUE_IS_NOT_ENCODABLE);
  }

  @Test
  public void encodeDataAsAddressShouldEncodeLongIfItsSerializedAndIfItsNotTooBig() {
    Long value = 0L;
    long expectedEncodedAddress = 123L;

    byte[] valueInBytes = EntryEventImpl.serialize(value);
    boolean isSerialized = true;
    boolean isCompressed = false;

    long encodedAddress =
        OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);

    assertThat(encodedAddress).isEqualTo(expectedEncodedAddress);
    assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
  }

  @Test
  public void encodeDataAsAddressShouldReturnZeroIfValueIsLongAndItIsSerializedAndBig() {
    Long value = Long.MAX_VALUE;

    byte[] valueInBytes = EntryEventImpl.serialize(value);
    boolean isSerialized = true;
    boolean isCompressed = false;

    long encodedAddress =
        OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);

    assertThat(encodedAddress).isEqualTo(VALUE_IS_NOT_ENCODABLE);
  }

  @Test
  public void encodeDataAsAddressShouldReturnZeroIfValueIsLargerThanEightBytesAndNotLong() {
    byte[] someValue = new byte[8];
    someValue[0] = DSCODE.CLASS.toByte();

    boolean isSerialized = true;
    boolean isCompressed = false;

    long encodedAddress =
        OffHeapRegionEntryHelper.encodeDataAsAddress(someValue, isSerialized, isCompressed);

    assertThat(encodedAddress).isEqualTo(VALUE_IS_NOT_ENCODABLE);
  }

  @Test
  public void encodeDataAsAddressShouldReturnValidAddressIfValueIsLesserThanSevenBytes() {
    long expectedAddress = 549755813697L;

    Integer value = Integer.MAX_VALUE;

    byte[] valueInBytes = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(value).array();
    boolean isSerialized = false;
    boolean isCompressed = false;

    long encodedAddress =
        OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);

    assertThat(encodedAddress).isEqualTo(expectedAddress);
    assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
  }

  @Test
  public void encodeDataAsAssressShouldSetSerialziedBitIfSerizliaed() {
    long expectedAddress = 63221918596947L;

    Integer value = Integer.MAX_VALUE;

    byte[] valueInBytes = EntryEventImpl.serialize(value);
    boolean isSerialized = true;
    boolean isCompressed = false;

    long encodedAddress =
        OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);

    assertThat(expectedAddress).isEqualTo(encodedAddress);
    assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
  }

  @Test
  public void encodeDataAsAssressShouldSetSerialziedBitIfCompressed() {
    long expectedAddress = 549755813701L;

    Integer value = Integer.MAX_VALUE;

    byte[] valueInBytes = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(value).array();
    boolean isSerialized = false;
    boolean isCompressed = true;

    long encodedAddress =
        OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);

    assertThat(encodedAddress).isEqualTo(expectedAddress);
    assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
  }

  @Test
  public void encodeDataAsAssressShouldSetBothSerialziedAndCompressedBitsIfSerializedAndCompressed() {
    long expectedAddress = 63221918596951L;

    Integer value = Integer.MAX_VALUE;

    byte[] valueInBytes = EntryEventImpl.serialize(value);
    boolean isSerialized = true;
    boolean isCompressed = true;

    long encodedAddress =
        OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);

    assertThat(expectedAddress).isEqualTo(encodedAddress);
    assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
  }

  private void assertSerializedAndCompressedBits(long encodedAddress,
      boolean shouldSerializedBitBeSet, boolean shouldCompressedBitBeSet) {
    boolean isSerializedBitSet = (encodedAddress
        & OffHeapRegionEntryHelper.SERIALIZED_BIT) == OffHeapRegionEntryHelper.SERIALIZED_BIT ? true
            : false;
    boolean isCompressedBitSet = (encodedAddress
        & OffHeapRegionEntryHelper.COMPRESSED_BIT) == OffHeapRegionEntryHelper.COMPRESSED_BIT ? true
            : false;

    assertThat(isSerializedBitSet).isEqualTo(shouldSerializedBitBeSet);
    assertThat(isCompressedBitSet).isEqualTo(shouldCompressedBitBeSet);
  }

  @Test
  public void decodeUncompressedAddressToBytesShouldReturnActualBytes() {
    long encodedAddress = 549755813697L;
    Integer value = Integer.MAX_VALUE;

    byte[] actual = OffHeapRegionEntryHelper.decodeUncompressedAddressToBytes(encodedAddress);
    byte[] expectedValue = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(value).array();

    assertThat(actual).isEqualTo(expectedValue);
  }

  @Test
  public void decodeUncompressedAddressToBytesShouldDecodeLongIfItsSerializedAndIfItsNotTooBig() {
    Long value = 0L;
    long encodedAddress = 123L;

    byte[] actual = OffHeapRegionEntryHelper.decodeUncompressedAddressToBytes(encodedAddress);
    byte[] expectedValue = EntryEventImpl.serialize(value);

    assertThat(actual).isEqualTo(expectedValue);
  }

  @Test(expected = AssertionError.class)
  public void decodeUncompressedAddressToBytesWithCompressedAddressShouldThrowException() {
    long encodedAddress = 549755813703L;
    OffHeapRegionEntryHelper.decodeUncompressedAddressToBytes(encodedAddress);
  }

  @Test
  public void decodeCompressedDataAsAddressToRawBytes() {
    long encodedAddress = 549755813703L;
    byte[] expected = new byte[] {127, -1, -1, -1};

    byte[] bytes = OffHeapRegionEntryHelper.decodeAddressToRawBytes(encodedAddress);

    assertThat(bytes).isEqualTo(expected);
  }

  @Test
  public void encodedAddressShouldBeDecodableEvenIfValueIsSerialized() {
    Integer value = Integer.MAX_VALUE;

    byte[] serializedValue = EntryEventImpl.serialize(value);
    boolean isSerialized = true;
    boolean isCompressed = false;

    long encodedAddress =
        OffHeapRegionEntryHelper.encodeDataAsAddress(serializedValue, isSerialized, isCompressed);

    Integer actualValue = (Integer) OffHeapRegionEntryHelper.decodeAddressToObject(encodedAddress);

    assertThat(actualValue).isEqualTo(value);
  }

  @Test
  public void encodedAddressShouldBeDecodableEvenIfValueIsUnserialized() {
    Integer value = Integer.MAX_VALUE;

    byte[] unSerializedValue = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(value).array();
    boolean isSerialized = false;
    boolean isCompressed = false;

    long encodedAddress =
        OffHeapRegionEntryHelper.encodeDataAsAddress(unSerializedValue, isSerialized, isCompressed);

    byte[] actualValue = (byte[]) OffHeapRegionEntryHelper.decodeAddressToObject(encodedAddress);

    assertThat(actualValue).isEqualTo(unSerializedValue);
  }

  @Test
  public void isSerializedShouldReturnTrueIfSerialized() {
    assertThat(OffHeapRegionEntryHelper.isSerialized(1000010L)).isTrue();
  }

  @Test
  public void isSerializedShouldReturnFalseIfNotSerialized() {
    assertThat(OffHeapRegionEntryHelper.isSerialized(1000000L)).isFalse();
  }

  @Test
  public void isCompressedShouldReturnTrueIfCompressed() {
    assertThat(OffHeapRegionEntryHelper.isCompressed(1000100L)).isTrue();
  }

  @Test
  public void isCompressedShouldReturnFalseIfNotCompressed() {
    assertThat(OffHeapRegionEntryHelper.isCompressed(1000000L)).isFalse();
  }

  @Test
  public void isOffHeapShouldReturnTrueIfAddressIsOnOffHeap() {
    OffHeapStoredObject value = createChunk(Long.MAX_VALUE);
    assertThat(OffHeapRegionEntryHelper.isOffHeap(value.getAddress())).isTrue();
  }

  @Test
  public void isOffHeapShouldReturnFalseIfAddressIsAnEncodedAddress() {
    byte[] data =
        ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt((Integer) Integer.MAX_VALUE).array();
    long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, false, false);
    assertThat(OffHeapRegionEntryHelper.isOffHeap(address)).isFalse();
  }

  @Test
  public void isOffHeapShouldReturnFalseForAnyTokenAddress() {
    assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.NULL_ADDRESS)).isFalse();
    assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.INVALID_ADDRESS))
        .isFalse();
    assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.LOCAL_INVALID_ADDRESS))
        .isFalse();
    assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.DESTROYED_ADDRESS))
        .isFalse();
    assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS))
        .isFalse();
    assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS))
        .isFalse();
    assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.END_OF_STREAM_ADDRESS))
        .isFalse();
    assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.NOT_AVAILABLE_ADDRESS))
        .isFalse();
    assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.TOMBSTONE_ADDRESS))
        .isFalse();
  }

  @Test
  public void setValueShouldChangeTheRegionEntryAddressToNewAddress() {
    // mock region entry
    OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);

    // some old address
    long oldAddress = 1L;

    // testing when the newValue is a chunk
    OffHeapStoredObject newValue = createChunk(Long.MAX_VALUE);
    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, newValue.getAddress())).thenReturn(Boolean.TRUE);

    // invoke the method under test
    OffHeapRegionEntryHelper.setValue(re, newValue);

    // verify oldAddress is replaced with newAddress
    verify(re, times(1)).setAddress(oldAddress, newValue.getAddress());
    // resetting the spy in-order to re-use
    reset(re);

    // testing when the newValue is DataAsAddress
    TinyStoredObject newAddress1 = new TinyStoredObject(2L);
    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, newAddress1.getAddress())).thenReturn(Boolean.TRUE);
    OffHeapRegionEntryHelper.setValue(re, newAddress1);

    // verify oldAddress is replaced with newAddress
    verify(re, times(1)).setAddress(oldAddress, newAddress1.getAddress());
    reset(re);

    // Testing when newValue is Token Objects

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.NULL_ADDRESS)).thenReturn(Boolean.TRUE);
    OffHeapRegionEntryHelper.setValue(re, null);

    // verify oldAddress is replaced with newAddress
    verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.NULL_ADDRESS);
    reset(re);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.INVALID_ADDRESS))
        .thenReturn(Boolean.TRUE);
    OffHeapRegionEntryHelper.setValue(re, Token.INVALID);

    // verify oldAddress is replaced with newAddress
    verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.INVALID_ADDRESS);
    reset(re);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.LOCAL_INVALID_ADDRESS))
        .thenReturn(Boolean.TRUE);
    OffHeapRegionEntryHelper.setValue(re, Token.LOCAL_INVALID);

    // verify oldAddress is replaced with newAddress
    verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.LOCAL_INVALID_ADDRESS);
    reset(re);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.DESTROYED_ADDRESS))
        .thenReturn(Boolean.TRUE);
    OffHeapRegionEntryHelper.setValue(re, Token.DESTROYED);

    // verify oldAddress is replaced with newAddress
    verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.DESTROYED_ADDRESS);
    reset(re);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS))
        .thenReturn(Boolean.TRUE);
    OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE1);

    // verify oldAddress is replaced with newAddress
    verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS);
    reset(re);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS))
        .thenReturn(Boolean.TRUE);
    OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE2);

    // verify oldAddress is replaced with newAddress
    verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS);
    reset(re);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.END_OF_STREAM_ADDRESS))
        .thenReturn(Boolean.TRUE);
    OffHeapRegionEntryHelper.setValue(re, Token.END_OF_STREAM);

    // verify oldAddress is replaced with newAddress
    verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.END_OF_STREAM_ADDRESS);
    reset(re);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.NOT_AVAILABLE_ADDRESS))
        .thenReturn(Boolean.TRUE);
    OffHeapRegionEntryHelper.setValue(re, Token.NOT_AVAILABLE);

    // verify oldAddress is replaced with newAddress
    verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.NOT_AVAILABLE_ADDRESS);
    reset(re);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.TOMBSTONE_ADDRESS))
        .thenReturn(Boolean.TRUE);
    OffHeapRegionEntryHelper.setValue(re, Token.TOMBSTONE);

    // verify oldAddress is replaced with newAddress
    verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.TOMBSTONE_ADDRESS);
    reset(re);
  }

  @Test
  public void setValueShouldChangeTheRegionEntryAddressToNewAddressAndReleaseOldValueIfItsOnOffHeap() {
    // mock region entry
    OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);

    OffHeapStoredObject oldValue = createChunk(Long.MAX_VALUE);
    OffHeapStoredObject newValue = createChunk(Long.MAX_VALUE - 1);

    // mock Chunk static methods - in-order to verify that release is called
    PowerMockito.spy(OffHeapStoredObject.class);
    PowerMockito.doNothing().when(OffHeapStoredObject.class);
    OffHeapStoredObject.release(oldValue.getAddress());

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldValue.getAddress());
    when(re.setAddress(oldValue.getAddress(), newValue.getAddress())).thenReturn(Boolean.TRUE);

    // invoke the method under test
    OffHeapRegionEntryHelper.setValue(re, newValue);

    // verify oldAddress is changed to newAddress
    verify(re, times(1)).setAddress(oldValue.getAddress(), newValue.getAddress());

    // verify oldAddress is released
    PowerMockito.verifyStatic(OffHeapStoredObject.class);
    OffHeapStoredObject.release(oldValue.getAddress());
  }

  @Test
  public void setValueShouldChangeTheRegionEntryAddressToNewAddressAndDoesNothingIfOldAddressIsAnEncodedAddress() {
    // mock region entry
    OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);

    byte[] oldData =
        ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt((Integer) Integer.MAX_VALUE).array();
    long oldAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(oldData, false, false);

    byte[] newData = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE)
        .putInt((Integer) Integer.MAX_VALUE - 1).array();
    TinyStoredObject newAddress =
        new TinyStoredObject(OffHeapRegionEntryHelper.encodeDataAsAddress(newData, false, false));

    // mock Chunk static methods - in-order to verify that release is never called
    PowerMockito.spy(OffHeapStoredObject.class);
    PowerMockito.doNothing().when(OffHeapStoredObject.class);
    OffHeapStoredObject.release(oldAddress);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, newAddress.getAddress())).thenReturn(Boolean.TRUE);

    // invoke the method under test
    OffHeapRegionEntryHelper.setValue(re, newAddress);

    // verify oldAddress is changed to newAddress
    verify(re, times(1)).setAddress(oldAddress, newAddress.getAddress());

    // verify that release is never called as the old address is not on offheap
    PowerMockito.verifyStatic(OffHeapStoredObject.class, never());
    OffHeapStoredObject.release(oldAddress);
  }

  @Test
  public void setValueShouldChangeTheRegionEntryAddressToNewAddressAndDoesNothingIfOldAddressIsATokenAddress() {
    // mock region entry
    OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);

    long oldAddress = OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS;

    Token newValue = Token.REMOVED_PHASE2;
    long newAddress = OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS;

    // mock Chunk static methods - in-order to verify that release is never called
    PowerMockito.spy(OffHeapStoredObject.class);
    PowerMockito.doNothing().when(OffHeapStoredObject.class);
    OffHeapStoredObject.release(oldAddress);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(oldAddress);
    when(re.setAddress(oldAddress, newAddress)).thenReturn(Boolean.TRUE);

    // invoke the method under test
    OffHeapRegionEntryHelper.setValue(re, newValue);

    // verify oldAddress is changed to newAddress
    verify(re, times(1)).setAddress(oldAddress, newAddress);

    // verify that release is never called as the old address is not on offheap
    PowerMockito.verifyStatic(OffHeapStoredObject.class, never());
    OffHeapStoredObject.release(oldAddress);
  }

  @Test(expected = IllegalStateException.class)
  public void setValueShouldThrowIllegalExceptionIfNewValueCannotBeConvertedToAddress() {
    // mock region entry
    OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(1L);

    // invoke the method under test with some object other than Chunk/DataAsAddress/Token
    OffHeapRegionEntryHelper.setValue(re, new Object());
  }

  @Test
  public void getValueAsTokenShouldReturnNotATokenIfValueIsOnOffHeap() {
    // mock region entry
    OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);

    OffHeapStoredObject chunk = createChunk(Long.MAX_VALUE);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(chunk.getAddress());
    Token token = OffHeapRegionEntryHelper.getValueAsToken(re);

    assertThat(token).isEqualTo(Token.NOT_A_TOKEN);
  }

  @Test
  public void getValueAsTokenShouldReturnNotATokenIfValueIsEncoded() {
    // mock region entry
    OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);

    byte[] data = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE).array();
    long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, false, false);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(address);
    Token token = OffHeapRegionEntryHelper.getValueAsToken(re);

    assertThat(token).isEqualTo(Token.NOT_A_TOKEN);
  }

  @Test
  public void getValueAsTokenShouldReturnAValidToken() {
    // mock region entry
    OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.NULL_ADDRESS);
    Token token = OffHeapRegionEntryHelper.getValueAsToken(re);

    assertThat(token).isNull();

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.INVALID_ADDRESS);
    token = OffHeapRegionEntryHelper.getValueAsToken(re);

    assertThat(token).isEqualTo(Token.INVALID);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.LOCAL_INVALID_ADDRESS);
    token = OffHeapRegionEntryHelper.getValueAsToken(re);

    assertThat(token).isEqualTo(Token.LOCAL_INVALID);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.DESTROYED_ADDRESS);
    token = OffHeapRegionEntryHelper.getValueAsToken(re);

    assertThat(token).isEqualTo(Token.DESTROYED);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS);
    token = OffHeapRegionEntryHelper.getValueAsToken(re);

    assertThat(token).isEqualTo(Token.REMOVED_PHASE1);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS);
    token = OffHeapRegionEntryHelper.getValueAsToken(re);

    assertThat(token).isEqualTo(Token.REMOVED_PHASE2);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.END_OF_STREAM_ADDRESS);
    token = OffHeapRegionEntryHelper.getValueAsToken(re);

    assertThat(token).isEqualTo(Token.END_OF_STREAM);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.NOT_AVAILABLE_ADDRESS);
    token = OffHeapRegionEntryHelper.getValueAsToken(re);

    assertThat(token).isEqualTo(Token.NOT_AVAILABLE);

    // mock region entry methods required for test
    when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.TOMBSTONE_ADDRESS);
    token = OffHeapRegionEntryHelper.getValueAsToken(re);

    assertThat(token).isEqualTo(Token.TOMBSTONE);
  }

  @Test
  public void addressToObjectShouldReturnValueFromChunk() {
    OffHeapStoredObject expected = createChunk(Long.MAX_VALUE);
    Object actual = OffHeapRegionEntryHelper.addressToObject(expected.getAddress(), false, null);

    assertThat(actual).isInstanceOf(OffHeapStoredObject.class);
    assertThat(actual).isEqualTo(expected);
  }

  @Test
  public void addressToObjectShouldReturnCachedDeserializableFromChunkIfAskedToDecompress() {
    byte[] data = EntryEventImpl.serialize(Long.MAX_VALUE);
    boolean isSerialized = true;
    boolean isCompressed = true;

    OffHeapStoredObject chunk =
        (OffHeapStoredObject) ma.allocateAndInitialize(data, isSerialized, isCompressed);

    // create the mock context
    RegionEntryContext regionContext = mock(RegionEntryContext.class);
    CachePerfStats cacheStats = mock(CachePerfStats.class);
    Compressor compressor = mock(Compressor.class);

    long startTime = 10000L;

    // mock required things
    when(regionContext.getCompressor()).thenReturn(compressor);
    when(compressor.decompress(data)).thenReturn(data);
    when(regionContext.getCachePerfStats()).thenReturn(cacheStats);
    when(cacheStats.startDecompression()).thenReturn(startTime);

    Object actual =
        OffHeapRegionEntryHelper.addressToObject(chunk.getAddress(), true, regionContext);

    assertThat(actual).isInstanceOf(VMCachedDeserializable.class);

    Long actualValue = (Long) ((VMCachedDeserializable) actual).getDeserializedForReading();
    assertThat(actualValue).isEqualTo(Long.MAX_VALUE);
  }

  @Test
  public void addressToObjectShouldReturnDecompressedValueFromChunkIfAskedToDecompress() {
    byte[] data = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(Long.MAX_VALUE).array();
    boolean isSerialized = false;
    boolean isCompressed = true;

    OffHeapStoredObject chunk =
        (OffHeapStoredObject) ma.allocateAndInitialize(data, isSerialized, isCompressed);

    // create the mock context
    RegionEntryContext regionContext = mock(RegionEntryContext.class);
    CachePerfStats cacheStats = mock(CachePerfStats.class);
    Compressor compressor = mock(Compressor.class);

    long startTime = 10000L;

    // mock required things
    when(regionContext.getCompressor()).thenReturn(compressor);
    when(compressor.decompress(data)).thenReturn(data);
    when(regionContext.getCachePerfStats()).thenReturn(cacheStats);
    when(cacheStats.startDecompression()).thenReturn(startTime);

    Object actual =
        OffHeapRegionEntryHelper.addressToObject(chunk.getAddress(), true, regionContext);

    assertThat(actual).isInstanceOf(byte[].class);
    assertThat(actual).isEqualTo(data);
  }

  @Test
  public void addressToObjectShouldReturnValueFromDataAsAddress() {
    byte[] data = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE).array();
    long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, false, false);

    TinyStoredObject expected = new TinyStoredObject(address);
    Object actual = OffHeapRegionEntryHelper.addressToObject(address, false, null);

    assertThat(actual).isInstanceOf(TinyStoredObject.class);
    assertThat(actual).isEqualTo(expected);
  }

  @Test
  public void addressToObjectShouldReturnCachedDeserializableFromSerializedDataAsAddressIfAskedToDecompress() {
    byte[] data = EntryEventImpl.serialize(Integer.MAX_VALUE);
    boolean isSerialized = true;
    boolean isCompressed = true;

    long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, isSerialized, isCompressed);

    // create the mock context
    RegionEntryContext regionContext = mock(RegionEntryContext.class);
    CachePerfStats cacheStats = mock(CachePerfStats.class);
    Compressor compressor = mock(Compressor.class);

    long startTime = 10000L;

    // mock required things
    when(regionContext.getCompressor()).thenReturn(compressor);
    when(compressor.decompress(data)).thenReturn(data);
    when(regionContext.getCachePerfStats()).thenReturn(cacheStats);
    when(cacheStats.startDecompression()).thenReturn(startTime);

    Object actual = OffHeapRegionEntryHelper.addressToObject(address, true, regionContext);

    assertThat(actual).isInstanceOf(VMCachedDeserializable.class);

    Integer actualValue = (Integer) ((VMCachedDeserializable) actual).getDeserializedForReading();
    assertThat(actualValue).isEqualTo(Integer.MAX_VALUE);
  }

  @Test
  public void addressToObjectShouldReturnDecompressedValueFromDataAsAddressIfAskedToDecompress() {
    byte[] data = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE).array();
    boolean isSerialized = false;
    boolean isCompressed = true;

    long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, isSerialized, isCompressed);

    // create the mock context
    RegionEntryContext regionContext = mock(RegionEntryContext.class);
    CachePerfStats cacheStats = mock(CachePerfStats.class);
    Compressor compressor = mock(Compressor.class);

    long startTime = 10000L;

    // mock required things
    when(regionContext.getCompressor()).thenReturn(compressor);
    when(compressor.decompress(data)).thenReturn(data);
    when(regionContext.getCachePerfStats()).thenReturn(cacheStats);
    when(cacheStats.startDecompression()).thenReturn(startTime);

    Object actual = OffHeapRegionEntryHelper.addressToObject(address, true, regionContext);

    assertThat(actual).isInstanceOf(byte[].class);
    assertThat(actual).isEqualTo(data);
  }

  @Test
  public void addressToObjectShouldReturnToken() {
    Token token = (Token) OffHeapRegionEntryHelper
        .addressToObject(OffHeapRegionEntryHelper.NULL_ADDRESS, false, null);
    assertThat(token).isNull();

    token = (Token) OffHeapRegionEntryHelper
        .addressToObject(OffHeapRegionEntryHelper.INVALID_ADDRESS, false, null);
    assertThat(token).isEqualTo(Token.INVALID);

    token = (Token) OffHeapRegionEntryHelper
        .addressToObject(OffHeapRegionEntryHelper.LOCAL_INVALID_ADDRESS, false, null);
    assertThat(token).isEqualTo(Token.LOCAL_INVALID);

    token = (Token) OffHeapRegionEntryHelper
        .addressToObject(OffHeapRegionEntryHelper.DESTROYED_ADDRESS, false, null);
    assertThat(token).isEqualTo(Token.DESTROYED);

    token = (Token) OffHeapRegionEntryHelper
        .addressToObject(OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS, false, null);
    assertThat(token).isEqualTo(Token.REMOVED_PHASE1);

    token = (Token) OffHeapRegionEntryHelper
        .addressToObject(OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS, false, null);
    assertThat(token).isEqualTo(Token.REMOVED_PHASE2);

    token = (Token) OffHeapRegionEntryHelper
        .addressToObject(OffHeapRegionEntryHelper.END_OF_STREAM_ADDRESS, false, null);
    assertThat(token).isEqualTo(Token.END_OF_STREAM);

    token = (Token) OffHeapRegionEntryHelper
        .addressToObject(OffHeapRegionEntryHelper.NOT_AVAILABLE_ADDRESS, false, null);
    assertThat(token).isEqualTo(Token.NOT_AVAILABLE);

    token = (Token) OffHeapRegionEntryHelper
        .addressToObject(OffHeapRegionEntryHelper.TOMBSTONE_ADDRESS, false, null);
    assertThat(token).isEqualTo(Token.TOMBSTONE);
  }

  @Test
  public void getSerializedLengthFromDataAsAddressShouldReturnValidLength() {
    byte[] data = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE).array();
    boolean isSerialized = false;
    boolean isCompressed = true;

    long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, isSerialized, isCompressed);
    TinyStoredObject daa = new TinyStoredObject(address);

    int actualLength = OffHeapRegionEntryHelper.getSerializedLength(daa);

    assertThat(actualLength).isEqualTo(data.length);
  }

  @Test
  public void getSerializedLengthFromDataAsAddressShouldReturnZeroForNonEncodedAddress() {
    TinyStoredObject nonEncodedAddress = new TinyStoredObject(100000L);
    int actualLength = OffHeapRegionEntryHelper.getSerializedLength(nonEncodedAddress);
    assertThat(actualLength).isZero();
  }

  @Test
  public void releaseEntryShouldSetValueToRemovePhase2() {
    // mock region entry
    OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);
    when(re.getAddress()).thenReturn(1L);
    when(re.setAddress(1L, OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS))
        .thenReturn(Boolean.TRUE);

    // mock required methods
    PowerMockito.spy(OffHeapRegionEntryHelper.class);
    PowerMockito.doNothing().when(OffHeapRegionEntryHelper.class);
    OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE2);

    OffHeapRegionEntryHelper.releaseEntry(re);

    PowerMockito.verifyStatic(OffHeapRegionEntryHelper.class);
    OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE2);
  }

  @Test
  public void releaseEntryShouldSetValueToRemovePhase2AndSetsAsyncToFalseForDiskEntry() {
    // mock region entry
    OffHeapRegionEntry re = mock(VersionedStatsDiskRegionEntryOffHeap.class);
    when(re.getAddress()).thenReturn(1L);
    when(re.setAddress(1L, OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS))
        .thenReturn(Boolean.TRUE);

    DiskId spy = Mockito.spy(DiskId.class);
    when(((DiskEntry) re).getDiskId()).thenReturn(spy);
    when(spy.isPendingAsync()).thenReturn(Boolean.TRUE);

    // mock required methods
    PowerMockito.spy(OffHeapRegionEntryHelper.class);
    PowerMockito.doNothing().when(OffHeapRegionEntryHelper.class);
    OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE2);

    OffHeapRegionEntryHelper.releaseEntry(re);

    verify(spy, times(1)).setPendingAsync(Boolean.FALSE);

    PowerMockito.verifyStatic(OffHeapRegionEntryHelper.class);
    OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE2);
  }

  @Test
  public void doWithOffHeapClearShouldSetTheThreadLocalToTrue() {
    // verify that threadlocal is not set
    assertThat(OffHeapRegionEntryHelper.doesClearNeedToCheckForOffHeap()).isFalse();

    OffHeapRegionEntryHelper.doWithOffHeapClear(new Runnable() {
      @Override
      public void run() {
        // verify that threadlocal is set when offheap is cleared
        assertThat(OffHeapRegionEntryHelper.doesClearNeedToCheckForOffHeap()).isTrue();
      }
    });

    // verify that threadlocal is reset after offheap is cleared
    assertThat(OffHeapRegionEntryHelper.doesClearNeedToCheckForOffHeap()).isFalse();
  }
}
