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>
24 #include <loggers/console_logger.h>
26 #include <mathematics/chaos.h>
28 #include <timely/time_stamp.h>
29 #include <unit_test/unit_base.h>
30 
32 
33 using namespace application;
34 using namespace basis;
35 using namespace loggers;
36 using namespace mathematics;
37 using namespace timely;
38 using namespace unit_test;
39 
40 //const float MAX_TEST_DURATION_ms = 28 * SECOND_ms;
41 const float MAX_TEST_DURATION_ms = 200;
42  // each of the tests calling on the templated tester will take this long.
43 
44 const int MAX_SIMULTANEOUS_OBJECTS = 42; // the maximum arrays tested.
45 
46 const int MIN_OBJECT = -30; // the smallest array we'll create.
47 const int MAX_OBJECT = 98; // the largest array we'll create.
48 
49 const int MIN_BLOCK = 100; // the smallest exemplar we'll use.
50 const 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 
57 static chaos a_randomizer;
58 
60 
61 class test_array : public application_shell, public unit_base
62 {
63 public:
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 
84 void 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 
97 void 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 
151 static astring blank_string;
152 
153 // jethro is a simple object for containment below.
154 class jethro
155 {
156 public:
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.
168 class test_content
169 {
170 public:
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 
224 template <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 
243 template <class contents>
244 void 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 
272  time_stamp exit_time(MAX_TEST_DURATION_ms);
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.
434  ASSERT_EQUAL(start, arrh.internal_block_start(),
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);
446  ASSERT_EQUAL(start, arrh.internal_block_start(),
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.
475  ASSERT_EQUAL(start, arrh.internal_block_start(),
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);
487  ASSERT_EQUAL(start, arrh.internal_block_start(),
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 
807 struct gerkin { int l; abyte *p; char *r; void *pffttt; };
808 
809 gerkin borgia;
810 
811 class foop
812 {
813 public:
814  virtual ~foop() {}
815  virtual gerkin *boorba() = 0;
816 };
817 
818 class boop : public foop
819 {
820 public:
821  virtual gerkin *boorba() { return &borgia; }
822 };
823 
824 void 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 
884 int 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 
928 HOOPLE_MAIN(test_array, )
929 
The application_shell is a base object for console programs.
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 put(int index, const contents &to_put)
Stores an object at the index "index" in the array.
Definition: array.h:834
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
const contents * internal_block_start() const
Gritty Internal: constant peek at the real allocated pointer.
Definition: array.h:249
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
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
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:45
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
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>
Definition: earth_time.cpp:37
Useful support functions for unit testing, especially within hoople.
Definition: unit_base.cpp:35
const int MAX_SIMULTANEOUS_OBJECTS
Definition: test_array.cpp:44
gerkin borgia
Definition: test_array.cpp:809
#define LOG(s)
Definition: test_array.cpp:55
const int MAX_OBJECT
Definition: test_array.cpp:47
const int MIN_OBJECT
Definition: test_array.cpp:46
const int MAX_BLOCK
Definition: test_array.cpp:50
const float MAX_TEST_DURATION_ms
Definition: test_array.cpp:41
const int MIN_BLOCK
Definition: test_array.cpp:49
bool compare_arrays(const array< contents > &a, const array< contents > &b)
Definition: test_array.cpp:225
#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