feisty meow concerns codebase  2.140
t_unpacker.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : unpacking octopus test *
4 * Author : Chris Koeritz *
5 * *
6 * Purpose: *
7 * *
8 * A test of octopuses used for unpacking flat structures. *
9 * *
10 *******************************************************************************
11 * Copyright (c) 2002-$now By Author. This program is free software; you can *
12 * redistribute it and/or modify it under the terms of the GNU General Public *
13 * License as published by the Free Software Foundation; either version 2 of *
14 * the License or (at your option) any later version. This is online at: *
15 * http://www.fsf.org/copyleft/gpl.html *
16 * Please send any updates to: fred@gruntose.com *
17 \*****************************************************************************/
18 
19 #include <basis/astring.h>
21 #include <octopus/entity_defs.h>
22 #include <octopus/infoton.h>
23 #include <octopus/octopus.h>
26 #include <loggers/console_logger.h>
27 #include <loggers/file_logger.h>
30 
31 //hmmm: provide equality ops to be able to check that same stuff
32 // came back out that went in.
33 
34 class test_unpacker : public application_shell
35 {
36 public:
37  test_unpacker() : application_shell(class_name()) {}
38  DEFINE_CLASS_NAME("test_unpacker");
39  virtual int execute();
40  void test_unpacking();
41 };
42 
44 
45 // the infotons here have a three level classifier. the outer level is
46 // for the benefit of the handler_arm tentacle that just checks that the
47 // group name is correct before passing off the request to its internal
48 // octopus. then the second level specifies which class of infotons are
49 // being managed. the third level specifies the leaf type of the infoton--
50 // the specific type of data being wrapped.
51 
52 const char *base_list[] = { "gruntiak" };
53 
54 SAFE_STATIC_CONST(string_array, base_classifier, (1, base_list))
55 
56 const char *math_list[] = { "math" };
57 
58 SAFE_STATIC_CONST(string_array, math_classifier, (base_classifier()
60 
61 const char *addr_list[] = { "address" };
62 
63 SAFE_STATIC_CONST(string_array, addr_classifier, (base_classifier()
64  + string_array(1, addr_list)))
65 
66 class address_ton : public infoton, public network_address
67 {
68 public:
69  address_ton() : infoton(addr_classifier() + "leaf") {}
70 
71  virtual void pack(byte_array &packed_form) const {
72  network_address::pack(packed_form);
73  }
74 
75  virtual bool unpack(byte_array &packed_form) {
76  return network_address::unpack(packed_form);
77  }
78 
79  virtual int packed_size() const {
80  return 5 * sizeof(int) + 128 /*address estimate*/;
81  }
82 
83  virtual clonable *clone() const {
84  return new address_ton(*this);
85  }
86 };
87 
88 //some floating point nums.
89 class float_ton : public infoton
90 {
91 public:
92  float f1;
93  double d1;
94 
95  float_ton() : infoton(math_classifier() + "float") {}
96 
97  virtual void pack(byte_array &packed_form) const {
98  structures::attach(packed_form, f1);
99  structures::attach(packed_form, d1);
100  }
101 
102  virtual int packed_size() const {
103  return sizeof(double) + sizeof(float);
104  }
105 
106  virtual bool unpack(byte_array &packed_form) {
107  double hold;
108  if (!structures::detach(packed_form, hold)) return false;
109  f1 = float(hold);
110  if (!structures::detach(packed_form, d1)) return false;
111  return true;
112  }
113 
114  virtual clonable *clone() const {
115  return new float_ton(*this);
116  }
117 };
118 
119 //an integer set.
120 class int_set_ton : public infoton
121 {
122 public:
123  int_set nums;
124 
125  int_set_ton() : infoton(math_classifier() + "intset") {}
126 
127  virtual void pack(byte_array &packed_form) const {
128  structures::attach(packed_form, nums.elements());
129  for (int i = 0; i < nums.elements(); i++)
130  structures::attach(packed_form, nums[i]);
131  }
132 
133  virtual int packed_size() const {
134  return sizeof(int) + nums.elements() * sizeof(int);
135  }
136 
137  virtual bool unpack(byte_array &packed_form) {
138  int len = 0;
139  nums.reset();
140  if (!structures::detach(packed_form, len)) return false;
141  for (int i = 0; i < len; i++) {
142  int got = 0;
143  if (!structures::detach(packed_form, got)) return false;
144  nums += got;
145  }
146  return true;
147  }
148 
149  virtual clonable *clone() const {
150  return new int_set_ton(*this);
151  }
152 };
153 
155 
156 // handles network addresses.
157 class address_chomper : public tentacle_helper<address_ton>
158 {
159 public:
160  address_chomper()
161  : tentacle_helper<address_ton>(addr_classifier().subarray(1, 1), true) {}
162 };
163 
164 // handles floats and int_sets.
165 class numerical_chomper : public tentacle
166 {
167 public:
168  numerical_chomper() : tentacle(math_classifier().subarray(1, 1), true) {}
169 
170  outcome reconstitute(const string_array &classifier, byte_array &packed_form,
171  infoton * &reformed)
172  {
173  reformed = NULL_POINTER;
174  if (classifier.length() < 2) return BAD_INPUT;
175  astring key = classifier[1];
176  if (key == "float") {
177  float_ton *to_return = new float_ton;
178  if (!to_return->unpack(packed_form)) {
179  WHACK(to_return);
180  return NULL_POINTER;
181  }
182  reformed = to_return;
183  return OKAY;
184  } else if (key == "intset") {
185  int_set_ton *to_return = new int_set_ton;
186  if (!to_return->unpack(packed_form)) {
187  WHACK(to_return);
188  return NULL_POINTER;
189  }
190  reformed = to_return;
191  return OKAY;
192  } else
193  return NO_HANDLER;
194  }
195 
196  outcome consume(infoton &formal(to_chow), const octopus_request_id &formal(item_id),
197  byte_array &transformed)
198  { transformed.reset(); return tentacle::BAD_INPUT; }
199 
200  virtual void expunge(const octopus_entity &formal(zapola)) {}
201 };
202 
204 
205 // delegates the unpacking to an internal tentacle. it peels off a level
206 // of classifier to find the real handler.
207 class outer_arm : public tentacle
208 {
209 public:
210  outer_arm()
211  : tentacle(base_classifier(), true),
212  _unpackers("local", 10 * MEGABYTE),
213  _numer(new numerical_chomper),
214  _addron(new address_chomper)
215  {
216  // register the two tentacles.
217  outcome ret = _unpackers.add_tentacle(_numer);
218  if (ret != tentacle::OKAY)
219  deadly_error(class_name(), "adding numerical tentacle",
220  astring("failed to add: ") + tentacle::outcome_name(ret));
221  ret = _unpackers.add_tentacle(_addron);
222  if (ret != tentacle::OKAY)
223  deadly_error(class_name(), "adding address tentacle",
224  astring("failed to add: ") + tentacle::outcome_name(ret));
225  }
226 
227  ~outer_arm() {
228  // just reset the two tentacles, since the _unpackers octopus should
229  // clean them up.
230  _numer = NULL_POINTER;
231  _addron = NULL_POINTER;
232  }
233 
234  outcome reconstitute(const string_array &classifier, byte_array &packed_form,
235  infoton * &reformed)
236  {
237  // strip first word of classifier.
238  string_array real_class = classifier;
239  real_class.zap(0, 0);
240  // route to octopus.
241  return _unpackers.restore(real_class, packed_form, reformed);
242  }
243 
244  outcome consume(infoton &to_chow, const octopus_request_id &item_id,
245  byte_array &transformed)
246  {
247  transformed.reset();
248  // strip first word of classifier.
249  string_array real_class = to_chow.classifier();
250  real_class.zap(0, 0);
251  to_chow.set_classifier(real_class);
252  // route to octopus.
253  return _unpackers.evaluate((infoton *)to_chow.clone(), item_id);
254  }
255 
256  void expunge(const octopus_entity &formal(whackola)) {}
257 
258 private:
259  octopus _unpackers;
260  numerical_chomper *_numer;
261  address_chomper *_addron;
262 };
263 
265 
266 void test_unpacker::test_unpacking()
267 {
268  octopus unpacky("local", 10 * MEGABYTE);
269  outer_arm *outer = new outer_arm;
270  outcome ret = unpacky.add_tentacle(outer);
271  if (ret != tentacle::OKAY)
272  deadly_error(class_name(), "adding outer tentacle",
273  astring("failed to add: ") + tentacle::outcome_name(ret));
274 
275  // test infoton fast packing.
276  int_set_ton jubjub;
277  jubjub.nums.add(299);
278  jubjub.nums.add(39274);
279  jubjub.nums.add(25182);
280  byte_array packed(10388); // have data in there to start.
281  infoton::fast_pack(packed, jubjub);
282  if (jubjub.packed_size() + infoton::fast_pack_overhead(jubjub.classifier())
283  != packed.length() - 10388)
284  deadly_error(class_name(), "packing test",
285  astring("erroneous size calculated for first fast_pack"));
286  string_array shirley_class;
287  byte_array shirley_data;
288  packed.zap(0, 10387); // remove the original data.
289 
290  // testing the overhead calculation.
291  byte_array junk_jub;
292  jubjub.pack(junk_jub);
293  if (packed.length() != junk_jub.length()
294  + infoton::fast_pack_overhead(jubjub.classifier()))
295  deadly_error(class_name(), "test fast pack overhead",
296  "sizes differed from calculated");
297 
298  if (!infoton::fast_unpack(packed, shirley_class, shirley_data))
299  deadly_error(class_name(), "test infoton fast pack",
300  "failed shirley unpack");
301  if (packed.length() != 0)
302  deadly_error(class_name(), "test infoton fast pack",
303  "shirley didn't consume all");
304  if (shirley_class != jubjub.classifier())
305  deadly_error(class_name(), "test infoton fast pack",
306  "inequal orig classifier");
307  int_set_ton scroop;
308  if (!scroop.unpack(shirley_data))
309  deadly_error(class_name(), "test infoton fast pack",
310  "failed scroop unpack");
311  if (shirley_data.length())
312  deadly_error(class_name(), "test infoton fast pack",
313  "scroop didn't consume all");
314  if (scroop.nums.length() != 3)
315  deadly_error(class_name(), "test infoton fast pack",
316  "wrong length in scroop");
317  if ( (scroop.nums[0] != jubjub.nums[0]) || (scroop.nums[1] != jubjub.nums[1])
318  || (scroop.nums[2] != jubjub.nums[2]) )
319  deadly_error(class_name(), "test infoton fast pack",
320  "erroneous information");
321 
322  byte_array fasting;
323  infoton::fast_pack(fasting, jubjub);
324  if (jubjub.packed_size() + infoton::fast_pack_overhead(jubjub.classifier())
325  != fasting.length())
326  deadly_error(class_name(), "packing test",
327  astring("erroneous size calculated for second fast_pack"));
328 
329  // another test of the overhead calculator.
330  byte_array junk_fast;
331  jubjub.pack(junk_fast);
332  if (fasting.length() != junk_fast.length()
333  + infoton::fast_pack_overhead(jubjub.classifier()))
334  deadly_error(class_name(), "test fast pack overhead 2",
335  "sizes differed from calculated");
336 
337  string_array nudge_class;
338  byte_array nudge_data;
339  if (!infoton::fast_unpack(fasting, nudge_class, nudge_data))
340  deadly_error(class_name(), "test infoton fast pack", "fast pack failed to unpack");
341  if (fasting.length())
342  deadly_error(class_name(), "test infoton fast pack", "fast pack didn't consume all");
343  int_set_ton croup;
344  if (!croup.unpack(nudge_data))
345  deadly_error(class_name(), "test infoton fast pack", "croup wouldn't unpack");
346  if ( (croup.nums[0] != jubjub.nums[0]) || (croup.nums[1] != jubjub.nums[1])
347  || (croup.nums[2] != jubjub.nums[2]) )
348  deadly_error(class_name(), "test infoton fast pack", "croup has errors");
349  byte_array chunkmo;
350  chunkmo += 0x23;
351  chunkmo += 0xf8;
352  chunkmo += 0x37;
353  chunkmo += 0x65;
354  address_ton norf;
355  (network_address &)norf = network_address(internet_address
356  (chunkmo, "urp", 23841));
357  chunkmo.reset();
358  infoton::fast_pack(chunkmo, norf);
359  string_array clarfiator;
360  byte_array pacula;
361  if (!infoton::fast_unpack(chunkmo, clarfiator, pacula))
362  deadly_error(class_name(), "test fast_unpack", "chunkmo has errors");
363  infoton *scrung = NULL_POINTER;
364 //log(astring("classif is ") + clarfiator.text_form());
365 
366  outcome scrung_ret = unpacky.restore(clarfiator, pacula, scrung);
367  if (scrung_ret != tentacle::OKAY)
368  deadly_error(class_name(), "test fast_unpack",
369  a_sprintf("can't restore scrung: %s",
370  tentacle::outcome_name(scrung_ret)));
371  address_ton *rescrung = dynamic_cast<address_ton *>(scrung);
372  if (!rescrung)
373  deadly_error(class_name(), "test fast_unpack", "wrong dynamic type for scrung");
374  address_ton &prescrung = *rescrung;
375  if ((network_address &)prescrung != (network_address &)norf)
376  deadly_error(class_name(), "test fast_unpack", "wrong network address restored");
377  WHACK(scrung);
378 }
379 
380 const int MAXIMUM_TESTS = 10;
381  // was added to check for memory leaks.
382 
383 int test_unpacker::execute()
384 {
385  int iters = 0;
386  while (iters++ < MAXIMUM_TESTS) {
387 //log(a_sprintf("iter #%d", iters));
388  test_unpacking();
389  }
390  log("unpacking octopus:: works for all functions tested.");
391 //time_control::sleep_ms(30000);
392  return 0;
393 }
394 
395 HOOPLE_MAIN(test_unpacker, )
396 
#define deadly_error(c, f, i)
#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 HOOPLE_MAIN(obj_name, obj_args)
options that should work for most unix and linux apps.
Definition: hoople_main.h:61
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
const int MEGABYTE
Number of bytes in a megabyte.
Definition: definitions.h:135
bool unpack(basis::byte_array &packed_form, set< contents > &to_unpack)
provides a way to unpack any set that stores packable objects.
Definition: set.h:139
void attach(byte_array &packed_form, const byte_array &to_attach)
Packs a byte_array "to_attach" into "packed_form".
void pack(basis::byte_array &packed_form, const set< contents > &to_pack)
provides a way to pack any set that stores packable objects.
Definition: set.h:131
bool detach(byte_array &packed_form, byte_array &to_detach)
Unpacks a byte_array "to_detach" from "packed_form".
int packed_size(const byte_array &packed_form)
Reports the size required to pack a byte array into a byte array.
#define SAFE_STATIC_CONST(type, func_name, parms)
this version returns a constant object instead.
const char * math_list[]
Definition: t_unpacker.cpp:56
string_array(1, math_list))) const char *addr_list[]
const int MAXIMUM_TESTS
Definition: t_unpacker.cpp:380
const char * base_list[]
Definition: t_unpacker.cpp:52
Automates some common tasks for tentacle implementations. This template provides some default impleme...