It is better to write and run incomplete tests than not to run complete tests. -- Martin Fowler

Sat, 05 Sep 2015 14:42:23 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Sat, 05 Sep 2015 14:42:23 +0100
changeset 0
2e31b584f8d9
child 1
017c5809d537

It is better to write and run incomplete tests than not to run complete tests. -- Martin Fowler

main.lua file | annotate | diff | comparison | revisions
scansion/objects/client.lua file | annotate | diff | comparison | revisions
scansion/parser.lua file | annotate | diff | comparison | revisions
scansion/xml.lua file | annotate | diff | comparison | revisions
scripts/basic.scs file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.lua	Sat Sep 05 14:42:23 2015 +0100
@@ -0,0 +1,26 @@
+#!/usr/bin/env lua5.1
+
+local parser = require "scansion.parser";
+
+io.input(arg[1]);
+local script_data = io.read("*a");
+
+local script = assert(parser.parse(script_data));
+
+local c = 0;
+for name, object in pairs(script.objects) do
+	local o = require("scansion.objects."..object.type);
+	object.handler = o;
+	o._validate(object);
+	c = c + 1;
+end
+
+print("Script defines "..c.." objects, and "..#script.actions.." actions");
+
+for _, action in pairs(script.actions) do
+	local object = script.objects[action.object_name];
+	local handler = object.handler;
+	assert(handler[action.action], "Objects of type '"..object.type.."' do not support action '"..action.action.."'");
+		
+	handler[action.action](object, action.extra);
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scansion/objects/client.lua	Sat Sep 05 14:42:23 2015 +0100
@@ -0,0 +1,24 @@
+local verse = require "verse";
+local parse_xml = require "scansion.xml".parse;
+return {
+	_validate = function (client)
+		assert(client.jid, "No JID specified");
+		client.stream = verse.new();
+	end;
+
+	connects = function (client)
+		client.stream:connect(client.jid, client.password);
+	end;
+
+	sends = function (client, data)
+		print(("%q"):format(table.concat(data)))
+		print(parse_xml(table.concat(data)));
+		print(stanza)
+	end;
+
+	receives = function (client, data)
+	end;
+
+	disconnects = function (client)
+	end;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scansion/parser.lua	Sat Sep 05 14:42:23 2015 +0100
@@ -0,0 +1,57 @@
+local function parse(data)
+	local parsed = {
+		objects = {};
+		actions = {};
+	};
+	
+	local line_number = 0;
+	local last_object;
+	
+	for line in data:gmatch("([^\r\n]+)\r?\n") do
+		line_number = line_number + 1;
+		print(line_number, line);
+		if line:sub(1,1) == "[" then
+			local obj_type, name, extra = line:match("^%[(%a+)%] (.+)$");
+			
+			if parsed.objects[name] then
+				return nil, "Duplicate definition of "..name.." on line "..line_number;
+			end
+			parsed.objects[name] = {
+				type = obj_type:lower();
+				name = name;
+				defined_line = line_number;
+			};
+			last_object = parsed.objects[name];
+			print(("%q"):format(obj_type))
+		elseif line:match("^%s+%a+:.+$") then
+			if not last_object then
+				return nil, "Line "..line_number.. "unexpected outside of an object definition";
+			end
+			local k, v = line:match("^%s+(%a+):(.+)$")
+			last_object[k] = v;
+		elseif #parsed.actions > 0 and line:sub(1,1) == "\t" then
+			table.insert(parsed.actions[#parsed.actions].extra, line:sub(2));
+		elseif line:match("^%s*$") or line:match("^#") or line:match("^([/-])%1") then
+			-- Blank line or comment
+		else
+			last_object = nil;
+			local name, action, extra = line:match("^(%a+) (%a+):?%s?(.*)$");
+			if not name then
+				return nil, "Unable to parse action on line "..line_number;
+			end
+			if not parsed.objects[name] then
+				return nil, "The object '"..name.."' used on line "..line_number.." was not declared";
+			end
+			table.insert(parsed.actions, {
+				object_name = name;
+				action = action:lower();
+				extra = {#extra>0 and extra or nil};
+			});
+		end
+	end
+	return parsed;
+end
+
+return {
+	parse = parse;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scansion/xml.lua	Sat Sep 05 14:42:23 2015 +0100
@@ -0,0 +1,59 @@
+
+local st = require "util.stanza";
+local lxp = require "lxp";
+
+local _ENV = nil;
+
+local parse_xml = (function()
+	local ns_prefixes = {
+		["http://www.w3.org/XML/1998/namespace"] = "xml";
+	};
+	local ns_separator = "\1";
+	local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$";
+	return function(xml)
+		--luacheck: ignore 212/self
+		local handler = {};
+		local stanza = st.stanza("root");
+		function handler:StartElement(tagname, attr)
+			local curr_ns,name = tagname:match(ns_pattern);
+			if name == "" then
+				curr_ns, name = "", curr_ns;
+			end
+			if curr_ns ~= "" then
+				attr.xmlns = curr_ns;
+			end
+			for i=1,#attr do
+				local k = attr[i];
+				attr[i] = nil;
+				local ns, nm = k:match(ns_pattern);
+				if nm ~= "" then
+					ns = ns_prefixes[ns];
+					if ns then
+						attr[ns..":"..nm] = attr[k];
+						attr[k] = nil;
+					end
+				end
+			end
+			stanza:tag(name, attr);
+		end
+		function handler:CharacterData(data)
+			stanza:text(data);
+		end
+		function handler:EndElement()
+			stanza:up();
+		end
+		local parser = lxp.new(handler, "\1");
+		local ok, err, line, col = parser:parse(xml);
+		if ok then ok, err, line, col = parser:parse(); end
+		--parser:close();
+		if ok then
+			return stanza.tags[1];
+		else
+			return ok, err.." (line "..line..", col "..col..")";
+		end
+	end;
+end)();
+
+return {
+	parse = parse_xml;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/basic.scs	Sat Sep 05 14:42:23 2015 +0100
@@ -0,0 +1,15 @@
+[Client] Romeo
+	jid: romeo@server
+
+---------
+
+Romeo connects
+
+Romeo sends:
+	<presence/>
+
+Romeo receives:
+	<presence from="romeo@server/resource" />
+
+Romeo disconnects
+

mercurial