/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.github.geophile.erdo.map.diskmap; import com.github.geophile.erdo.map.diskmap.CompressibleLongArray; import org.junit.Test; import static org.junit.Assert.*; public class CompressibleLongArrayTest { @Test public void testEmpty() { CompressibleLongArray a = new CompressibleLongArray(0); a.close(); assertEquals(-1L, a.min()); assertEquals(0, a.deltaBytes()); } @Test public void testSingleton() { final long X = 123L; CompressibleLongArray a = new CompressibleLongArray(1); a.append(X); assertEquals(X, a.min()); assertEquals(0, a.deltaBytes()); a.close(); assertEquals(X, a.min()); assertEquals(0, a.deltaBytes()); } @Test public void testAllDuplicates() { final int N = 10; final long X = 123L; CompressibleLongArray a = new CompressibleLongArray(N / 2); // To test growth of CULA.array for (int i = 0; i < N; i++) { assertEquals(i == 0 ? -1L : X, a.min()); assertEquals(0, a.deltaBytes()); a.append(X); } a.close(); assertEquals(X, a.min()); assertEquals(0, a.deltaBytes()); assertEquals(N, a.size()); } @Test public void test0Byte() { final int N = 10; final long X = 123L; CompressibleLongArray a = new CompressibleLongArray(N); for (int i = 0; i < N; i++) { a.append(X); } a.close(); assertEquals(0, a.deltaBytes()); try { a.deltas1Byte(); } catch (AssertionError e) {} try { a.deltas2Byte(); } catch (AssertionError e) {} try { a.deltas4Byte(); } catch (AssertionError e) {} try { a.deltas8Byte(); } catch (AssertionError e) {} } @Test public void test1Byte() { final int N = 0xff; final long X = 123L; CompressibleLongArray a = new CompressibleLongArray(N); for (int i = 0; i < N; i++) { a.append(X + i); } a.close(); assertEquals(1, a.deltaBytes()); byte[] deltas = a.deltas1Byte(); for (int i = 0; i < N; i++) { assertEquals(i, (deltas[i] & 0xff)); } try { a.deltas2Byte(); } catch (AssertionError e) {} try { a.deltas4Byte(); } catch (AssertionError e) {} try { a.deltas8Byte(); } catch (AssertionError e) {} } @Test public void test2Byte() { final int N = 0xffff; final long X = 123L; CompressibleLongArray a = new CompressibleLongArray(N); for (int i = 0; i < N; i++) { a.append(X + i); } a.close(); assertEquals(2, a.deltaBytes()); try { a.deltas1Byte(); } catch (AssertionError e) {} short[] deltas = a.deltas2Byte(); for (int i = 0; i < N; i++) { assertEquals(i, (deltas[i] & 0xffff)); } try { a.deltas4Byte(); } catch (AssertionError e) {} try { a.deltas8Byte(); } catch (AssertionError e) {} } @Test public void test4Byte() { CompressibleLongArray a = new CompressibleLongArray(32); long x = 1; for (int i = 0; i < 32; i++) { a.append(x); x <<= 1; } a.close(); assertEquals(4, a.deltaBytes()); try { a.deltas1Byte(); } catch (AssertionError e) {} try { a.deltas2Byte(); } catch (AssertionError e) {} x = 1; int[] deltas = a.deltas4Byte(); for (int i = 0; i < 32; i++) { assertEquals(x, 1 + deltas[i] & 0xffffffffL); x <<= 1; } try { a.deltas8Byte(); } catch (AssertionError e) {} } @Test public void test8Byte() { CompressibleLongArray a = new CompressibleLongArray(63); long x = 1; for (int i = 0; i < 63; i++) { a.append(x); x <<= 1; } a.close(); assertEquals(8, a.deltaBytes()); try { a.deltas1Byte(); } catch (AssertionError e) {} try { a.deltas2Byte(); } catch (AssertionError e) {} try { a.deltas4Byte(); } catch (AssertionError e) {} x = 1; long[] deltas = a.deltas8Byte(); for (int i = 0; i < 63; i++) { assertEquals(x, 1 + deltas[i]); x <<= 1; } } @Test public void testTransitions() { CompressibleLongArray a = new CompressibleLongArray(1); // Append 0 a.append(0L); assertEquals(0L, a.min()); assertEquals(0, a.deltaBytes()); // Append 1 .. 0xff for (long x = 1; x <= 0xff; x++) { a.append(x); assertEquals(0L, a.min()); assertEquals(1, a.deltaBytes()); } // Append 0x100 a.append(0x100L); assertEquals(0L, a.min()); assertEquals(2, a.deltaBytes()); // Append 0xffff a.append(0xffffL); assertEquals(0L, a.min()); assertEquals(2, a.deltaBytes()); // Append 0x10000 a.append(0x10000L); assertEquals(0L, a.min()); assertEquals(4, a.deltaBytes()); // Append 0xffffffff a.append(0xffffffffL); assertEquals(0L, a.min()); assertEquals(4, a.deltaBytes()); // Append 0x100000000 a.append(0x100000000L); assertEquals(0L, a.min()); assertEquals(8, a.deltaBytes()); // close and check final state a.close(); assertEquals(0L, a.min()); assertEquals(8, a.deltaBytes()); long[] offsets = a.deltas8Byte(); int i = 0; while (i <= 0xff) { assertEquals(i, offsets[i]); i++; } assertEquals(0x100L, offsets[i++]); assertEquals(0xffffL, offsets[i++]); assertEquals(0x10000L, offsets[i++]); assertEquals(0xffffffffL, offsets[i++]); assertEquals(0x100000000L, offsets[i++]); assertEquals(a.size(), i); } @Test public void testRemoval() { for (int nAppend = 1; nAppend <= 63; nAppend++) { for (int nRemove = 1; nRemove <= nAppend; nRemove++) { CompressibleLongArray a = new CompressibleLongArray(1); long mask = 0x1L; for (int i = 0; i < nAppend; i++) { a.append(mask); mask = mask << 1; } for (int i = 0; i < nRemove; i++) { a.removeLast(); } a.close(); int n = nAppend - nRemove; if (n == 0) { assertEquals(0, a.size()); } else { // The values in a should be 1 << 0, ..., 1 << (n - 1). mask = 0x1L; for (int i = 0; i < n; i++) { assertEquals(mask, a.at(i)); mask = mask << 1; } int deltaBytes = a.deltaBytes(); long maxDelta = a.at(n - 1) - a.at(0); switch (deltaBytes) { case 0: assertEquals(1, n); break; case 1: assertTrue(maxDelta <= 0xffL); break; case 2: assertTrue(maxDelta > 0xffL); assertTrue(maxDelta <= 0xffffL); break; case 4: assertTrue(maxDelta > 0xffffL); assertTrue(maxDelta <= 0xffffffffL); break; case 8: assertTrue(maxDelta > 0xffffffffL); break; default: fail(); break; } } } } } }