feisty meow concerns codebase 2.140
test_array.cpp
Go to the documentation of this file.
1/*****************************************************************************\
2* *
3* Name : test_array *
4* Author : Chris Koeritz *
5* *
6*******************************************************************************
7* Copyright (c) 1991-$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//#define DEBUG_ARRAY
16 // when this flag is turned on, extra checking will be done in the allocator.
17
19#include <basis/array.h>
20#include <basis/byte_array.h>
21#include <basis/enhance_cpp.h>
22#include <basis/functions.h>
23#include <basis/astring.h>
26#include <mathematics/chaos.h>
28#include <timely/time_stamp.h>
29#include <unit_test/unit_base.h>
30
32
33using namespace application;
34using namespace basis;
35using namespace loggers;
36using namespace mathematics;
37using namespace timely;
38using namespace unit_test;
39
40//const float MAX_TEST_DURATION_ms = 28 * SECOND_ms;
41const float MAX_TEST_DURATION_ms = 200;
42 // each of the tests calling on the templated tester will take this long.
43
44const int MAX_SIMULTANEOUS_OBJECTS = 42; // the maximum arrays tested.
45
46const int MIN_OBJECT = -30; // the smallest array we'll create.
47const int MAX_OBJECT = 98; // the largest array we'll create.
48
49const int MIN_BLOCK = 100; // the smallest exemplar we'll use.
50const int MAX_BLOCK = MAX_OBJECT * 2; // the largest exempler.
51
52//#define DEBUG_TEST_ARRAY
53 // uncomment for noisy version.
54
55#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
56
57static chaos a_randomizer;
58
60
61class test_array : public application_shell, public unit_base
62{
63public:
64 test_array()
66 unit_base()
67 {
68//hmmm: should go into app shell
70}
71 DEFINE_CLASS_NAME("test_array");
72 virtual int execute();
73 void dump_array(array<void *> &ar, const char *name);
74 void test_arrays_of_void_pointer();
75 void test_iteration_speed();
76
77 template <class contents>
78 void array_tester(test_array &ta, const contents &formal(bogus), basis::un_short flags);
79
80};
81
83
84void test_array::dump_array(array<void *> &ar, const char *name)
85{
86#ifdef DEBUG_TEST_ARRAY
87 FUNCDEF("dump_array");
88 LOG(a_sprintf("array named \"%s\" has:", name));
89 for (int i = 0; i < ar.length(); i++) {
90 LOG(a_sprintf("\t%4d: %d", i, (int)ar[i]));
91 }
92#else
93 if (ar.length() && name) {}
94#endif
95}
96
97void test_array::test_arrays_of_void_pointer()
98{
99 FUNCDEF("void pointer test");
100 const int MAX_VOID_ARRAY = 20;
101 array<void *> argh(MAX_VOID_ARRAY, NULL_POINTER, byte_array::SIMPLE_COPY
102 | byte_array::EXPONE | byte_array::FLUSH_INVISIBLE);
103 array<void *> argh2(argh);
104 ASSERT_EQUAL(argh.length(), MAX_VOID_ARRAY, "check first array length");
105 ASSERT_EQUAL(argh2.length(), MAX_VOID_ARRAY, "check copied array length");
106 int wrong_counter = 0;
107 for (int o = 0; o < MAX_VOID_ARRAY; o++)
108 if (argh[o] != argh2[o]) wrong_counter++;
109 ASSERT_EQUAL(wrong_counter, 0, "compare array contents");
110
111 // fill it with values.
112 int starter;
113 for (int i = 0; i < MAX_VOID_ARRAY; i++)
114 argh[i] = (void *)(&starter + i);
115 dump_array(argh, "first version");
116
117 // check the values.
118 wrong_counter = 0;
119 for (int j = 0; j < MAX_VOID_ARRAY; j++)
120 if (argh[j] != (void *)(&starter + j) ) wrong_counter++;
121 ASSERT_EQUAL(wrong_counter, 0, "compare values that were set");
122
123 // add a constant to the values.
124 for (int k = 0; k < MAX_VOID_ARRAY; k++)
125 argh[k] = (void *)((int *)argh[k] + 23);
126 dump_array(argh, "second version");
127
128 // check assignment.
129 argh2 = argh;
130 wrong_counter = 0;
131 for (int n = 0; n < MAX_VOID_ARRAY; n++)
132 if (argh2[n] != (void *)(&starter + n + 23)) wrong_counter++;
133 ASSERT_EQUAL(wrong_counter, 0, "compare values that were assigned");
134
135 // now test that values are kept in place after rearrangement.
136 argh.zap(3, 4);
137 dump_array(argh, "third version");
138 wrong_counter = 0;
139 for (int l = 0; l < 3; l++)
140 if (argh[l] != (void *)(&starter + l + 23)) wrong_counter++;
141 ASSERT_EQUAL(wrong_counter, 0, "zap low values test");
142 wrong_counter = 0;
143 for (int m = 3; m < MAX_VOID_ARRAY - 2; m++)
144 if (argh[m] != (void *)(&starter + m + 2 + 23)) wrong_counter++;
145 ASSERT_EQUAL(wrong_counter, 0, "zap high values test");
146//hmmm: add more tests if void pointer arrays seem in question.
147}
148
150
151static astring blank_string;
152
153// jethro is a simple object for containment below.
154class jethro
155{
156public:
157 jethro(const astring &i = blank_string) : _truck(i) {}
158
159 astring _truck;
160
161 bool operator ==(const jethro &tc) const { return tc._truck == _truck; }
162};
163
165
166// the test_content object is an object with proper copy constructor
167// and assignment operator that also has deep contents.
168class test_content
169{
170public:
171 abyte _q;
172 astring _ted;
173 astring _jed;
174 int_array _ned;
175
176 test_content(abyte q = 3)
177 : _q(q), _ted("bl"), _jed("orp"),
178 _ned(12, NULL_POINTER)
179/* _med(3, 2),
180 _red(2, 4) */
181 {
182 for (int i = 0; i < _ned.length(); i++)
183 _ned[i] = -i;
184/*
185 for (int r = 0; r < _med.rows(); r++)
186 for (int c = 0; c < _med.columns(); c++)
187 _med[r][c] = jethro(astring((r*c) % 256, 1));
188 for (int j = 0; j < _red.rows(); j++)
189 for (int k = 0; k < _red.columns(); k++)
190 _red[j][k] = j * k;
191*/
192 }
193
194 bool operator ==(const test_content &tc) const {
195 if (tc._q != _q) return false;
196 if (tc._ted != _ted) return false;
197 if (tc._jed != _jed) return false;
198 if (tc._ned.length() != _ned.length()) return false;
199 for (int i = 0; i < _ned.length(); i++)
200 if (tc._ned[i] != _ned[i]) return false;
201
202/*
203 if (tc._med.rows() != _med.rows()) return false;
204 if (tc._med.columns() != _med.columns()) return false;
205 for (int c = 0; c < _med.columns(); c++)
206 for (int r = 0; r < _med.rows(); r++)
207 if (tc._med.get(r, c) != _med.get(r, c)) return false;
208
209 if (tc._red.rows() != _red.rows()) return false;
210 if (tc._red.columns() != _red.columns()) return false;
211 for (int j = 0; j < _red.rows(); j++)
212 for (int k = 0; k < _red.columns(); k++)
213 if (tc._red.get(j, k) != _red.get(j, k)) return false;
214*/
215
216 return true;
217 }
218
219 operator abyte() const { return _q; }
220};
221
223
224template <class contents>
226{
227 if (a.length() != b.length()) return false;
228 for (int i = 0; i < a.length(); i++)
229 if (a[i] != b[i]) return false;
230 return true;
231}
232
234
235// this is a templated test for arrays, with some requirements. the contents
236// object must support a constructor that takes a simple byte, whether
237// that's meaningful for the object or not. if your type to test doesn't
238// have that, derive a simple object from it, give it that constructor, and
239// then it can be used below. the object must also support comparison with
240// == and != for this test to be used. it must also provide a conversion
241// to integer that returns the value passed to the constructor.
242
243template <class contents>
244void test_array::array_tester(test_array &ta, const contents &formal(bogus), basis::un_short flags)
245{
246 FUNCDEF("array_tester");
247 // the space that all training for arrays comes from.
248 contents *junk_space = new contents[MAX_OBJECT + MAX_BLOCK];
249 for (int i = 0; i < MAX_OBJECT - 1; i++)
250 junk_space[i] = contents(a_randomizer.inclusive('a', 'z'));
251 junk_space[MAX_OBJECT + MAX_BLOCK - 1] = '\0';
252
254 for (int c = 0; c < MAX_SIMULTANEOUS_OBJECTS; c++) {
255 // set up the initial array guys.
256 testers[c] = new array<contents>(a_randomizer.inclusive(MIN_OBJECT, MAX_OBJECT),
257 NULL_POINTER, flags);
258 // copy the randomized junk space into the new object.
259 for (int i = 0; i < testers[c]->length(); i++)
260 testers[c]->put(i, junk_space[i]);
261 }
262
263 // these are the actions we try out with the array during the test.
264 // the first and last elements must be identical to the first and last
265 // tests to perform.
266 enum actions { first, do_train = first, do_size, do_assign,
267 do_access, do_zap, do_resizer, do_shrink, do_reset, do_indices,
268 do_concatenating, do_concatenating2, do_subarray, do_insert,
269 do_overwrite, do_stuff, do_memory_paring, do_snarf, do_flush,
270 do_observe, last = do_observe };
271
273 while (time_stamp() < exit_time) {
274 int index = a_randomizer.inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
275 int choice = a_randomizer.inclusive(first, last);
276 switch (choice) {
277 case do_train: {
278#ifdef DEBUG_TEST_ARRAY
279 LOG(a_sprintf("do_train"));
280#endif
281 int new_size = a_randomizer.inclusive(MIN_OBJECT, MAX_OBJECT);
282 testers[index]->retrain(new_size, (contents *)junk_space);
283 int wrong_counter = 0;
284 for (int i = 0; i < new_size; i++)
285 if (junk_space[i] != (*testers[index])[i]) wrong_counter++;
286 ASSERT_EQUAL(wrong_counter, 0, "test contents after retrain");
287 break;
288 }
289 case do_size: {
290#ifdef DEBUG_TEST_ARRAY
291 LOG(a_sprintf("do_size"));
292#endif
293 array<contents> old_version = *testers[index];
294 bool at_front = bool(a_randomizer.inclusive(0, 1));
295 int new_size = a_randomizer.inclusive(MIN_OBJECT, MAX_OBJECT);
296 bool smaller = new_size < old_version.length();
297 int difference = absolute_value(new_size - old_version.length());
298 testers[index]->resize(new_size,
299 at_front? old_version.NEW_AT_BEGINNING
300 : old_version.NEW_AT_END);
301 if (!smaller && difference) {
302 // neuter the contents in the new section so we can compare. this
303 // space is filled with whatever the object's constructor chooses.
304 if (at_front) {
305 for (int i = 0; i < difference; i++)
306 testers[index]->put(i, 'Q');
307 } else {
308 for (int i = old_version.length();
309 i < old_version.length() + difference; i++)
310 testers[index]->put(i, 'Q');
311 }
312 }
313 // now compute an equivalent form of what the state should be.
314 array<contents> equivalent(0, NULL_POINTER, flags);
315 if (at_front) {
316 if (smaller) {
317 equivalent = old_version.subarray(difference,
318 old_version.length() - 1);
319 } else {
320 array<contents> blank(difference, NULL_POINTER, flags);
321 for (int i = 0; i < blank.length(); i++)
322 blank[i] = 'Q';
323 equivalent = blank + old_version;
324 }
325 } else {
326 if (smaller) {
327 equivalent = old_version.subarray(0, old_version.length()
328 - difference - 1);
329 } else {
330 array<contents> blank(difference, NULL_POINTER, flags);
331 for (int i = 0; i < blank.length(); i++)
332 blank[i] = 'Q';
333 equivalent = old_version + blank;
334 }
335 }
336 ASSERT_EQUAL(equivalent.length(), testers[index]->length(),
337 "check length of resized form");
338 ASSERT_TRUE(compare_arrays(*testers[index], equivalent),
339 "check contents of resized form");
340 break;
341 }
342 case do_assign: {
343#ifdef DEBUG_TEST_ARRAY
344 LOG(a_sprintf("do_assign"));
345#endif
346 array<contents> arrh = *testers[index]; // copy old value.
347 int to_assign = a_randomizer.inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
348 *testers[index] = *testers[to_assign];
349 ASSERT_TRUE(compare_arrays(*testers[index], *testers[to_assign]),
350 "check result of assign copying array");
351 *testers[to_assign] = arrh; // recopy contents to new place.
352 ASSERT_TRUE(compare_arrays(*testers[to_assign], arrh),
353 "check result of second assign");
354 break;
355 }
356 case do_access: {
357#ifdef DEBUG_TEST_ARRAY
358 LOG(a_sprintf("do_access"));
359#endif
360 int start = a_randomizer.inclusive(0, testers[index]->length());
361 int end = a_randomizer.inclusive(0, testers[index]->length());
362 flip_increasing(start, end);
363 array<contents> accumulator(0, NULL_POINTER, flags);
364 for (int i = start; i < end; i++) {
365 contents c = contents(a_randomizer.inclusive(1, 255));
366 testers[index]->access()[i] = c;
367 accumulator += c;
368 }
369 for (int j = start; j < end; j++)
370 ASSERT_EQUAL(accumulator[j - start], (*testers[index])[j],
371 "comparison accessing at index must be equal");
372 break;
373 }
374 case do_indices: {
375#ifndef CATCH_ERRORS // only works if not catching errors.
376 #ifdef DEBUG_TEST_ARRAY
377 LOG(a_sprintf("do_indices"));
378 #endif
379 // does some tests on bad indices.
380 contents c1 = testers[index]->operator[](-50);
381 contents c2 = testers[index]->operator[](-MAX_OBJECT);
382 bool test = (c1 == c2);
383 ASSERT_TRUE(test, "invalid values should be the same");
384 int tests = a_randomizer.inclusive(100, 500);
385 for (int i = 0; i < tests; i++) {
386 int indy = a_randomizer.inclusive(-1000, MAX_OBJECT * 3);
387 // testing if we can access without explosions.
388 contents c3 = testers[index]->operator[](indy);
389 contents c4 = c3;
390 ASSERT_EQUAL(c3, c4, "for do_indices, values should be the same");
391 }
392#endif
393 break;
394 }
395 case do_observe: {
396#ifdef DEBUG_TEST_ARRAY
397 LOG(a_sprintf("do_observe"));
398#endif
399 // tests contents returned by observe.
400 int start = a_randomizer.inclusive(0, testers[index]->length());
401 int end = a_randomizer.inclusive(0, testers[index]->length());
402 flip_increasing(start, end);
403 double total_1 = 0;
404 for (int i = start; i < end; i++)
405 total_1 += testers[index]->observe()[i];
406 double total_2 = 0;
407 for (int j = end - 1; j >= start; j--)
408 total_2 += testers[index]->observe()[j];
409 ASSERT_EQUAL(total_1, total_2, "totals should match up");
410 break;
411 }
412 case do_resizer: {
413#ifdef DEBUG_TEST_ARRAY
414 LOG(a_sprintf("do_resizer"));
415#endif
416 // tests whether the array will reuse space when it should be able to.
417 array<contents> &arrh = *testers[index];
418 // fill with known data.
419 int i;
420 for (i = 0; i < arrh.length(); i++)
421 arrh[i] = contents((i + 23) % 256);
422 // record the old starting point.
423 const contents *start = arrh.internal_block_start();
424 int zap_amount = a_randomizer.inclusive(1, arrh.length() - 1);
425 // now take out a chunk from the array at the beginning.
426 arrh.zap(0, zap_amount - 1);
427 // test the contents.
428 for (i = 0; i < arrh.length(); i++)
429 ASSERT_EQUAL(arrh[i], contents((i + 23 + zap_amount) % 256),
430 "the resized form should have same contents after zap");
431 // now add back in the space we ate.
432 arrh.resize(arrh.length() + zap_amount, arrh.NEW_AT_END);
433 // check the pointer; it should not have changed.
435 "the resized form should have same start address");
436 // test the contents again. they should start at zero and have the
437 // same zap_amount offset. the stuff past the original point shouldn't
438 // be tested since we haven't set it.
439 for (i = 0; i < arrh.length() - zap_amount; i++)
440 ASSERT_EQUAL(arrh[i], contents((i + 23 + zap_amount) % 256),
441 "the resized form should still have same contents");
442 // now a test of all values through the zap_amount.
443 arrh.zap(0, zap_amount - 1);
444 for (i = 0; i < zap_amount; i++) {
445 arrh.resize(arrh.length() + 1, arrh.NEW_AT_END);
447 "the slowly resized form should have same start address");
448 }
449 // test the contents once more. they should start at zero and have
450 // double the zap_amount offset. the stuff past the original point
451 // shouldn't be tested since we haven't set it.
452 for (i = 0; i < arrh.length() - 2 * zap_amount; i++)
453 ASSERT_EQUAL(arrh[i], contents((i + 23 + 2 * zap_amount) % 256),
454 "the slowly resized form should have same contents");
455
456 // the tests below should be nearly identical to the ones above, but
457 // they use the NEW_AT_BEGINNING style of copying.
458
459 // fill with known data.
460 for (i = 0; i < arrh.length(); i++)
461 arrh[i] = contents((i + 23) % 256);
462 // record the old starting point.
463 start = arrh.internal_block_start();
464 zap_amount = a_randomizer.inclusive(1, arrh.length() - 1);
465 // now take out a chunk from the array at the beginning.
466 arrh.zap(0, zap_amount - 1);
467 // test the contents.
468 for (i = 0; i < arrh.length(); i++)
469 ASSERT_EQUAL(arrh[i], contents((i + 23 + zap_amount) % 256),
470 "the resized form with known data should have right contents");
471 // now add back in the space we ate.
472 arrh.resize(arrh.length() + zap_amount,
473 arrh.NEW_AT_BEGINNING);
474 // check the pointer; it should not have changed.
476 "the resized form with known data should have same start address");
477 // test the contents again. they should start at zap_amount but have
478 // the same zap_amount offset. the stuff before the original point
479 // shouldn't be tested since we haven't set it.
480 for (i = zap_amount; i < arrh.length(); i++)
481 ASSERT_EQUAL(arrh[i], contents((i + 23) % 256),
482 "the known data resized form should have same contents");
483 // now a test of all values through the zap_amount.
484 arrh.zap(0, zap_amount - 1);
485 for (i = 0; i < zap_amount; i++) {
486 arrh.resize(arrh.length() + 1, arrh.NEW_AT_BEGINNING);
488 "the known data slowly resized form should have same start address");
489 }
490 // test the contents once more. the zap_amount offset should stay the
491 // same since we clobbered the place we added originally, then added
492 // more space in. so we skip the first part still.
493 for (i = zap_amount; i < arrh.length(); i++)
494 ASSERT_EQUAL(arrh[i], contents((i + 23) % 256),
495 "the known data slowly resized form should have same contents");
496 break;
497 }
498 case do_zap: {
499#ifdef DEBUG_TEST_ARRAY
500 LOG(a_sprintf("do_zap"));
501#endif
502 int start;
503 int end;
504 bool erroneous = false;
505 int chose = a_randomizer.inclusive(1, 100);
506 if (chose <= 90) {
507 // there's a ninety percent chance we pick a range that's valid.
508 start = a_randomizer.inclusive(0, testers[index]->length() - 1);
509 end = a_randomizer.inclusive(0, testers[index]->length() - 1);
510 } else if (chose <= 95) {
511 // and a 5 percent chance we pick to choose the zero index as our
512 // start; this gets at the code for fast zapping.
513 start = 0;
514 end = a_randomizer.inclusive(0, testers[index]->length() - 1);
515 } else {
516 // and a 5 percent chance we'll allow picking a bad index. the
517 // actual chance of picking a bad one is less.
518 erroneous = true;
519 start = a_randomizer.inclusive(-2, testers[index]->length() + 3);
520 end = a_randomizer.inclusive(-2, testers[index]->length() + 3);
521 }
522 flip_increasing(start, end);
523 array<contents> old_version = *testers[index];
524 testers[index]->zap(start, end);
525 if (!erroneous) {
526 array<contents> old_head = old_version.subarray(0, start - 1);
527 array<contents> old_tail = old_version.subarray(end + 1,
528 old_version.length() - 1);
529 array<contents> equivalent = old_head + old_tail;
530 ASSERT_EQUAL(equivalent.length(), testers[index]->length(),
531 "the zapped form should not have erroneous length");
532 ASSERT_TRUE(compare_arrays(*testers[index], equivalent),
533 "the zapped form should not have erroneous contents");
534 }
535 break;
536 }
537 case do_reset: {
538#ifdef DEBUG_TEST_ARRAY
539 LOG(a_sprintf("do_reset"));
540#endif
541 int junk_start = a_randomizer.inclusive(MIN_BLOCK, MAX_BLOCK);
542 int junk_end = a_randomizer.inclusive(MIN_BLOCK, MAX_BLOCK);
543 flip_increasing(junk_start, junk_end);
544 int len = junk_end - junk_start + 1;
545 testers[index]->reset(len, (contents *)&junk_space[junk_start]);
546 ASSERT_EQUAL(testers[index]->length(), len, "reset should have proper length");
547 for (int i = 0; i < len; i++)
548 ASSERT_EQUAL(testers[index]->get(i), junk_space[junk_start + i],
549 "reset should copy data");
550 break;
551 }
552 case do_shrink: {
553#ifdef DEBUG_TEST_ARRAY
554 LOG(a_sprintf("do_shrink"));
555#endif
556 array<contents> garp = *testers[index];
557 testers[index]->shrink();
558 int new_diff = testers[index]->internal_real_length()
559 - testers[index]->length();
560 ASSERT_TRUE(compare_arrays(garp, *testers[index]), "shrink should keep contents");
561 // now force a real shrinkage.
562 if (testers[index]->length() < 5) continue; // need some room.
563 // pick an element to keep that is not first or last.
564 int kept = a_randomizer.inclusive(1, testers[index]->last() - 1);
565 // whack all but the lucky element.
566 testers[index]->zap(kept + 1, testers[index]->last());
567 testers[index]->zap(0, kept - 1);
568 // shrink it again, now a big shrink.
569 testers[index]->shrink();
570 // check the difference now.
571 new_diff = testers[index]->internal_real_length()
572 - testers[index]->length();
573 ASSERT_FALSE(new_diff > 1, "massive shrink size should be correct");
574
575 // restore the original contents and block size.
576 *testers[index] = garp;
577 break;
578 }
579 case do_concatenating: {
580#ifdef DEBUG_TEST_ARRAY
581 LOG(a_sprintf("do_concatenating"));
582#endif
583 for (int i = 0; i < a_randomizer.inclusive(1, 20); i++) {
584 contents new_c = contents(a_randomizer.inclusive('a', 'z'));
585 testers[index]->concatenate(new_c);
586 ASSERT_EQUAL(new_c, testers[index]->get(testers[index]->last()),
587 "value should be equal after concatenate");
588 }
589 int indy = a_randomizer.inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
590 array<contents> flirpan = *testers[indy];
591 int start = a_randomizer.inclusive(0, flirpan.length() - 1);
592 int end = a_randomizer.inclusive(0, flirpan.length() - 1);
593 flip_increasing(start, end);
594 flirpan = flirpan.subarray(start, end);
595 array<contents> grumzor = *testers[index]; // old copy.
596 testers[index]->concatenate(flirpan);
597 array<contents> bubula = grumzor + flirpan;
598 ASSERT_TRUE(compare_arrays(bubula, *testers[index]),
599 "contents should be correct after concatenate or concatenation");
600 contents first_value;
601 contents second_value;
602 if (testers[index]->length() >= 1)
603 first_value = testers[index]->get(0);
604 if (testers[index]->length() >= 2)
605 second_value = testers[index]->get(1);
606 const int max_iters = a_randomizer.inclusive(1, 42);
607 for (int j = 0; j < max_iters; j++) {
608 contents new_c = contents(a_randomizer.inclusive('a', 'z'));
609 *testers[index] = *testers[index] + new_c;
610 // correct our value checks if new indices became available.
611 if (testers[index]->length() == 1) {
612 first_value = testers[index]->get(0);
613 } else if (testers[index]->length() == 2) {
614 second_value = testers[index]->get(1);
615 }
616
617 ASSERT_EQUAL(new_c, testers[index]->get(testers[index]->last()),
618 "value should not be wrong after concatenation");
619
620 ASSERT_FALSE((testers[index]->length() >= 1) && (first_value != testers[index]->get(0)),
621 "first value should not be corrupted");
622 ASSERT_FALSE((testers[index]->length() >= 2) && (second_value != testers[index]->get(1)),
623 "second value should not be corrupted");
624
625 *testers[index] += new_c;
626 // we don't have to correct the first value any more, but might have
627 // to correct the second.
628 if (testers[index]->length() == 2) {
629 second_value = testers[index]->get(1);
630 }
631 ASSERT_EQUAL(new_c, testers[index]->get(testers[index]->last()),
632 "value should be right after second concatenation");
633 ASSERT_FALSE( (testers[index]->length() >= 1) && (first_value != testers[index]->get(0)),
634 "first value should be uncorrupted after second concat");
635 ASSERT_FALSE((testers[index]->length() >= 2) && (second_value != testers[index]->get(1)),
636 "second value should be uncorrupted after second concat");
637 }
638 break;
639 }
640 case do_concatenating2: {
641 // this tests the new concatenate content array method for array.
642#ifdef DEBUG_TEST_ARRAY
643 LOG(a_sprintf("do_concatenating2"));
644#endif
645 array<contents> &flirpan = *testers[index];
646 int new_len = a_randomizer.inclusive(0, 140);
647 contents *to_add = new contents[new_len];
648 for (int i = 0; i < new_len; i++) {
649 int rando = a_randomizer.inclusive(0, MAX_BLOCK - 1);
650 to_add[i] = junk_space[rando];
651 }
652 int old_len = flirpan.length();
653 flirpan.concatenate(to_add, new_len);
654 for (int i = 0; i < new_len; i++) {
655 ASSERT_EQUAL(flirpan[i + old_len], to_add[i],
656 "value should not be wrong after content array concatenation");
657 }
658 delete [] to_add; // clean up.
659 break;
660 }
661 case do_subarray: {
662#ifdef DEBUG_TEST_ARRAY
663 LOG(a_sprintf("do_subarray"));
664#endif
665 array<contents> flirpan = *testers[index];
666 int start = a_randomizer.inclusive(0, flirpan.length() - 1);
667 int end = a_randomizer.inclusive(0, flirpan.length() - 1);
668 flip_increasing(start, end);
669 flirpan = flirpan.subarray(start, end);
670 for (int i = 0; i < end - start; i++)
671 ASSERT_EQUAL(flirpan[i], testers[index]->get(i + start),
672 "subarray should produce right array");
673 break;
674 }
675 case do_memory_paring: {
676#ifdef DEBUG_TEST_ARRAY
677 LOG(a_sprintf("do_memory_paring"));
678#endif
679 for (int i = 0; i < MAX_SIMULTANEOUS_OBJECTS; i++) {
680 // zap extra junk off so we bound the memory usage.
681 if (testers[i]->length() > MAX_OBJECT) {
682 testers[i]->zap(MAX_OBJECT, testers[i]->length() - 1);
683 testers[i]->shrink();
684 }
685 }
686 break;
687 }
688 case do_snarf: {
689#ifdef DEBUG_TEST_ARRAY
690 LOG(a_sprintf("do_snarf"));
691#endif
692 array<contents> flirpan = *testers[index];
693// int start = a_randomizer.inclusive(0, flirpan.length() - 1);
694// int end = a_randomizer.inclusive(0, flirpan.length() - 1);
695// flip_increasing(start, end);
696// flirpan = flirpan.subarray(start, end);
697 int rand_index = a_randomizer.inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
698 if (index == rand_index) continue; // skip it; try again later.
699 array<contents> nugwort = *testers[rand_index];
700 // perform a swap between two of our arrays.
701 array<contents> temp_hold(0, NULL_POINTER, flags);
702 temp_hold.snarf(*testers[index]);
703 testers[index]->snarf(*testers[rand_index]);
704 testers[rand_index]->snarf(temp_hold);
705 // the copies should have flipped places now. check them.
706 ASSERT_EQUAL(flirpan.length(), testers[rand_index]->length(),
707 "snarf needs to produce right length at A");
708 for (int i = 0; i < flirpan.length(); i++)
709 ASSERT_EQUAL(flirpan[i], testers[rand_index]->get(i),
710 "snarf needs to produce right array at A");
711 ASSERT_EQUAL(nugwort.length(), testers[index]->length(),
712 "snarf needs to produce right length at B");
713 for (int j = 0; j < nugwort.length(); j++)
714 ASSERT_EQUAL(nugwort[j], testers[index]->get(j),
715 "snarf needs to produce right array at B");
716 break;
717 }
718 case do_flush: {
719#ifdef DEBUG_TEST_ARRAY
720 LOG(a_sprintf("do_flush"));
721#endif
722 array<contents> flirpan = *testers[index];
723
725
727
728
729 break;
730 }
731
732 case do_insert: {
733#ifdef DEBUG_TEST_ARRAY
734 LOG(a_sprintf("do_insert"));
735#endif
736 array<contents> hold = *testers[index];
737 int where = a_randomizer.inclusive(0, hold.last());
738 int how_many = a_randomizer.inclusive(0, 25);
739 testers[index]->insert(where, how_many);
740 for (int i = 0; i < where; i++)
741 ASSERT_EQUAL(hold[i], testers[index]->get(i),
742 "should have good contents on left after insert");
743 for (int j = where + how_many; j < testers[index]->length(); j++)
744 ASSERT_EQUAL(hold[j - how_many], testers[index]->get(j),
745 "should have good contents on right after insert");
746 break;
747 }
748 case do_overwrite: {
749#ifdef DEBUG_TEST_ARRAY
750 LOG(a_sprintf("do_overwrite"));
751#endif
752 if (!testers[index]->length()) continue;
753 array<contents> hold = *testers[index];
754 int index2 = index;
755 while (index2 == index)
756 index2 = a_randomizer.inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
757 array<contents> &hold2 = *testers[index2];
758 if (!hold2.length()) continue;
759 int write_indy = a_randomizer.inclusive(0, hold.last());
760 int write_len = minimum(hold2.length(), (hold.length() - write_indy));
761// LOG(a_sprintf("len1 = %d len2 = %d wrindy=%d wrlen=%d", hold.length(), hold2.length(), write_indy, write_len));
762 outcome ret = testers[index]->overwrite(write_indy,
763 *testers[index2], write_len);
764 ASSERT_EQUAL(ret.value(), common::OKAY,
765 astring("should not have had outcome=") + common::outcome_name(ret));
766 for (int i = 0; i < write_indy; i++)
767 ASSERT_EQUAL(hold[i], testers[index]->get(i),
768 "should have good contents on left after overwrite");
769 for (int j = write_indy; j < write_indy + write_len; j++)
770 ASSERT_EQUAL(hold2[j - write_indy], testers[index]->get(j),
771 "should have good contents in middle after overwrite");
772 for (int k = write_indy + write_len; k < testers[index]->length(); k++)
773 ASSERT_EQUAL(hold[k], testers[index]->get(k),
774 "should have good contents on right after overwrite");
775 break;
776 }
777 case do_stuff: {
778#ifdef DEBUG_TEST_ARRAY
779 LOG(a_sprintf("do_stuff"));
780#endif
781 array<contents> &hold = *testers[index];
782 contents burgers[100];
783 int stuff_len = a_randomizer.inclusive(0, hold.length());
784 stuff_len = minimum(stuff_len, 100);
785 outcome ret = hold.stuff(stuff_len, burgers);
786 ASSERT_EQUAL(ret.value(), common::OKAY,
787 astring("should not have had outcome=") + common::outcome_name(ret));
788 for (int i = 0; i < stuff_len; i++)
789 ASSERT_EQUAL(burgers[i], hold[i],
790 "should have good contents after stuff");
791 break;
792 }
793 default: {
794 ASSERT_FALSE(true, "test cases should have no invalid choices!");
795 break;
796 }
797 }
798 }
799
800 // clean up.
801 delete [] junk_space;
802 for (int d = 0; d < MAX_SIMULTANEOUS_OBJECTS; d++) delete testers[d];
803}
804
806
807struct gerkin { int l; abyte *p; char *r; void *pffttt; };
808
809gerkin borgia;
810
811class foop
812{
813public:
814 virtual ~foop() {}
815 virtual gerkin *boorba() = 0;
816};
817
818class boop : public foop
819{
820public:
821 virtual gerkin *boorba() { return &borgia; }
822};
823
824void test_array::test_iteration_speed()
825{
826 FUNCDEF("test_iteration_speed");
827 const int MAX_CHUNK = 100000;
828 const int MAX_REPS = 20;
829 byte_array chunky(MAX_CHUNK);
830
831 {
832 time_stamp start;
833 int sum = 0;
834 for (int j = 0; j < MAX_REPS; j++) {
835 for (int i = 0; i < MAX_CHUNK; i++) {
836 sum += chunky[i];
837 }
838 }
839 int duration = int(time_stamp().value() - start.value());
840
841 a_sprintf message("iteration over %d elements took %d ms,\t"
842 "or %f ms per 1000 iters.",
843 MAX_CHUNK * MAX_REPS, duration,
844 double(duration) / double(MAX_CHUNK * MAX_REPS) * 1000.0);
845//base_logger &b = program_wide_logger::get();
846 LOG(message);
847 }
848
849 {
850 time_stamp start;
851 int sum = 0;
852 const abyte *head = chunky.observe();
853 for (int j = 0; j < MAX_REPS; j++) {
854 for (int i = 0; i < MAX_CHUNK; i++) {
855 sum += head[i];
856 }
857 }
858 int duration = int(time_stamp().value() - start.value());
859
860 LOG(a_sprintf("less-safe iteration over %d elements took %d ms,\tor %f ms per 1000 iters.",
861 MAX_CHUNK * MAX_REPS, duration,
862 double(duration) / double(MAX_CHUNK * MAX_REPS) * 1000.0));
863 }
864 {
865 time_stamp start;
866 boop tester;
867// int sum = 0;
868 for (int j = 0; j < MAX_REPS; j++) {
869 for (int i = 0; i < MAX_CHUNK; i++) {
870// chunky.modus().sampler();
871 tester.boorba();
872 }
873 }
874 int duration = int(time_stamp().value() - start.value());
875
876 LOG(a_sprintf("virtual-function-only over %d elements took %d ms,\tor %f ms per 1000 iters.",
877 MAX_CHUNK * MAX_REPS, duration,
878 double(duration) / double(MAX_CHUNK * MAX_REPS) * 1000.0));
879 }
880}
881
883
884int test_array::execute()
885{
886 FUNCDEF("execute");
887#if 0
888// if enabled for the abusive type tests, then allow this one...
889 test_iteration_speed();
890// LOG(a_sprintf("did iteration test."));
891#endif
892
893 int_array checking_start;
894 ASSERT_FALSE(checking_start.length(),
895 "int_array should not have contents from empty constructor");
896
897 double_plus bogus4 = float(12.32);
898 array_tester<double_plus >(*this, bogus4,
899 byte_array::SIMPLE_COPY | byte_array::EXPONE
900 | byte_array::FLUSH_INVISIBLE);
901// LOG(a_sprintf("did float array test."));
902
903 int bogus2 = 39;
904 array_tester<int>(*this, bogus2,
905 byte_array::SIMPLE_COPY | byte_array::EXPONE
906 | byte_array::FLUSH_INVISIBLE);
907// LOG(a_sprintf("did int array test."));
908
909 test_content bogus3(12);
910 array_tester<test_content>(*this, bogus3, byte_array::EXPONE
911 | byte_array::FLUSH_INVISIBLE);
912// LOG(a_sprintf("did test_content array test."));
913
914 test_arrays_of_void_pointer();
915// LOG(a_sprintf("did void * array test."));
916
917 abyte bogus1 = 'c';
918 array_tester<abyte>(*this, bogus1,
919 byte_array::SIMPLE_COPY | byte_array::EXPONE
920 | byte_array::FLUSH_INVISIBLE);
921// LOG(a_sprintf("did byte array test."));
922
924
925 return final_report();
926}
927
928HOOPLE_MAIN(test_array, )
929
The application_shell is a base object for console programs.
virtual int execute()=0
< retrieves the command line from the /proc hierarchy on linux.
application_shell()
constructs an application_shell to serve as the root of the program.
a_sprintf is a specialization of astring that provides printf style support.
Definition astring.h:440
Represents a sequential, ordered, contiguous collection of objects.
Definition array.h:54
@ NEW_AT_BEGINNING
Definition array.h:67
@ NEW_AT_END
Definition array.h:67
outcome insert(int index, int new_indices)
Adds "new_indices" new positions for objects into the array at "index".
Definition array.h:803
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
Definition array.h:349
outcome shrink()
Cuts loose any allocated space that is beyond the real length.
Definition array.h:463
outcome overwrite(int index, const array &write_with, int count=-1)
Stores the array "write_with" into the current array at the "index".
Definition array.h:490
array & concatenate(const array &to_concatenate)
Appends the array "to_concatenate" onto "this" and returns "this".
Definition array.h:379
array subarray(int start, int end) const
Returns the array segment between the indices "start" and "end".
Definition array.h:443
const contents & get(int index) const
Accesses individual objects stored in "this" at the "index" position.
Definition array.h:372
contents * access()
A non-constant access of the underlying C-array. BE REALLY CAREFUL.
Definition array.h:175
outcome retrain(int new_size, const contents *to_copy)
Resizes the C array and stuffs it with the contents in "to_copy".
Definition array.h:731
outcome resize(int new_size, how_to_copy way=NEW_AT_END)
Changes the size of the C array to "new_size".
Definition array.h:585
int length() const
Returns the current reported length of the allocated C array.
Definition array.h:115
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
Definition array.h:769
outcome stuff(int length, contents *to_stuff) const
Copies at most "length" elements from this into the array "to_stuff".
Definition array.h:476
const contents * internal_block_start() const
Gritty Internal: constant peek at the real allocated pointer.
Definition array.h:249
int internal_real_length() const
Gritty Internal: the real allocated length.
Definition array.h:245
int last() const
Returns the last valid element in the array.
Definition array.h:118
void snarf(array &new_contents)
Drops "this" array's contents into the dustbin and uses "new_contents".
Definition array.h:845
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
A very common template for a dynamic array of bytes.
Definition byte_array.h:36
static const char * outcome_name(const outcome &to_name)
Returns a string representation of the outcome "to_name".
A simple object that wraps a templated array of ints.
Definition array.h:275
Outcomes describe the state of completion for an operation.
Definition outcome.h:31
int value() const
Definition outcome.h:51
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
Represents a point in time relative to the operating system startup time.
Definition time_stamp.h:38
time_representation value() const
returns the time_stamp in terms of the lower level type.
Definition time_stamp.h:61
#define formal(parameter)
This macro just eats what it's passed; it marks unused formal parameters.
Definition definitions.h:48
#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
const int MAX_CHUNK
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 flip_increasing(type &a, type &b)
Makes sure that two values are in increasing order (a < b).
Definition functions.h:95
unsigned short un_short
Abbreviated name for unsigned short integers.
Definition definitions.h:64
type minimum(type a, type b)
maximum returns the greater of two values.
Definition functions.h:29
type absolute_value(type a)
Returns a if a is non-negative, and returns -a otherwise.
Definition functions.h:33
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
#include <time.h>
Useful support functions for unit testing, especially within hoople.
Definition unit_base.cpp:35
const int MAX_SIMULTANEOUS_OBJECTS
gerkin borgia
#define LOG(s)
const int MAX_OBJECT
const int MIN_OBJECT
const int MAX_BLOCK
const float MAX_TEST_DURATION_ms
const int MIN_BLOCK
bool compare_arrays(const array< contents > &a, const array< contents > &b)
#define test(expr)
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