first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / library / tests_structures / test_symbol_table.cpp
1 /*
2 *  Name   : test_symbol_table
3 *  Author : Chris Koeritz
4 **
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                               *
11 */
12
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>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27
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;
37
38 //#define DEBUG_SYMBOL_TABLE
39   // uncomment for noisy version.
40
41 const int test_iterations = 4;
42
43 const int FIND_ITERATIONS = 10;
44 const int MAXIMUM_RANDOM_ADDS = 20;
45
46 #define LOG(to_print) EMERGENCY_LOG(program_wide_logger::get(), astring(to_print))
47
48 //#define OLD_TEST
49   // uncomment for the older version of symbol table.
50
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;
57
58 //////////////
59
60 class my_table_def : virtual public hoople_standard, virtual public symbol_table<byte_array>
61 ///, virtual public equalizable
62 {
63 public:
64   DEFINE_CLASS_NAME("my_table_def");
65
66   virtual void text_form(base_string &state_fill) const {
67     state_fill.assign(astring(class_name()) + ": uhhh not really implemented");
68   }
69
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;
77     }
78     return true;
79   }
80 };
81
82 //////////////
83
84 // jethro is a simple object for containment below.
85 class jethro
86 {
87 public:
88   astring _truck;
89
90   bool operator ==(const jethro &tc) const { return tc._truck == _truck; }
91   bool operator !=(const jethro &tc) const { return !(*this == tc); }
92 };
93
94 //////////////
95
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
99 {
100 public:
101   int _q;
102   astring _ted;
103   astring _jed;
104   int_array _ned;
105   matrix<jethro> _med;
106
107   test_content() : _q(9) {}
108
109   test_content(const astring &ted, const astring &jed) : _q(4), _ted(ted),
110           _jed(jed) {}
111
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);
117   }
118   int packed_size() const {
119     return sizeof(_q) + _ted.packed_size() + _jed.packed_size();
120   }
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;
125     return true;
126   }
127
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;
135     
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;
141
142     return true;
143   }
144   bool operator !=(const test_content &tc) const { return !operator ==(tc); }
145
146   operator int() const { return _q; }
147 };
148
149 //////////////
150
151 class second_table_def : virtual public hoople_standard, virtual public symbol_table<test_content>
152 {
153 public:
154   DEFINE_CLASS_NAME("second_table_def")
155
156   virtual void text_form(base_string &state_fill) const {
157     state_fill.assign(astring(class_name()) + ": uhhh not really implemented");
158   }
159
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;
165     }
166     return true;
167   }
168 };
169
170 //////////////
171
172 class test_symbol_table : public virtual application_shell, public virtual unit_base
173 {
174 public:
175   test_symbol_table() {}
176   DEFINE_CLASS_NAME("test_symbol_table");
177
178   void test_1();
179
180   virtual int execute();
181
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);
184
185   void ADD2(second_table_def &syms, const astring &name, const test_content &to_add);
186
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);
189
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);
192
193   void test_byte_table();
194   void test_tc_table();
195 };
196
197 //////////////
198
199 void test_symbol_table::ADD(my_table_def &syms, const astring &name, const astring &to_add)
200 {
201   FUNCDEF("ADD")
202   byte_array to_stuff(to_add.length() + 1, (abyte *)to_add.s());
203   time_stamp start;
204   outcome added = syms.add(name, to_stuff);
205   ASSERT_EQUAL(added.value(), common::IS_NEW, "should not already be in table");
206   time_stamp end;
207   time_in_add += end.value() - start.value();
208   start.reset();
209 #ifdef OLD_TEST
210   int indy = syms.find(name);
211   ASSERT_FALSE(negative(indy), "should be in table after add");
212   end.reset();
213   time_in_dep_find += end.value() - start.value();
214   const byte_array *found = &syms[indy];
215 #else
216   byte_array *found = syms.find(name);
217   ASSERT_TRUE(found, "really should be in table after add");
218   end.reset();
219   time_in_new_find += end.value() - start.value();
220 #endif
221   ASSERT_EQUAL(*found, to_stuff, "value should be right in table after add");
222 }
223
224 void test_symbol_table::FIND(const my_table_def &syms, const astring &name, const astring &to_add)
225 {
226   FUNCDEF("FIND")
227   byte_array to_stuff(to_add.length() + 1, (abyte *)to_add.s());
228   for (int i = 0; i < FIND_ITERATIONS; i++) {
229     time_stamp start;
230 #ifdef OLD_TEST
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];
237     time_stamp end;
238     time_in_dep_find += end.value() - start.value();
239 #else
240     int indy = syms.dep_find(name);
241     ASSERT_FALSE(negative(indy), "should locate item in table (dep_find)");
242     time_stamp end;
243     time_in_dep_find += end.value() - start.value();
244     start.reset();
245     byte_array *found = syms.find(name);
246     ASSERT_TRUE(found, "second find should see item in table (new_find)");
247     end.reset();
248     time_in_new_find += end.value() - start.value();
249 #endif
250   }
251 }
252
253 void test_symbol_table::pack(byte_array &packed_form, const my_table_def &to_pack)
254 {
255   attach(packed_form, to_pack.symbols());
256   astring name;
257   byte_array content;
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);
262   }
263 }
264
265 bool test_symbol_table::unpack(byte_array &packed_form, my_table_def &to_unpack)
266 {
267   to_unpack.reset();
268   int syms = 0;
269   if (!detach(packed_form, syms)) return false;
270   astring name;
271   byte_array chunk;
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());
276   }
277   return true;
278 }
279
280 void test_symbol_table::pack(byte_array &packed_form, const second_table_def &to_pack)
281 {
282   attach(packed_form, to_pack.symbols());
283   astring name;
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);
289   }
290 }
291
292 bool test_symbol_table::unpack(byte_array &packed_form, second_table_def &to_unpack)
293 {
294   to_unpack.reset();
295   int syms = 0;
296   if (!detach(packed_form, syms)) return false;
297   astring name;
298   test_content chunk;
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);
303   }
304   return true;
305 }
306
307 //////////////
308
309 my_table_def creatapose()
310 {
311   my_table_def to_return;
312   astring name;
313   astring content;
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);
319   }
320   return to_return;
321 }
322
323 //////////////
324
325 void test_symbol_table::test_byte_table()
326 {
327   FUNCDEF("test_byte_table")
328   my_table_def syms;
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));
335 #endif
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.");
344     ADD(syms, xname, x);
345     astring aname("fleeny-brickle");
346     astring a("lallax menick publum.");
347     ADD(syms, aname, a);
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");
359     ADD(syms, zname, z);
360
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);
369
370     astring name;
371     astring content;
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);
377     }
378
379     // test copying the table.
380     time_stamp start;  // click, on.
381     my_table_def copy1(syms);
382     {
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");
390     }
391     ASSERT_FALSE(! (syms == copy1), "copy test B: symbol tables should be same still");
392     time_stamp end;
393     time_in_copy += end.value() - start.value();
394
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...");
398 #endif
399
400 #ifdef DEBUG_SYMBOL_TABLE
401     LOG("now unpacking from packed form");
402 #endif
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");
406
407 #ifdef DEBUG_SYMBOL_TABLE
408 ///    LOG(astring(astring::SPRINTF, "unpacked form has:\n%s", new_syms->text_form().s()));
409 #endif
410     ASSERT_FALSE(! (syms == new_syms), "unpacked test symbol tables must be equal");
411
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...");
415 #endif
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...");
423 #endif
424     start = time_stamp();
425     ASSERT_TRUE(unpack(packed_again, newer_syms), "newer unpacking should working be");
426     end = time_stamp();
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()));
430 #endif
431     ASSERT_EQUAL(new_syms, newer_syms,
432         "unpacked test these just aren't getting it but should be same");
433   }
434 }
435
436 //////////////
437
438 void test_symbol_table::ADD2(second_table_def &syms, const astring &name,
439     const test_content &to_add)
440
441   FUNCDEF("ADD2")
442   time_stamp start;
443   outcome added = syms.add(name, to_add);
444   ASSERT_EQUAL(added.value(), common::IS_NEW, "new item should not already be in table");
445   time_stamp end;
446   time_in_add += end.value() - start.value();
447   start = time_stamp();  // reset start.
448 #ifdef OLD_TEST
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();
456 #else
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();
466 #endif
467   astring name_out;
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");
472   }
473 }
474
475 //////////////
476
477 void test_symbol_table::test_tc_table()
478 {
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++) {
484     syms.reset();
485 #ifdef DEBUG_SYMBOL_TABLE
486     LOG(astring(astring::SPRINTF, "index %d", qq));
487 #endif
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);
512
513     // test copying the table.
514     time_stamp start;
515     second_table_def copy1(syms);
516     {
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");
520     }
521     ASSERT_FALSE(! (syms == copy1), "copy test D: symbol tables shouldn't be different");
522     time_stamp end;
523     time_in_copy += end.value() - start.value();
524
525 #ifdef DEBUG_SYMBOL_TABLE
526     astring texto;
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...");
530 #endif
531
532 #ifdef DEBUG_SYMBOL_TABLE
533     LOG("now unpacking from packed form");
534 #endif
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);
541 #endif
542     ASSERT_FALSE(! (syms == new_syms), "unpacked test symbol tables should be equivalent");
543
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...");
548 #endif
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...");
553 #endif
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);
558 #endif
559     ASSERT_FALSE(! (new_syms == newer_syms), "unpacked test symbol tables should stay same");
560   }
561 }
562
563 //////////////
564
565 int test_symbol_table::execute()
566 {
567 #ifdef DEBUG_SYMBOL_TABLE
568   LOG(astring("starting test 1: ") + time_stamp::notarize(false));
569 #endif
570   test_byte_table();
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));
574 #endif
575
576   test_tc_table();
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));
584 #endif
585   return final_report();
586 }
587
588 //////////////
589
590 HOOPLE_MAIN(test_symbol_table, )
591