X-Git-Url: https://feistymeow.org/gitweb/?a=blobdiff_plain;f=octopi%2Flibrary%2Ftests_octopus%2Ft_unpacker.cpp;fp=octopi%2Flibrary%2Ftests_octopus%2Ft_unpacker.cpp;h=a12412a3ba40f2217b53ea372da03e20cf65d2f4;hb=aad83c15eb10a34baff9b6472f88d1dfa1db9d77;hp=0000000000000000000000000000000000000000;hpb=7b499c3676de8069f7cfa13bca61837e9ee1f970;p=feisty_meow.git diff --git a/octopi/library/tests_octopus/t_unpacker.cpp b/octopi/library/tests_octopus/t_unpacker.cpp new file mode 100644 index 00000000..a12412a3 --- /dev/null +++ b/octopi/library/tests_octopus/t_unpacker.cpp @@ -0,0 +1,396 @@ +/*****************************************************************************\ +* * +* Name : unpacking octopus test * +* Author : Chris Koeritz * +* * +* Purpose: * +* * +* A test of octopuses used for unpacking flat structures. * +* * +******************************************************************************* +* Copyright (c) 2002-$now By Author. This program is free software; you can * +* redistribute it and/or modify it under the terms of the GNU General Public * +* License as published by the Free Software Foundation; either version 2 of * +* the License or (at your option) any later version. This is online at: * +* http://www.fsf.org/copyleft/gpl.html * +* Please send any updates to: fred@gruntose.com * +\*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//hmmm: provide equality ops to be able to check that same stuff +// came back out that went in. + +class test_unpacker : public application_shell +{ +public: + test_unpacker() : application_shell(class_name()) {} + DEFINE_CLASS_NAME("test_unpacker"); + virtual int execute(); + void test_unpacking(); +}; + +////////////// + +// the infotons here have a three level classifier. the outer level is +// for the benefit of the handler_arm tentacle that just checks that the +// group name is correct before passing off the request to its internal +// octopus. then the second level specifies which class of infotons are +// being managed. the third level specifies the leaf type of the infoton-- +// the specific type of data being wrapped. + +const char *base_list[] = { "gruntiak" }; + +SAFE_STATIC_CONST(string_array, base_classifier, (1, base_list)) + +const char *math_list[] = { "math" }; + +SAFE_STATIC_CONST(string_array, math_classifier, (base_classifier() + + string_array(1, math_list))) + +const char *addr_list[] = { "address" }; + +SAFE_STATIC_CONST(string_array, addr_classifier, (base_classifier() + + string_array(1, addr_list))) + +class address_ton : public infoton, public network_address +{ +public: + address_ton() : infoton(addr_classifier() + "leaf") {} + + virtual void pack(byte_array &packed_form) const { + network_address::pack(packed_form); + } + + virtual bool unpack(byte_array &packed_form) { + return network_address::unpack(packed_form); + } + + virtual int packed_size() const { + return 5 * sizeof(int) + 128 /*address estimate*/; + } + + virtual clonable *clone() const { + return new address_ton(*this); + } +}; + +//some floating point nums. +class float_ton : public infoton +{ +public: + float f1; + double d1; + + float_ton() : infoton(math_classifier() + "float") {} + + virtual void pack(byte_array &packed_form) const { + structures::attach(packed_form, f1); + structures::attach(packed_form, d1); + } + + virtual int packed_size() const { + return sizeof(double) + sizeof(float); + } + + virtual bool unpack(byte_array &packed_form) { + double hold; + if (!structures::detach(packed_form, hold)) return false; + f1 = float(hold); + if (!structures::detach(packed_form, d1)) return false; + return true; + } + + virtual clonable *clone() const { + return new float_ton(*this); + } +}; + +//an integer set. +class int_set_ton : public infoton +{ +public: + int_set nums; + + int_set_ton() : infoton(math_classifier() + "intset") {} + + virtual void pack(byte_array &packed_form) const { + structures::attach(packed_form, nums.elements()); + for (int i = 0; i < nums.elements(); i++) + structures::attach(packed_form, nums[i]); + } + + virtual int packed_size() const { + return sizeof(int) + nums.elements() * sizeof(int); + } + + virtual bool unpack(byte_array &packed_form) { + int len = 0; + nums.reset(); + if (!structures::detach(packed_form, len)) return false; + for (int i = 0; i < len; i++) { + int got = 0; + if (!structures::detach(packed_form, got)) return false; + nums += got; + } + return true; + } + + virtual clonable *clone() const { + return new int_set_ton(*this); + } +}; + +////////////// + +// handles network addresses. +class address_chomper : public tentacle_helper +{ +public: + address_chomper() + : tentacle_helper(addr_classifier().subarray(1, 1), true) {} +}; + +// handles floats and int_sets. +class numerical_chomper : public tentacle +{ +public: + numerical_chomper() : tentacle(math_classifier().subarray(1, 1), true) {} + + outcome reconstitute(const string_array &classifier, byte_array &packed_form, + infoton * &reformed) + { + reformed = NIL; + if (classifier.length() < 2) return BAD_INPUT; + astring key = classifier[1]; + if (key == "float") { + float_ton *to_return = new float_ton; + if (!to_return->unpack(packed_form)) { + WHACK(to_return); + return NIL; + } + reformed = to_return; + return OKAY; + } else if (key == "intset") { + int_set_ton *to_return = new int_set_ton; + if (!to_return->unpack(packed_form)) { + WHACK(to_return); + return NIL; + } + reformed = to_return; + return OKAY; + } else + return NO_HANDLER; + } + + outcome consume(infoton &formal(to_chow), const octopus_request_id &formal(item_id), + byte_array &transformed) + { transformed.reset(); return tentacle::BAD_INPUT; } + + virtual void expunge(const octopus_entity &formal(zapola)) {} +}; + +////////////// + +// delegates the unpacking to an internal tentacle. it peels off a level +// of classifier to find the real handler. +class outer_arm : public tentacle +{ +public: + outer_arm() + : tentacle(base_classifier(), true), + _unpackers("local", 10 * MEGABYTE), + _numer(new numerical_chomper), + _addron(new address_chomper) + { + // register the two tentacles. + outcome ret = _unpackers.add_tentacle(_numer); + if (ret != tentacle::OKAY) + deadly_error(class_name(), "adding numerical tentacle", + astring("failed to add: ") + tentacle::outcome_name(ret)); + ret = _unpackers.add_tentacle(_addron); + if (ret != tentacle::OKAY) + deadly_error(class_name(), "adding address tentacle", + astring("failed to add: ") + tentacle::outcome_name(ret)); + } + + ~outer_arm() { + // just reset the two tentacles, since the _unpackers octopus should + // clean them up. + _numer = NIL; + _addron = NIL; + } + + outcome reconstitute(const string_array &classifier, byte_array &packed_form, + infoton * &reformed) + { + // strip first word of classifier. + string_array real_class = classifier; + real_class.zap(0, 0); + // route to octopus. + return _unpackers.restore(real_class, packed_form, reformed); + } + + outcome consume(infoton &to_chow, const octopus_request_id &item_id, + byte_array &transformed) + { + transformed.reset(); + // strip first word of classifier. + string_array real_class = to_chow.classifier(); + real_class.zap(0, 0); + to_chow.set_classifier(real_class); + // route to octopus. + return _unpackers.evaluate((infoton *)to_chow.clone(), item_id); + } + + void expunge(const octopus_entity &formal(whackola)) {} + +private: + octopus _unpackers; + numerical_chomper *_numer; + address_chomper *_addron; +}; + +////////////// + +void test_unpacker::test_unpacking() +{ + octopus unpacky("local", 10 * MEGABYTE); + outer_arm *outer = new outer_arm; + outcome ret = unpacky.add_tentacle(outer); + if (ret != tentacle::OKAY) + deadly_error(class_name(), "adding outer tentacle", + astring("failed to add: ") + tentacle::outcome_name(ret)); + + // test infoton fast packing. + int_set_ton jubjub; + jubjub.nums.add(299); + jubjub.nums.add(39274); + jubjub.nums.add(25182); + byte_array packed(10388); // have data in there to start. + infoton::fast_pack(packed, jubjub); + if (jubjub.packed_size() + infoton::fast_pack_overhead(jubjub.classifier()) + != packed.length() - 10388) + deadly_error(class_name(), "packing test", + astring("erroneous size calculated for first fast_pack")); + string_array shirley_class; + byte_array shirley_data; + packed.zap(0, 10387); // remove the original data. + + // testing the overhead calculation. + byte_array junk_jub; + jubjub.pack(junk_jub); + if (packed.length() != junk_jub.length() + + infoton::fast_pack_overhead(jubjub.classifier())) + deadly_error(class_name(), "test fast pack overhead", + "sizes differed from calculated"); + + if (!infoton::fast_unpack(packed, shirley_class, shirley_data)) + deadly_error(class_name(), "test infoton fast pack", + "failed shirley unpack"); + if (packed.length() != 0) + deadly_error(class_name(), "test infoton fast pack", + "shirley didn't consume all"); + if (shirley_class != jubjub.classifier()) + deadly_error(class_name(), "test infoton fast pack", + "inequal orig classifier"); + int_set_ton scroop; + if (!scroop.unpack(shirley_data)) + deadly_error(class_name(), "test infoton fast pack", + "failed scroop unpack"); + if (shirley_data.length()) + deadly_error(class_name(), "test infoton fast pack", + "scroop didn't consume all"); + if (scroop.nums.length() != 3) + deadly_error(class_name(), "test infoton fast pack", + "wrong length in scroop"); + if ( (scroop.nums[0] != jubjub.nums[0]) || (scroop.nums[1] != jubjub.nums[1]) + || (scroop.nums[2] != jubjub.nums[2]) ) + deadly_error(class_name(), "test infoton fast pack", + "erroneous information"); + + byte_array fasting; + infoton::fast_pack(fasting, jubjub); + if (jubjub.packed_size() + infoton::fast_pack_overhead(jubjub.classifier()) + != fasting.length()) + deadly_error(class_name(), "packing test", + astring("erroneous size calculated for second fast_pack")); + + // another test of the overhead calculator. + byte_array junk_fast; + jubjub.pack(junk_fast); + if (fasting.length() != junk_fast.length() + + infoton::fast_pack_overhead(jubjub.classifier())) + deadly_error(class_name(), "test fast pack overhead 2", + "sizes differed from calculated"); + + string_array nudge_class; + byte_array nudge_data; + if (!infoton::fast_unpack(fasting, nudge_class, nudge_data)) + deadly_error(class_name(), "test infoton fast pack", "fast pack failed to unpack"); + if (fasting.length()) + deadly_error(class_name(), "test infoton fast pack", "fast pack didn't consume all"); + int_set_ton croup; + if (!croup.unpack(nudge_data)) + deadly_error(class_name(), "test infoton fast pack", "croup wouldn't unpack"); + if ( (croup.nums[0] != jubjub.nums[0]) || (croup.nums[1] != jubjub.nums[1]) + || (croup.nums[2] != jubjub.nums[2]) ) + deadly_error(class_name(), "test infoton fast pack", "croup has errors"); + byte_array chunkmo; + chunkmo += 0x23; + chunkmo += 0xf8; + chunkmo += 0x37; + chunkmo += 0x65; + address_ton norf; + (network_address &)norf = network_address(internet_address + (chunkmo, "urp", 23841)); + chunkmo.reset(); + infoton::fast_pack(chunkmo, norf); + string_array clarfiator; + byte_array pacula; + if (!infoton::fast_unpack(chunkmo, clarfiator, pacula)) + deadly_error(class_name(), "test fast_unpack", "chunkmo has errors"); + infoton *scrung = NIL; +//log(astring("classif is ") + clarfiator.text_form()); + + outcome scrung_ret = unpacky.restore(clarfiator, pacula, scrung); + if (scrung_ret != tentacle::OKAY) + deadly_error(class_name(), "test fast_unpack", + a_sprintf("can't restore scrung: %s", + tentacle::outcome_name(scrung_ret))); + address_ton *rescrung = dynamic_cast(scrung); + if (!rescrung) + deadly_error(class_name(), "test fast_unpack", "wrong dynamic type for scrung"); + address_ton &prescrung = *rescrung; + if ((network_address &)prescrung != (network_address &)norf) + deadly_error(class_name(), "test fast_unpack", "wrong network address restored"); + WHACK(scrung); +} + +const int MAXIMUM_TESTS = 10; + // was added to check for memory leaks. + +int test_unpacker::execute() +{ + int iters = 0; + while (iters++ < MAXIMUM_TESTS) { +//log(a_sprintf("iter #%d", iters)); + test_unpacking(); + } + log("unpacking octopus:: works for all functions tested."); +//time_control::sleep_ms(30000); + return 0; +} + +HOOPLE_MAIN(test_unpacker, ) +