feisty meow concerns codebase 2.140
test_amorph.cpp
Go to the documentation of this file.
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
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>
27#include <unit_test/unit_base.h>
28
29#include <memory.h>
30#include <stdlib.h>
31
32using namespace application;
33using namespace basis;
34using namespace mathematics;
35using namespace filesystem;
36using namespace loggers;
37using namespace structures;
38using namespace textual;
39using namespace timely;
40using 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
58
59class t_amorph : virtual public unit_base, virtual public application_shell
60{
61public:
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
78HOOPLE_MAIN(t_amorph, );
79
81
83
84const int MAX_LIMBS = 200;
85 // the highest number of items stored in the amorphs here.
86
87const int MIN_CHUBBY = 60;
88 // the smallest chunk to allocate for storing text strings... all strings
89 // must therefore be shorter than this length.
90const 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
95int 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
115byte_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
163amorph<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
185int 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");
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 {
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
336int 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
353int 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
377
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
475 // each of the tests calling on the templated tester will take this long.
476
477const int MAX_SIMULTANEOUS_OBJECTS = 42; // the maximum length tested.
478
479//hmmm: this test_amorph_of is not completed.
480
481template <class contents>
482int 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
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 return 0;
518}
519
520int t_amorph::execute()
521{
523 int errs = 0;
524 int retval = test_byte_array_amorph();
525 if (retval != 0) errs += retval;
526 retval = test_bogon_amorph();
527 if (retval != 0) errs += retval;
528
529//incorporate these errors somehow also.
530
531// if (retval == 0)
532// critical_events::alert_message("amorph:: works for those functions tested.");
533// else
534// critical_events::alert_message("amorph:: there were errors!");
535 return final_report();
536}
537
The application_shell is a base object for console programs.
virtual int execute()=0
< retrieves the command line from the /proc hierarchy on linux.
contents * access()
A non-constant access of the underlying C-array. BE REALLY CAREFUL.
Definition array.h:175
int length() const
Returns the current reported length of the allocated C array.
Definition array.h:115
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition astring.h:113
void stuff(char *to_stuff, int count) const
a synonym for copy().
Definition astring.h:216
int length() const
Returns the current length of the string.
Definition astring.cpp:132
virtual char * access()
provides access to the actual string held.
Definition astring.cpp:136
virtual const char * observe() const
observes the underlying pointer to the zero-terminated string.
Definition astring.cpp:140
A very common template for a dynamic array of bytes.
Definition byte_array.h:36
Definition bogon.h:30
a platform-independent way to acquire random numbers in a specific range.
Definition chaos.h:51
int inclusive(int low, int high) const
< Returns a pseudo-random number r, such that "low" <= r <= "high".
Definition chaos.h:88
int elements() const
the maximum number of elements currently allowed in this amorph.
Definition amorph.h:66
basis::outcome put(int field, const contents *data)
Enters an object into the field at index "field" in the amorph.
Definition amorph.h:370
basis::outcome zap(int start, int end)
Removes a range of indices from the amorph.
Definition amorph.h:357
void adjust(int new_max)
Changes the maximum number of elements for this amorph.
Definition amorph.h:321
const contents * get(int field) const
Returns a constant pointer to the information at the index "field".
Definition amorph.h:312
int valid_fields() const
Returns the number of fields that have non-null contents.
Definition amorph.h:69
Represents a point in time relative to the operating system startup time.
Definition time_stamp.h:38
#define SETUP_COMBO_LOGGER
a macro that retasks the program-wide logger as a combo_logger.
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
Definition enhance_cpp.h:42
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
Provides macros that implement the 'main' program of an application.
#define HOOPLE_MAIN(obj_name, obj_args)
options that should work for most unix and linux apps.
Definition hoople_main.h:61
Implements an application lock to ensure only one is running at once.
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
unsigned char abyte
A fairly important unit which is seldom defined...
Definition definitions.h:51
void attach(byte_array &packed_form, const char *to_attach)
Packs a character string "to_attach" into "packed_form".
Definition astring.cpp:1018
bool detach(byte_array &packed_form, astring &to_detach)
Unpacks a character string "to_attach" from "packed_form".
Definition astring.cpp:1026
const int MINUTE_ms
Number of milliseconds in a minute.
A platform independent way to obtain the timestamp of a file.
A logger that sends to the console screen using the standard output device.
An extension to floating point primitives providing approximate equality.
Definition averager.h:21
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
void amorph_assign(amorph< contents > &to_assign, const amorph< contents > &to_copy)
This can be used when the templated object has a copy constructor.
Definition amorph.h:503
#include <time.h>
Useful support functions for unit testing, especially within hoople.
Definition unit_base.cpp:35
#define PACK_BLOB_SIZE(max_limbs)
const int MAX_SIMULTANEOUS_OBJECTS
const int MIN_CHUBBY
const int MAX_TEST_DURATION
const int default_test_iterations
const int MAX_RANDO
#define LOG(to_print)
const int MAX_LIMBS
int test_amorph_of(const contents &bogus)
#define randomizer()
chaos rando
#define ASSERT_EQUAL(a, b, test_name)
Definition unit_base.h:38
#define ASSERT_TRUE(a, test_name)
Definition unit_base.h:46
#define ASSERT_FALSE(a, test_name)
Definition unit_base.h:50
#define ASSERT_INEQUAL(a, b, test_name)
Definition unit_base.h:42