Files
haiku-beta6/src/tests/system/kernel/util/BOpenHashTableTest.cpp
T
Kacper Kasper fa4502cdb5 Fix unit tests to work with test_app_server
* Test suite runs to completion (with failures).
* Observed sporadic hang in "BMessageQueue::Concurrency Test #1
  (with list)".
* Disabled Deskbar tests because they can mess up system's Deskbar.
  Something like test_app_server needs to be provided.
* Disabled B_CMAP8 conversion tests due to #19885.
* Fixed typo in variable names in haikudepot Jamfile.
* "TARGET_PLATFORM=libbe_test jam -q install-unittest-libs" should
  prepare complete testing environment.

Change-Id: Ie73fc3aaec5e6f73e310421404acda08f0b7faf4
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10224
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
2026-01-12 22:45:52 +00:00

400 lines
10 KiB
C++

#include <cppunit/TestAssert.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestSuite.h>
#include <TestShell.h>
#include <os/support/ObjectList.h>
#include <shared/AutoDeleter.h>
#include <util/OpenHashTable.h>
#include "BOpenHashTableTest.h"
namespace {
class Entry {
public:
Entry(uint32_t value)
:
fValue(value),
fNext(NULL)
{
}
const uint32_t Value() const
{
return fValue;
}
Entry* Next() const
{
return fNext;
}
private:
uint32_t fValue;
Entry *fNext;
friend class EntryDefinition;
};
class EntryDefinition {
public:
typedef uint32_t KeyType;
typedef Entry ValueType;
size_t HashKey(const KeyType& key) const
{
return key;
}
size_t Hash(Entry* entry) const
{
return entry->fValue;
}
bool Compare(const KeyType& key, Entry* entry) const
{
return key == entry->fValue;
}
Entry*& GetLink(Entry* entry) const
{
return entry->fNext;
}
};
}
CppUnit::Test* BOpenHashTableTest::Suite()
{
CppUnit::TestSuite* suite = new CppUnit::TestSuite("BOpenHashTable");
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Insert test",
&BOpenHashTableTest::InsertTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Insert unchecked test",
&BOpenHashTableTest::InsertUncheckedTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Insert unchecked uninitialized test",
&BOpenHashTableTest::InsertUncheckedUninitializedTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Iterate and count test",
&BOpenHashTableTest::IterateAndCountTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Lookup test",
&BOpenHashTableTest::LookupTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Resize test",
&BOpenHashTableTest::ResizeTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Remove test",
&BOpenHashTableTest::RemoveTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Remove unchecked test",
&BOpenHashTableTest::RemoveUncheckedTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Remove when not present test",
&BOpenHashTableTest::RemoveWhenNotPresentTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Duplicate insert test",
&BOpenHashTableTest::DuplicateInsertTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Disable auto expand",
&BOpenHashTableTest::DisableAutoExpandTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Init with zero size",
&BOpenHashTableTest::InitWithZeroSizeTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Clear test",
&BOpenHashTableTest::ClearTest));
suite->addTest(new CppUnit::TestCaller<BOpenHashTableTest>(
"BOpenHashTable::Clear and return test",
&BOpenHashTableTest::ClearAndReturnTest));
return suite;
}
BOpenHashTableTest::BOpenHashTableTest(std::string name)
: BTestCase(name)
{
}
void BOpenHashTableTest::InsertTest()
{
Entry entry(123);
BOpenHashTable<EntryDefinition> table;
CPPUNIT_ASSERT_EQUAL(table.Init(), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Insert(&entry), B_OK);
}
void BOpenHashTableTest::InsertUncheckedTest()
{
Entry entry(123);
BOpenHashTable<EntryDefinition> table;
CPPUNIT_ASSERT_EQUAL(table.Init(), B_OK);
table.InsertUnchecked(&entry);
}
void BOpenHashTableTest::InsertUncheckedUninitializedTest()
{
Entry entry(123);
BOpenHashTable<EntryDefinition> table;
CPPUNIT_ASSERT_EQUAL(table.Init(), B_OK);
table.InsertUnchecked(&entry);
}
void BOpenHashTableTest::IterateAndCountTest() {
const size_t kEntryCount = 20;
BObjectList<Entry, true> entries(20);
BOpenHashTable<EntryDefinition> table;
CPPUNIT_ASSERT_EQUAL(table.Init(kEntryCount * 2), B_OK);
for (uint32_t i = 0; i < kEntryCount; ++i) {
Entry* entry = new Entry(i);
entries.AddItem(entry);
CPPUNIT_ASSERT_EQUAL(table.Insert(entry), B_OK);
}
// Verify that the table contains the expected values.
uint64_t map = 0;
BOpenHashTable<EntryDefinition>::Iterator iterator = table.GetIterator();
while (iterator.HasNext()) {
Entry* entry = iterator.Next();
CPPUNIT_ASSERT_EQUAL(0, map & (1 << entry->Value()));
map |= (1 << entry->Value());
}
CPPUNIT_ASSERT_EQUAL(map, (1 << kEntryCount) - 1);
CPPUNIT_ASSERT_EQUAL(kEntryCount, table.CountElements());
}
void BOpenHashTableTest::ResizeTest()
{
// This is the same as IterateAndCountTest, except that the table will
// be resized mid insertion.
const size_t kEntryCount = 20;
BObjectList<Entry, true> entries(20);
BOpenHashTable<EntryDefinition> table;
// Start off with capacity for 8 elements. This will mean that the table
// will be resized in the loop below since we are inserting 20 elements.
CPPUNIT_ASSERT_EQUAL(table.Init(8), B_OK);
for (uint32_t i = 0; i < kEntryCount; ++i) {
Entry* entry = new Entry(i);
entries.AddItem(entry);
CPPUNIT_ASSERT_EQUAL(table.Insert(entry), B_OK);
}
// Verify that after resize the expected elements are present within
// the table.
uint64_t map = 0;
BOpenHashTable<EntryDefinition>::Iterator iterator = table.GetIterator();
while (iterator.HasNext()) {
Entry* entry = iterator.Next();
CPPUNIT_ASSERT_EQUAL(0, map & (1 << entry->Value()));
map |= (1 << entry->Value());
}
CPPUNIT_ASSERT_EQUAL(map, (1 << kEntryCount) - 1);
CPPUNIT_ASSERT_EQUAL(kEntryCount, table.CountElements());
}
void BOpenHashTableTest::LookupTest() {
Entry entry(123);
BOpenHashTable<EntryDefinition> table;
CPPUNIT_ASSERT_EQUAL(table.Init(0), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Insert(&entry), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Lookup(123), &entry);
}
void BOpenHashTableTest::RemoveTest() {
Entry entry(123);
BOpenHashTable<EntryDefinition> table;
CPPUNIT_ASSERT_EQUAL(table.Init(0), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Insert(&entry), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Lookup(123), &entry);
table.Remove(&entry);
CPPUNIT_ASSERT_EQUAL(table.Lookup(123), NULL);
}
void BOpenHashTableTest::RemoveUncheckedTest()
{
Entry entry(123);
BOpenHashTable<EntryDefinition> table;
CPPUNIT_ASSERT_EQUAL(table.Init(0), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Insert(&entry), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Lookup(123), &entry);
table.RemoveUnchecked(&entry);
CPPUNIT_ASSERT_EQUAL(table.Lookup(123), NULL);
}
void BOpenHashTableTest::RemoveWhenNotPresentTest()
{
Entry entry1(123);
Entry entry2(456);
Entry entry3(789);
BOpenHashTable<EntryDefinition> table;
CPPUNIT_ASSERT_EQUAL(table.Init(), B_OK);
// Only add the first two entries.
table.Insert(&entry1);
table.Insert(&entry2);
// entry3 is not in the table, but we'll remove it anyway.
table.Remove(&entry3);
table.RemoveUnchecked(&entry3);
// The original two entries should still be there.
CPPUNIT_ASSERT_EQUAL(table.CountElements(), 2);
CPPUNIT_ASSERT_EQUAL(table.Lookup(123), &entry1);
CPPUNIT_ASSERT_EQUAL(table.Lookup(456), &entry2);
CPPUNIT_ASSERT_EQUAL(table.Lookup(789), NULL);
}
void BOpenHashTableTest::DuplicateInsertTest()
{
Entry entry(123);
BOpenHashTable<EntryDefinition, true, true> table;
CPPUNIT_ASSERT_EQUAL(table.Init(0), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Insert(&entry), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Lookup(123), &entry);
CPPUNIT_ASSERT_DEBUGGER(table.Insert(&entry));
CPPUNIT_ASSERT_EQUAL(table.Lookup(123), &entry);
// The item can basically never be removed now since there is a cycle,
// but we'll break into the debugger on remove when that happens as well.
CPPUNIT_ASSERT_DEBUGGER(table.Remove(&entry));
CPPUNIT_ASSERT_EQUAL(table.Lookup(123), &entry);
CPPUNIT_ASSERT_DEBUGGER(table.Remove(&entry));
CPPUNIT_ASSERT_EQUAL(table.Lookup(123), &entry);
}
void BOpenHashTableTest::DisableAutoExpandTest()
{
// Insert multiple items into a table with a fixed size of 1. This
// essentially turns this BOpenHashTable into a linked list, since resize
// will never occur.
Entry entry1(123);
Entry entry2(456);
BOpenHashTable<EntryDefinition, false> table;
CPPUNIT_ASSERT_EQUAL(table.Init(1), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Insert(&entry1), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Insert(&entry2), B_OK);
CPPUNIT_ASSERT_EQUAL(table.CountElements(), 2);
}
void BOpenHashTableTest::InitWithZeroSizeTest()
{
Entry entry(123);
BOpenHashTable<EntryDefinition> table;
CPPUNIT_ASSERT_EQUAL(table.Init(0), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Insert(&entry), B_OK);
CPPUNIT_ASSERT_EQUAL(table.Lookup(123), &entry);
}
void BOpenHashTableTest::ClearTest()
{
const size_t kEntryCount = 3;
BObjectList<Entry, true> entries(20);
BOpenHashTable<EntryDefinition> table;
CPPUNIT_ASSERT_EQUAL(table.Init(), B_OK);
for (uint32_t i = 0; i < kEntryCount; ++i) {
Entry* entry = new Entry(i);
entries.AddItem(entry);
CPPUNIT_ASSERT_EQUAL(table.Insert(entry), B_OK);
}
CPPUNIT_ASSERT_EQUAL(table.CountElements(), kEntryCount);
CPPUNIT_ASSERT(table.Lookup(2) != NULL);
CPPUNIT_ASSERT_EQUAL(table.Clear(false), NULL);
CPPUNIT_ASSERT_EQUAL(table.CountElements(), 0);
CPPUNIT_ASSERT_EQUAL(table.Lookup(2), NULL);
CPPUNIT_ASSERT_EQUAL(table.GetIterator().HasNext(), false);
}
void BOpenHashTableTest::ClearAndReturnTest()
{
// Same as ClearTest(), except that Clear(true) is called, which tells
// the BOpenHashTable<T> to return a linked list of entries before clearing
// the table.
const size_t kEntryCount = 3;
BOpenHashTable<EntryDefinition> table;
CPPUNIT_ASSERT_EQUAL(table.Init(), B_OK);
for (uint32_t i = 0; i < kEntryCount; ++i) {
Entry* entry = new Entry(i);
CPPUNIT_ASSERT_EQUAL(table.Insert(entry), B_OK);
}
CPPUNIT_ASSERT_EQUAL(table.CountElements(), kEntryCount);
CPPUNIT_ASSERT(table.Lookup(2) != NULL);
Entry* head = table.Clear(true);
CPPUNIT_ASSERT(head != NULL);
CPPUNIT_ASSERT_EQUAL(table.CountElements(), 0);
CPPUNIT_ASSERT_EQUAL(table.Lookup(2), NULL);
CPPUNIT_ASSERT_EQUAL(table.GetIterator().HasNext(), false);
size_t items_returned = 0;
while (head != NULL) {
Entry* next = head->Next();
delete head;
head = next;
++items_returned;
}
CPPUNIT_ASSERT_EQUAL(items_returned, kEntryCount);
}