/*
 * 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.apache.geode.internal.offheap.OffHeapRegionEntryHelperInstance.COMPRESSED_BIT;
import static org.apache.geode.internal.offheap.OffHeapRegionEntryHelperInstance.DESTROYED_ADDRESS;
import static org.apache.geode.internal.offheap.OffHeapRegionEntryHelperInstance.END_OF_STREAM_ADDRESS;
import static org.apache.geode.internal.offheap.OffHeapRegionEntryHelperInstance.INVALID_ADDRESS;
import static org.apache.geode.internal.offheap.OffHeapRegionEntryHelperInstance.LOCAL_INVALID_ADDRESS;
import static org.apache.geode.internal.offheap.OffHeapRegionEntryHelperInstance.NOT_AVAILABLE_ADDRESS;
import static org.apache.geode.internal.offheap.OffHeapRegionEntryHelperInstance.NULL_ADDRESS;
import static org.apache.geode.internal.offheap.OffHeapRegionEntryHelperInstance.REMOVED_PHASE1_ADDRESS;
import static org.apache.geode.internal.offheap.OffHeapRegionEntryHelperInstance.REMOVED_PHASE2_ADDRESS;
import static org.apache.geode.internal.offheap.OffHeapRegionEntryHelperInstance.SERIALIZED_BIT;
import static org.apache.geode.internal.offheap.OffHeapRegionEntryHelperInstance.TOMBSTONE_ADDRESS;
import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;

import java.nio.ByteBuffer;
import java.util.function.Function;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import org.apache.geode.compression.Compressor;
import org.apache.geode.internal.cache.CachePerfStats;
import org.apache.geode.internal.cache.CachedDeserializable;
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.offheap.MemoryAllocatorImpl.DummyNonRealTimeStatsUpdater;
import org.apache.geode.internal.serialization.DSCODE;

public class OffHeapRegionEntryHelperInstanceTest {

  private static final long VALUE_IS_NOT_ENCODABLE = 0L;

  private MemoryAllocator memoryAllocator;
  private ReferenceCounterInstance referenceCounter;
  private OffHeapStoredObject offHeapStoredObject;

  private OffHeapRegionEntryHelperInstance offHeapRegionEntryHelperInstance;

  @Before
  public void setUp() {
    OutOfOffHeapMemoryListener listener = mock(OutOfOffHeapMemoryListener.class);
    OffHeapMemoryStats stats = mock(OffHeapMemoryStats.class);
    Function<Long, OffHeapStoredObject> offHeapStoredObjectFactory =
        uncheckedCast(mock(Function.class));
    offHeapStoredObject = mock(OffHeapStoredObject.class);
    referenceCounter = mock(ReferenceCounterInstance.class);

    when(offHeapStoredObjectFactory.apply(anyLong()))
        .thenReturn(offHeapStoredObject);

    memoryAllocator =
        MemoryAllocatorImpl.create(listener, stats, 1, OffHeapStorage.MIN_SLAB_SIZE,
            OffHeapStorage.MIN_SLAB_SIZE, null, () -> new DummyNonRealTimeStatsUpdater());

    offHeapRegionEntryHelperInstance =
        spy(new OffHeapRegionEntryHelperInstance(ohAddress -> offHeapStoredObject,
            referenceCounter));
  }

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

  @Test
  public void encodeDataAsAddressShouldReturnZeroIfValueIsGreaterThanSevenBytes() {
    byte[] valueInBytes =
        ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(Long.MAX_VALUE).array();

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

    long encodedAddress =
        offHeapRegionEntryHelperInstance.encodeDataAsAddress(valueInBytes, false, false);

    assertThat(encodedAddress)
        .isEqualTo(VALUE_IS_NOT_ENCODABLE);
  }

  @Test
  public void encodeDataAsAddressShouldEncodeLongIfItsSerializedAndIfItsNotTooBig() {
    byte[] valueInBytes = EntryEventImpl.serialize(0L);
    boolean isSerialized = true;
    boolean isCompressed = false;

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

    long expectedEncodedAddress = 123L;
    assertThat(encodedAddress)
        .isEqualTo(expectedEncodedAddress);

    assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
  }

  @Test
  public void encodeDataAsAddressShouldReturnZeroIfValueIsLongAndItIsSerializedAndBig() {
    byte[] valueInBytes = EntryEventImpl.serialize(Long.MAX_VALUE);

    long encodedAddress =
        offHeapRegionEntryHelperInstance.encodeDataAsAddress(valueInBytes, true,
            false);

    assertThat(encodedAddress)
        .isEqualTo(VALUE_IS_NOT_ENCODABLE);
  }

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

    long encodedAddress =
        offHeapRegionEntryHelperInstance.encodeDataAsAddress(someValue, true, false);

    assertThat(encodedAddress)
        .isEqualTo(VALUE_IS_NOT_ENCODABLE);
  }

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

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

    long expectedAddress = 549755813697L;
    assertThat(encodedAddress)
        .isEqualTo(expectedAddress);

    assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
  }

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

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

    long expectedAddress = 63221918596947L;
    assertThat(expectedAddress)
        .isEqualTo(encodedAddress);

    assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
  }

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

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

    long expectedAddress = 549755813701L;
    assertThat(encodedAddress)
        .isEqualTo(expectedAddress);

    assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
  }

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

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

    long expectedAddress = 63221918596951L;
    assertThat(expectedAddress)
        .isEqualTo(encodedAddress);

    assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
  }

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

    byte[] actual =
        offHeapRegionEntryHelperInstance.decodeUncompressedAddressToBytes(encodedAddress);

    byte[] expectedValue = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(value).array();
    assertThat(actual)
        .isEqualTo(expectedValue);
  }

  @Test
  public void decodeUncompressedAddressToBytesShouldDecodeLongIfItsSerializedAndIfItsNotTooBig() {
    byte[] actual = offHeapRegionEntryHelperInstance.decodeUncompressedAddressToBytes(123L);

    byte[] expectedValue = EntryEventImpl.serialize(0L);
    assertThat(actual)
        .isEqualTo(expectedValue);
  }

  @Test
  public void decodeUncompressedAddressToBytesWithCompressedAddressShouldThrowException() {
    long encodedAddress = 549755813703L;

    Throwable thrown = catchThrowable(() -> {
      offHeapRegionEntryHelperInstance.decodeUncompressedAddressToBytes(encodedAddress);
    });

    assertThat(thrown)
        .isInstanceOf(AssertionError.class);
  }

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

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

    assertThat(bytes)
        .isEqualTo(expected);
  }

  @Test
  public void encodedAddressShouldBeDecodableEvenIfValueIsSerialized() {
    int value = Integer.MAX_VALUE;
    byte[] serializedValue = EntryEventImpl.serialize(value);

    long encodedAddress =
        offHeapRegionEntryHelperInstance.encodeDataAsAddress(serializedValue, true, false);

    int actualValue =
        (int) offHeapRegionEntryHelperInstance.decodeAddressToObject(encodedAddress);

    assertThat(actualValue)
        .isEqualTo(value);
  }

  @Test
  public void encodedAddressShouldBeDecodableEvenIfValueIsUnserialized() {
    int value = Integer.MAX_VALUE;
    byte[] unSerializedValue = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(value).array();
    long encodedAddress =
        offHeapRegionEntryHelperInstance.encodeDataAsAddress(unSerializedValue, false, false);

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

    assertThat(actualValue)
        .isEqualTo(unSerializedValue);
  }

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

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

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

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

  @Test
  public void isOffHeapShouldReturnTrueIfAddressIsOnOffHeap() {
    OffHeapStoredObject value = createChunk(Long.MAX_VALUE);

    assertThat(offHeapRegionEntryHelperInstance.isOffHeap(value.getAddress())).isTrue();
  }

  @Test
  public void isOffHeapShouldReturnFalseIfAddressIsAnEncodedAddress() {
    byte[] data = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE).array();

    long address = offHeapRegionEntryHelperInstance.encodeDataAsAddress(data, false, false);

    assertThat(offHeapRegionEntryHelperInstance.isOffHeap(address)).isFalse();
  }

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

  @Test
  public void setValueShouldChangeTheRegionEntryAddressToNewAddress() {
    // mock region entry
    OffHeapRegionEntry regionEntry = 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(regionEntry.getAddress()).thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, newValue.getAddress())).thenReturn(Boolean.TRUE);

    // invoke the method under test
    offHeapRegionEntryHelperInstance.setValue(regionEntry, newValue);

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

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

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

    // Testing when newValue is Token Objects

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, NULL_ADDRESS)).thenReturn(true);
    offHeapRegionEntryHelperInstance.setValue(regionEntry, null);

    // verify oldAddress is replaced with newAddress
    verify(regionEntry).setAddress(oldAddress, NULL_ADDRESS);
    reset(regionEntry);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, INVALID_ADDRESS)).thenReturn(true);
    offHeapRegionEntryHelperInstance.setValue(regionEntry, Token.INVALID);

    // verify oldAddress is replaced with newAddress
    verify(regionEntry).setAddress(oldAddress, INVALID_ADDRESS);
    reset(regionEntry);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, LOCAL_INVALID_ADDRESS)).thenReturn(true);
    offHeapRegionEntryHelperInstance.setValue(regionEntry, Token.LOCAL_INVALID);

    // verify oldAddress is replaced with newAddress
    verify(regionEntry).setAddress(oldAddress, LOCAL_INVALID_ADDRESS);
    reset(regionEntry);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, DESTROYED_ADDRESS)).thenReturn(true);
    offHeapRegionEntryHelperInstance.setValue(regionEntry, Token.DESTROYED);

    // verify oldAddress is replaced with newAddress
    verify(regionEntry).setAddress(oldAddress, DESTROYED_ADDRESS);
    reset(regionEntry);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, REMOVED_PHASE1_ADDRESS)).thenReturn(true);
    offHeapRegionEntryHelperInstance.setValue(regionEntry, Token.REMOVED_PHASE1);

    // verify oldAddress is replaced with newAddress
    verify(regionEntry).setAddress(oldAddress, REMOVED_PHASE1_ADDRESS);
    reset(regionEntry);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, REMOVED_PHASE2_ADDRESS)).thenReturn(true);
    offHeapRegionEntryHelperInstance.setValue(regionEntry, Token.REMOVED_PHASE2);

    // verify oldAddress is replaced with newAddress
    verify(regionEntry).setAddress(oldAddress, REMOVED_PHASE2_ADDRESS);
    reset(regionEntry);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, END_OF_STREAM_ADDRESS)).thenReturn(true);
    offHeapRegionEntryHelperInstance.setValue(regionEntry, Token.END_OF_STREAM);

    // verify oldAddress is replaced with newAddress
    verify(regionEntry).setAddress(oldAddress, END_OF_STREAM_ADDRESS);
    reset(regionEntry);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, NOT_AVAILABLE_ADDRESS)).thenReturn(true);
    offHeapRegionEntryHelperInstance.setValue(regionEntry, Token.NOT_AVAILABLE);

    // verify oldAddress is replaced with newAddress
    verify(regionEntry).setAddress(oldAddress, NOT_AVAILABLE_ADDRESS);
    reset(regionEntry);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, TOMBSTONE_ADDRESS)).thenReturn(true);
    offHeapRegionEntryHelperInstance.setValue(regionEntry, Token.TOMBSTONE);

    // verify oldAddress is replaced with newAddress
    verify(regionEntry).setAddress(oldAddress, TOMBSTONE_ADDRESS);
  }

  @Test
  public void setValueShouldChangeTheRegionEntryAddressToNewAddressAndReleaseOldValueIfItsOnOffHeap() {
    OffHeapStoredObject oldValue = createChunk(Long.MAX_VALUE);
    OffHeapStoredObject newValue = createChunk(Long.MAX_VALUE - 1);
    OffHeapRegionEntry regionEntry = mock(OffHeapRegionEntry.class);

    // mock Chunk static methods - in-order to verify that release is called
    doNothing().when(offHeapStoredObject).release();

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

    // invoke the method under test
    offHeapRegionEntryHelperInstance.setValue(regionEntry, newValue);

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

    // verify oldAddress is released
    verify(referenceCounter)
        .release(oldValue.getAddress());
  }

  @Test
  public void setValueShouldChangeTheRegionEntryAddressToNewAddressAndDoesNothingIfOldAddressIsAnEncodedAddress() {
    byte[] oldData =
        ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE).array();
    byte[] newData =
        ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE - 1).array();
    long oldAddress = offHeapRegionEntryHelperInstance.encodeDataAsAddress(oldData, false, false);
    StoredObject newAddress = new TinyStoredObject(
        offHeapRegionEntryHelperInstance.encodeDataAsAddress(newData, false, false));
    OffHeapRegionEntry regionEntry = mock(OffHeapRegionEntry.class);

    // mock region entry methods required for test
    when(regionEntry.getAddress())
        .thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, newAddress.getAddress()))
        .thenReturn(true);

    // invoke the method under test
    offHeapRegionEntryHelperInstance.setValue(regionEntry, newAddress);

    // verify oldAddress is changed to newAddress
    verify(regionEntry)
        .setAddress(oldAddress, newAddress.getAddress());

    // verify that release is never called as the old address is not on offheap
    verifyNoInteractions(offHeapStoredObject);
  }

  @Test
  public void setValueShouldChangeTheRegionEntryAddressToNewAddressAndDoesNothingIfOldAddressIsATokenAddress() {
    long oldAddress = REMOVED_PHASE1_ADDRESS;
    long newAddress = REMOVED_PHASE2_ADDRESS;
    OffHeapRegionEntry regionEntry = mock(OffHeapRegionEntry.class);

    when(regionEntry.getAddress())
        .thenReturn(oldAddress);
    when(regionEntry.setAddress(oldAddress, newAddress))
        .thenReturn(true);

    // invoke the method under test
    offHeapRegionEntryHelperInstance.setValue(regionEntry, Token.REMOVED_PHASE2);

    // verify oldAddress is changed to newAddress
    verify(regionEntry)
        .setAddress(oldAddress, newAddress);
  }

  @Test
  public void setValueShouldThrowIllegalExceptionIfNewValueCannotBeConvertedToAddress() {
    OffHeapRegionEntry regionEntry = mock(OffHeapRegionEntry.class);

    when(regionEntry.getAddress())
        .thenReturn(1L);

    // invoke the method under test with some object other than Chunk/DataAsAddress/Token
    Throwable thrown = catchThrowable(() -> {
      offHeapRegionEntryHelperInstance.setValue(regionEntry, new Object());
    });

    assertThat(thrown)
        .isInstanceOf(IllegalStateException.class);
  }

  @Test
  public void getValueAsTokenShouldReturnNotATokenIfValueIsOnOffHeap() {
    OffHeapStoredObject chunk = createChunk(Long.MAX_VALUE);
    OffHeapRegionEntry regionEntry = mock(OffHeapRegionEntry.class);

    when(regionEntry.getAddress())
        .thenReturn(chunk.getAddress());

    Token token = offHeapRegionEntryHelperInstance.getValueAsToken(regionEntry);

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

  @Test
  public void getValueAsTokenShouldReturnNotATokenIfValueIsEncoded() {
    byte[] data = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE).array();
    long address = offHeapRegionEntryHelperInstance.encodeDataAsAddress(data, false, false);
    OffHeapRegionEntry regionEntry = mock(OffHeapRegionEntry.class);

    when(regionEntry.getAddress())
        .thenReturn(address);

    Token token = offHeapRegionEntryHelperInstance.getValueAsToken(regionEntry);

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

  @Test
  public void getValueAsTokenShouldReturnAValidToken() {
    OffHeapRegionEntry regionEntry = mock(OffHeapRegionEntry.class);

    when(regionEntry.getAddress()).thenReturn(NULL_ADDRESS);
    Token token = offHeapRegionEntryHelperInstance.getValueAsToken(regionEntry);
    assertThat(token).isNull();

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(INVALID_ADDRESS);
    token = offHeapRegionEntryHelperInstance.getValueAsToken(regionEntry);
    assertThat(token).isEqualTo(Token.INVALID);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(LOCAL_INVALID_ADDRESS);
    token = offHeapRegionEntryHelperInstance.getValueAsToken(regionEntry);
    assertThat(token).isEqualTo(Token.LOCAL_INVALID);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(DESTROYED_ADDRESS);
    token = offHeapRegionEntryHelperInstance.getValueAsToken(regionEntry);
    assertThat(token).isEqualTo(Token.DESTROYED);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(REMOVED_PHASE1_ADDRESS);
    token = offHeapRegionEntryHelperInstance.getValueAsToken(regionEntry);
    assertThat(token).isEqualTo(Token.REMOVED_PHASE1);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(REMOVED_PHASE2_ADDRESS);
    token = offHeapRegionEntryHelperInstance.getValueAsToken(regionEntry);
    assertThat(token).isEqualTo(Token.REMOVED_PHASE2);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(END_OF_STREAM_ADDRESS);
    token = offHeapRegionEntryHelperInstance.getValueAsToken(regionEntry);
    assertThat(token).isEqualTo(Token.END_OF_STREAM);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(NOT_AVAILABLE_ADDRESS);
    token = offHeapRegionEntryHelperInstance.getValueAsToken(regionEntry);
    assertThat(token).isEqualTo(Token.NOT_AVAILABLE);

    // mock region entry methods required for test
    when(regionEntry.getAddress()).thenReturn(TOMBSTONE_ADDRESS);
    token = offHeapRegionEntryHelperInstance.getValueAsToken(regionEntry);
    assertThat(token).isEqualTo(Token.TOMBSTONE);
  }

  @Test
  public void addressToObjectShouldReturnValueFromChunk() {
    OffHeapRegionEntryHelperInstance offHeapRegionEntryHelperInstance =
        new OffHeapRegionEntryHelperInstance();
    OffHeapStoredObject expected = createChunk(Long.MAX_VALUE);

    Object actual =
        offHeapRegionEntryHelperInstance.addressToObject(expected.getAddress(), false, null);

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

  @Test
  public void addressToObjectShouldReturnCachedDeserializableFromChunkIfAskedToDecompress() {
    byte[] data = EntryEventImpl.serialize(Long.MAX_VALUE);
    RegionEntryContext regionContext = mock(RegionEntryContext.class);
    CachePerfStats cacheStats = mock(CachePerfStats.class);
    Compressor compressor = mock(Compressor.class);

    when(regionContext.getCompressor())
        .thenReturn(compressor);
    when(compressor.decompress(data))
        .thenReturn(data);
    when(regionContext.getCachePerfStats())
        .thenReturn(cacheStats);
    when(cacheStats.startDecompression())
        .thenReturn(10000L);

    MemoryBlock chunk =
        (MemoryBlock) memoryAllocator.allocateAndInitialize(data, true, true);
    offHeapRegionEntryHelperInstance =
        spy(new OffHeapRegionEntryHelperInstance(OffHeapStoredObject::new, referenceCounter));

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

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

    long actualValue = (long) ((CachedDeserializable) 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();
    RegionEntryContext regionContext = mock(RegionEntryContext.class);
    CachePerfStats cacheStats = mock(CachePerfStats.class);
    Compressor compressor = mock(Compressor.class);

    when(regionContext.getCompressor())
        .thenReturn(compressor);
    when(compressor.decompress(data))
        .thenReturn(data);
    when(regionContext.getCachePerfStats())
        .thenReturn(cacheStats);
    when(cacheStats.startDecompression())
        .thenReturn(10000L);

    MemoryBlock chunk = (MemoryBlock) memoryAllocator.allocateAndInitialize(data, false, true);
    offHeapRegionEntryHelperInstance =
        spy(new OffHeapRegionEntryHelperInstance(OffHeapStoredObject::new, referenceCounter));

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

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

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

    Object actual = offHeapRegionEntryHelperInstance.addressToObject(address, false, null);

    TinyStoredObject expected = new TinyStoredObject(address);

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

  @Test
  public void addressToObjectShouldReturnCachedDeserializableFromSerializedDataAsAddressIfAskedToDecompress() {
    byte[] data = EntryEventImpl.serialize(Integer.MAX_VALUE);
    RegionEntryContext regionContext = mock(RegionEntryContext.class);
    CachePerfStats cacheStats = mock(CachePerfStats.class);
    Compressor compressor = mock(Compressor.class);

    when(regionContext.getCompressor())
        .thenReturn(compressor);
    when(compressor.decompress(data))
        .thenReturn(data);
    when(regionContext.getCachePerfStats())
        .thenReturn(cacheStats);
    when(cacheStats.startDecompression())
        .thenReturn(10000L);

    long address =
        offHeapRegionEntryHelperInstance.encodeDataAsAddress(data, true, true);

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

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

    int actualValue = (int) ((CachedDeserializable) 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();
    RegionEntryContext regionContext = mock(RegionEntryContext.class);
    CachePerfStats cacheStats = mock(CachePerfStats.class);
    Compressor compressor = mock(Compressor.class);

    when(regionContext.getCompressor())
        .thenReturn(compressor);
    when(compressor.decompress(data))
        .thenReturn(data);
    when(regionContext.getCachePerfStats())
        .thenReturn(cacheStats);
    when(cacheStats.startDecompression())
        .thenReturn(10000L);

    long address =
        offHeapRegionEntryHelperInstance.encodeDataAsAddress(data, false, true);

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

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

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

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

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

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

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

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

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

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

    token = (Token) offHeapRegionEntryHelperInstance
        .addressToObject(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();
    long address =
        offHeapRegionEntryHelperInstance.encodeDataAsAddress(data, false, true);
    TinyStoredObject tinyStoredObject = new TinyStoredObject(address);

    int actualLength = offHeapRegionEntryHelperInstance.getSerializedLength(tinyStoredObject);

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

  @Test
  public void getSerializedLengthFromDataAsAddressShouldReturnZeroForNonEncodedAddress() {
    TinyStoredObject nonEncodedAddress = new TinyStoredObject(100000L);

    int actualLength = offHeapRegionEntryHelperInstance.getSerializedLength(nonEncodedAddress);

    assertThat(actualLength)
        .isZero();
  }

  @Test
  public void releaseEntryShouldSetValueToRemovePhase2() {
    OffHeapRegionEntry regionEntry = mock(OffHeapRegionEntry.class);

    when(regionEntry.getAddress())
        .thenReturn(1L);
    when(regionEntry.setAddress(1L, REMOVED_PHASE2_ADDRESS))
        .thenReturn(Boolean.TRUE);

    offHeapRegionEntryHelperInstance.releaseEntry(regionEntry);

    verify(offHeapRegionEntryHelperInstance)
        .setValue(regionEntry, Token.REMOVED_PHASE2);
  }

  @Test
  public void releaseEntryShouldSetValueToRemovePhase2AndSetsAsyncToFalseForDiskEntry() {
    OffHeapRegionEntry regionEntry = mock(VersionedStatsDiskRegionEntryOffHeap.class);
    DiskId diskId = spy(DiskId.class);

    when(regionEntry.getAddress())
        .thenReturn(1L);
    when(regionEntry.setAddress(1L, REMOVED_PHASE2_ADDRESS))
        .thenReturn(Boolean.TRUE);
    when(((DiskEntry) regionEntry).getDiskId())
        .thenReturn(diskId);
    when(diskId.isPendingAsync())
        .thenReturn(Boolean.TRUE);

    offHeapRegionEntryHelperInstance.releaseEntry(regionEntry);

    verify(offHeapRegionEntryHelperInstance)
        .setValue(regionEntry, Token.REMOVED_PHASE2);
    verify(diskId)
        .setPendingAsync(Boolean.FALSE);
  }

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

    OffHeapClearRequired.doWithOffHeapClear(() -> {
      // verify that threadlocal is set when offheap is cleared
      assertThat(OffHeapClearRequired.doesClearNeedToCheckForOffHeap()).isTrue();
    });

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

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

    StoredObject chunk = memoryAllocator.allocateAndInitialize(bytes, true, false);

    return (OffHeapStoredObject) chunk;
  }

  private static void assertSerializedAndCompressedBits(long encodedAddress,
      boolean shouldSerializedBitBeSet, boolean shouldCompressedBitBeSet) {
    boolean isSerializedBitSet = (encodedAddress & SERIALIZED_BIT) == SERIALIZED_BIT;

    assertThat(isSerializedBitSet)
        .isEqualTo(shouldSerializedBitBeSet);

    boolean isCompressedBitSet = (encodedAddress & COMPRESSED_BIT) == COMPRESSED_BIT;

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