2 * Name : test_byte_array_amorph
3 * Author : Chris Koeritz
5 * Puts the amorph object through its paces.
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 *
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>
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;
43 // uncomment to enable array debugging.
46 // uncomment to enable amorph debugging.
48 //#define DEBUG_TEST_AMORPH
49 // uncomment for this program to be noisier.
51 #ifdef DEBUG_TEST_AMORPH
52 #define LOG(to_print) EMERGENCY_LOG(program_wide_logger::get(), to_print)
54 #define LOG(to_print) {}
59 class t_amorph : virtual public unit_base, virtual public application_shell
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);
71 struct blob_hold { int size; int offset; };
73 virtual int execute();
76 #define PACK_BLOB_SIZE(max_limbs) (max_limbs * sizeof(blob_hold))
78 HOOPLE_MAIN(t_amorph, );
82 const int default_test_iterations = 2;
84 const int MAX_LIMBS = 200;
85 // the highest number of items stored in the amorphs here.
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.
93 #define PROGRAM_NAME astring("test_amorph")
95 int t_amorph::compare(amorph<byte_array> &one, amorph<byte_array> &two)
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()),
115 byte_array t_amorph::fake_pack(amorph<byte_array> &me)
117 FUNCDEF("fake_pack");
118 // snagged from the packable_amorph pack function!
119 // count the whole size needed to store the amorph.
121 amorph<byte_array> hold_packed_bits(me.elements());
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();
131 int len = amo_size + sizeof(int) + PACK_BLOB_SIZE(me.elements());
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.
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());
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.
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();
159 ASSERT_EQUAL(current_offset, len, "offset is incorrect after packing");
163 amorph<byte_array> *t_amorph::fake_amorph_unpack(byte_array &packed_amorph)
165 // snagged from the packable_amorph unpack function!
167 memcpy(&max_limbs, (int *)packed_amorph.access(), sizeof(max_limbs));
168 amorph<byte_array> *to_return = new amorph<byte_array>(max_limbs);
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);
181 delete [] blob_array;
185 int t_amorph::test_byte_array_amorph()
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));
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");
199 for (int j = 0; j < 20; j++) {
200 byte_array *freds = new byte_array(6, (abyte *)"hello");
203 amorph_assign(gen, fred);
204 LOG("done with fred & gen");
207 LOG("before fred creation");
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");
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);
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);
225 LOG("after first loop");
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!");
235 LOG("after copies performed");
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);
249 text = "frunkwioioio";
250 byte_array *to_stuff2 = new byte_array(text.length()+1, (abyte *)text.s());
251 fred.put(12, to_stuff2);
253 fred.clear(98); fred.clear(122); fred.clear(123);
259 LOG("after second loop");
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");
268 = (new_fred->get(14)? (*new_fred)[14]->access() : (abyte *)"NULL_POINTER");
270 = (new_fred->get(20)? (*new_fred)[20]->access() : (abyte *)"NULL_POINTER");
272 = (new_fred->get(36)? (*new_fred)[36]->access() : (abyte *)"NULL_POINTER");
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);
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");
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);
291 byte_array intermed(size);
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);
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);
304 text = "frunkwioioio";
305 byte_array *to_stuff = new byte_array(text.length()+1, (abyte *)text.s());
306 fred.put(12, to_stuff);
309 LOG("survived the clear_alls");
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");
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");
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");
336 int t_amorph::compare(const amorph<bogon> &one, const amorph<bogon> &two)
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");
353 int t_amorph::test_bogon_amorph()
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));
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");
367 for (int j = 0; j < 20; j++) {
368 bogon *freds = new bogon((abyte *)"hello");
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");
378 amorph<bogon> fred(MAX_LIMBS);
380 LOG("after append nil");
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);
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);
395 LOG("after first loop");
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!");
408 text = "hello this is part one.";
409 bogon *to_stuff = new bogon((abyte *)text.s());
410 fred.put(32, to_stuff);
412 text = "wonky tuniea bellowbop";
413 bogon *to_stuff1 = new bogon((abyte *)text.s());
414 fred.put(84, to_stuff1);
416 text = "frunkwioioio";
417 bogon *to_stuff2 = new bogon((abyte *)text.s());
418 fred.put(27, to_stuff2);
420 fred.clear(98); fred.clear(122); fred.clear(123);
426 LOG("after second loop");
428 amorph<bogon> fred(randomizer.inclusive(20, 30));
429 astring text("bogus burfonium nuggets");
430 astring burph(astring::SPRINTF, " ung %d ", 2314);
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);
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);
442 text = "frunkwioioio";
443 bogon *to_stuff = new bogon((abyte *)text.s());
444 fred.put(6, to_stuff);
447 LOG("survived the clear_alls");
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");
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");
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");
474 const int MAX_TEST_DURATION = 1 * MINUTE_ms;
475 // each of the tests calling on the templated tester will take this long.
477 const int MAX_SIMULTANEOUS_OBJECTS = 42; // the maximum length tested.
479 //hmmm: this test_amorph_of is not completed.
481 template <class contents>
482 int test_amorph_of(const contents &bogus)
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
489 enum actions { first, do_zap = first, do_adjust, do_assign,
492 do_borrow, last = do_borrow};
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);
519 int t_amorph::execute()
523 int retval = test_byte_array_amorph();
524 if (retval != 0) errs += retval;
525 retval = test_bogon_amorph();
526 if (retval != 0) errs += retval;
528 //incorporate these errors somehow also.
531 // critical_events::alert_message("amorph:: works for those functions tested.");
533 // critical_events::alert_message("amorph:: there were errors!");
534 return final_report();