t_unpacker.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : unpacking octopus test                                            *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *  Purpose:                                                                   *
00007 *                                                                             *
00008 *    A test of octopuses used for unpacking flat structures.                  *
00009 *                                                                             *
00010 *******************************************************************************
00011 * Copyright (c) 2002-$now By Author.  This program is free software; you can  *
00012 * redistribute it and/or modify it under the terms of the GNU General Public  *
00013 * License as published by the Free Software Foundation; either version 2 of   *
00014 * the License or (at your option) any later version.  This is online at:      *
00015 *     http://www.fsf.org/copyleft/gpl.html                                    *
00016 * Please send any updates to: fred@gruntose.com                               *
00017 \*****************************************************************************/
00018 
00019 #include <basis/istring.h>
00020 #include <data_struct/static_memory_gremlin.h>
00021 #include <octopus/entity_defs.h>
00022 #include <octopus/infoton.h>
00023 #include <octopus/octopus.h>
00024 #include <octopus/tentacle_helper.h>
00025 #include <opsystem/application_shell.h>
00026 #include <loggers/console_logger.h>
00027 #include <loggers/file_logger.h>
00028 #include <data_struct/static_memory_gremlin.h>
00029 #include <sockets/address.h>
00030 
00031 //hmmm: provide equality ops to be able to check that same stuff
00032 //      came back out that went in.
00033 
00034 class test_unpacker : public application_shell
00035 {
00036 public:
00037   test_unpacker() : application_shell(class_name()) {}
00038   IMPLEMENT_CLASS_NAME("test_unpacker");
00039   virtual int execute();
00040   void test_unpacking();
00041 };
00042 
00044 
00045 // the infotons here have a three level classifier.  the outer level is
00046 // for the benefit of the handler_arm tentacle that just checks that the
00047 // group name is correct before passing off the request to its internal
00048 // octopus.  then the second level specifies which class of infotons are
00049 // being managed.  the third level specifies the leaf type of the infoton--
00050 // the specific type of data being wrapped.
00051 
00052 const char *base_list[] = { "gruntiak" };
00053 
00054 SAFE_STATIC_CONST(string_array, base_classifier, (1, base_list))
00055 
00056 const char *math_list[] = { "math" };
00057 
00058 SAFE_STATIC_CONST(string_array, math_classifier, (base_classifier()
00059     + string_array(1, math_list)))
00060 
00061 const char *addr_list[] = { "address" };
00062 
00063 SAFE_STATIC_CONST(string_array, addr_classifier, (base_classifier()
00064     + string_array(1, addr_list)))
00065 
00066 class address_ton : public infoton, public network_address
00067 {
00068 public:
00069   address_ton() : infoton(addr_classifier() + "leaf") {}
00070 
00071   virtual void pack(byte_array &packed_form) const {
00072     network_address::pack(packed_form);
00073   }
00074 
00075   virtual bool unpack(byte_array &packed_form) {
00076     return network_address::unpack(packed_form);
00077   }
00078 
00079   virtual int packed_size() const {
00080     return 5 * sizeof(int) + 128 /*address estimate*/;
00081   }
00082 
00083   virtual clonable *clone() const {
00084     return new address_ton(*this);
00085   }
00086 };
00087 
00088 //some floating point nums.
00089 class float_ton : public infoton
00090 {
00091 public:
00092   float f1;
00093   double d1;
00094 
00095   float_ton() : infoton(math_classifier() + "float") {}
00096 
00097   virtual void pack(byte_array &packed_form) const {
00098     basis::attach(packed_form, f1);
00099     basis::attach(packed_form, d1);
00100   }
00101 
00102   virtual int packed_size() const {
00103     return sizeof(double) + sizeof(float);
00104   }
00105 
00106   virtual bool unpack(byte_array &packed_form) {
00107     double hold;
00108     if (!basis::detach(packed_form, hold)) return false;
00109     f1 = float(hold);
00110     if (!basis::detach(packed_form, d1)) return false;
00111     return true;
00112   }
00113 
00114   virtual clonable *clone() const {
00115     return new float_ton(*this);
00116   }
00117 };
00118 
00119 //an integer set.
00120 class int_set_ton : public infoton
00121 {
00122 public:
00123   int_set nums;
00124 
00125   int_set_ton() : infoton(math_classifier() + "intset") {}
00126 
00127   virtual void pack(byte_array &packed_form) const {
00128     basis::attach(packed_form, nums.elements());
00129     for (int i = 0; i < nums.elements(); i++)
00130       basis::attach(packed_form, nums[i]);
00131   }
00132 
00133   virtual int packed_size() const {
00134     return sizeof(int) + nums.elements() * sizeof(int);
00135   }
00136 
00137   virtual bool unpack(byte_array &packed_form) {
00138     int len = 0;
00139     nums.reset();
00140     if (!basis::detach(packed_form, len)) return false;
00141     for (int i = 0; i < len; i++) {
00142       int got = 0;
00143       if (!basis::detach(packed_form, got)) return false;
00144       nums += got;
00145     }
00146     return true;
00147   }
00148 
00149   virtual clonable *clone() const {
00150     return new int_set_ton(*this);
00151   }
00152 };
00153 
00155 
00156 // handles network addresses.
00157 class address_chomper : public tentacle_helper<address_ton>
00158 {
00159 public:
00160   address_chomper()
00161   : tentacle_helper<address_ton>(addr_classifier().subarray(1, 1), true) {}
00162 };
00163 
00164 // handles floats and int_sets.
00165 class numerical_chomper : public tentacle
00166 {
00167 public:
00168   numerical_chomper() : tentacle(math_classifier().subarray(1, 1), true) {}
00169 
00170   outcome reconstitute(const string_array &classifier, byte_array &packed_form,
00171       infoton * &reformed)
00172   {
00173     reformed = NIL;
00174     if (classifier.length() < 2) return BAD_INPUT;
00175     istring key = classifier[1];
00176     if (key == "float") {
00177       float_ton *to_return = new float_ton;
00178       if (!to_return->unpack(packed_form)) {
00179         WHACK(to_return);
00180         return NIL;
00181       }
00182       reformed = to_return;
00183       return OKAY;
00184     } else if (key == "intset") {
00185       int_set_ton *to_return = new int_set_ton;
00186       if (!to_return->unpack(packed_form)) {
00187         WHACK(to_return);
00188         return NIL;
00189       }
00190       reformed = to_return;
00191       return OKAY;
00192     } else
00193       return NO_HANDLER;
00194   }
00195 
00196   outcome consume(infoton &formal(to_chow), const octopus_request_id &formal(item_id),
00197           byte_array &transformed)
00198   { transformed.reset(); return tentacle::BAD_INPUT; }
00199 
00200   virtual void expunge(const octopus_entity &formal(zapola)) {}
00201 };
00202 
00204 
00205 // delegates the unpacking to an internal tentacle.  it peels off a level
00206 // of classifier to find the real handler.
00207 class outer_arm : public tentacle
00208 {
00209 public:
00210   outer_arm()
00211   : tentacle(base_classifier(), true),
00212     _unpackers("local", 10 * MEGABYTE),
00213     _numer(new numerical_chomper),
00214     _addron(new address_chomper)
00215   {
00216     // register the two tentacles.
00217     outcome ret = _unpackers.add_tentacle(_numer);
00218     if (ret != tentacle::OKAY)
00219       deadly_error(class_name(), "adding numerical tentacle",
00220           istring("failed to add: ") + tentacle::outcome_name(ret));
00221     ret = _unpackers.add_tentacle(_addron);
00222     if (ret != tentacle::OKAY)
00223       deadly_error(class_name(), "adding address tentacle",
00224           istring("failed to add: ") + tentacle::outcome_name(ret));
00225   }
00226 
00227   ~outer_arm() {
00228     // just reset the two tentacles, since the _unpackers octopus should
00229     // clean them up.
00230     _numer = NIL;
00231     _addron = NIL;
00232   }
00233 
00234   outcome reconstitute(const string_array &classifier, byte_array &packed_form,
00235       infoton * &reformed)
00236   {
00237     // strip first word of classifier.
00238     string_array real_class = classifier;
00239     real_class.zap(0, 0);
00240     // route to octopus.
00241     return _unpackers.restore(real_class, packed_form, reformed);
00242   }
00243 
00244   outcome consume(infoton &to_chow, const octopus_request_id &item_id,
00245           byte_array &transformed)
00246   {
00247     transformed.reset();
00248     // strip first word of classifier.
00249     string_array real_class = to_chow.classifier();
00250     real_class.zap(0, 0);
00251     to_chow.set_classifier(real_class);
00252     // route to octopus.
00253     return _unpackers.evaluate((infoton *)to_chow.clone(), item_id);
00254   }
00255 
00256   void expunge(const octopus_entity &formal(whackola)) {}
00257 
00258 private:
00259   octopus _unpackers;
00260   numerical_chomper *_numer;
00261   address_chomper *_addron;
00262 };
00263 
00265 
00266 void test_unpacker::test_unpacking()
00267 {
00268   octopus unpacky("local", 10 * MEGABYTE);
00269   outer_arm *outer = new outer_arm;
00270   outcome ret = unpacky.add_tentacle(outer);
00271   if (ret != tentacle::OKAY)
00272     deadly_error(class_name(), "adding outer tentacle",
00273         istring("failed to add: ") + tentacle::outcome_name(ret));
00274 
00275   // test infoton fast packing.
00276   int_set_ton jubjub;
00277   jubjub.nums.add(299);
00278   jubjub.nums.add(39274);
00279   jubjub.nums.add(25182);
00280   byte_array packed(10388);  // have data in there to start.
00281   infoton::fast_pack(packed, jubjub);
00282   if (jubjub.packed_size() + infoton::fast_pack_overhead(jubjub.classifier())
00283       != packed.length() - 10388)
00284     deadly_error(class_name(), "packing test",
00285         istring("erroneous size calculated for first fast_pack"));
00286   string_array shirley_class;
00287   byte_array shirley_data;
00288   packed.zap(0, 10387);  // remove the original data.
00289 
00290   // testing the overhead calculation.
00291   byte_array junk_jub;
00292   jubjub.pack(junk_jub);
00293   if (packed.length() != junk_jub.length()
00294       + infoton::fast_pack_overhead(jubjub.classifier()))
00295     deadly_error(class_name(), "test fast pack overhead",
00296         "sizes differed from calculated");
00297 
00298   if (!infoton::fast_unpack(packed, shirley_class, shirley_data))
00299     deadly_error(class_name(), "test infoton fast pack",
00300         "failed shirley unpack");
00301   if (packed.length() != 0)
00302     deadly_error(class_name(), "test infoton fast pack",
00303         "shirley didn't consume all");
00304   if (shirley_class != jubjub.classifier())
00305     deadly_error(class_name(), "test infoton fast pack",
00306         "inequal orig classifier");
00307   int_set_ton scroop;
00308   if (!scroop.unpack(shirley_data))
00309     deadly_error(class_name(), "test infoton fast pack",
00310         "failed scroop unpack");
00311   if (shirley_data.length())
00312     deadly_error(class_name(), "test infoton fast pack",
00313         "scroop didn't consume all");
00314   if (scroop.nums.length() != 3)
00315     deadly_error(class_name(), "test infoton fast pack",
00316         "wrong length in scroop");
00317   if ( (scroop.nums[0] != jubjub.nums[0]) || (scroop.nums[1] != jubjub.nums[1])
00318       || (scroop.nums[2] != jubjub.nums[2]) )
00319     deadly_error(class_name(), "test infoton fast pack",
00320         "erroneous information");
00321 
00322   byte_array fasting;
00323   infoton::fast_pack(fasting, jubjub);
00324   if (jubjub.packed_size() + infoton::fast_pack_overhead(jubjub.classifier())
00325       != fasting.length())
00326     deadly_error(class_name(), "packing test",
00327         istring("erroneous size calculated for second fast_pack"));
00328 
00329   // another test of the overhead calculator.
00330   byte_array junk_fast;
00331   jubjub.pack(junk_fast);
00332   if (fasting.length() != junk_fast.length()
00333       + infoton::fast_pack_overhead(jubjub.classifier()))
00334     deadly_error(class_name(), "test fast pack overhead 2",
00335         "sizes differed from calculated");
00336 
00337   string_array nudge_class;
00338   byte_array nudge_data;
00339   if (!infoton::fast_unpack(fasting, nudge_class, nudge_data))
00340     deadly_error(class_name(), "test infoton fast pack", "fast pack failed to unpack");
00341   if (fasting.length())
00342     deadly_error(class_name(), "test infoton fast pack", "fast pack didn't consume all");
00343   int_set_ton croup;
00344   if (!croup.unpack(nudge_data))
00345     deadly_error(class_name(), "test infoton fast pack", "croup wouldn't unpack");
00346   if ( (croup.nums[0] != jubjub.nums[0]) || (croup.nums[1] != jubjub.nums[1])
00347       || (croup.nums[2] != jubjub.nums[2]) )
00348     deadly_error(class_name(), "test infoton fast pack", "croup has errors");
00349   byte_array chunkmo;
00350   chunkmo += 0x23;
00351   chunkmo += 0xf8;
00352   chunkmo += 0x37;
00353   chunkmo += 0x65;
00354   address_ton norf;
00355   (network_address &)norf = network_address(internet_address
00356       (chunkmo, "urp", 23841));
00357   chunkmo.reset();
00358   infoton::fast_pack(chunkmo, norf);
00359   string_array clarfiator;
00360   byte_array pacula;
00361   if (!infoton::fast_unpack(chunkmo, clarfiator, pacula))
00362     deadly_error(class_name(), "test fast_unpack", "chunkmo has errors");
00363   infoton *scrung = NIL;
00364 //log(istring("classif is ") + clarfiator.text_form());
00365 
00366   outcome scrung_ret = unpacky.restore(clarfiator, pacula, scrung);
00367   if (scrung_ret != tentacle::OKAY)
00368     deadly_error(class_name(), "test fast_unpack",
00369         isprintf("can't restore scrung: %s",
00370             tentacle::outcome_name(scrung_ret)));
00371   address_ton *rescrung = dynamic_cast<address_ton *>(scrung);
00372   if (!rescrung)
00373     deadly_error(class_name(), "test fast_unpack", "wrong dynamic type for scrung");
00374   address_ton &prescrung = *rescrung;
00375   if ((network_address &)prescrung != (network_address &)norf)
00376     deadly_error(class_name(), "test fast_unpack", "wrong network address restored");
00377   WHACK(scrung);
00378 }
00379 
00380 const int MAXIMUM_TESTS = 10;
00381   // was added to check for memory leaks.
00382 
00383 int test_unpacker::execute()
00384 {
00385   int iters = 0;
00386   while (iters++ < MAXIMUM_TESTS) {
00387 //log(isprintf("iter #%d", iters));
00388     test_unpacking();
00389   }
00390   log("unpacking octopus:: works for all functions tested.");
00391 //portable::sleep_ms(30000);
00392   return 0;
00393 }
00394 
00395 HOOPLE_MAIN(test_unpacker, )
00396 

Generated on Fri Nov 28 04:29:39 2008 for HOOPLE Libraries by  doxygen 1.5.1