30 using namespace basis;
84 : snacky_string(string_manipulation::make_random_name()),
85 chunk(chao.
inclusive(100, 10000)), food_bar(0), hungry(
false) {}
100 int unused_random_id();
121 bool test_find_zap_add();
122 bool test_acquire_add_zap();
123 bool test_find_add_find();
124 bool test_reset(
bool always_run =
false);
125 bool test_check_sanity();
129 static bool equivalence_applier(
const int &key, data_shuttle &item,
void *dlink);
144 test_hash_table::test_hash_table()
153 int test_hash_table::raw_random_id()
158 int test_hash_table::unused_random_id()
161 int checking = raw_random_id();
162 if (!_keys_in_use.member(checking))
return checking;
167 int test_hash_table::execute()
175 #ifdef DEBUG_HASH_TABLE
176 log(
a_sprintf(
"did %d tests.\n", _tested));
177 log(
astring(
"Test Activity:"));
181 log(
a_sprintf(
"note that test %d will seldom be executed.",
RESET));
183 return final_report();
189 case ADD:
return "ADD";
190 case ADD_ADD:
return "ADD_ADD";
191 case ZAP:
return "ZAP";
192 case ADD_ZAP:
return "ADD_ZAP";
193 case ZAP_ADD:
return "ZAP_ADD";
194 case FIND:
return "FIND";
195 case ACQUIRE:
return "ACQUIRE";
199 case RESET:
return "RESET";
200 case COPY:
return "COPY";
201 case REHASH:
return "REHASH";
203 default:
return "UnknownTest";
207 bool test_hash_table::perform_a_test(
test_actions test_type)
214 case ADD:
return test_add();
215 case ADD_ADD:
return test_add_add();
216 case ZAP:
return test_zap();
217 case ADD_ZAP:
return test_add_zap();
218 case ZAP_ADD:
return test_zap_add();
219 case FIND:
return test_find();
220 case ACQUIRE:
return test_acquire();
224 case RESET:
return test_reset();
225 case COPY:
return test_copy();
226 case REHASH:
return test_rehash();
229 ASSERT_TRUE(
false,
"should not see any missing cases");
234 bool test_hash_table::pick_a_test()
241 bool test_hash_table::test_add()
245 int random_id = raw_random_id();
246 data_shuttle *to_add =
new data_shuttle;
247 to_add->snacky_string = string_manipulation::make_random_name();
248 to_add->food_bar = random_id;
249 outcome expected = common::IS_NEW;
251 if (_keys_in_use.member(random_id))
return false;
253 "add should give proper outcome based on expectation");
254 if (_keys_in_use.member(random_id))
256 _keys_in_use.add(random_id);
265 #undef UNIT_BASE_THIS_OBJECT
266 #define UNIT_BASE_THIS_OBJECT (*dynamic_cast<unit_base *>(application_shell::single_instance()))
268 bool test_hash_table::equivalence_applier(
const int &key, data_shuttle &item,
void *dlink)
270 FUNCDEF(
"equivalence_applier");
272 if (!dlink)
return false;
279 if (!found)
return false;
284 ASSERT_EQUAL(item.snacky_string, found->snacky_string,
test_name +
": snacky_string should not differ");
289 #undef UNIT_BASE_THIS_OBJECT
290 #define UNIT_BASE_THIS_OBJECT (*this)
294 bool test_hash_table::test_rehash()
301 if (maybe < 32)
return true;
306 _the_table.estimated_elements());
313 _the_table.rehash(
randomizer().inclusive(1, 20));
317 table_copy.
apply(equivalence_applier, (
void*)func);
323 bool test_hash_table::test_copy()
330 if (maybe > 16)
return true;
341 table_copy.apply(equivalence_applier, (
void*)func);
349 bool test_hash_table::test_add_add()
353 int random_id = unused_random_id();
354 data_shuttle *to_add =
new data_shuttle;
355 to_add->snacky_string = string_manipulation::make_random_name();
356 to_add->food_bar = random_id;
357 ASSERT_EQUAL(_the_table.add(random_id, to_add).value(), common::IS_NEW,
358 "new addition should be seen as such");
360 _keys_in_use.add(random_id);
363 data_shuttle *next_add =
new data_shuttle;
364 next_add->snacky_string = string_manipulation::make_random_name();
365 next_add->food_bar = random_id;
366 ASSERT_EQUAL(_the_table.add(random_id, next_add).value(), our_hash::EXISTING,
367 "second add should not say first failed");
372 bool test_hash_table::test_zap()
376 if (maybe > 50)
return true;
377 if (!_keys_in_use.elements())
return false;
379 int rand_indy =
randomizer().inclusive(0, _keys_in_use.elements() - 1);
380 int dead_key = _keys_in_use[rand_indy];
381 _keys_in_use.remove(dead_key);
382 ASSERT_TRUE(_the_table.zap(dead_key),
"key should be present in table");
386 bool test_hash_table::test_add_zap()
391 int random_id = unused_random_id();
392 data_shuttle *to_add =
new data_shuttle;
393 to_add->snacky_string = string_manipulation::make_random_name();
394 to_add->food_bar = random_id;
395 ASSERT_EQUAL(_the_table.add(random_id, to_add).value(), common::IS_NEW,
396 "putting new item in should be seen as new");
398 ASSERT_TRUE(_the_table.zap(random_id),
"key should be present after add");
402 bool test_hash_table::test_zap_add()
405 if (!_keys_in_use.elements())
return false;
407 int rand_indy =
randomizer().inclusive(0, _keys_in_use.elements() - 1);
409 int dead_key = _keys_in_use[rand_indy];
410 ASSERT_TRUE(_the_table.zap(dead_key),
"key should be there when we look");
412 data_shuttle *to_add =
new data_shuttle;
413 to_add->snacky_string = string_manipulation::make_random_name();
414 to_add->food_bar = dead_key;
415 outcome ret = _the_table.add(dead_key, to_add);
416 ASSERT_EQUAL(ret.
value(), our_hash::IS_NEW,
"key should not be present already");
420 bool test_hash_table::test_find()
423 if (!_keys_in_use.elements())
return false;
425 int rand_indy =
randomizer().inclusive(0, _keys_in_use.elements() - 1);
426 int find_key = _keys_in_use[rand_indy];
428 ASSERT_TRUE(_the_table.find(find_key, found),
"key should be there as expected");
430 ASSERT_EQUAL(found->food_bar, find_key,
"stored key should be same as real key");
431 ASSERT_TRUE(found->snacky_string.length(),
"stored string should have length");
435 bool test_hash_table::test_acquire()
439 if (maybe > 150)
return true;
440 if (!_keys_in_use.elements())
return false;
442 int rand_indy =
randomizer().inclusive(0, _keys_in_use.elements() - 1);
443 int find_key = _keys_in_use[rand_indy];
444 _keys_in_use.remove(find_key);
445 data_shuttle *found = _the_table.acquire(find_key);
447 ASSERT_EQUAL(found->food_bar, find_key,
"stored key should be same as real key");
448 ASSERT_TRUE(found->snacky_string.length(),
"stored string should not have zero length");
450 found = _the_table.acquire(find_key);
451 ASSERT_NULL(found,
"key should not be there after zap");
455 bool test_hash_table::test_find_zap_add()
459 if (!_keys_in_use.elements())
return false;
461 int rand_indy =
randomizer().inclusive(0, _keys_in_use.elements() - 1);
463 int find_key = _keys_in_use[rand_indy];
465 ASSERT_TRUE(_the_table.find(find_key, found),
"key should be locateable");
467 ASSERT_EQUAL(found->food_bar, find_key,
"stored key should be equal to real key");
468 ASSERT_TRUE(found->snacky_string.length(),
"stored string should not have zero length");
470 ASSERT_TRUE(_the_table.zap(find_key),
"should be able to zap the item we had found");
472 data_shuttle *to_add =
new data_shuttle;
473 to_add->snacky_string = string_manipulation::make_random_name();
474 to_add->food_bar = find_key;
475 ASSERT_EQUAL(_the_table.add(find_key, to_add).value(), our_hash::IS_NEW,
476 "the item we zapped should be gone");
480 bool test_hash_table::test_reset(
bool always_run)
486 if ( (maybe > 372) || (maybe < 368) )
return true;
492 for (
int i = _keys_in_use.elements() - 1; i >= 0; i--) {
493 int dead_key = _keys_in_use[i];
494 ASSERT_FALSE(_the_table.acquire(dead_key),
"after reset, we should not find item");
495 _keys_in_use.remove(dead_key);
502 bool test_hash_table::test_acquire_add_zap()
508 bool test_hash_table::test_find_add_find()
514 bool test_hash_table::test_check_sanity()
The application_shell is a base object for console programs.
a_sprintf is a specialization of astring that provides printf style support.
Provides a dynamically resizable ASCII character string.
A very common template for a dynamic array of bytes.
Outcomes describe the state of completion for an operation.
a platform-independent way to acquire random numbers in a specific range.
int inclusive(int low, int high) const
< Returns a pseudo-random number r, such that "low" <= r <= "high".
void apply(apply_function *to_apply, void *data_link)
Invokes the function "to_apply" on every entry in the table.
bool find(const key_type &key, contents *&item_found) const
locates the item specified by the "key", if possible.
A simple object that wraps a templated set of ints.
Implements a hashing algorithm based on the contents stored in an object.
Represents a point in time relative to the operating system startup time.
#define NULL_POINTER
The value representing a pointer to nothing.
#define MAXINT32
Maximum 32-bit integer value.
#define DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Provides macros that implement the 'main' program of an application.
#define HOOPLE_MAIN(obj_name, obj_args)
options that should work for most unix and linux apps.
Implements an application lock to ensure only one is running at once.
The guards collection helps in testing preconditions and reporting errors.
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
const int MINUTE_ms
Number of milliseconds in a minute.
A platform independent way to obtain the timestamp of a file.
A logger that sends to the console screen using the standard output device.
An extension to floating point primitives providing approximate equality.
A dynamic container class that holds any kind of object via pointers.
void copy_hash_table(hash_table< key_type, contents > &target, const hash_table< key_type, contents > &source)
Copies the entire hash table, given a contents type that supports copying.
Useful support functions for unit testing, especially within hoople.
hash_table< int, data_shuttle > * _hang_on
const double TEST_DURATION
hash_table< int, data_shuttle > our_hash
#define ASSERT_EQUAL(a, b, test_name)
#define ASSERT_TRUE(a, test_name)
#define ASSERT_NULL(x, y)
#define ASSERT_FALSE(a, test_name)
#define ASSERT_NON_NULL(x, y)