beegfs/common/tests/TestBitStore.cpp
2025-08-10 01:34:16 +02:00

252 lines
6.8 KiB
C++

#include <common/toolkit/BitStore.h>
#include <common/toolkit/Random.h>
#include <cmath>
#include <gtest/gtest.h>
#define TESTBITSTORE_MAX_BITSTORE_SIZE 242
#define TESTBITSTORE_RANDOM_VALUES_COUNT 75
struct TestBitStoreBlockCountResult
{
int blockCount; // the needed blockCount
};
/**
* The number of blocks required to store a certain number of bits.
*/
struct TestBitStoreBlockCountResult const __TESTBITSTORE_BLOCK_COUNT_RESULTS[] =
{
{1 + ( ( (32*1)-1) / BitStore::LIMB_SIZE) }, // result for bits 1 to 32
{1 + ( ( (32*2)-1) / BitStore::LIMB_SIZE) }, // result for bits 33 to 64
{1 + ( ( (32*3)-1) / BitStore::LIMB_SIZE) }, // result for bits 65 to 96
{1 + ( ( (32*4)-1) / BitStore::LIMB_SIZE) }, // result for bits 97 to 128
{1 + ( ( (32*5)-1) / BitStore::LIMB_SIZE) }, // result for bits 129 to 160
{1 + ( ( (32*6)-1) / BitStore::LIMB_SIZE) }, // result for bits 161 to 192
{1 + ( ( (32*7)-1) / BitStore::LIMB_SIZE) }, // result for bits 193 to 224
{1 + ( ( (32*8)-1) / BitStore::LIMB_SIZE) }, // result for bits 125 to 256
};
class TestBitStore : public ::testing::Test {
protected:
BitStore::limb_type& lowerBits(BitStore& store) { return store.lowerBits; }
BitStore::limb_type* higherBits(BitStore& store) { return store.higherBits.get(); }
};
TEST_F(TestBitStore, calculateBitBlockCount)
{
unsigned blockCount;
unsigned resultIndex = 0;
for(int size = 1; size < TESTBITSTORE_MAX_BITSTORE_SIZE; size++)
{
if(size < 33)
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[0].blockCount;
else
if(size < 65)
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[1].blockCount;
else
if(size < 97)
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[2].blockCount;
else
if(size < 129)
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[3].blockCount;
else
if(size < 161)
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[4].blockCount;
else
if(size < 193)
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[5].blockCount;
else
if(size < 225)
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[6].blockCount;
else
if(size < 257)
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[7].blockCount;
blockCount = BitStore::calculateBitBlockCount(size);
EXPECT_EQ(blockCount, resultIndex);
}
}
TEST_F(TestBitStore, setSizeAndReset)
{
const int initValue = 32896;
int size = 1;
bool reverse = false;
bool finished = false;
BitStore store(size);
while(finished)
{
int higherBitsBlockCount = BitStore::calculateBitBlockCount(size) - 1;
//set some data to the bit store
lowerBits(store) = initValue;
for(int blockIndex = 0; blockIndex < higherBitsBlockCount; blockIndex++)
{
higherBits(store)[blockIndex] = initValue;
}
// set the new size and reset all values
store.setSize(size);
store.clearBits();
//check the lower bits
EXPECT_EQ(lowerBits(store), 0u);
//check the higher bits
for(int blockIndex = 0; blockIndex < higherBitsBlockCount; blockIndex++)
EXPECT_EQ(higherBits(store)[blockIndex], 0u);
if(size == TESTBITSTORE_MAX_BITSTORE_SIZE)
reverse = true;
if(reverse)
size--;
else
size++;
//
// finish test or set the new size
if(reverse && size == 0)
finished = true;
}
}
TEST_F(TestBitStore, getter)
{
BitStore store(TESTBITSTORE_MAX_BITSTORE_SIZE);
// check the getter for all bits
for(int index = 0; index < TESTBITSTORE_MAX_BITSTORE_SIZE; index++)
{
// set a bit
int blockIndexOfBit = index / BitStore::LIMB_SIZE;
BitStore::limb_type value = 1UL << (index % BitStore::LIMB_SIZE);
if(blockIndexOfBit == 0)
lowerBits(store) = value;
else
higherBits(store)[blockIndexOfBit - 1] = value;
// check if all bits contain the correct value
for(int testIndex = 0; testIndex < TESTBITSTORE_MAX_BITSTORE_SIZE; testIndex++)
{
if(testIndex != index)
EXPECT_FALSE(store.getBitNonAtomic(testIndex));
else
EXPECT_TRUE(store.getBitNonAtomic(testIndex));
}
store.clearBits();
}
}
TEST_F(TestBitStore, setter)
{
BitStore store(TESTBITSTORE_MAX_BITSTORE_SIZE);
int higherBitsBlockCount = BitStore::calculateBitBlockCount(TESTBITSTORE_MAX_BITSTORE_SIZE) - 1;
// check the setter for all bits
for(int index = 0; index < TESTBITSTORE_MAX_BITSTORE_SIZE; index++)
{
store.setBit(index, true);
// check if all bit blocks contains the correct value
int blockIndexOfBit = index / BitStore::LIMB_SIZE;
BitStore::limb_type neededValue = 1UL << (index % BitStore::LIMB_SIZE);
// check lower bit block
if(blockIndexOfBit == 0)
EXPECT_EQ(lowerBits(store), neededValue);
else
EXPECT_EQ(lowerBits(store), 0u);
// check higher bit blocks
for(int blockIndex = 0; blockIndex < higherBitsBlockCount; blockIndex++)
{
if(blockIndex != (blockIndexOfBit - 1) )
EXPECT_EQ(higherBits(store)[blockIndex], 0u);
else
EXPECT_EQ(higherBits(store)[blockIndex], neededValue);
}
store.clearBits();
}
}
static void checkSerialization(BitStore* store)
{
BitStore secondStore;
unsigned serialLen;
{
Serializer ser;
ser % *store;
serialLen = ser.size();
}
boost::scoped_array<char> buf(new char[serialLen]);
unsigned serializationRes;
{
Serializer ser(buf.get(), serialLen);
ser % *store;
serializationRes = ser.size();
}
ASSERT_EQ(serialLen, serializationRes);
unsigned deserLen;
bool success;
{
Deserializer des(buf.get(), serialLen);
des % secondStore;
deserLen = des.size();
success = des.good();
}
EXPECT_TRUE(success) << "BitStore deserialization failed.";
EXPECT_EQ(deserLen, serialLen);
EXPECT_EQ(*store, secondStore);
}
TEST_F(TestBitStore, serialization)
{
// check serialization for different BitStore size
for(int size = 1; size <= TESTBITSTORE_MAX_BITSTORE_SIZE; size++)
{
BitStore store(size);
// check serialization for all bits, only one bit is set
for(int index = 0; index < size; index++)
{
store.setBit(index, true);
checkSerialization(&store);
store.clearBits();
}
}
// check serialization for BitStore with random values
BitStore store(TESTBITSTORE_MAX_BITSTORE_SIZE);
Random rand;
for(int count = 0; count < TESTBITSTORE_RANDOM_VALUES_COUNT; count++)
{
int randIndex = rand.getNextInRange(0, TESTBITSTORE_MAX_BITSTORE_SIZE - 1);
store.setBit(randIndex, true);
}
checkSerialization(&store);
}