first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / library / tests_structures / test_string_table.cpp
1 /*****************************************************************************\
2 *                                                                             *
3 *  Name   : test_string_table                                                 *
4 *  Author : Chris Koeritz                                                     *
5 *                                                                             *
6 *******************************************************************************
7 * Copyright (c) 1994-$now By Author.  This program is free software; you can  *
8 * redistribute it and/or modify it under the terms of the GNU General Public  *
9 * License as published by the Free Software Foundation; either version 2 of   *
10 * the License or (at your option) any later version.  This is online at:      *
11 *     http://www.fsf.org/copyleft/gpl.html                                    *
12 * Please send any updates to: fred@gruntose.com                               *
13 \*****************************************************************************/
14
15 #include <basis/byte_array.h>
16 #include <basis/guards.h>
17 #include <basis/astring.h>
18 #include <structures/matrix.h>
19 #include <structures/string_table.h>
20 #include <timely/time_stamp.h>
21 #include <loggers/console_logger.h>
22 #include <structures/static_memory_gremlin.h>
23 #include <textual/string_manipulation.h>
24 #include <application/hoople_main.h>
25 #include <unit_test/unit_base.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 using namespace application;
31 using namespace basis;
32 ///using namespace configuration;
33 using namespace mathematics;
34 using namespace filesystem;
35 using namespace loggers;
36 using namespace structures;
37 using namespace textual;
38 using namespace timely;
39 using namespace unit_test;
40
41 //#define DEBUG_SYMBOL_TABLE
42   // uncomment to get lots of noise out of base class.
43
44 //#define DEBUG_STRING_TABLE
45   // uncomment for noisy version.
46
47 //#define TEST_SIZE_TABLE
48   // uncomment for testing the size of a string_table.
49
50 //#define OLD_TEST
51   // uncomment for the older version of symbol table.
52
53 const int test_iterations = 25;
54
55 const int FIND_ITERATIONS = 20;
56 const int MAXIMUM_RANDOM_ADDS = 50;
57
58 const int TEST_SIZE_TABLE_COUNT = 10000;
59   // the number of string_table elements we create for checking how
60   // big one of them is.
61
62 #define LOG(to_print) EMERGENCY_LOG(program_wide_logger::get(), astring(to_print))
63
64 double time_in_add = 0;
65 double time_in_find = 0;
66 double time_in_pack = 0;
67 double time_in_unpack = 0;
68 basis::un_int operations = 0;
69
70 class test_string_table : public virtual application_shell, public virtual unit_base
71 {
72 public:
73   test_string_table() {}
74   DEFINE_CLASS_NAME("test_string_table");
75
76   void ADD(string_table &syms, const astring &name, const astring &to_add);
77   void FIND(const string_table &syms, const astring &name, const astring &to_find);
78
79   void test_1();
80
81   virtual int execute();
82 };
83
84 //////////////
85
86 void test_string_table::ADD(string_table &syms, const astring &name, const astring &to_add)
87 {
88   FUNCDEF("ADD")
89 //LOG(astring("add of ") + name + " => " + to_add);
90   time_stamp start;
91   outcome added = syms.add(name, to_add);
92   operations++;
93   ASSERT_INEQUAL(added.value(), common::EXISTING, "should not already be in table");
94   time_stamp end;
95   time_in_add += end.value() - start.value();
96 }
97
98 void test_string_table::FIND(const string_table &syms, const astring &name, const astring &to_find)
99 {
100   FUNCDEF("FIND")
101   for (int i = 0; i < FIND_ITERATIONS; i++) {
102     time_stamp start;
103     astring *found = syms.find(name);
104     operations++;
105     time_stamp end;
106     time_in_find += end.value() - start.value();
107     ASSERT_TRUE(found, "should be in table");
108     ASSERT_EQUAL(*found, to_find, "string in table should be correct");
109   }
110 }
111
112 //////////////
113
114 void test_string_table::test_1()
115 {
116   FUNCDEF("test_string_table");
117 #ifdef TEST_SIZE_TABLE
118   {
119     array<string_table> symso(TEST_SIZE_TABLE_COUNT);
120     operations++;
121     guards::alert_message(astring(astring::SPRINTF, "we should effectively "
122         "have swamped out the size of other code in the program now.  the size "
123         "should represent %d string_table instantiations.  take the current "
124         "memory size (minus maybe 2 megs) and divide by %d and you will have "
125         "a fairly accurate cost for instantiating a string table.  hit a key.",
126         TEST_SIZE_TABLE_COUNT, TEST_SIZE_TABLE_COUNT));
127     #ifdef _CONSOLE
128     getchar();
129     #elif defined(__UNIX__)
130     getchar();
131     #endif
132   }
133 #endif
134
135   string_table syms;
136   string_table new_syms;
137   string_table newer_syms;
138   operations += 3;
139   for (int qq = 0; qq < test_iterations; qq++) {
140     syms.reset();  // still could be costly.
141     operations++;
142 #ifdef DEBUG_STRING_TABLE
143     LOG(astring(astring::SPRINTF, "index %d", qq));
144 #endif
145     astring freudname("blurgh");
146     astring freud("Sigmund Freud was a very freaked dude.");
147     ADD(syms, freudname, freud);
148     astring borgname("borg");
149     astring borg("You will be assimilated.");
150     ADD(syms, borgname, borg);
151     astring xname("X-Men");
152     astring x("The great unknown superhero cartoon.");
153     ADD(syms, xname, x);
154     astring aname("fleeny-brickle");
155     astring a("lallax menick publum.");
156     ADD(syms, aname, a);
157     astring axname("ax");
158     astring ax("Lizzy Borden has a very large hatchet.");
159     ADD(syms, axname, ax);
160     astring bloinkname("urg.");
161     astring bloink("this is a short and stupid string");
162     ADD(syms, bloinkname, bloink);
163     astring faxname("fax");
164     astring fax("alligators in my teacup.");
165     ADD(syms, faxname, fax);
166     astring zname("eagle ovaries");
167     astring z("malfeasors beware");
168     ADD(syms, zname, z);
169
170     FIND(syms, freudname, freud);
171     FIND(syms, borgname, borg);
172     FIND(syms, xname, x);
173     FIND(syms, aname, a);
174     FIND(syms, axname, ax);
175     FIND(syms, bloinkname, bloink);
176     FIND(syms, faxname, fax);
177     FIND(syms, zname, z);
178
179     astring name;
180     astring content;
181     for (int y = 0; y < MAXIMUM_RANDOM_ADDS; y++) {
182       name = string_manipulation::make_random_name(40, 108);
183       content = string_manipulation::make_random_name(300, 1000);
184       ADD(syms, name, content);
185       FIND(syms, name, content);
186     }
187
188     // test copying of the string tables.
189     string_table chronos = syms;
190     operations++;
191     {
192       string_table mary = syms;
193       operations++;
194       string_table june = mary;
195       operations++;
196       ASSERT_TRUE(mary == syms, "copy test should compare properly");
197       operations++;
198     }
199     ASSERT_TRUE(syms == chronos, "copy test original should not be harmed");
200     operations++;
201
202     {
203       // test the bug we think we found in the operator =.
204       string_table fred;
205       fred.add("urp", "rarp");
206       fred.add("hyurgh", "ralph");
207       string_table med;
208       med.add("urp", "rarp");
209       med.add("hyurgh", "ralph");
210       fred = med;  // the deadly assignment.
211       fred = med;  // the deadly assignment.
212       fred = med;  // the deadly assignment.
213       fred = med;  // the deadly assignment.
214       fred.add("urp", "rarp");
215       fred.add("gurp", "flaarp");  // a new entry.
216       astring *urp = fred.find("urp");
217       astring *hyurgh = fred.find("hyurgh");
218       ASSERT_TRUE(urp, "urp should not go missing");
219       ASSERT_TRUE(hyurgh, "hyurgh should not go missing");
220 #ifdef DEBUG_STRING_TABLE
221       LOG(astring("got urp as ") + (urp? *urp : "empty!!!!"));
222       LOG(astring("got hyurgh as ") + (hyurgh? *hyurgh : "empty!!!!"));
223 #endif
224       astring urp_val = fred[0];
225         // AH HA!  this one finds it.  accessing via bracket or other methods
226         // that use the internal get() method will fail.
227         // if there is no outright crash, then the bug is gone.
228 #ifdef DEBUG_STRING_TABLE
229       LOG(astring("got urp_val as ") + (urp_val.t()? urp_val : "empty!!!!"));
230 #endif
231     }
232
233 #ifdef DEBUG_STRING_TABLE
234 ////    LOG(astring(astring::SPRINTF,"This is the symbol table before any manipulation\n%s", syms.text_form()));
235     LOG("now packing the symbol table...");
236 #endif
237     byte_array packed_form;
238     time_stamp start;
239     syms.pack(packed_form);
240     operations++;
241     time_stamp end;
242     time_in_pack += end.value() - start.value();
243 #ifdef DEBUG_STRING_TABLE
244     LOG("now unpacking from packed form");
245 #endif
246     start.reset();
247     ASSERT_TRUE(new_syms.unpack(packed_form), "unpack test should succeed in unpacking");
248     operations++;
249     end.reset();  // click, off.
250     time_in_unpack += end.value() - start.value();
251
252 #ifdef DEBUG_STRING_TABLE
253 ///    LOG(astring(astring::SPRINTF, "unpacked form has:\n%s", new_syms->text_form().s()));
254 #endif
255     ASSERT_FALSE(! (syms == new_syms), "unpacked test symbol tables should be same");
256     operations++;
257
258 #ifdef DEBUG_STRING_TABLE
259     LOG("now deleting old symbol table...");
260 #endif
261
262 #ifdef DEBUG_STRING_TABLE
263 ///    LOG(astring(astring::SPRINTF, "got the unpacked form, and dumping it:\n%s", new_syms->text_form().s()));
264     LOG("packing the symbol table again...");
265 #endif
266     byte_array packed_again(0);
267     start.reset();  // click, on.
268     new_syms.pack(packed_again);
269     operations++;
270     end.reset();  // click, off.
271     time_in_pack += end.value() - start.value();
272 #ifdef DEBUG_STRING_TABLE
273     LOG("now unpacking from packed form again...");
274 #endif
275     start = time_stamp();
276     newer_syms.unpack(packed_again);
277     operations++;
278     end = time_stamp();
279     time_in_unpack += end.value() - start.value();
280 #ifdef DEBUG_STRING_TABLE
281     LOG(astring(astring::SPRINTF, "got the unpacked form, and dumping "
282         "it:\n%s", newer_syms.text_form().s()));
283 #endif
284     ASSERT_TRUE(new_syms == newer_syms, "unpacked test should not be different symbol tables");
285     operations++;
286
287 #ifdef DEBUG_STRING_TABLE
288     LOG("now deleting new and newer symbol table...");
289 #endif
290   }
291 }
292
293 //////////////
294
295 int test_string_table::execute()
296 {
297 #ifdef DEBUG_STRING_TABLE
298   LOG(astring("starting test: ") + time_stamp::notarize(false));
299 #endif
300   test_1();
301 #ifdef DEBUG_STRING_TABLE
302   LOG(astring("done test: ") + time_stamp::notarize(false));
303   LOG(astring(astring::SPRINTF, "time in add=%f", time_in_add));
304   LOG(astring(astring::SPRINTF, "time in find=%f", time_in_find));
305   LOG(astring(astring::SPRINTF, "time in pack=%f", time_in_pack));
306   LOG(astring(astring::SPRINTF, "time in unpack=%f", time_in_unpack));
307   LOG(astring(astring::SPRINTF, "total operations=%u", operations));
308 #endif
309
310   return final_report();
311 }
312
313 HOOPLE_MAIN(test_string_table, )
314