2 * Name : test_symbol_table
3 * Author : Chris Koeritz
5 * Copyright (c) 1994-$now By Author. This program is free software; you can *
6 * redistribute it and/or modify it under the terms of the GNU General Public *
7 * License as published by the Free Software Foundation; either version 2 of *
8 * the License or (at your option) any later version. This is online at: *
9 * http://www.fsf.org/copyleft/gpl.html *
10 * Please send any updates to: fred@gruntose.com *
13 #include <basis/byte_array.h>
14 #include <basis/guards.h>
15 #include <basis/astring.h>
16 #include <structures/matrix.h>
17 #include <structures/symbol_table.h>
18 #include <timely/time_stamp.h>
19 #include <loggers/console_logger.h>
20 #include <structures/static_memory_gremlin.h>
21 #include <textual/string_manipulation.h>
22 #include <application/hoople_main.h>
23 #include <unit_test/unit_base.h>
28 using namespace application;
29 using namespace basis;
30 using namespace mathematics;
31 using namespace filesystem;
32 using namespace loggers;
33 using namespace structures;
34 using namespace textual;
35 using namespace timely;
36 using namespace unit_test;
38 //#define DEBUG_SYMBOL_TABLE
39 // uncomment for noisy version.
41 const int test_iterations = 4;
43 const int FIND_ITERATIONS = 10;
44 const int MAXIMUM_RANDOM_ADDS = 20;
46 #define LOG(to_print) EMERGENCY_LOG(program_wide_logger::get(), astring(to_print))
49 // uncomment for the older version of symbol table.
51 double time_in_add = 0;
52 double time_in_dep_find = 0;
53 double time_in_new_find = 0;
54 double time_in_pack = 0;
55 double time_in_unpack = 0;
56 double time_in_copy = 0;
60 class my_table_def : virtual public hoople_standard, virtual public symbol_table<byte_array>
61 ///, virtual public equalizable
64 DEFINE_CLASS_NAME("my_table_def");
66 virtual void text_form(base_string &state_fill) const {
67 state_fill.assign(astring(class_name()) + ": uhhh not really implemented");
70 virtual bool equal_to(const equalizable &s2) const {
71 const my_table_def *to_compare = dynamic_cast<const my_table_def *>(&s2);
72 if (!to_compare) return false;
73 if (symbols() != to_compare->symbols()) return false;
74 for (int i = 0; i < symbols(); i++) {
75 if (name(i) != to_compare->name(i)) return false;
76 if (operator [](i) != (*to_compare)[i]) return false;
84 // jethro is a simple object for containment below.
90 bool operator ==(const jethro &tc) const { return tc._truck == _truck; }
91 bool operator !=(const jethro &tc) const { return !(*this == tc); }
96 // the test_content object is an object with proper copy constructor
97 // and assignment operator that also has deep contents.
98 class test_content : public packable
107 test_content() : _q(9) {}
109 test_content(const astring &ted, const astring &jed) : _q(4), _ted(ted),
112 //hmmm: pack and unpack don't do everything.
113 void pack(byte_array &packed_form) const {
114 attach(packed_form, _q);
115 _ted.pack(packed_form);
116 _jed.pack(packed_form);
118 int packed_size() const {
119 return sizeof(_q) + _ted.packed_size() + _jed.packed_size();
121 bool unpack(byte_array &packed_form) {
122 if (!detach(packed_form, _q)) return false;
123 if (!_ted.unpack(packed_form)) return false;
124 if (!_jed.unpack(packed_form)) return false;
128 bool operator ==(const test_content &tc) const {
129 if (tc._q != _q) return false;
130 if (tc._ted != _ted) return false;
131 if (tc._jed != _jed) return false;
132 if (tc._ned.length() != _ned.length()) return false;
133 for (int i = 0; i < _ned.length(); i++)
134 if (tc._ned[i] != _ned[i]) return false;
136 if (tc._med.rows() != _med.rows()) return false;
137 if (tc._med.columns() != _med.columns()) return false;
138 for (int c = 0; c < _med.columns(); c++)
139 for (int r = 0; r < _med.rows(); r++)
140 if (tc._med.get(r, c) != _med.get(r, c)) return false;
144 bool operator !=(const test_content &tc) const { return !operator ==(tc); }
146 operator int() const { return _q; }
151 class second_table_def : virtual public hoople_standard, virtual public symbol_table<test_content>
154 DEFINE_CLASS_NAME("second_table_def")
156 virtual void text_form(base_string &state_fill) const {
157 state_fill.assign(astring(class_name()) + ": uhhh not really implemented");
160 virtual bool equal_to(const equalizable &s2) const {
161 const second_table_def *to_compare = dynamic_cast<const second_table_def *>(&s2);
162 if (symbols() != to_compare->symbols()) return false;
163 for (int i = 0; i < symbols(); i++) {
164 if ((*this)[i] != (*to_compare)[i]) return false;
172 class test_symbol_table : public virtual application_shell, public virtual unit_base
175 test_symbol_table() {}
176 DEFINE_CLASS_NAME("test_symbol_table");
180 virtual int execute();
182 void ADD(my_table_def &syms, const astring &name, const astring &to_add);
183 void FIND(const my_table_def &syms, const astring &name, const astring &to_find);
185 void ADD2(second_table_def &syms, const astring &name, const test_content &to_add);
187 void pack(byte_array &packed_form, const my_table_def &to_pack);
188 bool unpack(byte_array &packed_form, my_table_def &to_unpack);
190 void pack(byte_array &packed_form, const second_table_def &to_pack);
191 bool unpack(byte_array &packed_form, second_table_def &to_unpack);
193 void test_byte_table();
194 void test_tc_table();
199 void test_symbol_table::ADD(my_table_def &syms, const astring &name, const astring &to_add)
202 byte_array to_stuff(to_add.length() + 1, (abyte *)to_add.s());
204 outcome added = syms.add(name, to_stuff);
205 ASSERT_EQUAL(added.value(), common::IS_NEW, "should not already be in table");
207 time_in_add += end.value() - start.value();
210 int indy = syms.find(name);
211 ASSERT_FALSE(negative(indy), "should be in table after add");
213 time_in_dep_find += end.value() - start.value();
214 const byte_array *found = &syms[indy];
216 byte_array *found = syms.find(name);
217 ASSERT_TRUE(found, "really should be in table after add");
219 time_in_new_find += end.value() - start.value();
221 ASSERT_EQUAL(*found, to_stuff, "value should be right in table after add");
224 void test_symbol_table::FIND(const my_table_def &syms, const astring &name, const astring &to_add)
227 byte_array to_stuff(to_add.length() + 1, (abyte *)to_add.s());
228 for (int i = 0; i < FIND_ITERATIONS; i++) {
231 // double the calls so we roughly match the other test.
232 int indy = syms.find(name);
233 ASSERT_FALSE(negative(indy), "should locate item in table");
234 indy = syms.find(name);
235 ASSERT_FALSE(negative(indy), "second find should locate item in table");
236 byte_array *found = &syms[indy];
238 time_in_dep_find += end.value() - start.value();
240 int indy = syms.dep_find(name);
241 ASSERT_FALSE(negative(indy), "should locate item in table (dep_find)");
243 time_in_dep_find += end.value() - start.value();
245 byte_array *found = syms.find(name);
246 ASSERT_TRUE(found, "second find should see item in table (new_find)");
248 time_in_new_find += end.value() - start.value();
253 void test_symbol_table::pack(byte_array &packed_form, const my_table_def &to_pack)
255 attach(packed_form, to_pack.symbols());
258 for (int i = 0; i < to_pack.symbols(); i++) {
259 to_pack.retrieve(i, name, content);
260 name.pack(packed_form);
261 attach(packed_form, content);
265 bool test_symbol_table::unpack(byte_array &packed_form, my_table_def &to_unpack)
269 if (!detach(packed_form, syms)) return false;
272 for (int i = 0; i < syms; i++) {
273 if (!name.unpack(packed_form)) return false;
274 if (!detach(packed_form, chunk)) return false;
275 ADD(to_unpack, name, (char *)chunk.observe());
280 void test_symbol_table::pack(byte_array &packed_form, const second_table_def &to_pack)
282 attach(packed_form, to_pack.symbols());
284 test_content content;
285 for (int i = 0; i < to_pack.symbols(); i++) {
286 to_pack.retrieve(i, name, content);
287 name.pack(packed_form);
288 content.pack(packed_form);
292 bool test_symbol_table::unpack(byte_array &packed_form, second_table_def &to_unpack)
296 if (!detach(packed_form, syms)) return false;
299 for (int i = 0; i < syms; i++) {
300 if (!name.unpack(packed_form)) return false;
301 if (!chunk.unpack(packed_form)) return false;
302 to_unpack.add(name, chunk);
309 my_table_def creatapose()
311 my_table_def to_return;
314 for (int y = 0; y < MAXIMUM_RANDOM_ADDS; y++) {
315 name = string_manipulation::make_random_name(40, 108);
316 content = string_manipulation::make_random_name(300, 1000);
317 byte_array to_stuff(content.length() + 1, (abyte *)content.s());
318 to_return.add(name, to_stuff);
325 void test_symbol_table::test_byte_table()
327 FUNCDEF("test_byte_table")
329 my_table_def new_syms;
330 my_table_def newer_syms;
331 for (int qq = 0; qq < test_iterations; qq++) {
332 syms.reset(); // still could be costly.
333 #ifdef DEBUG_SYMBOL_TABLE
334 LOG(astring(astring::SPRINTF, "index %d", qq));
336 astring freudname("blurgh");
337 astring freud("Sigmund Freud was a very freaked dude.");
338 ADD(syms, freudname, freud);
339 astring borgname("borg");
340 astring borg("You will be assimilated.");
341 ADD(syms, borgname, borg);
342 astring xname("X-Men");
343 astring x("The great unknown superhero cartoon.");
345 astring aname("fleeny-brickle");
346 astring a("lallax menick publum.");
348 astring axname("ax");
349 astring ax("Lizzy Borden has a very large hatchet.");
350 ADD(syms, axname, ax);
351 astring bloinkname("urg.");
352 astring bloink("this is a short and stupid string");
353 ADD(syms, bloinkname, bloink);
354 astring faxname("fax");
355 astring fax("alligators in my teacup.");
356 ADD(syms, faxname, fax);
357 astring zname("eagle ovaries");
358 astring z("malfeasors beware");
361 FIND(syms, freudname, freud);
362 FIND(syms, borgname, borg);
363 FIND(syms, xname, x);
364 FIND(syms, aname, a);
365 FIND(syms, axname, ax);
366 FIND(syms, bloinkname, bloink);
367 FIND(syms, faxname, fax);
368 FIND(syms, zname, z);
372 for (int y = 0; y < MAXIMUM_RANDOM_ADDS; y++) {
373 name = string_manipulation::make_random_name(40, 108);
374 content = string_manipulation::make_random_name(300, 1000);
375 ADD(syms, name, content);
376 FIND(syms, name, content);
379 // test copying the table.
380 time_stamp start; // click, on.
381 my_table_def copy1(syms);
383 my_table_def joe(copy1);
384 my_table_def joe2 = joe;
385 ASSERT_EQUAL(joe2, joe, "copy test A: symbol tables should be same");
386 my_table_def joe3 = creatapose(); // on stack.
387 my_table_def joe4 = joe3;
388 my_table_def joe5 = joe4;
389 ASSERT_EQUAL(joe5, joe3, "copy test A2: symbol tables should be same");
391 ASSERT_FALSE(! (syms == copy1), "copy test B: symbol tables should be same still");
393 time_in_copy += end.value() - start.value();
395 #ifdef DEBUG_SYMBOL_TABLE
396 //// LOG(astring(astring::SPRINTF,"This is the symbol table before any manipulation\n%s", syms.text_form()));
397 LOG("now packing the symbol table...");
400 #ifdef DEBUG_SYMBOL_TABLE
401 LOG("now unpacking from packed form");
403 byte_array packed_form;
404 pack(packed_form, syms);
405 ASSERT_TRUE(unpack(packed_form, new_syms), "unpack test should not fail to unpack");
407 #ifdef DEBUG_SYMBOL_TABLE
408 /// LOG(astring(astring::SPRINTF, "unpacked form has:\n%s", new_syms->text_form().s()));
410 ASSERT_FALSE(! (syms == new_syms), "unpacked test symbol tables must be equal");
412 #ifdef DEBUG_SYMBOL_TABLE
413 /// LOG(astring(astring::SPRINTF, "got the unpacked form, and dumping it:\n%s", new_syms->text_form().s()));
414 LOG("packing the symbol table again...");
416 byte_array packed_again(0);
417 start.reset(); // click, on.
418 pack(packed_again, new_syms);
419 end.reset(); // click, off.
420 time_in_pack += end.value() - start.value();
421 #ifdef DEBUG_SYMBOL_TABLE
422 LOG("now unpacking from packed form again...");
424 start = time_stamp();
425 ASSERT_TRUE(unpack(packed_again, newer_syms), "newer unpacking should working be");
427 time_in_unpack += end.value() - start.value();
428 #ifdef DEBUG_SYMBOL_TABLE
429 /// LOG(astring(astring::SPRINTF, "got the unpacked form, and dumping it:\n%s", newer_syms->text_form().s()));
431 ASSERT_EQUAL(new_syms, newer_syms,
432 "unpacked test these just aren't getting it but should be same");
438 void test_symbol_table::ADD2(second_table_def &syms, const astring &name,
439 const test_content &to_add)
443 outcome added = syms.add(name, to_add);
444 ASSERT_EQUAL(added.value(), common::IS_NEW, "new item should not already be in table");
446 time_in_add += end.value() - start.value();
447 start = time_stamp(); // reset start.
449 int indy = syms.find(name);
450 ASSERT_FALSE(negative(indy), "item should be found after add");
451 // refind to balance timing.
452 indy = syms.find(name);
453 ASSERT_FALSE(negative(indy), "item should be found after second add");
454 end = time_stamp(); // reset end.
455 time_in_dep_find += end.value() - start.value();
457 int indy = syms.dep_find(name);
458 ASSERT_FALSE(negative(indy), "finding item after add should work");
459 end = time_stamp(); // reset end.
460 time_in_dep_find += end.value() - start.value();
461 start = time_stamp();
462 test_content *found = syms.find(name);
463 ASSERT_TRUE(found, "item shouldn't be nil that we found");
464 end = time_stamp(); // reset end.
465 time_in_new_find += end.value() - start.value();
468 test_content content_out;
469 if (syms.retrieve(indy, name_out, content_out) != common::OKAY) {
470 ASSERT_EQUAL(name_out, name, "name should be correct after retrieve");
471 ASSERT_EQUAL(content_out, to_add, "content should be correct after retrieve");
477 void test_symbol_table::test_tc_table()
479 FUNCDEF("test_tc_table")
480 second_table_def syms;
481 second_table_def new_syms;
482 second_table_def newer_syms;
483 for (int qq = 0; qq < test_iterations; qq++) {
485 #ifdef DEBUG_SYMBOL_TABLE
486 LOG(astring(astring::SPRINTF, "index %d", qq));
488 astring freudname("blurgh");
489 test_content freud("Sigmund Freud was a very freaked dude.", "flutenorf");
490 ADD2(syms, freudname, freud);
491 astring borgname("borg");
492 test_content borg("You will be assimilated.", "alabaster");
493 ADD2(syms, borgname, borg);
494 astring xname("X-Men");
495 test_content x("The great unknown superhero cartoon.", "somnambulist");
496 ADD2(syms, xname, x);
497 astring aname("fleeny-brickle");
498 test_content a("lallax menick publum.", "aglos bagnort pavlod");
499 ADD2(syms, aname, a);
500 astring axname("ax");
501 test_content ax("Lizzy Borden has a very large hatchet.", "chop");
502 ADD2(syms, axname, ax);
503 astring bloinkname("urg.");
504 test_content bloink("this is a short and stupid string", "not that short");
505 ADD2(syms, bloinkname, bloink);
506 astring faxname("fax");
507 test_content fax("alligators in my teacup.", "lake placid");
508 ADD2(syms, faxname, fax);
509 astring zname("eagle ovaries");
510 test_content z("malfeasors beware", "endangered");
511 ADD2(syms, zname, z);
513 // test copying the table.
515 second_table_def copy1(syms);
517 second_table_def joe(copy1);
518 second_table_def joe2 = joe;
519 ASSERT_EQUAL(joe2, joe, "copy test C: should have same symbol tables");
521 ASSERT_FALSE(! (syms == copy1), "copy test D: symbol tables shouldn't be different");
523 time_in_copy += end.value() - start.value();
525 #ifdef DEBUG_SYMBOL_TABLE
527 syms.text_form(texto);
528 LOG(astring("This is the symbol table before any manipulation\n") + texto);
529 LOG("now packing the symbol table...");
532 #ifdef DEBUG_SYMBOL_TABLE
533 LOG("now unpacking from packed form");
535 byte_array packed_form;
536 pack(packed_form, syms);
537 ASSERT_TRUE(unpack(packed_form, new_syms), "crikey all these unpacks should work");
538 #ifdef DEBUG_SYMBOL_TABLE
539 new_syms.text_form(texto);
540 LOG(astring("unpacked form has:\n") + texto);
542 ASSERT_FALSE(! (syms == new_syms), "unpacked test symbol tables should be equivalent");
544 #ifdef DEBUG_SYMBOL_TABLE
545 new_syms.text_form(texto);
546 LOG(astring("got the unpacked form, and dumping it:\n") + texto);
547 LOG("packing the symbol table again...");
549 byte_array packed_again(0);
550 pack(packed_again, new_syms);
551 #ifdef DEBUG_SYMBOL_TABLE
552 LOG("now unpacking from packed form again...");
554 ASSERT_TRUE(unpack(packed_again, newer_syms), "unpacking should get back the goods");
555 #ifdef DEBUG_SYMBOL_TABLE
556 newer_syms.text_form(texto);
557 LOG(astring("got the unpacked form, and dumping it:\n") + texto);
559 ASSERT_FALSE(! (new_syms == newer_syms), "unpacked test symbol tables should stay same");
565 int test_symbol_table::execute()
567 #ifdef DEBUG_SYMBOL_TABLE
568 LOG(astring("starting test 1: ") + time_stamp::notarize(false));
571 #ifdef DEBUG_SYMBOL_TABLE
572 LOG(astring("done test 1: ") + time_stamp::notarize(false));
573 LOG(astring("starting test 2: ") + time_stamp::notarize(false));
577 #ifdef DEBUG_SYMBOL_TABLE
578 LOG(astring("done test 2: ") + time_stamp::notarize(false));
579 LOG(astring(astring::SPRINTF, "time in add=%f", time_in_add));
580 LOG(astring(astring::SPRINTF, "time in dep_find=%f", time_in_dep_find));
581 LOG(astring(astring::SPRINTF, "time in new_find=%f", time_in_new_find));
582 LOG(astring(astring::SPRINTF, "time in pack=%f", time_in_pack));
583 LOG(astring(astring::SPRINTF, "time in unpack=%f", time_in_unpack));
585 return final_report();
590 HOOPLE_MAIN(test_symbol_table, )