package net.yadan.banana.memory.malloc;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import java.util.Arrays;
import java.util.Collection;
import net.yadan.banana.memory.IMemAllocator;
import net.yadan.banana.memory.OutOfMemoryException;
import net.yadan.banana.memory.initializers.MemSetInitializer;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(value = Parameterized.class)
public abstract class AbstractMemAllocatorTest {
protected IMemAllocator m;
protected int m_allocationSize;
public AbstractMemAllocatorTest(int numBlocks, int blockSize, int allocationSize) {
m_allocationSize = allocationSize;
init(numBlocks, blockSize);
}
public abstract void init(int numBlocks, int blockSize);
@Parameters
public static Collection<Object[]> data() {
//@formatter:off
Object[][] data = new Object[][] {
{ 100, 5, 5}, // normal non indexed block
{ 100, 5, 10},// single index block
{ 100, 5, 20},// single index block, full utilization
{ 200, 3, 7},
{ 200, 3, 14},
{ 200, 3, 60},
{ 50, 3, 9},
};
return Arrays.asList(data);
}
//@formatter:on
@After
public void postTest() {
if (m != null) {
assertEquals("Test leaks memory", 0, m.usedBlocks());
}
m = null;
}
@Test
public void testUpperShort() {
int p = m.malloc(m_allocationSize);
int offset = 0;
m.setInt(p, offset, 0);
assertEquals(0, m.getLowerShort(p, offset));
assertEquals(0, m.getUpperShort(p, offset));
m.setUpperShort(p, offset, 99);
assertEquals(0, m.getLowerShort(p, offset));
assertEquals(99, m.getUpperShort(p, offset));
offset = m_allocationSize / 2;
m.setInt(p, offset, 0);
assertEquals(0, m.getLowerShort(p, offset));
assertEquals(0, m.getUpperShort(p, offset));
m.setUpperShort(p, offset, 99);
assertEquals(0, m.getLowerShort(p, offset));
assertEquals(99, m.getUpperShort(p, offset));
m.free(p);
}
@Test
public void testLowerShort() {
int p = m.malloc(m_allocationSize);
int offset = 0;
m.setInt(p, offset, 0);
assertEquals(0, m.getLowerShort(p, offset));
assertEquals(0, m.getUpperShort(p, offset));
m.setLowerShort(p, offset, 99);
assertEquals(99, m.getLowerShort(p, offset));
assertEquals(0, m.getUpperShort(p, offset));
offset = m_allocationSize / 2;
m.setInt(p, offset, 0);
assertEquals(0, m.getLowerShort(p, offset));
assertEquals(0, m.getUpperShort(p, offset));
m.setLowerShort(p, offset, 99);
assertEquals(99, m.getLowerShort(p, offset));
assertEquals(0, m.getUpperShort(p, offset));
m.free(p);
}
@Test
public void tesIntAccess() {
int pointer = m.malloc(m_allocationSize);
for (int i = 0; i < m_allocationSize; i++) {
m.setInt(pointer, i, i);
}
for (int i = 0; i < m_allocationSize; i++) {
assertEquals(i, m.getInt(pointer, i));
}
m.free(pointer);
}
@Test
public void tesFloatAccess() {
int pointer = m.malloc(m_allocationSize);
for (int i = 0; i < m_allocationSize; i++) {
m.setFloat(pointer, i, i * 2f);
}
for (int i = 0; i < m_allocationSize; i++) {
assertEquals(i * 2f, m.getFloat(pointer, i), Float.MIN_VALUE);
}
m.free(pointer);
}
@Test
public void tesDoubleAccess() {
int pointer = m.malloc(m_allocationSize);
for (int i = 0; i < m_allocationSize / 2; i++) {
m.setDouble(pointer, i * 2, i * 3f);
}
for (int i = 0; i < m_allocationSize / 2; i++) {
assertEquals(i * 3f, m.getDouble(pointer, i * 2), Float.MIN_VALUE);
}
m.free(pointer);
}
@Test
public void testLong() {
int p = m.malloc(10);
m.setLong(p, 0, 0x00000000ffffffffL);
assertEquals(0x00000000ffffffffL, m.getLong(p, 0));
m.free(p);
}
@Test
public void testLongOnBlockBoundary() {
int p = m.malloc(10);
m.setLong(p, 5, Long.MAX_VALUE);
assertEquals(Long.MAX_VALUE, m.getLong(p, 5));
m.free(p);
}
@Test
public void testSetIntsFullBlocks() {
int p = m.malloc(m_allocationSize);
int buf[] = new int[m_allocationSize];
for (int i = 0; i < m_allocationSize; i++) {
buf[i] = i;
}
// set ints using setInts
m.setInts(p, 0, buf, 0, m_allocationSize);
// verify ints are correct using getInt
for (int i = 0; i < m_allocationSize; i++) {
assertEquals(i, m.getInt(p, i));
}
m.free(p);
}
@Test
public void testGetIntsFullBlocks() {
int p = m.malloc(m_allocationSize);
int buf[] = new int[m_allocationSize];
for (int i = 0; i < m_allocationSize; i++) {
buf[i] = i;
}
for (int i = 0; i < buf.length; i++) {
m.setInt(p, i, buf[i]);
}
int buf2[] = new int[m_allocationSize];
m.getInts(p, 0, buf2, 0, m_allocationSize);
assertArrayEquals(buf, buf2);
m.free(p);
}
@Test
public void testSetIntsPartialFirstBlock() {
int p = m.malloc(m_allocationSize);
int buf[] = new int[m_allocationSize - 1];
for (int i = 0; i < buf.length; i++) {
buf[i] = i;
}
m.setInt(p, 0, -100);
m.setInts(p, 1, buf, 0, buf.length);
// verify ints are correct using getInt
assertEquals(-100, m.getInt(p, 0));
for (int i = 0; i < buf.length; i++) {
assertEquals(buf[i], m.getInt(p, i + 1));
}
m.free(p);
}
@Test
public void testGetIntsPartialFirstBlock() {
int p = m.malloc(m_allocationSize);
int buf[] = new int[m_allocationSize - 1];
for (int i = 0; i < m_allocationSize - 1; i++) {
buf[i] = i;
}
m.setInt(p, 0, -100);
for (int i = 0; i < buf.length; i++) {
m.setInt(p, i + 1, buf[i]);
}
int buf2[] = new int[buf.length];
m.getInts(p, 1, buf2, 0, buf.length);
assertArrayEquals(buf, buf2);
m.free(p);
}
@Test
public void testSetIntsPartialFirstBlockDeep() {
int p = m.malloc(m_allocationSize);
int dst_offset = m.blockSize() + 1;
if (dst_offset > m_allocationSize) {
dst_offset = m_allocationSize / 2;
}
int buf[] = new int[m_allocationSize - dst_offset];
for (int i = 0; i < buf.length; i++) {
buf[i] = i;
}
for (int i = 0; i < dst_offset; i++) {
m.setInt(p, i, 100 + i);
}
m.setInts(p, dst_offset, buf, 0, buf.length);
// verify ints are correct using getInt
for (int i = 0; i < dst_offset; i++) {
assertEquals(100 + i, m.getInt(p, i));
}
for (int i = 0; i < buf.length; i++) {
assertEquals(buf[i], m.getInt(p, i + dst_offset));
}
m.free(p);
}
@Test
public void testGetIntsPartialFirstBlockDeep() {
int src_offset = m.blockSize() + 1;
if (src_offset > m_allocationSize) {
src_offset = m_allocationSize / 2;
}
int p = m.malloc(m_allocationSize);
int buf[] = new int[m_allocationSize - src_offset];
for (int i = 0; i < m_allocationSize - src_offset; i++) {
buf[i] = i;
}
for (int i = 0; i < src_offset; i++) {
m.setInt(p, i, 100 + i);
}
for (int i = 0; i < buf.length; i++) {
m.setInt(p, i + src_offset, buf[i]);
}
int buf2[] = new int[buf.length];
m.getInts(p, src_offset, buf2, 0, buf2.length);
assertArrayEquals(buf, buf2);
m.free(p);
}
@Test
public void testSetIntsPartialLastBlock() {
int p = m.malloc(m_allocationSize);
int buf[] = new int[m_allocationSize - 1];
for (int i = 0; i < buf.length; i++) {
buf[i] = i;
}
m.setInt(p, m_allocationSize - 1, -100);
m.setInts(p, 0, buf, 0, buf.length);
// verify ints are correct using getInt
assertEquals(-100, m.getInt(p, m_allocationSize - 1));
for (int i = 0; i < buf.length; i++) {
assertEquals(buf[i], m.getInt(p, i));
}
m.free(p);
}
@Test
public void testGetIntsPartialLastBlock() {
int p = m.malloc(m_allocationSize);
int buf[] = new int[m_allocationSize - 1];
for (int i = 0; i < m_allocationSize - 1; i++) {
buf[i] = i;
}
m.setInt(p, m_allocationSize - 1, -100);
for (int i = 0; i < buf.length; i++) {
m.setInt(p, i, buf[i]);
}
int buf2[] = new int[m_allocationSize - 1];
m.getInts(p, 0, buf2, 0, m_allocationSize - 1);
assertArrayEquals(buf, buf2);
m.free(p);
}
@Test
public void testMallocAndFree() {
int pointer = m.malloc(m_allocationSize);
m.free(pointer);
assertEquals(0, m.usedBlocks());
}
@Test
public void testSetGetIntsInLoop() {
try {
int maxBlocks = m.maxBlocks();
int blockSize = m.blockSize();
int buf[] = new int[maxBlocks * blockSize];
for (int i = 0; i < maxBlocks * blockSize; i++) {
buf[i] = i;
}
for (int numBlocks = 20; numBlocks < maxBlocks; numBlocks++) {
try {
int size = numBlocks * m.blockSize();
int p = m.malloc(size);
m.setInts(p, 0, buf, 0, size);
int out[] = new int[size];
m.getInts(p, 0, out, 0, size);
for (int j = 0; j < size; j++) {
assertEquals("Int at index " + j, buf[j], out[j]);
}
m.free(p);
assertEquals(0, m.usedBlocks());
} catch (AssertionError e) {
System.out.println("Error, numBlocks = " + numBlocks);
throw e;
}
}
} catch (OutOfMemoryException e) {
// expected to happen in this test.
}
}
@Test
public void testBigAllocationForFirstBlock() {
// first allocation pointer never be 0 or -1 because those are reserved for
// signaling null/invalid pointer by data structures
int p = m.malloc(m.blockSize() * 10);
assertNotEquals(0, p);
assertNotEquals(-1, p);
m.free(p);
p = m.malloc(m.blockSize());
assertNotEquals(0, p);
assertNotEquals(-1, p);
m.free(p);
}
@Test
public void testFreeInLoop() {
for (int i = 0; i < m.maxBlocks(); i++) {
try {
int p = m.malloc(i * m.blockSize());
m.free(p);
assertEquals(0, m.usedBlocks());
} catch (OutOfMemoryException e) {
assertEquals(0, m.usedBlocks());
break;
}
}
}
@Test
public void testMemCopyFull() {
}
@Test
public void testMemCopyPartialFirstBlock() {
}
@Test
public void testInitialize() {
m.setInitializer(new MemSetInitializer(-1));
int size = 50;
int p = m.malloc(size);
try {
int expected[] = new int[size]; // initialized to zeros
m.memSet(p, 0, size, 0); // all zeros
int out[] = new int[size];
m.getInts(p, 0, out, 0, size);
assertArrayEquals(expected, out);
m.initialize(p);
m.getInts(p, 0, out, 0, size);
for (int i = 0; i < size; i++) {
assertEquals(-1, out[i]);
}
} finally {
m.free(p);
}
}
@Override
public String toString() {
return m.toString();
}
}