summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordeva <deva>2009-07-24 16:05:18 +0000
committerdeva <deva>2009-07-24 16:05:18 +0000
commit680c646011ec55dd4c639a5b61d8c42a10272ae2 (patch)
tree171aea7bbd680a1dc7cf80bc5cdabc55c82a7618
parent408c7c5b36e1058a76741a22876593ee8c042dd4 (diff)
More extensive testing, and documentation in the header files.
-rw-r--r--server/src/Makefile.am12
-rw-r--r--server/src/luaquerymapper.cc121
-rw-r--r--server/src/luaquerymapper.h36
-rw-r--r--server/src/queryparser.cc72
-rw-r--r--server/src/queryparser.h32
5 files changed, 203 insertions, 70 deletions
diff --git a/server/src/Makefile.am b/server/src/Makefile.am
index 3fa0aad..dbc481a 100644
--- a/server/src/Makefile.am
+++ b/server/src/Makefile.am
@@ -130,7 +130,7 @@ test: $(TESTFILES)
@echo "All tests done."
test_clean:
- rm -f $(TESTFILES)
+ rm -f $(TESTFILES) $(TESTLOGS)
TEST_VERSIONSTR_FILES = \
versionstr.cc \
@@ -168,8 +168,6 @@ test_queryhandlerpracro: $(TEST_QUERYHANDLERPRACRO_FILES)
TEST_QUERYPARSER_FILES = \
queryparser.cc \
- queryhandlerpentominos.cc \
- tcpsocket.cc \
$(BASICFILES) \
$(PARSERFILES)
test_queryparser: $(TEST_QUERYPARSER_FILES)
@@ -177,13 +175,9 @@ test_queryparser: $(TEST_QUERYPARSER_FILES)
TEST_LUAQUERMAPPER_FILES = \
luaquerymapper.cc \
- queryparser.cc \
- queryhandlerpentominos.cc \
- tcpsocket.cc \
- $(BASICFILES) \
- $(PARSERFILES)
+ $(BASICFILES)
test_luaquerymapper: $(TEST_LUAQUERMAPPER_FILES)
- @../../tools/test $(TEST_LUAQUERMAPPER_FILES) $(LUA_LIBS) $(BASICFLAGS) $(PARSERFLAGS)
+ @../../tools/test $(TEST_LUAQUERMAPPER_FILES) $(LUA_LIBS) $(BASICFLAGS)
TEST_TEMPLATEPARSER_FILES = \
templateparser.cc \
diff --git a/server/src/luaquerymapper.cc b/server/src/luaquerymapper.cc
index d6ec531..7ee43ff 100644
--- a/server/src/luaquerymapper.cc
+++ b/server/src/luaquerymapper.cc
@@ -28,8 +28,6 @@
#include <sstream>
-#include "exception.h"
-
static std::string loadresultstring(QueryResult &res, std::string group = "")
{
std::string s;
@@ -46,7 +44,7 @@ static std::string loadresultstring(QueryResult &res, std::string group = "")
std::map< std::string, QueryResult >::iterator g = res.groups.begin();
while(g != res.groups.end()) {
- if(group + (*g).first != "") s += group + (*g).first + " = {}\n";
+ s += group + (*g).first + " = {}\n";
s += loadresultstring((*g).second, group + (*g).first + ".");
g++;
}
@@ -54,8 +52,10 @@ static std::string loadresultstring(QueryResult &res, std::string group = "")
return s;
}
-LUAQueryMapper::LUAQueryMapper()
+LUAQueryMapper::LUAQueryMapper() throw(Exception)
{
+ clean_top = -1;
+
L = luaL_newstate();
if(L == NULL) {
error("Could not create LUA state.");
@@ -69,16 +69,15 @@ LUAQueryMapper::LUAQueryMapper()
LUAQueryMapper::~LUAQueryMapper()
{
- lua_close(L);
+ if(L) lua_close(L);
}
-void LUAQueryMapper::addQueryResult(QueryResult &result)
+void LUAQueryMapper::addQueryResult(QueryResult &result) throw(Exception)
{
std::string preload = loadresultstring(result);
PRACRO_DEBUG(querymapper, "Preload:\n%s\n", preload.c_str());
-
if(luaL_loadbuffer(L, preload.c_str(), preload.size(), "preload")) {
error(lua_tostring(L, lua_gettop(L)));
return;
@@ -93,7 +92,7 @@ void LUAQueryMapper::addQueryResult(QueryResult &result)
clean_top = lua_gettop(L);
}
-Value LUAQueryMapper::map(const std::string &mapper)
+Value LUAQueryMapper::map(const std::string &mapper) throw(Exception)
{
Value v;
@@ -123,17 +122,13 @@ Value LUAQueryMapper::map(const std::string &mapper)
// Check if app messed up the stack.
if(lua_gettop(L) != clean_top + 3) {
- error("Wrong number of return values in " + mapper);
- lua_pop(L, lua_gettop(L) - clean_top);
+ error("Wrong number of return values (should be value, timestamp, source) in " + mapper);
return v;
}
- // value, timestamp, source
-
// Check if the types are right
if(lua_isstring(L, lua_gettop(L)) == false) {
error("Source is not a string in " + mapper);
- lua_pop(L, 3);
return v;
}
v.source = lua_tostring(L, lua_gettop(L));
@@ -142,7 +137,6 @@ Value LUAQueryMapper::map(const std::string &mapper)
// Check if the types are right
if(lua_isnumber(L, lua_gettop(L)) == false) {
error("Timestamp is not an integer in " + mapper);
- lua_pop(L, 2);
return v;
}
v.timestamp = lua_tointeger(L, lua_gettop(L));
@@ -151,7 +145,6 @@ Value LUAQueryMapper::map(const std::string &mapper)
// Check if the types are right
if(lua_isstring(L, lua_gettop(L)) == false) {
error("Value is not a string in " + mapper);
- lua_pop(L, 1);
return v;
}
v.value = lua_tostring(L, lua_gettop(L));
@@ -163,42 +156,106 @@ Value LUAQueryMapper::map(const std::string &mapper)
return v;
}
-void LUAQueryMapper::error(std::string message)
+void LUAQueryMapper::error(std::string message) throw(Exception)
{
+ if(clean_top != -1) lua_pop(L, lua_gettop(L) - clean_top); // Clean up stack
throw Exception("ERROR in LUAQueryMapper: " + message);
}
#ifdef TEST_LUAQUERYMAPPER
-#include "queryhandlerpentominos.h"
-#include "queryparser.h"
-#include "tcpsocket.h"
-
int main()
{
- TCPSocket s;
- s.connect("localhost", 11108);
-
- QueryHandlerPentominos qh(&s, "2003791613");
+ QueryResult res;
- Query q1;
- q1.attributes["device_id"] = "lensmeter";
- q1.attributes["device_type"] = "lensmeter";
+ time_t now = time(NULL);
- QueryResult res = qh.exec(q1);
+ res.groups["test"].timestamp = now;
+ res.groups["test"].source = "test app";
+ res.groups["test"].values["somevalue"] = "hello world";
+ res.groups["test"].values["pi"] = "3.1416";
printf("%s\n", loadresultstring(res).c_str());
LUAQueryMapper mapper;
mapper.addQueryResult(res);
- std::string luamap = "return status.errstr.value, 0, 0";
+ // Test simple value forwarding
+ std::string luamap = "return test.somevalue.value, test.somevalue.timestamp, test.somevalue.source";
Value value = mapper.map(luamap);
- printf("%s : %s, %lu\n", luamap.c_str(), value.value.c_str(), value.timestamp);
+ printf("%s =>\n %s, %lu, %s\n", luamap.c_str(), value.value.c_str(), value.timestamp, value.source.c_str());
+ if(value.value != "hello world" || value.timestamp != now || value.source != "test app")
+ return 1;
+
+ // Do some calculations
+ luamap = "return 2 * tonumber(test.pi.value), test.pi.timestamp, test.pi.source";
+ value = mapper.map(luamap);
+ printf("%s =>\n %s, %lu, %s\n", luamap.c_str(), value.value.c_str(), value.timestamp, value.source.c_str());
+ if(value.value != "6.2832" || value.timestamp != now || value.source != "test app")
+ return 1;
+
+ // Attempt to access nonexisting value (should throw an exception)
+ try {
+ luamap = "return test.somevalue2.value, test.somevalue2.timestamp, test.somevalue2.source";
+ value = mapper.map(luamap);
+ printf("%s =>\n %s, %lu, %s\n", luamap.c_str(), value.value.c_str(), value.timestamp, value.source.c_str());
+ if(value.value != "hello world" || value.timestamp != now || value.source != "test app")
+ return 1;
+ } catch(Exception &e) {
+ printf("ERROR: %s\n", e.what());
+ goto onandon;
+ }
+ return 1;
+ onandon:
+
+ // Attempt to access nonexisting group (should throw an exception)
+ try {
+ luamap = "return test2.somevalue.value, test2.somevalue.timestamp, test2.somevalue.source";
+ value = mapper.map(luamap);
+ printf("%s =>\n %s, %lu, %s\n", luamap.c_str(), value.value.c_str(), value.timestamp, value.source.c_str());
+ if(value.value != "hello world" || value.timestamp != now || value.source != "test app")
+ return 1;
+ } catch(Exception &e) {
+ printf("ERROR: %s\n", e.what());
+ goto stillonandon;
+ }
+ return 1;
+ stillonandon:
+
+ // Switch order of return vars (should throw an exception)
+ try {
+ luamap = "return test.somevalue.source, test.somevalue.value, test.somevalue.timestamp";
+ value = mapper.map(luamap);
+ printf("%s =>\n %s, %lu, %s\n", luamap.c_str(), value.value.c_str(), value.timestamp, value.source.c_str());
+ if(value.value != "hello world" || value.timestamp != now || value.source != "test app")
+ return 1;
+ } catch(Exception &e) {
+ printf("ERROR: %s\n", e.what());
+ goto onandonagain;
+ }
+ return 1;
+ onandonagain:
+
+ // Syntax error (should throw an exception)
+ try {
+ luamap = "this(is{] not() - a != legal lua program!]";
+ value = mapper.map(luamap);
+ printf("%s =>\n %s, %lu, %s\n", luamap.c_str(), value.value.c_str(), value.timestamp, value.source.c_str());
+ if(value.value != "hello world" || value.timestamp != now || value.source != "test app")
+ return 1;
+ } catch(Exception &e) {
+ printf("ERROR: %s\n", e.what());
+ goto stillonandonagain;
+ }
+ return 1;
+ stillonandonagain:
- luamap = "return math.sin(status.errstr.timestamp) * 2, 0, 0";
+ // And finally test if we haven't broken enything while being hostile to the lua engine...
+ luamap = "return test.somevalue.value, test.somevalue.timestamp, test.somevalue.source";
value = mapper.map(luamap);
- printf("%s : %s, %lu\n", luamap.c_str(), value.value.c_str(), value.timestamp);
+ printf("%s =>\n %s, %lu, %s\n", luamap.c_str(), value.value.c_str(), value.timestamp, value.source.c_str());
+ if(value.value != "hello world" || value.timestamp != now || value.source != "test app")
+ return 1;
return 0;
}
diff --git a/server/src/luaquerymapper.h b/server/src/luaquerymapper.h
index 4648606..e8a25f8 100644
--- a/server/src/luaquerymapper.h
+++ b/server/src/luaquerymapper.h
@@ -33,7 +33,9 @@
#include <lauxlib.h>
// For class Value
-#include "database.h"
+#include "dbtypes.h"
+
+#include "exception.h"
/**
* The LUAQueryMapper class takes the result of an external data query and
@@ -41,23 +43,39 @@
*/
class LUAQueryMapper {
public:
- LUAQueryMapper();
+ /**
+ * Constructor.
+ * Initialises the LUA library, and opens a LUA instance.
+ * Throws an exception if any of these things fail.
+ */
+ LUAQueryMapper() throw(Exception);
~LUAQueryMapper();
/**
* Applies the mapping program to the result-namespace, and returns the
- * resulting value.
+ * resulting value. The map must return 3 values; value (a string), timestamp
+ * (an integer) and the source (string).
+ * If the program fails to load, fails to run, returns wrong number of values,
+ * or the wrong types, it will thorw an exception.
+ * @param mapper A std::string containing the mapping program.
+ * @return A Value object containing the three result values.
*/
- Value map(const std::string &mapper);
-
- void error(std::string message);
-
- void addQueryResult(QueryResult &result);
+ Value map(const std::string &mapper) throw(Exception);
+
+ /**
+ * Add a result to be included in the mapper namespace.
+ * If in some way the generated values fail (illegal names for example) an exception
+ * will be thrown.
+ * @param result The QueryResult object containing the values to add to the
+ * namespace.
+ */
+ void addQueryResult(QueryResult &result) throw(Exception);
private:
+ void error(std::string message) throw(Exception);
+
lua_State *L;
int clean_top;
-
};
diff --git a/server/src/queryparser.cc b/server/src/queryparser.cc
index 2b0dbdc..602ba80 100644
--- a/server/src/queryparser.cc
+++ b/server/src/queryparser.cc
@@ -76,12 +76,50 @@ void QueryParser::parseError(char *buf, size_t len, std::string error, int linen
if(fwrite(buf, len, 1, stderr) != len) {}
fprintf(stderr, "]\n");
fflush(stderr);
+
+ char *slineno;
+ if(asprintf(&slineno, " at line %d\n", lineno) != -1) {
+ throw Exception(error + slineno);
+ free(slineno);
+ }
+
}
#ifdef TEST_QUERYPARSER
-#include "queryhandlerpentominos.h"
-#include "tcpsocket.h"
+#include <string.h>
+
+static char xml[] =
+ "<?xml version='1.0' encoding='UTF-8'?>\n"
+ "<results>\n"
+ " <result class=\"testclass\" timestamp=\"1234567890\">\n"
+ " <group name=\"testgroup\">\n"
+ " <value name=\"testvalue\" value=\"42\"/>\n"
+ " <value name=\"anothertestvalue\" value=\"42\"/>\n"
+ " </group>\n"
+ " <group name=\"anothertestgroup\">\n"
+ " <value name=\"testvalue\" value=\"42\"/>\n"
+ " <value name=\"anothertestvalue\" value=\"42\"/>\n"
+ " </group>\n"
+ " </result>\n"
+ " <result class=\"anothertestclass\" timestamp=\"1234567890\">\n"
+ " <group name=\"testgroup\">\n"
+ " <value name=\"testvalue\" value=\"42\"/>\n"
+ " <value name=\"anothertestvalue\" value=\"42\"/>\n"
+ " </group>\n"
+ " <group name=\"anothertestgroup\">\n"
+ " <value name=\"testvalue\" value=\"42\"/>\n"
+ " <value name=\"anothertestvalue\" value=\"42\"/>\n"
+ " </group>\n"
+ " </result>\n"
+ "</results>\n"
+;
+
+static char badxml[] =
+ "<?xml version='1.0' encoding='UTF-8'?>\n"
+ "<results>\n"
+ "</sulrets>\n"
+;
static std::string loadresultstring(QueryResult &res, std::string group = "")
{
@@ -105,20 +143,26 @@ static std::string loadresultstring(QueryResult &res, std::string group = "")
int main()
{
- TCPSocket s;
- s.connect("localhost", 11108);
-
- QueryHandlerPentominos qh(&s, "2003791613");
-
- Query q1;
- q1.attributes["device_id"] = "lensmeter";
- q1.attributes["device_type"] = "lensmeter";
+ // Parse something
+ {
+ QueryParser parser;
+ parser.parse(xml, strlen(xml));
+ printf("%s\n", loadresultstring(parser.result).c_str());
+ }
- QueryResult res = qh.exec(q1);
-
- printf("%s\n", loadresultstring(res).c_str());
+ // Parse something, and fail!
+ try {
+ QueryParser parser;
+ parser.parse(badxml, strlen(badxml));
+ printf("%s\n", loadresultstring(parser.result).c_str());
+ } catch(Exception &e) {
+ printf("ERROR: %s\n", e.what());
+ goto weitergehen;
+ }
+ return 1;
+ weitergehen:
return 0;
}
-#endif
+#endif/*TEST_QUERYPARSER*/
diff --git a/server/src/queryparser.h b/server/src/queryparser.h
index 947767c..3a73aa2 100644
--- a/server/src/queryparser.h
+++ b/server/src/queryparser.h
@@ -27,27 +27,47 @@
#ifndef __PRACRO_QUERYPARSER_H__
#define __PRACRO_QUERYPARSER_H__
-#include <time.h>
-
-#include "queryresult.h"
#include "saxparser.h"
+#include <time.h>
#include <vector>
+#include "queryresult.h"
#include "utf8.h"
+#include "exception.h"
/**
- * This class parses xml entyties into a QueryResult structure.
+ * This class parses xml entities into a QueryResult structure.
+ * Call the parent (SAXParser) method parse in order to actually parse something.
+ * If the parser fails (syntax error) it will throw an Exception.
+ * @see QueryResult result, in order to get the parsed data.
*/
class QueryParser : public SAXParser {
public:
+ /**
+ * Constructor.
+ */
QueryParser();
+ /**
+ * The object will contain the result when the parsing is done.
+ */
+ QueryResult result;
+
+ /**
+ * Private parser callback.
+ */
void startTag(std::string name, std::map< std::string, std::string> attributes);
+
+ /**
+ * Private parser callback.
+ */
void endTag(std::string name);
- void parseError(char *buf, size_t len, std::string error, int lineno);
- QueryResult result;
+ /**
+ * Private parser callback.
+ */
+ void parseError(char *buf, size_t len, std::string error, int lineno);
private:
// For read