--- /dev/null
+/*****************************************************************************\
+* *
+* Name : test_safe_callback *
+* Author : Chris Koeritz *
+* *
+* Purpose: *
+* *
+* Tests the safe callback object slightly. Mainly this is to ensure that *
+* no memory leaks are being caused by the object and that minimal support is *
+* provided by the object. *
+* *
+*******************************************************************************
+* Copyright (c) 1998-$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 <application/hoople_main.h>
+#include <basis/astring.h>
+#include <basis/guards.h>
+#include <configuration/application_configuration.h>
+#include <loggers/critical_events.h>
+#include <loggers/program_wide_logger.h>
+//#include <loggers/file_logger.h>
+#include <processes/safe_callback.h>
+#include <structures/static_memory_gremlin.h>
+#include <unit_test/unit_base.h>
+
+using namespace application;
+using namespace basis;
+using namespace configuration;
+//using namespace mathematics;
+//using namespace filesystem;
+using namespace loggers;
+using namespace processes;
+//using namespace structures;
+//using namespace textual;
+using namespace timely;
+using namespace unit_test;
+
+#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), astring(s))
+
+//////////////
+
+const astring LOGFILE_NAME = application_configuration::make_logfile_name
+ ("t_safe_callback.log");
+ // where our debugging output goes by default.
+
+///#define LOG(to_print) log.log(timestamp(true) + astring(to_print))
+ // our macro for logging with a timestamp.
+
+//hmmm: this tester doesn't really do very much at all.
+// how about a more aggressive test, which has a bunch of threads using
+// safe callback?
+
+class cb_tester : public safe_callback
+{
+public:
+ cb_tester() : safe_callback() {}
+ ~cb_tester() { end_availability(); }
+
+ virtual void real_callback(callback_data_block &)
+ { /* do nothing. */ }
+};
+
+//hmmm: move this to using a class based approach, based on unit_test and application_shell.
+
+int main(int formal(argc), char *formal(argv)[])
+{
+/// file_logger log(LOGFILE_NAME);
+
+ cb_tester testing;
+
+ critical_events::alert_message("safe_callback:: works for all functions tested.");
+ return 0;
+}
+
--- /dev/null
+/*****************************************************************************\
+* *
+* Name : test_state_machine *
+* Author : Chris Koeritz *
+* *
+* Purpose: *
+* *
+* Sets up a simple state machine for a pattern matcher. *
+* *
+*******************************************************************************
+* Copyright (c) 1992-$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 *
+\*****************************************************************************/
+
+// This simple state machine recognizes all strings that are of the form
+// *.[cho], which means any string with either .o, .c, or .h on the end.
+
+#include <application/application_shell.h>
+#include <application/hoople_main.h>
+#include <basis/astring.h>
+#include <basis/byte_array.h>
+#include <basis/functions.h>
+#include <basis/guards.h>
+#include <configuration/application_configuration.h>
+#include <filesystem/byte_filer.h>
+#include <loggers/console_logger.h>
+#include <loggers/critical_events.h>
+#include <loggers/program_wide_logger.h>
+#include <processes/state_machine.h>
+#include <structures/static_memory_gremlin.h>
+#include <unit_test/unit_base.h>
+
+#include <string.h>
+
+using namespace application;
+using namespace basis;
+using namespace configuration;
+//using namespace mathematics;
+using namespace filesystem;
+using namespace loggers;
+using namespace processes;
+//using namespace structures;
+//using namespace textual;
+using namespace timely;
+using namespace unit_test;
+
+#undef LOG
+#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), astring(s))
+
+//////////////
+
+enum recognizer_states { GET_ANY = 1, GOT_DOT, GOT_CHO, RECOGNIZED, REJECTED };
+
+//#undef LOG
+//#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
+
+class test_state_machine : public application_shell
+{
+public:
+ test_state_machine();
+ DEFINE_CLASS_NAME("test_state_machine");
+ int execute();
+ void setup_state_machine(transition_map &recog);
+ void print_instructions();
+};
+
+astring state_text(recognizer_states to_show)
+{
+ switch (to_show) {
+ case GET_ANY: return "get_any";
+ case GOT_DOT: return "got_dot";
+ case GOT_CHO: return "got_cho";
+ case RECOGNIZED: return "recognized";
+ case REJECTED: return "rejected";
+ default: return "unknown!";
+ }
+}
+
+#define TEST(action) \
+ if (!action) \
+ deadly_error(class_name(), "setup", a_sprintf("failed on %s", #action))
+
+void test_state_machine::setup_state_machine(transition_map &recog)
+{
+ TEST(recog.add_state(GET_ANY));
+ TEST(recog.add_state(GOT_DOT));
+ TEST(recog.add_state(GOT_CHO));
+ TEST(recog.add_state(RECOGNIZED));
+ TEST(recog.add_state(REJECTED));
+
+ TEST(recog.set_start(GET_ANY));
+
+// bogus for test!
+//TEST(recog.add_range_transition(GET_ANY, 29378, 0, 0));
+
+ TEST(recog.add_range_transition(GET_ANY, REJECTED, 0, 0));
+ TEST(recog.add_range_transition(GET_ANY, GET_ANY, 1, '.'-1));
+ TEST(recog.add_range_transition(GET_ANY, GOT_DOT, '.', '.'));
+ TEST(recog.add_range_transition(GET_ANY, GET_ANY, '.'+1, 255));
+
+ // we wouldn't need so many cases if the update function made the
+ // jump out of GOT_DOT when an unsatisfactory pulse is seen?
+ TEST(recog.add_range_transition(GOT_DOT, REJECTED, '\0', '\0'));
+ TEST(recog.add_range_transition(GOT_DOT, GET_ANY, 1, '.'-1));
+ TEST(recog.add_range_transition(GOT_DOT, GOT_DOT, '.', '.'));
+ TEST(recog.add_range_transition(GOT_DOT, GET_ANY, '.'+1, 'c'-1));
+ TEST(recog.add_range_transition(GOT_DOT, GOT_CHO, 'c', 'c'));
+ TEST(recog.add_range_transition(GOT_DOT, GET_ANY, 'c'+1, 'h'-1));
+ TEST(recog.add_range_transition(GOT_DOT, GOT_CHO, 'h', 'h'));
+ TEST(recog.add_range_transition(GOT_DOT, GET_ANY, 'h'+1, 'o'-1));
+ TEST(recog.add_range_transition(GOT_DOT, GOT_CHO, 'o', 'o'));
+ TEST(recog.add_range_transition(GOT_DOT, GET_ANY, 'o'+1, 255));
+/// if update was doing it; TEST(recog.add_simple_transition(GOT_DOT, GET_ANY));
+
+ TEST(recog.add_range_transition(GOT_CHO, RECOGNIZED, '\0', '\0'));
+ TEST(recog.add_range_transition(GOT_CHO, GET_ANY, 1, '.'-1));
+ TEST(recog.add_range_transition(GOT_CHO, GOT_DOT, '.', '.'));
+ TEST(recog.add_range_transition(GOT_CHO, GET_ANY, '.'+1, 255));
+
+ int hosed;
+ if (recog.validate(hosed) != transition_map::OKAY)
+ deadly_error(class_name(), "check_machine",
+ astring(astring::SPRINTF, "invalid state_machine due to state %d", hosed).s());
+}
+
+test_state_machine::test_state_machine()
+: application_shell()
+{}
+
+void test_state_machine::print_instructions()
+{
+ critical_events::alert_message("\
+This program demonstrates the state machine class by constructing a machine\n\
+that recognizes the regular expression *.[cho], which is all strings ending\n\
+in a period followed by c, h, or o. The first parameter is the name of a\n\
+file to load strings from.\n");
+}
+
+int test_state_machine::execute()
+{
+ FUNCDEF("execute");
+ transition_map recog;
+ setup_state_machine(recog);
+
+ if (application::_global_argc < 2) {
+ print_instructions();
+ return 1;
+ }
+ astring filename = astring(application::_global_argv[1]);
+/// int indy = filename.find(' ');
+ if (!filename) {
+ print_instructions();
+ return 1;
+ }
+ ///filename.zap(indy, filename.end());
+
+ byte_filer fil(filename.s(), "r");
+
+//LOG(astring("filename is ") + filename.raw());
+
+ while (!fil.eof()) {
+ state_machine m;
+ recog.reset(m);
+
+ byte_array typed_string(901);
+//need a getline function for byte filer...
+ fil.getline(typed_string, 900);
+
+ int len = int(strlen((char *)typed_string.access()));
+ if (!len) continue; // skip blank lines...
+
+ int position = 0;
+ while ( (m.current() != RECOGNIZED) && (m.current() != REJECTED) ) {
+ recog.pulse(m, typed_string[position++]);
+ }
+
+ if (m.current() == RECOGNIZED) {
+ LOG((char *)typed_string.access());
+ } else if (m.current() == REJECTED) {
+ LOG("rejected...");
+ } else {
+ LOG("unknown final state!");
+ }
+ }
+ return 0;
+}
+
+//////////////
+
+HOOPLE_MAIN(test_state_machine, )
+
--- /dev/null
+/*****************************************************************************\
+* *
+* Name : test_time_stamp *
+* Author : Chris Koeritz *
+* *
+*******************************************************************************
+* Copyright (c) 1998-$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 <application/application_shell.h>
+#include <application/hoople_main.h>
+#include <basis/astring.h>
+#include <basis/guards.h>
+#include <loggers/program_wide_logger.h>
+#include <structures/static_memory_gremlin.h>
+#include <timely/time_control.h>
+#include <timely/time_stamp.h>
+#include <unit_test/unit_base.h>
+
+using namespace application;
+using namespace basis;
+using namespace loggers;
+using namespace structures;
+using namespace textual;
+using namespace timely;
+using namespace unit_test;
+
+#undef LOG
+#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
+
+//////////////
+
+//#define DEBUG_TIME_STAMP
+
+//const int RUN_DURATION = 5 * MINUTE_ms;
+const int RUN_DURATION = 3 * SECOND_ms;
+ // how long the test will run.
+
+const int SLEEP_DURATION = 42;
+ // the period of sleep between checks on the time stamp.
+
+const int REPORT_INTERVAL = 500; // every half second.
+ // how often we show the current time stamp.
+
+//////////////
+
+class time_stamp_tester : virtual public unit_base, virtual public application_shell
+{
+public:
+ time_stamp_tester() : application_shell() {}
+
+ DEFINE_CLASS_NAME("time_stamp_tester");
+
+ int execute() {
+ time_stamp start;
+ log(a_sprintf("initial time stamp: %0.0f", start.value()));
+
+ time_stamp curr;
+ time_stamp get_out(RUN_DURATION);
+ time_stamp report_time(REPORT_INTERVAL);
+ int iterations = RUN_DURATION / SLEEP_DURATION;
+ while (iterations-- > 0) {
+ if (time_stamp() < curr)
+ deadly_error(class_name(), "compare test", "failure; now is less "
+ "than earlier!");
+
+//hmmm: how about some more verifications, like the sleep time we asked for is reflected (or nearly) in the time stamp difference?
+
+ time_control::sleep_ms(SLEEP_DURATION);
+ curr = time_stamp();
+ if (time_stamp() >= report_time) {
+ log(a_sprintf("current time stamp: %0.0f", time_stamp().value()));
+ report_time.reset(REPORT_INTERVAL);
+ }
+ }
+
+ time_stamp end;
+ log(a_sprintf(" ending time stamp: %0.0f", end.value()));
+
+ critical_events::alert_message("time_stamp:: works for those functions tested.");
+ return 0;
+ }
+};
+
+//////////////
+
+HOOPLE_MAIN(time_stamp_tester, )
+