blob: 3fed17cc1f68517fda44559d9253f5fded28d7df [file] [log] [blame]
/* 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.
*/
#define C_LUCY_TESTBITVECTOR
#include "Lucy/Util/ToolSet.h"
#include "Lucy/Test.h"
#include "Lucy/Test/TestUtils.h"
#include "Lucy/Test/Object/TestBitVector.h"
static void
test_Set_and_Get(TestBatch *batch) {
unsigned i, max;
const uint32_t three = 3;
const uint32_t seventeen = 17;
BitVector *bit_vec = BitVec_new(8);
BitVec_Set(bit_vec, three);
TEST_TRUE(batch, BitVec_Get_Capacity(bit_vec) < seventeen,
"set below cap");
BitVec_Set(bit_vec, seventeen);
TEST_TRUE(batch, BitVec_Get_Capacity(bit_vec) > seventeen,
"set above cap causes BitVector to grow");
for (i = 0, max = BitVec_Get_Capacity(bit_vec); i < max; i++) {
if (i == three || i == seventeen) {
TEST_TRUE(batch, BitVec_Get(bit_vec, i), "set/get %d", i);
}
else {
TEST_FALSE(batch, BitVec_Get(bit_vec, i), "get %d", i);
}
}
TEST_FALSE(batch, BitVec_Get(bit_vec, i), "out of range get");
DECREF(bit_vec);
}
static void
test_Flip(TestBatch *batch) {
BitVector *bit_vec = BitVec_new(0);
int i;
for (i = 0; i <= 20; i++) { BitVec_Flip(bit_vec, i); }
for (i = 0; i <= 20; i++) {
TEST_TRUE(batch, BitVec_Get(bit_vec, i), "flip on %d", i);
}
TEST_FALSE(batch, BitVec_Get(bit_vec, i), "no flip %d", i);
for (i = 0; i <= 20; i++) { BitVec_Flip(bit_vec, i); }
for (i = 0; i <= 20; i++) {
TEST_FALSE(batch, BitVec_Get(bit_vec, i), "flip off %d", i);
}
TEST_FALSE(batch, BitVec_Get(bit_vec, i), "still no flip %d", i);
DECREF(bit_vec);
}
static void
test_Flip_Block_ascending(TestBatch *batch) {
BitVector *bit_vec = BitVec_new(0);
int i;
for (i = 0; i <= 20; i++) {
BitVec_Flip_Block(bit_vec, i, 21 - i);
}
for (i = 0; i <= 20; i++) {
if (i % 2 == 0) {
TEST_TRUE(batch, BitVec_Get(bit_vec, i),
"Flip_Block ascending %d", i);
}
else {
TEST_FALSE(batch, BitVec_Get(bit_vec, i),
"Flip_Block ascending %d", i);
}
}
DECREF(bit_vec);
}
static void
test_Flip_Block_descending(TestBatch *batch) {
BitVector *bit_vec = BitVec_new(0);
int i;
for (i = 19; i >= 0; i--) {
BitVec_Flip_Block(bit_vec, 1, i);
}
for (i = 0; i <= 20; i++) {
if (i % 2) {
TEST_TRUE(batch, BitVec_Get(bit_vec, i),
"Flip_Block descending %d", i);
}
else {
TEST_FALSE(batch, BitVec_Get(bit_vec, i),
"Flip_Block descending %d", i);
}
}
DECREF(bit_vec);
}
static void
test_Flip_Block_bulk(TestBatch *batch) {
int32_t offset;
for (offset = 0; offset <= 17; offset++) {
int32_t len;
for (len = 0; len <= 17; len++) {
int i;
int upper = offset + len - 1;
BitVector *bit_vec = BitVec_new(0);
BitVec_Flip_Block(bit_vec, offset, len);
for (i = 0; i <= 17; i++) {
if (i >= offset && i <= upper) {
if (!BitVec_Get(bit_vec, i)) { break; }
}
else {
if (BitVec_Get(bit_vec, i)) { break; }
}
}
TEST_INT_EQ(batch, i, 18, "Flip_Block(%d, %d)", offset, len);
DECREF(bit_vec);
}
}
}
static void
test_Mimic(TestBatch *batch) {
int foo;
for (foo = 0; foo <= 17; foo++) {
int bar;
for (bar = 0; bar <= 17; bar++) {
int i;
BitVector *foo_vec = BitVec_new(0);
BitVector *bar_vec = BitVec_new(0);
BitVec_Set(foo_vec, foo);
BitVec_Set(bar_vec, bar);
BitVec_Mimic(foo_vec, (Obj*)bar_vec);
for (i = 0; i <= 17; i++) {
if (BitVec_Get(foo_vec, i) && i != bar) { break; }
}
TEST_INT_EQ(batch, i, 18, "Mimic(%d, %d)", foo, bar);
DECREF(foo_vec);
DECREF(bar_vec);
}
}
}
static BitVector*
S_create_set(int set_num) {
int i;
int nums_1[] = { 1, 2, 3, 10, 20, 30, 0 };
int nums_2[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0
};
int *nums = set_num == 1 ? nums_1 : nums_2;
BitVector *bit_vec = BitVec_new(31);
for (i = 0; nums[i] != 0; i++) {
BitVec_Set(bit_vec, nums[i]);
}
return bit_vec;
}
#define OP_OR 1
#define OP_XOR 2
#define OP_AND 3
#define OP_AND_NOT 4
static int
S_verify_logical_op(BitVector *bit_vec, BitVector *set_1, BitVector *set_2,
int op) {
int i;
for (i = 0; i < 50; i++) {
bool_t wanted;
switch (op) {
case OP_OR:
wanted = BitVec_Get(set_1, i) || BitVec_Get(set_2, i);
break;
case OP_XOR:
wanted = (!BitVec_Get(set_1, i)) != (!BitVec_Get(set_2, i));
break;
case OP_AND:
wanted = BitVec_Get(set_1, i) && BitVec_Get(set_2, i);
break;
case OP_AND_NOT:
wanted = BitVec_Get(set_1, i) && (!BitVec_Get(set_2, i));
break;
default:
wanted = false;
THROW(ERR, "unknown op: %d", op);
}
if (BitVec_Get(bit_vec, i) != wanted) { break; }
}
return i;
}
static void
test_Or(TestBatch *batch) {
BitVector *smaller = S_create_set(1);
BitVector *larger = S_create_set(2);
BitVector *set_1 = S_create_set(1);
BitVector *set_2 = S_create_set(2);
BitVec_Or(smaller, set_2);
TEST_INT_EQ(batch, S_verify_logical_op(smaller, set_1, set_2, OP_OR),
50, "OR with self smaller than other");
BitVec_Or(larger, set_1);
TEST_INT_EQ(batch, S_verify_logical_op(larger, set_1, set_2, OP_OR),
50, "OR with other smaller than self");
DECREF(smaller);
DECREF(larger);
DECREF(set_1);
DECREF(set_2);
}
static void
test_Xor(TestBatch *batch) {
BitVector *smaller = S_create_set(1);
BitVector *larger = S_create_set(2);
BitVector *set_1 = S_create_set(1);
BitVector *set_2 = S_create_set(2);
BitVec_Xor(smaller, set_2);
TEST_INT_EQ(batch, S_verify_logical_op(smaller, set_1, set_2, OP_XOR),
50, "XOR with self smaller than other");
BitVec_Xor(larger, set_1);
TEST_INT_EQ(batch, S_verify_logical_op(larger, set_1, set_2, OP_XOR),
50, "XOR with other smaller than self");
DECREF(smaller);
DECREF(larger);
DECREF(set_1);
DECREF(set_2);
}
static void
test_And(TestBatch *batch) {
BitVector *smaller = S_create_set(1);
BitVector *larger = S_create_set(2);
BitVector *set_1 = S_create_set(1);
BitVector *set_2 = S_create_set(2);
BitVec_And(smaller, set_2);
TEST_INT_EQ(batch, S_verify_logical_op(smaller, set_1, set_2, OP_AND),
50, "AND with self smaller than other");
BitVec_And(larger, set_1);
TEST_INT_EQ(batch, S_verify_logical_op(larger, set_1, set_2, OP_AND),
50, "AND with other smaller than self");
DECREF(smaller);
DECREF(larger);
DECREF(set_1);
DECREF(set_2);
}
static void
test_And_Not(TestBatch *batch) {
BitVector *smaller = S_create_set(1);
BitVector *larger = S_create_set(2);
BitVector *set_1 = S_create_set(1);
BitVector *set_2 = S_create_set(2);
BitVec_And_Not(smaller, set_2);
TEST_INT_EQ(batch,
S_verify_logical_op(smaller, set_1, set_2, OP_AND_NOT),
50, "AND_NOT with self smaller than other");
BitVec_And_Not(larger, set_1);
TEST_INT_EQ(batch,
S_verify_logical_op(larger, set_2, set_1, OP_AND_NOT),
50, "AND_NOT with other smaller than self");
DECREF(smaller);
DECREF(larger);
DECREF(set_1);
DECREF(set_2);
}
static void
test_Count(TestBatch *batch) {
int i;
int shuffled[64];
BitVector *bit_vec = BitVec_new(64);
for (i = 0; i < 64; i++) { shuffled[i] = i; }
for (i = 0; i < 64; i++) {
int shuffle_pos = rand() % 64;
int temp = shuffled[shuffle_pos];
shuffled[shuffle_pos] = shuffled[i];
shuffled[i] = temp;
}
for (i = 0; i < 64; i++) {
BitVec_Set(bit_vec, shuffled[i]);
if (BitVec_Count(bit_vec) != (uint32_t)(i + 1)) { break; }
}
TEST_INT_EQ(batch, i, 64, "Count() returns the right number of bits");
DECREF(bit_vec);
}
static void
test_Next_Hit(TestBatch *batch) {
int i;
for (i = 24; i <= 33; i++) {
int probe;
BitVector *bit_vec = BitVec_new(64);
BitVec_Set(bit_vec, i);
TEST_INT_EQ(batch, BitVec_Next_Hit(bit_vec, 0), i,
"Next_Hit for 0 is %d", i);
TEST_INT_EQ(batch, BitVec_Next_Hit(bit_vec, 0), i,
"Next_Hit for 1 is %d", i);
for (probe = 15; probe <= i; probe++) {
TEST_INT_EQ(batch, BitVec_Next_Hit(bit_vec, probe), i,
"Next_Hit for %d is %d", probe, i);
}
for (probe = i + 1; probe <= i + 9; probe++) {
TEST_INT_EQ(batch, BitVec_Next_Hit(bit_vec, probe), -1,
"no Next_Hit for %d when max is %d", probe, i);
}
DECREF(bit_vec);
}
}
static void
test_Clear_All(TestBatch *batch) {
BitVector *bit_vec = BitVec_new(64);
BitVec_Flip_Block(bit_vec, 0, 63);
BitVec_Clear_All(bit_vec);
TEST_INT_EQ(batch, BitVec_Next_Hit(bit_vec, 0), -1, "Clear_All");
DECREF(bit_vec);
}
static void
test_Clone(TestBatch *batch) {
int i;
BitVector *self = BitVec_new(30);
BitVector *twin;
BitVec_Set(self, 2);
BitVec_Set(self, 3);
BitVec_Set(self, 10);
BitVec_Set(self, 20);
twin = BitVec_Clone(self);
for (i = 0; i < 50; i++) {
if (BitVec_Get(self, i) != BitVec_Get(twin, i)) { break; }
}
TEST_INT_EQ(batch, i, 50, "Clone");
TEST_INT_EQ(batch, BitVec_Count(twin), 4, "clone Count");
DECREF(self);
DECREF(twin);
}
static int
S_compare_u64s(void *context, const void *va, const void *vb) {
uint64_t a = *(uint64_t*)va;
uint64_t b = *(uint64_t*)vb;
UNUSED_VAR(context);
return a == b ? 0 : a < b ? -1 : 1;
}
static void
test_To_Array(TestBatch *batch) {
uint64_t *source_ints = TestUtils_random_u64s(NULL, 20, 0, 200);
BitVector *bit_vec = BitVec_new(0);
I32Array *array;
long num_unique = 0;
long i;
// Unique the random ints.
Sort_quicksort(source_ints, 20, sizeof(uint64_t),
S_compare_u64s, NULL);
for (i = 0; i < 19; i++) {
if (source_ints[i] != source_ints[i + 1]) {
source_ints[num_unique] = source_ints[i];
num_unique++;
}
}
// Set bits.
for (i = 0; i < num_unique; i++) {
BitVec_Set(bit_vec, (uint32_t)source_ints[i]);
}
// Create the array and compare it to the source.
array = BitVec_To_Array(bit_vec);
for (i = 0; i < num_unique; i++) {
if (I32Arr_Get(array, i) != (int32_t)source_ints[i]) { break; }
}
TEST_INT_EQ(batch, i, num_unique, "To_Array (%ld == %ld)", i,
num_unique);
DECREF(array);
DECREF(bit_vec);
FREEMEM(source_ints);
}
// Valgrind only - detect off-by-one error.
static void
test_off_by_one_error() {
int cap;
for (cap = 5; cap <= 24; cap++) {
BitVector *bit_vec = BitVec_new(cap);
BitVec_Set(bit_vec, cap - 2);
DECREF(bit_vec);
}
}
void
TestBitVector_run_tests() {
TestBatch *batch = TestBatch_new(1029);
TestBatch_Plan(batch);
test_Set_and_Get(batch);
test_Flip(batch);
test_Flip_Block_ascending(batch);
test_Flip_Block_descending(batch);
test_Flip_Block_bulk(batch);
test_Mimic(batch);
test_Or(batch);
test_Xor(batch);
test_And(batch);
test_And_Not(batch);
test_Count(batch);
test_Next_Hit(batch);
test_Clear_All(batch);
test_Clone(batch);
test_To_Array(batch);
test_off_by_one_error();
DECREF(batch);
}