Merge branch 'release-2.140.101'
[feisty_meow.git] / nucleus / library / tests_structures / test_amorph.cpp
1 /*
2 *  Name   : test_byte_array_amorph
3 *  Author : Chris Koeritz
4 *  Purpose:
5 *    Puts the amorph object through its paces.
6 **
7 * Copyright (c) 2000-$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 "bogon.h"
16
17 #include <application/hoople_main.h>
18 #include <mathematics/chaos.h>
19 #include <basis/functions.h>
20 #include <basis/guards.h>
21 #include <structures/amorph.h>
22 #include <timely/time_stamp.h>
23 #include <loggers/file_logger.h>
24 #include <loggers/console_logger.h>
25 #include <loggers/combo_logger.h>
26 #include <structures/static_memory_gremlin.h>
27 #include <unit_test/unit_base.h>
28
29 #include <memory.h>
30 #include <stdlib.h>
31
32 using namespace application;
33 using namespace basis;
34 using namespace mathematics;
35 using namespace filesystem;
36 using namespace loggers;
37 using namespace structures;
38 using namespace textual;
39 using namespace timely;
40 using namespace unit_test;
41
42 #define DEBUG_ARRAY
43   // uncomment to enable array debugging.
44
45 #define DEBUG_AMORPH
46   // uncomment to enable amorph debugging.
47
48 //#define DEBUG_TEST_AMORPH
49   // uncomment for this program to be noisier.
50
51 #ifdef DEBUG_TEST_AMORPH
52   #define LOG(to_print) EMERGENCY_LOG(program_wide_logger::get(), to_print)
53 #else
54   #define LOG(to_print) {}
55 #endif
56
57 //////////////
58
59 class t_amorph : virtual public unit_base, virtual public application_shell
60 {
61 public:
62   t_amorph() : unit_base() {}
63   DEFINE_CLASS_NAME("t_amorph");
64   int test_bogon_amorph();
65   int test_byte_array_amorph();
66   byte_array fake_pack(amorph<byte_array> &me);
67   int compare(amorph<byte_array> &one, amorph<byte_array> &two);
68   amorph<byte_array> *fake_amorph_unpack(byte_array &packed_amorph);
69   int compare(const amorph<bogon> &one, const amorph<bogon> &two);
70
71   struct blob_hold { int size; int offset; };
72
73   virtual int execute();
74 };
75
76 #define PACK_BLOB_SIZE(max_limbs) (max_limbs * sizeof(blob_hold))
77
78 HOOPLE_MAIN(t_amorph, );
79
80 //////////////
81
82 const int default_test_iterations = 2;
83
84 const int MAX_LIMBS = 200;
85   // the highest number of items stored in the amorphs here.
86
87 const int MIN_CHUBBY = 60;
88   // the smallest chunk to allocate for storing text strings...  all strings
89   // must therefore be shorter than this length.
90 const int MAX_RANDO = 275;
91   // the maximum amount of space to add when allocating a randomly sized chunk.
92
93 #define PROGRAM_NAME astring("test_amorph")
94
95 int t_amorph::compare(amorph<byte_array> &one, amorph<byte_array> &two)
96 {
97   FUNCDEF("compare amorph<byte_array>");
98   ASSERT_EQUAL(one.elements(), two.elements(), "elements comparison");
99   if (one.elements() != two.elements()) return false;
100   ASSERT_EQUAL(one.valid_fields(), two.valid_fields(), "valid fields comparison");
101   if (one.valid_fields() != two.valid_fields()) return false;
102   for (int i = 0; i < one.elements(); i++) {
103     if (!one.get(i) && !two.get(i)) continue;
104     ASSERT_FALSE(!one.get(i) || !two.get(i), "inequal emptiness");
105     ASSERT_EQUAL(one.get(i)->length(), two.get(i)->length(), "inequal sizes");
106     if (one.get(i)->length() > 0) {
107       ASSERT_INEQUAL(one[i]->observe(), two[i]->observe(), "pointer in use twice");
108       ASSERT_FALSE(memcmp(one[i]->observe(), two[i]->observe(), one[i]->length()),
109             "inequal contents");
110     }
111   }
112   return true;
113 }
114
115 byte_array t_amorph::fake_pack(amorph<byte_array> &me)
116 {
117   FUNCDEF("fake_pack");
118   // snagged from the packable_amorph pack function!
119   // count the whole size needed to store the amorph.
120   int amo_size = 0;
121   amorph<byte_array> hold_packed_bits(me.elements());
122
123   for (int i = 0; i < me.elements(); i++)
124     if (me.get(i) && me.get(i)->length()) {
125       byte_array packed_item;
126       attach(packed_item, *me[i]);
127       byte_array *to_stuff = new byte_array(packed_item);
128       hold_packed_bits.put(i, to_stuff);
129       amo_size += packed_item.length();
130     }
131   int len = amo_size + sizeof(int) + PACK_BLOB_SIZE(me.elements());
132
133   // allocate a storage area for the packed form.
134   byte_array to_return(len);
135   int temp = me.elements();
136   memcpy((int *)to_return.access(), &temp, sizeof(int));
137     // size of package is stored at the beginning of the memory.
138
139   int current_offset = sizeof(int);
140   // the indices into the packed form are located after the amorph header.
141   blob_hold *blob_array = (blob_hold *)(to_return.access() + current_offset);
142   current_offset += PACK_BLOB_SIZE(me.elements());
143
144   // the entire amorph is replicated into the new buffer.
145   for (int j = 0; j < me.elements(); j++) {
146     // the offset of this limb in the packed area is saved in the hold.
147     blob_array[j].size
148       = (hold_packed_bits[j]? hold_packed_bits[j]->length() : 0);
149     blob_array[j].offset = current_offset;
150     if (hold_packed_bits[j] && hold_packed_bits[j]->length()) {
151       // the actual data is copied....
152       memcpy(to_return.access() + current_offset,
153             (abyte *)hold_packed_bits[j]->observe(),
154             hold_packed_bits[j]->length());
155       // and the "address" is updated.
156       current_offset += hold_packed_bits[j]->length();
157     }
158   }
159   ASSERT_EQUAL(current_offset, len, "offset is incorrect after packing");
160   return to_return;
161 }
162
163 amorph<byte_array> *t_amorph::fake_amorph_unpack(byte_array &packed_amorph)
164 {
165   // snagged from the packable_amorph unpack function!
166   int max_limbs;
167   memcpy(&max_limbs, (int *)packed_amorph.access(), sizeof(max_limbs));
168   amorph<byte_array> *to_return = new amorph<byte_array>(max_limbs);
169
170   blob_hold *blob_array = new blob_hold[max_limbs];
171   memcpy(blob_array, (blob_hold *)(packed_amorph.access()
172      + sizeof(int)), PACK_BLOB_SIZE(max_limbs));
173   for (int i = 0; i < to_return->elements(); i++)
174     if (blob_array[i].size) {
175       abyte *source = packed_amorph.access() + blob_array[i].offset;
176       byte_array packed_byte_array(blob_array[i].size, source);
177       byte_array *unpacked = new byte_array;
178       detach(packed_byte_array, *unpacked);
179       to_return->put(i, unpacked);
180     }
181   delete [] blob_array;
182   return to_return;
183 }
184
185 int t_amorph::test_byte_array_amorph()
186 {
187   FUNCDEF("test_byte_array_amorph");
188   LOG("start of amorph of abyte array test");
189   for (int qq = 0; qq < default_test_iterations; qq++) {
190     LOG(astring(astring::SPRINTF, "index %d", qq));
191     {
192       // some simple creation and stuffing tests....
193       amorph<byte_array> fred(20);
194       amorph<byte_array> gen(10);
195       for (int i=0; i < 10; i++)  {
196         byte_array *gens = new byte_array(8, (abyte *)"goodbye");
197         gen.put(i, gens);
198       }
199       for (int j = 0; j < 20; j++)  {
200         byte_array *freds = new byte_array(6, (abyte *)"hello");
201          fred.put(j, freds);
202       }
203       amorph_assign(gen, fred);
204       LOG("done with fred & gen");
205     }
206
207     LOG("before fred creation");
208     chaos randomizer;
209     amorph<byte_array> fred(MAX_LIMBS - 1);
210     fred.append(NULL_POINTER);  // add one to make it max limbs big.
211     LOG("after append nil");
212     {
213       for (int i = 0; i < fred.elements(); i++) {
214         int size = MIN_CHUBBY + randomizer.inclusive(0, MAX_RANDO);
215         astring text("bogus burfonium nuggets");
216         astring burph(astring::SPRINTF, " ung %d ", i);
217         text += burph;
218         abyte *temp = new abyte[size];
219         text.stuff((char *)temp, text.length()+1);
220         byte_array *to_stuff = new byte_array(size, temp);
221         fred.put(i, to_stuff);
222         delete [] temp;
223       }
224     }
225     LOG("after first loop");
226     {
227       amorph<byte_array> bungee3;
228       amorph_assign(bungee3, fred);
229       amorph<byte_array> burglar2;
230       amorph_assign(burglar2, bungee3);
231       amorph<byte_array> trunklid;
232       amorph_assign(trunklid, burglar2);
233       ASSERT_INEQUAL(trunklid.elements(), 0, "const constructor test - no elements!");
234     }
235     LOG("after copies performed");
236     {
237       astring text;
238       text = "hello this is part one.";
239       LOG(astring(astring::SPRINTF, "len is %d, content is %s",
240           text.length(), text.observe()));
241       char *tadr = text.access();
242       abyte *badr = (abyte *)tadr;
243       byte_array *to_stuff = new byte_array(text.length() + 1, badr);
244       fred.put(183, to_stuff);
245       text = "wonky tuniea bellowbop";
246       byte_array *to_stuff1 = new byte_array(text.length()+1, (abyte *)text.s());
247       fred.put(90, to_stuff1);
248
249       text = "frunkwioioio";
250       byte_array *to_stuff2 = new byte_array(text.length()+1, (abyte *)text.s());
251       fred.put(12, to_stuff2);
252
253       fred.clear(98); fred.clear(122); fred.clear(123);
254       fred.clear(256);
255       fred.clear(129);
256       fred.zap(82, 90);
257       fred.zap(93, 107);
258     }
259     LOG("after second loop");
260     {
261       byte_array packed = fake_pack(fred);
262       LOG(astring(astring::SPRINTF, "done packing in %s, pack has %d "
263           "elems.", class_name(), packed.length()));
264       amorph<byte_array> *new_fred = fake_amorph_unpack(packed);
265       LOG("done unpacking in test_amorph");
266       ASSERT_TRUE(compare(fred, *new_fred), "first pack test, amorphs not the same");
267       abyte *cont1
268         = (new_fred->get(14)? (*new_fred)[14]->access() : (abyte *)"NULL_POINTER");
269       abyte *cont2
270         = (new_fred->get(20)? (*new_fred)[20]->access() : (abyte *)"NULL_POINTER");
271       abyte *cont3
272         = (new_fred->get(36)? (*new_fred)[36]->access() : (abyte *)"NULL_POINTER");
273
274       if (cont1) LOG(astring(astring::SPRINTF, "14: %s", cont1));
275       if (cont2) LOG(astring(astring::SPRINTF, "20: %s", cont2));
276       if (cont3) LOG(astring(astring::SPRINTF, "36: %s", cont3));
277       LOG("fields all compare identically after pack and unpack");
278       byte_array packed_second = fake_pack(*new_fred);
279       delete new_fred;
280       amorph<byte_array> *newer_fred = fake_amorph_unpack(packed_second);
281       ASSERT_TRUE(compare(*newer_fred, fred), "second pack test, amorphs not the same");
282       delete newer_fred;
283     }
284
285     {
286       amorph<byte_array> fred(randomizer.inclusive(20, 30));
287       int size = MIN_CHUBBY + randomizer.inclusive(0, MAX_RANDO);
288       astring text("bogus burfonium nuggets");
289       astring burph(astring::SPRINTF, " ung %d ", 2314);
290       text += burph;
291       byte_array intermed(size);
292
293       for (int i = 0; i < fred.elements(); i += 5) {
294         byte_array *to_stuff = new byte_array(size, intermed.access());
295         memcpy(intermed.access(), (abyte *)text.s(), text.length() + 1);
296         fred.put(i, to_stuff);
297       }
298       fred.clear_all();
299       for (int j = 0; j < fred.elements(); j += 5) {
300         byte_array *to_stuff = new byte_array(size, intermed.access());
301         memcpy(intermed.access(), (abyte *)text.s(), text.length() + 1);
302         fred.put(j, to_stuff);
303       }
304       text = "frunkwioioio";
305       byte_array *to_stuff = new byte_array(text.length()+1, (abyte *)text.s());
306       fred.put(12, to_stuff);
307       fred.clear_all();
308     }
309     LOG("survived the clear_alls");
310     {
311       amorph<byte_array> *ted = new amorph<byte_array>(0);
312       amorph_assign(*ted, fred);
313       ASSERT_TRUE(compare(*ted, fred), "ted and fred aren't the same");
314       {
315         amorph<byte_array> *george = new amorph<byte_array>(0);
316         amorph_assign(*george, fred);
317         ASSERT_TRUE(compare(*george, fred), "fred and george aren't the same");
318         ted->zap(3, 20);
319         george->zap(3, 10);
320         george->zap(3, 12);
321         ASSERT_TRUE(compare(*ted, *george), "after zap, ted and george aren't the same");
322         ted->adjust(ted->elements() - 20);
323         george->adjust(george->elements() - 5);
324         george->adjust(george->elements() - 5);
325         george->adjust(george->elements() - 5);
326         george->adjust(george->elements() - 5);
327         ASSERT_TRUE(compare(*ted, *george), "after adjust, ted and george aren't the same");
328         delete george;
329       }
330       delete ted;
331     }
332   }
333   return 0;
334 }
335
336 int t_amorph::compare(const amorph<bogon> &one, const amorph<bogon> &two)
337 {
338   FUNCDEF("compare amorph<bogon>");
339   if (one.elements() != two.elements()) return false;
340   for (int i = 0; i < one.elements(); i++) {
341     if (!one.get(i) && !two.get(i)) continue;
342     ASSERT_FALSE(!one.get(i) || !two.get(i), "both should be non-nil");
343     ASSERT_EQUAL(one.get(i)->size(), two.get(i)->size(), "sizes should be equal");
344     if (one.get(i)->size() > 0) {
345       ASSERT_INEQUAL(one.get(i)->held(), two.get(i)->held(), "pointer should not be in use twice");
346       ASSERT_FALSE(memcmp(one.get(i)->held(), two.get(i)->held(), one.get(i)->size()),
347           "contents should be equal");
348     }
349   }
350   return true;
351 }
352
353 int t_amorph::test_bogon_amorph()
354 {
355   FUNCDEF("test_bogon_amorph");
356   LOG("start of amorph of bogon test");
357   for (int qq = 0; qq < default_test_iterations; qq++) {
358     LOG(astring(astring::SPRINTF, "index %d", qq));
359     {
360       // some simple creation and stuffing tests....
361       amorph<bogon> fred(20);
362       amorph<bogon> gen(10);
363       for (int i = 0; i < 10; i++)  {
364         bogon *gens = new bogon((abyte *)"goodbye");
365         gen.put(i, gens);
366       }
367       for (int j = 0; j < 20; j++)  {
368         bogon *freds = new bogon((abyte *)"hello");
369         fred.put(j, freds);
370       }
371       ASSERT_FALSE(compare(fred, gen), "fred and gen ARE the same");
372       amorph_assign(gen, fred);
373       ASSERT_TRUE(compare(fred, gen), "fred and gen aren't the same");
374     }
375
376     chaos randomizer;
377
378     amorph<bogon> fred(MAX_LIMBS);
379
380     LOG("after append nil");
381     {
382       for (int i = 0; i < fred.elements(); i++) {
383         int size = MIN_CHUBBY + randomizer.inclusive(0, MAX_RANDO);
384         astring text("bogus burfonium nuggets");
385         astring burph(astring::SPRINTF, " ung %d ", i);
386         text += burph;
387         abyte *temp = new abyte[size];
388         text.stuff((char *)temp, text.length()+1);
389         bogon *to_stuff = new bogon(temp);
390         fred.put(i, to_stuff);
391         delete [] temp;
392       }
393     }
394
395     LOG("after first loop");
396     {
397       amorph<bogon> bungee3;
398       amorph_assign(bungee3, fred);
399       amorph<bogon> burglar2;
400       amorph_assign(burglar2, bungee3);
401       amorph_assign(burglar2, bungee3);
402       amorph<bogon> trunklid;
403       amorph_assign(trunklid, burglar2);
404       ASSERT_TRUE(trunklid.elements(), "const constructor test: no elements!");
405     }
406     {
407       astring text;
408       text = "hello this is part one.";
409       bogon *to_stuff = new bogon((abyte *)text.s());
410       fred.put(32, to_stuff);
411
412       text = "wonky tuniea bellowbop";
413       bogon *to_stuff1 = new bogon((abyte *)text.s());
414       fred.put(84, to_stuff1);
415
416       text = "frunkwioioio";
417       bogon *to_stuff2 = new bogon((abyte *)text.s());
418       fred.put(27, to_stuff2);
419
420       fred.clear(98); fred.clear(122); fred.clear(123);
421       fred.clear(256);
422       fred.clear(129);
423       fred.zap(82, 90);
424       fred.zap(93, 107);
425     }
426     LOG("after second loop");
427     {
428       amorph<bogon> fred(randomizer.inclusive(20, 30));
429       astring text("bogus burfonium nuggets");
430       astring burph(astring::SPRINTF, " ung %d ", 2314);
431       text += burph;
432
433       for (int i = 0; i < fred.elements(); i += 5) {
434         bogon *to_stuff = new bogon((abyte *)text.s());
435         fred.put(i, to_stuff);
436       }
437       fred.clear_all();
438       for (int j = 0; j < fred.elements(); j += 5) {
439         bogon *to_stuff = new bogon((abyte *)text.s());
440         fred.put(j, to_stuff);
441       }
442       text = "frunkwioioio";
443       bogon *to_stuff = new bogon((abyte *)text.s());
444       fred.put(6, to_stuff);
445       fred.clear_all();
446     }
447     LOG("survived the clear_alls");
448     {
449       amorph<bogon> *ted = new amorph<bogon>();
450       amorph_assign(*ted, fred);
451       ASSERT_TRUE(compare(*ted, fred), "after assign, ted and fred aren't the same");
452       {
453         amorph<bogon> *george = new amorph<bogon>();
454         amorph_assign(*george, fred);
455         ASSERT_TRUE(compare(*george, fred), "pre-zap, george and fred aren't the same");
456         ted->zap(3, 20);
457         george->zap(3, 10);
458         george->zap(3, 12);
459         ASSERT_TRUE(compare(*ted, *george), "after zap, ted and george aren't the same");
460         ted->adjust(ted->elements()-20);
461         george->adjust(george->elements()-5);
462         george->adjust(george->elements()-5);
463         george->adjust(george->elements()-5);
464         george->adjust(george->elements()-5);
465         ASSERT_TRUE(compare(*ted, *george), "after more zaps, ted and george aren't the same");
466         delete george;
467       }
468       delete ted;
469     }
470   }
471   return 0;
472 }
473
474 const int MAX_TEST_DURATION = 1 * MINUTE_ms;
475   // each of the tests calling on the templated tester will take this long.
476
477 const int MAX_SIMULTANEOUS_OBJECTS = 42;  // the maximum length tested.
478
479 //hmmm: this test_amorph_of is not completed.
480
481 template <class contents>
482 int test_amorph_of(const contents &bogus)
483 {
484   chaos rando;
485
486   // these are the actions we try on the amorph during the test.
487   // the first and last elements must be identical to the first and last
488   // tests to perform.
489   enum actions { first, do_zap = first, do_adjust, do_assign,
490
491
492       do_borrow, last = do_borrow};
493
494   time_stamp exit_time(::MAX_TEST_DURATION);
495   while (time_stamp() < exit_time) {
496     int index = rando.inclusive(0, ::MAX_SIMULTANEOUS_OBJECTS - 1);
497     int choice = rando.inclusive(first, last);
498     switch (choice) {
499       case do_zap: {
500
501         break;
502       }
503       case do_adjust: {
504
505         break;
506       }
507       case do_assign: {
508
509         break;
510       }
511       case do_borrow: {
512
513         break;
514       }
515     }
516   }
517 }
518
519 int t_amorph::execute()
520 {
521   SETUP_COMBO_LOGGER;
522   int errs = 0;
523   int retval = test_byte_array_amorph();
524   if (retval != 0) errs += retval;
525   retval = test_bogon_amorph();
526   if (retval != 0) errs += retval;
527
528 //incorporate these errors somehow also.
529
530 //  if (retval == 0)
531 //    critical_events::alert_message("amorph:: works for those functions tested.");
532 //  else
533 //    critical_events::alert_message("amorph:: there were errors!");
534   return final_report();
535 }
536