1 /*****************************************************************************\
3 * Name : unpacking octopus test *
4 * Author : Chris Koeritz *
8 * A test of octopuses used for unpacking flat structures. *
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 \*****************************************************************************/
19 #include <basis/astring.h>
20 #include <structures/static_memory_gremlin.h>
21 #include <octopus/entity_defs.h>
22 #include <octopus/infoton.h>
23 #include <octopus/octopus.h>
24 #include <octopus/tentacle_helper.h>
25 #include <application/application_shell.h>
26 #include <loggers/console_logger.h>
27 #include <loggers/file_logger.h>
28 #include <structures/static_memory_gremlin.h>
29 #include <sockets/internet_address.h>
31 //hmmm: provide equality ops to be able to check that same stuff
32 // came back out that went in.
34 class test_unpacker : public application_shell
37 test_unpacker() : application_shell(class_name()) {}
38 DEFINE_CLASS_NAME("test_unpacker");
39 virtual int execute();
40 void test_unpacking();
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.
52 const char *base_list[] = { "gruntiak" };
54 SAFE_STATIC_CONST(string_array, base_classifier, (1, base_list))
56 const char *math_list[] = { "math" };
58 SAFE_STATIC_CONST(string_array, math_classifier, (base_classifier()
59 + string_array(1, math_list)))
61 const char *addr_list[] = { "address" };
63 SAFE_STATIC_CONST(string_array, addr_classifier, (base_classifier()
64 + string_array(1, addr_list)))
66 class address_ton : public infoton, public network_address
69 address_ton() : infoton(addr_classifier() + "leaf") {}
71 virtual void pack(byte_array &packed_form) const {
72 network_address::pack(packed_form);
75 virtual bool unpack(byte_array &packed_form) {
76 return network_address::unpack(packed_form);
79 virtual int packed_size() const {
80 return 5 * sizeof(int) + 128 /*address estimate*/;
83 virtual clonable *clone() const {
84 return new address_ton(*this);
88 //some floating point nums.
89 class float_ton : public infoton
95 float_ton() : infoton(math_classifier() + "float") {}
97 virtual void pack(byte_array &packed_form) const {
98 structures::attach(packed_form, f1);
99 structures::attach(packed_form, d1);
102 virtual int packed_size() const {
103 return sizeof(double) + sizeof(float);
106 virtual bool unpack(byte_array &packed_form) {
108 if (!structures::detach(packed_form, hold)) return false;
110 if (!structures::detach(packed_form, d1)) return false;
114 virtual clonable *clone() const {
115 return new float_ton(*this);
120 class int_set_ton : public infoton
125 int_set_ton() : infoton(math_classifier() + "intset") {}
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]);
133 virtual int packed_size() const {
134 return sizeof(int) + nums.elements() * sizeof(int);
137 virtual bool unpack(byte_array &packed_form) {
140 if (!structures::detach(packed_form, len)) return false;
141 for (int i = 0; i < len; i++) {
143 if (!structures::detach(packed_form, got)) return false;
149 virtual clonable *clone() const {
150 return new int_set_ton(*this);
156 // handles network addresses.
157 class address_chomper : public tentacle_helper<address_ton>
161 : tentacle_helper<address_ton>(addr_classifier().subarray(1, 1), true) {}
164 // handles floats and int_sets.
165 class numerical_chomper : public tentacle
168 numerical_chomper() : tentacle(math_classifier().subarray(1, 1), true) {}
170 outcome reconstitute(const string_array &classifier, byte_array &packed_form,
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)) {
182 reformed = to_return;
184 } else if (key == "intset") {
185 int_set_ton *to_return = new int_set_ton;
186 if (!to_return->unpack(packed_form)) {
190 reformed = to_return;
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; }
200 virtual void expunge(const octopus_entity &formal(zapola)) {}
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
211 : tentacle(base_classifier(), true),
212 _unpackers("local", 10 * MEGABYTE),
213 _numer(new numerical_chomper),
214 _addron(new address_chomper)
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));
228 // just reset the two tentacles, since the _unpackers octopus should
230 _numer = NULL_POINTER;
231 _addron = NULL_POINTER;
234 outcome reconstitute(const string_array &classifier, byte_array &packed_form,
237 // strip first word of classifier.
238 string_array real_class = classifier;
239 real_class.zap(0, 0);
241 return _unpackers.restore(real_class, packed_form, reformed);
244 outcome consume(infoton &to_chow, const octopus_request_id &item_id,
245 byte_array &transformed)
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);
253 return _unpackers.evaluate((infoton *)to_chow.clone(), item_id);
256 void expunge(const octopus_entity &formal(whackola)) {}
260 numerical_chomper *_numer;
261 address_chomper *_addron;
266 void test_unpacker::test_unpacking()
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));
275 // test infoton fast packing.
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.
290 // testing the overhead calculation.
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");
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");
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");
323 infoton::fast_pack(fasting, jubjub);
324 if (jubjub.packed_size() + infoton::fast_pack_overhead(jubjub.classifier())
326 deadly_error(class_name(), "packing test",
327 astring("erroneous size calculated for second fast_pack"));
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");
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");
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");
355 (network_address &)norf = network_address(internet_address
356 (chunkmo, "urp", 23841));
358 infoton::fast_pack(chunkmo, norf);
359 string_array clarfiator;
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());
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);
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");
380 const int MAXIMUM_TESTS = 10;
381 // was added to check for memory leaks.
383 int test_unpacker::execute()
386 while (iters++ < MAXIMUM_TESTS) {
387 //log(a_sprintf("iter #%d", iters));
390 log("unpacking octopus:: works for all functions tested.");
391 //time_control::sleep_ms(30000);
395 HOOPLE_MAIN(test_unpacker, )