feisty meow concerns codebase 2.140
test_stack.cpp
Go to the documentation of this file.
1/*
2* Name : t_stack
3* Author : Chris Koeritz
4* Purpose:
5* Tests out the stack object with both flat objects (byte_array) but also
6* deep objects (pointer to byte_array). Both bounded and unbounded stacks
7* are tested for each.
8**
9* Copyright (c) 1992-$now By Author. This program is free software; you can *
10* redistribute it and/or modify it under the terms of the GNU General Public *
11* License as published by the Free Software Foundation; either version 2 of *
12* the License or (at your option) any later version. This is online at: *
13* http://www.fsf.org/copyleft/gpl.html *
14* Please send any updates to: fred@gruntose.com *
15\*****************************************************************************/
16
18#include <basis/byte_array.h>
19#include <basis/guards.h>
20#include <basis/astring.h>
22#include <mathematics/chaos.h>
23#include <structures/stack.h>
25#include <unit_test/unit_base.h>
26
27#ifdef DEBUG_STACK
28 #define LOG(to_print) EMERGENCY_LOG(program_wide_logger::get(), to_print)
29#endif
30
31#include <stdlib.h>
32#include <string.h>
33
34using namespace application;
35using namespace basis;
37using namespace mathematics;
38using namespace filesystem;
39using namespace loggers;
40using namespace structures;
41using namespace textual;
42using namespace timely;
43using namespace unit_test;
44
45//HOOPLE_STARTUP_CODE;
46
47//#define DEBUG_STACK
48 // uncomment for a noisier version.
49
50const int test_iterations = 40;
51
52
53class test_stack : public virtual unit_base, public virtual application_shell
54{
55public:
56 test_stack() {}
57 DEFINE_CLASS_NAME("test_stack");
58 int execute();
59
60 void test_stack_with_objects();
61 void test_stack_with_pointers();
62
63 void CHECK_STACK_RESULT(outcome retval, const astring &place);
64 byte_array generate_flat(const char *to_store);
65 byte_array *generate_deep(const char *to_store);
66 astring text_form(stack<byte_array *> &s);
67 astring text_form(stack<byte_array> &s);
68};
69
70// CHECK_STACK_RESULT: a function that takes care of error testing for a
71// stack command. if executing the command ends in full or empty, then
72// that is reported.
73void test_stack::CHECK_STACK_RESULT(outcome retval, const astring &place)
74{
75#ifdef DEBUG_STACK
76 if (retval == common::IS_FULL)
77 LOG(astring(astring::SPRINTF, "returned IS_FULL at %s", place.s()))
78 else if (retval == common::IS_EMPTY)
79 LOG(astring(astring::SPRINTF, "returned IS_EMPTY at %s", place.s()));
80#else
81 if (retval.value() || !place) {}
82#endif
83}
84
85byte_array test_stack::generate_flat(const char *to_store)
86{
87 byte_array to_return = byte_array(int(strlen(to_store) + 1), (abyte *)to_store);
88 return to_return;
89}
90
91byte_array *test_stack::generate_deep(const char *to_store)
92{
93 byte_array *to_return = new byte_array(int(strlen(to_store) + 1),
94 (abyte *)to_store);
95 return to_return;
96}
97
98astring test_stack::text_form(stack<byte_array *> &s)
99{
100 astring to_return;
101 for (int i = 0; i < s.elements(); i++) {
102 to_return += astring(astring::SPRINTF, "#%d: %s\n", i, s[i]->observe());
103 }
104 return to_return;
105}
106
107astring test_stack::text_form(stack<byte_array> &s)
108{
109 astring to_return;
110 for (int i = 0; i < s.elements(); i++) {
111 to_return += astring(astring::SPRINTF, "#%d: %s\n", i, s[i].observe());
112 }
113 return to_return;
114}
115
116void test_stack::test_stack_with_objects()
117{
118 FUNCDEF("test_stack_with_objects");
119 for (int qq = 0; qq < test_iterations; qq++) {
120#ifdef DEBUG_STACK
121 LOG(astring(astring::SPRINTF, "index %d", qq));
122#endif
123 stack<byte_array > bounded_stack(3);
124 stack<byte_array > unlimited_stack(0);
126
127 {
128#ifdef DEBUG_STACK
129 LOG("testing the bounded stack first:");
130#endif
131 CHECK_STACK_RESULT(bounded_stack.push(generate_flat("the first line")), "first push");
132 CHECK_STACK_RESULT(bounded_stack.push(generate_flat("the second line")), "second push");
133 CHECK_STACK_RESULT(bounded_stack.push(generate_flat("the final and third")), "third push");
134 byte_array gend = generate_flat("this shouldn't work");
135 ASSERT_EQUAL(bounded_stack.push(gend).value(), common::IS_FULL,
136 "the bounded stack push should catch IS_FULL");
137#ifdef DEBUG_STACK
138 LOG("pushing worked successfully...");
139 LOG("printing the stack in element order");
140#endif
141 for (int i = 0; i < bounded_stack.size(); i++) {
142#ifdef DEBUG_STACK
143 LOG(astring(astring::SPRINTF, "depth %d has %s.", i,
144 bounded_stack[i].observe()));
145#endif
146 }
147#ifdef DEBUG_STACK
148 LOG("now popping the stack all the way back.");
149#endif
150 int full_size = bounded_stack.size();
151 for (int j = 0; j < full_size; j++) {
152#ifdef DEBUG_STACK
153 LOG(astring(astring::SPRINTF, "pop %d, stack size is %d, has %s", j+1,
154 bounded_stack.size(), bounded_stack.top().observe()));
155#endif
156 byte_array found;
157 bounded_stack.acquire_pop(found);
158 astring got((char *)found.observe());
159 switch (j) {
160 case 0:
161 ASSERT_EQUAL(got, astring("the final and third"),
162 "acquire_pop should have right contents at 2");
163 break;
164 case 1:
165 ASSERT_EQUAL(got, astring("the second line"),
166 "acquire_pop should have right contents at 1");
167 break;
168 case 2:
169 ASSERT_EQUAL(got, astring("the first line"),
170 "acquire_pop should have right contents at 0");
171 break;
172 }
173 }
174 ASSERT_EQUAL(bounded_stack.pop().value(), common::IS_EMPTY,
175 "bounded pop should have right outcome");
176 }
177
178 {
179#ifdef DEBUG_STACK
180 LOG("testing the unbounded stack now:");
181#endif
182 for (int j = 0; j < 24; j++) {
183 astring line(astring::SPRINTF, "{posn %d here}", j);
184 CHECK_STACK_RESULT(unlimited_stack.push(generate_flat(line.s())), "unbound push");
185 }
186#ifdef DEBUG_STACK
187 LOG("unbounded stack in element order:");
188#endif
189 for (int k = 0; k < unlimited_stack.size(); k++) {
190#ifdef DEBUG_STACK
191 LOG(astring(astring::SPRINTF, "#%d is %s", k, unlimited_stack[k].observe()));
192#endif
193 }
194#ifdef DEBUG_STACK
195 LOG("now popping fresh order:");
196#endif
197 while (unlimited_stack.size()) {
198#ifdef DEBUG_STACK
199 LOG(astring(astring::SPRINTF, "size %d, content %s",
200 unlimited_stack.size(), unlimited_stack.top().observe()));
201#endif
202 unlimited_stack.pop();
203 }
204#ifdef DEBUG_STACK
205 LOG("");
206#endif
207 ASSERT_EQUAL(unlimited_stack.pop().value(), common::IS_EMPTY,
208 "unlimited pop should return empty as expected");
209#ifdef DEBUG_STACK
210 LOG("\
211----------------------------------------------\n\
212both types of stack exercises were successful.\n\
213----------------------------------------------");
214#endif
215 }
216
217#ifdef DEBUG_STACK
218 LOG("now setting up some simple stacks...");
219#endif
220
221 {
222#ifdef DEBUG_STACK
223 LOG("bounded first...");
224#endif
225 stack<byte_array > bounder(randomizer.inclusive(30, 80));
226#ifdef DEBUG_STACK
227 LOG(astring(astring::SPRINTF, "length of bounder is max %d, curr %d", bounder.elements(), bounder.size()));
228#endif
229 int max = bounder.elements();
230 for (int i = 0; i < max; i++) {
231 ASSERT_EQUAL(bounder.size(), i, "the bounder size should be in step with loop");
232 int byte_array_size = randomizer.inclusive(259, 287);
233 byte_array to_stuff(byte_array_size);
234 astring visible(astring::SPRINTF, "entry %d...", i);
235 visible.stuff((char *)to_stuff.access(), visible.length() + 1);
236 for (int j = visible.length() + 1; j < to_stuff.length(); j++)
237 *(to_stuff.access() + j) = '\0';
238#ifdef DEBUG_STACK
239 LOG(astring(astring::SPRINTF, "pushing index %d", i));
240#endif
241 outcome ret = bounder.push(to_stuff);
242 ASSERT_EQUAL(ret.value(), common::OKAY, "pushing should not fail in simple test");
243 }
244 ASSERT_EQUAL(bounder.elements(), bounder.size(), "bounder set should see size and max same");
245#ifdef DEBUG_STACK
246 LOG("inverting:");
247#endif
248 bounder.invert();
249#ifdef DEBUG_STACK
250 LOG(astring(astring::SPRINTF, "inverted is:\n%s", text_form(bounder).s()));
251#endif
252 while (bounder.size()) bounder.pop();
253 }
254 }
255}
256
257void test_stack::test_stack_with_pointers()
258{
259 FUNCDEF("test_stack_with_pointers")
260 for (int qq = 0; qq < test_iterations; qq++) {
261#ifdef DEBUG_STACK
262 LOG(astring(astring::SPRINTF, "index %d", qq));
263#endif
264 stack<byte_array *> bounded_stack(3);
265 stack<byte_array *> unlimited_stack(0);
267
268 {
269#ifdef DEBUG_STACK
270 LOG("testing the bounded stack first:");
271#endif
272 CHECK_STACK_RESULT(bounded_stack.push(generate_deep("the first line")), "first push");
273 CHECK_STACK_RESULT(bounded_stack.push(generate_deep("the second line")), "second push");
274 CHECK_STACK_RESULT(bounded_stack.push(generate_deep("the final and third")), "third push");
275 byte_array *gend = generate_deep("this shouldn't work");
276 ASSERT_EQUAL(bounded_stack.push(gend).value(), common::IS_FULL,
277 "the bounded stack push should catch IS_FULL");
278 delete gend;
279#ifdef DEBUG_STACK
280 LOG("pushing worked successfully...");
281 LOG("printing the stack in element order");
282#endif
283 for (int i = 0; i < bounded_stack.size(); i++) {
284#ifdef DEBUG_STACK
285 LOG(astring(astring::SPRINTF, "depth %d has: %s", i, bounded_stack[i]->observe()));
286#endif
287 }
288#ifdef DEBUG_STACK
289 LOG("now popping the stack all the way back.");
290#endif
291 int full_size = bounded_stack.size();
292 for (int j = 0; j < full_size; j++) {
293#ifdef DEBUG_STACK
294 LOG(astring(astring::SPRINTF, "pop %d, stack size is %d, has %s", j+1, bounded_stack.size(), bounded_stack.top()->observe()));
295#endif
296 byte_array *found;
297 bounded_stack.acquire_pop(found);
298 ASSERT_TRUE(found, "acquire_pop test should not return nil");
299 ASSERT_TRUE(found->observe(), "acquire_pop test should have non-nil observe");
300 astring got((char *)found->observe());
301 switch (j) {
302 case 0:
303 ASSERT_EQUAL(got, astring("the final and third"),
304 "popping should have right contents at 2");
305 break;
306 case 1:
307 ASSERT_EQUAL(got, astring("the second line"),
308 "popping should have right contents at 1");
309 break;
310 case 2:
311 ASSERT_EQUAL(got, astring("the first line"),
312 "popping should have right contents at 0");
313 break;
314 }
315 delete found;
316 }
317 ASSERT_EQUAL(bounded_stack.pop().value(), common::IS_EMPTY,
318 "bounded pop failure in result");
319 }
320
321 {
322#ifdef DEBUG_STACK
323 LOG("testing the unbounded stack now:");
324#endif
325 for (int j = 0; j < 24; j++) {
326 astring line(astring::SPRINTF, "{posn %d here}", j);
327 CHECK_STACK_RESULT(unlimited_stack.push(generate_deep(line.s())), "unbound push");
328 }
329#ifdef DEBUG_STACK
330 LOG("unbounded stack in element order:");
331#endif
332 for (int k = 0; k < unlimited_stack.size(); k++) {
333#ifdef DEBUG_STACK
334 LOG(astring(astring::SPRINTF, "#%d is %s", k, unlimited_stack[k]->observe()));
335#endif
336 }
337#ifdef DEBUG_STACK
338 LOG("\nnow popping order:");
339#endif
340 while (unlimited_stack.size()) {
341#ifdef DEBUG_STACK
342 LOG(astring(astring::SPRINTF, "size %d, content %s", unlimited_stack.size(), unlimited_stack.top()->observe()));
343#endif
344 byte_array *to_zap = unlimited_stack.top();
345 unlimited_stack.pop();
346 delete to_zap;
347 // okay because the pointer was copied, and the reference from top
348 // is not being relied on.
349 }
350#ifdef DEBUG_STACK
351 LOG("");
352#endif
353 ASSERT_EQUAL(unlimited_stack.pop().value(), common::IS_EMPTY,
354 "unlimited pop should return empty as expected");
355#ifdef DEBUG_STACK
356 LOG("\n\
357----------------------------------------------\n\
358both types of stack exercises were successful.\n\
359----------------------------------------------");
360#endif
361 }
362
363#ifdef DEBUG_STACK
364 LOG("now setting up some simple stacks...");
365#endif
366
367 {
368#ifdef DEBUG_STACK
369 LOG("bounded first...");
370#endif
371 stack<byte_array *> bounder(randomizer.inclusive(30, 80));
372#ifdef DEBUG_STACK
373 LOG(astring(astring::SPRINTF, "length of bounder is max %d, curr %d",
374 bounder.elements(), bounder.size()));
375#endif
376 int max = bounder.elements();
377 for (int i = 0; i < max; i++) {
378 ASSERT_EQUAL(bounder.size(), i, "bounder size should remain in step with loop");
379 int byte_array_size = randomizer.inclusive(259, 287);
380 byte_array *to_stuff = new byte_array(byte_array(byte_array_size));
381 astring visible(astring::SPRINTF, "entry %d...", i);
382 visible.stuff((char *)to_stuff->observe(), visible.length() + 1);
383 for (int j = visible.length() + 1; j < to_stuff->length(); j++)
384 *(to_stuff->access() + j) = '\0';
385 ASSERT_EQUAL(bounder.push(to_stuff).value(), common::OKAY,
386 "pushing should not fail in bound simple test");
387 }
388 ASSERT_EQUAL(bounder.elements(), bounder.size(), "bounder set must have size and max agree");
389#ifdef DEBUG_STACK
390 LOG("inverting:");
391#endif
392 bounder.invert();
393#ifdef DEBUG_STACK
394 LOG(astring(astring::SPRINTF, "inverted is:\n%s", text_form(bounder).s()));
395#endif
396 while (bounder.size()) {
397 byte_array *to_zap = bounder.top();
398 bounder.pop();
399 delete to_zap;
400 }
401 }
402 }
403}
404
405int test_stack::execute()
406{
407 test_stack_with_objects();
408 test_stack_with_pointers();
409 return final_report();
410}
411
412HOOPLE_MAIN(test_stack, )
413
#define LOG(s)
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
const contents * observe() const
Returns a pointer to the underlying C array of data.
Definition array.h:172
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
A very common template for a dynamic array of bytes.
Definition byte_array.h:36
the "common" class defines our common_outcomes.
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
An abstraction that represents a stack data structure.
Definition stack.h:30
int elements() const
Returns the number of elements used by the stack.
Definition stack.h:136
#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
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
#include <time.h>
Useful support functions for unit testing, especially within hoople.
Definition unit_base.cpp:35
#define randomizer()
const int test_iterations
#define ASSERT_EQUAL(a, b, test_name)
Definition unit_base.h:38
#define ASSERT_TRUE(a, test_name)
Definition unit_base.h:46