feisty meow concerns codebase 2.140
test_state_machine.cpp
Go to the documentation of this file.
1/*****************************************************************************\
2* *
3* Name : test_state_machine *
4* Author : Chris Koeritz *
5* *
6* Purpose: *
7* *
8* Sets up a simple state machine for a pattern matcher. *
9* *
10*******************************************************************************
11* Copyright (c) 1992-$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// This simple state machine recognizes all strings that are of the form
20// *.[cho], which means any string with either .o, .c, or .h on the end.
21
24#include <basis/astring.h>
25#include <basis/byte_array.h>
26#include <basis/functions.h>
27#include <basis/guards.h>
35#include <unit_test/unit_base.h>
36
37#include <string.h>
38
39using namespace application;
40using namespace basis;
41using namespace configuration;
42//using namespace mathematics;
43using namespace filesystem;
44using namespace loggers;
45using namespace processes;
46//using namespace structures;
47//using namespace textual;
48using namespace timely;
49using namespace unit_test;
50
51#undef LOG
52#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), astring(s))
53
55
57
58//#undef LOG
59//#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
60
61class test_state_machine : public application_shell
62{
63public:
64 test_state_machine();
65 DEFINE_CLASS_NAME("test_state_machine");
66 int execute();
67 void setup_state_machine(transition_map &recog);
68 void print_instructions();
69};
70
72{
73 switch (to_show) {
74 case GET_ANY: return "get_any";
75 case GOT_DOT: return "got_dot";
76 case GOT_CHO: return "got_cho";
77 case RECOGNIZED: return "recognized";
78 case REJECTED: return "rejected";
79 default: return "unknown!";
80 }
81}
82
83#define TEST(action) \
84 if (!action) \
85 deadly_error(class_name(), "setup", a_sprintf("failed on %s", #action))
86
87void test_state_machine::setup_state_machine(transition_map &recog)
88{
89 TEST(recog.add_state(GET_ANY));
90 TEST(recog.add_state(GOT_DOT));
91 TEST(recog.add_state(GOT_CHO));
93 TEST(recog.add_state(REJECTED));
94
95 TEST(recog.set_start(GET_ANY));
96
97// bogus for test!
98//TEST(recog.add_range_transition(GET_ANY, 29378, 0, 0));
99
101 TEST(recog.add_range_transition(GET_ANY, GET_ANY, 1, '.'-1));
102 TEST(recog.add_range_transition(GET_ANY, GOT_DOT, '.', '.'));
103 TEST(recog.add_range_transition(GET_ANY, GET_ANY, '.'+1, 255));
104
105 // we wouldn't need so many cases if the update function made the
106 // jump out of GOT_DOT when an unsatisfactory pulse is seen?
107 TEST(recog.add_range_transition(GOT_DOT, REJECTED, '\0', '\0'));
108 TEST(recog.add_range_transition(GOT_DOT, GET_ANY, 1, '.'-1));
109 TEST(recog.add_range_transition(GOT_DOT, GOT_DOT, '.', '.'));
110 TEST(recog.add_range_transition(GOT_DOT, GET_ANY, '.'+1, 'c'-1));
111 TEST(recog.add_range_transition(GOT_DOT, GOT_CHO, 'c', 'c'));
112 TEST(recog.add_range_transition(GOT_DOT, GET_ANY, 'c'+1, 'h'-1));
113 TEST(recog.add_range_transition(GOT_DOT, GOT_CHO, 'h', 'h'));
114 TEST(recog.add_range_transition(GOT_DOT, GET_ANY, 'h'+1, 'o'-1));
115 TEST(recog.add_range_transition(GOT_DOT, GOT_CHO, 'o', 'o'));
116 TEST(recog.add_range_transition(GOT_DOT, GET_ANY, 'o'+1, 255));
118
119 TEST(recog.add_range_transition(GOT_CHO, RECOGNIZED, '\0', '\0'));
120 TEST(recog.add_range_transition(GOT_CHO, GET_ANY, 1, '.'-1));
121 TEST(recog.add_range_transition(GOT_CHO, GOT_DOT, '.', '.'));
122 TEST(recog.add_range_transition(GOT_CHO, GET_ANY, '.'+1, 255));
123
124 int hosed;
125 if (recog.validate(hosed) != transition_map::OKAY)
126 deadly_error(class_name(), "check_machine",
127 astring(astring::SPRINTF, "invalid state_machine due to state %d", hosed).s());
128}
129
130test_state_machine::test_state_machine()
132{}
133
134void test_state_machine::print_instructions()
135{
137This program demonstrates the state machine class by constructing a machine\n\
138that recognizes the regular expression *.[cho], which is all strings ending\n\
139in a period followed by c, h, or o. The first parameter is the name of a\n\
140file to load strings from.\n");
141}
142
143int test_state_machine::execute()
144{
145 FUNCDEF("execute");
146 transition_map recog;
147 setup_state_machine(recog);
148
151 // automating for unit test with a simple input file.
152 filename = "./input_data_state_machine.txt";
155 } else {
157 }
159 if (!filename) {
161 return 1;
162 }
164
165 byte_filer fil(filename.s(), "r");
166
167//LOG(astring("filename is ") + filename.raw());
168
169 while (!fil.eof()) {
171 recog.reset(m);
172
173 byte_array typed_string(901);
174//need a getline function for byte filer...
175 fil.getline(typed_string, 900);
176
177 int len = int(strlen((char *)typed_string.access()));
178 if (!len) continue; // skip blank lines...
179
180 int position = 0;
181 while ( (m.current() != RECOGNIZED) && (m.current() != REJECTED) ) {
182 recog.pulse(m, typed_string[position++]);
183 }
184
185 if (m.current() == RECOGNIZED) {
186 LOG((char *)typed_string.access());
187 } else if (m.current() == REJECTED) {
188 LOG("rejected...");
189 } else {
190 LOG("unknown final state!");
191 }
192 }
193 return 0;
194}
195
197
198HOOPLE_MAIN(test_state_machine, )
199
int print_instructions(bool good, const astring &program_name)
Definition checker.cpp:45
The application_shell is a base object for console programs.
virtual int execute()=0
< retrieves the command line from the /proc hierarchy on linux.
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition astring.h:113
A very common template for a dynamic array of bytes.
Definition byte_array.h:36
Provides file managment services using the standard I/O support.
Definition byte_filer.h:32
Provides operations commonly needed on file names.
Definition filename.h:64
static void alert_message(const char *info, const char *title="Alert Message")
shows the message in "info", with an optional "title" on the message.
Monitors objects with multiple states and the transitions between states.
int current() const
returns the current state.
The transition_map manages state machines and causes state changes to occur.
bool add_range_transition(int current, int next, int low, int high)
adds a transition that listens to triggers in the pulse() method.
bool set_start(int starting_state)
assigns a state as the first state.
bool pulse(state_machine &m, int trigger)
applies a "trigger" to possibly cause a range transition.
bool reset(state_machine &m)
bool add_state(int state_number)
registers a legal state in the transition_map.
basis::outcome validate(int &examine)
checks to that all required transition conditions are satisfied.
#define deadly_error(c, f, i)
#define DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
Definition enhance_cpp.h:42
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
Provides macros that implement the 'main' program of an application.
#define HOOPLE_MAIN(obj_name, obj_args)
options that should work for most unix and linux apps.
Definition hoople_main.h:61
Implements an application lock to ensure only one is running at once.
char ** _global_argv
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
A platform independent way to obtain the timestamp of a file.
A logger that sends to the console screen using the standard output device.
#include <time.h>
Useful support functions for unit testing, especially within hoople.
Definition unit_base.cpp:35
recognizer_states
#define LOG(s)
astring state_text(recognizer_states to_show)
#define TEST(action)