Changeset

8236:4878e4159e12

Port tests to the `busted` test runner
author Waqas Hussain <waqas20@gmail.com>
date Fri, 15 Sep 2017 17:07:57 -0400
parents 8235:7d9a2c200736
children 8237:f81cd9aaf994
files spec/core_configmanager_spec.lua spec/core_moduleapi_spec.lua spec/json/fail1.json spec/json/fail10.json spec/json/fail11.json spec/json/fail12.json spec/json/fail13.json spec/json/fail14.json spec/json/fail15.json spec/json/fail16.json spec/json/fail17.json spec/json/fail18.json spec/json/fail19.json spec/json/fail2.json spec/json/fail20.json spec/json/fail21.json spec/json/fail22.json spec/json/fail23.json spec/json/fail24.json spec/json/fail25.json spec/json/fail26.json spec/json/fail27.json spec/json/fail28.json spec/json/fail29.json spec/json/fail3.json spec/json/fail30.json spec/json/fail31.json spec/json/fail32.json spec/json/fail33.json spec/json/fail4.json spec/json/fail5.json spec/json/fail6.json spec/json/fail7.json spec/json/fail8.json spec/json/fail9.json spec/json/pass1.json spec/json/pass2.json spec/json/pass3.json spec/net_http_parser_spec.lua spec/utf8_sequences.txt spec/util_cache_spec.lua spec/util_encodings_spec.lua spec/util_http_spec.lua spec/util_ip_spec.lua spec/util_jid_spec.lua spec/util_json_spec.lua spec/util_multitable_spec.lua spec/util_queue_spec.lua spec/util_random_spec.lua spec/util_rfc6724_spec.lua spec/util_stanza_spec.lua spec/util_throttle_spec.lua spec/util_uuid_spec.lua spec/util_xml_spec.lua spec/util_xmppstream_spec.lua tests/json/fail1.json tests/json/fail10.json tests/json/fail11.json tests/json/fail12.json tests/json/fail13.json tests/json/fail14.json tests/json/fail15.json tests/json/fail16.json tests/json/fail17.json tests/json/fail18.json tests/json/fail19.json tests/json/fail2.json tests/json/fail20.json tests/json/fail21.json tests/json/fail22.json tests/json/fail23.json tests/json/fail24.json tests/json/fail25.json tests/json/fail26.json tests/json/fail27.json tests/json/fail28.json tests/json/fail29.json tests/json/fail3.json tests/json/fail30.json tests/json/fail31.json tests/json/fail32.json tests/json/fail33.json tests/json/fail4.json tests/json/fail5.json tests/json/fail6.json tests/json/fail7.json tests/json/fail8.json tests/json/fail9.json tests/json/pass1.json tests/json/pass2.json tests/json/pass3.json tests/modulemanager_option_conversion.lua tests/reports/empty tests/run_tests.bat tests/run_tests.sh tests/test.lua tests/test_core_configmanager.lua tests/test_core_s2smanager.lua tests/test_core_stanza_router.lua tests/test_net_http_parser.lua tests/test_sasl.lua tests/test_utf8.lua tests/test_util_async.lua tests/test_util_cache.lua tests/test_util_http.lua tests/test_util_ip.lua tests/test_util_jid.lua tests/test_util_json.lua tests/test_util_json.sh tests/test_util_multitable.lua tests/test_util_queue.lua tests/test_util_random.lua tests/test_util_rfc6724.lua tests/test_util_sasl_scram.lua tests/test_util_stanza.lua tests/test_util_throttle.lua tests/test_util_uuid.lua tests/test_util_xml.lua tests/test_util_xmppstream.lua tests/utf8_sequences.txt tests/util/logger.lua
diffstat 121 files changed, 1620 insertions(+), 2455 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/core_configmanager_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,31 @@
+
+local configmanager = require "core.configmanager";
+
+describe("core.configmanager", function()
+	describe("#get()", function()
+		it("should work", function()
+			configmanager.set("example.com", "testkey", 123);
+			assert.are.equal(configmanager.get("example.com", "testkey"), 123, "Retrieving a set key");
+
+			configmanager.set("*", "testkey1", 321);
+			assert.are.equal(configmanager.get("*", "testkey1"), 321, "Retrieving a set global key");
+			assert.are.equal(configmanager.get("example.com", "testkey1"), 321, "Retrieving a set key of undefined host, of which only a globally set one exists");
+
+			configmanager.set("example.com", ""); -- Creates example.com host in config
+			assert.are.equal(configmanager.get("example.com", "testkey1"), 321, "Retrieving a set key, of which only a globally set one exists");
+
+			assert.are.equal(configmanager.get(), nil, "No parameters to get()");
+			assert.are.equal(configmanager.get("undefined host"), nil, "Getting for undefined host");
+			assert.are.equal(configmanager.get("undefined host", "undefined key"), nil, "Getting for undefined host & key");
+		end);
+	end);
+
+	describe("#set()", function()
+		it("should work", function()
+			assert.are.equal(configmanager.set("*"), false, "Set with no key");
+
+			assert.are.equal(configmanager.set("*", "set_test", "testkey"), true, "Setting a nil global value");
+			assert.are.equal(configmanager.set("*", "set_test", "testkey", 123), true, "Setting a global value");
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/core_moduleapi_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,76 @@
+
+package.loaded["core.configmanager"] = {};
+package.loaded["core.statsmanager"] = {};
+package.loaded["net.server"] = {};
+
+local set = require "util.set";
+
+_G.prosody = { hosts = {}, core_post_stanza = true };
+
+local api = require "core.moduleapi";
+
+local module = setmetatable({}, {__index = api});
+local opt = nil;
+function module:log() end
+function module:get_option(name)
+	if name == "opt" then
+		return opt;
+	else
+		return nil;
+	end
+end
+
+function test_option_value(value, returns)
+	opt = value;
+	assert(module:get_option_number("opt") == returns.number, "number doesn't match");
+	assert(module:get_option_string("opt") == returns.string, "string doesn't match");
+	assert(module:get_option_boolean("opt") == returns.boolean, "boolean doesn't match");
+
+	if type(returns.array) == "table" then
+		local target_array, returned_array = returns.array, module:get_option_array("opt");
+		assert(#target_array == #returned_array, "array length doesn't match");
+		for i=1,#target_array do
+			assert(target_array[i] == returned_array[i], "array item doesn't match");
+		end
+	else
+		assert(module:get_option_array("opt") == returns.array, "array is returned (not nil)");
+	end
+
+	if type(returns.set) == "table" then
+		local target_items, returned_items = set.new(returns.set), module:get_option_set("opt");
+		assert(target_items == returned_items, "set doesn't match");
+	else
+		assert(module:get_option_set("opt") == returns.set, "set is returned (not nil)");
+	end
+end
+
+describe("core.moduleapi", function()
+	describe("#get_option_*()", function()
+		it("should handle missing options", function()
+			test_option_value(nil, {});
+		end);
+
+		it("should return correctly handle boolean options", function()
+			test_option_value(true, { boolean = true, string = "true", array = {true}, set = {true} });
+			test_option_value(false, { boolean = false, string = "false", array = {false}, set = {false} });
+			test_option_value("true", { boolean = true, string = "true", array = {"true"}, set = {"true"} });
+			test_option_value("false", { boolean = false, string = "false", array = {"false"}, set = {"false"} });
+			test_option_value(1, { boolean = true, string = "1", array = {1}, set = {1}, number = 1 });
+			test_option_value(0, { boolean = false, string = "0", array = {0}, set = {0}, number = 0 });
+		end);
+
+		it("should return handle strings", function()
+			test_option_value("hello world", { string = "hello world", array = {"hello world"}, set = {"hello world"} });
+		end);
+
+		it("should return handle numbers", function()
+			test_option_value(1234, { string = "1234", number = 1234, array = {1234}, set = {1234} });
+		end);
+
+		it("should return handle arrays", function()
+			test_option_value({1, 2, 3}, { boolean = true, string = "1", number = 1, array = {1, 2, 3}, set = {1, 2, 3} });
+			test_option_value({1, 2, 3, 3, 4}, {boolean = true, string = "1", number = 1, array = {1, 2, 3, 3, 4}, set = {1, 2, 3, 4} });
+			test_option_value({0, 1, 2, 3}, { boolean = false, string = "0", number = 0, array = {0, 1, 2, 3}, set = {0, 1, 2, 3} });	
+		end);
+	end)
+end)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail1.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+"A JSON payload should be an object or array, not a string."
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail10.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+{"Extra value after close": true} "misplaced quoted value"
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail11.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+{"Illegal expression": 1 + 2}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail12.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+{"Illegal invocation": alert()}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail13.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+{"Numbers cannot have leading zeroes": 013}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail14.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+{"Numbers cannot be hex": 0x14}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail15.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["Illegal backslash escape: \x15"]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail16.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+[\naked]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail17.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["Illegal backslash escape: \017"]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail18.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail19.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+{"Missing colon" null}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail2.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["Unclosed array"
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail20.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+{"Double colon":: null}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail21.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+{"Comma instead of colon", null}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail22.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["Colon instead of comma": false]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail23.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["Bad value", truth]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail24.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+['single quote']
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail25.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["	tab	character	in	string	"]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail26.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["tab\   character\   in\  string\  "]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail27.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,2 @@
+["line
+break"]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail28.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,2 @@
+["line\
+break"]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail29.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+[0e]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail3.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+{unquoted_key: "keys must be quoted"}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail30.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+[0e+]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail31.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+[0e+-1]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail32.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+{"Comma instead if closing brace": true,
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail33.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["mismatch"}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail4.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["extra comma",]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail5.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["double extra comma",,]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail6.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+[   , "<-- missing value"]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail7.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["Comma after the close"],
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail8.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+["Extra close"]]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/fail9.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+{"Extra comma": true,}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/pass1.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,58 @@
+[
+    "JSON Test Pattern pass1",
+    {"object with 1 member":["array with 1 element"]},
+    {},
+    [],
+    -42,
+    true,
+    false,
+    null,
+    {
+        "integer": 1234567890,
+        "real": -9876.543210,
+        "e": 0.123456789e-12,
+        "E": 1.234567890E+34,
+        "":  23456789012E66,
+        "zero": 0,
+        "one": 1,
+        "space": " ",
+        "quote": "\"",
+        "backslash": "\\",
+        "controls": "\b\f\n\r\t",
+        "slash": "/ & \/",
+        "alpha": "abcdefghijklmnopqrstuvwyz",
+        "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
+        "digit": "0123456789",
+        "0123456789": "digit",
+        "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
+        "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
+        "true": true,
+        "false": false,
+        "null": null,
+        "array":[  ],
+        "object":{  },
+        "address": "50 St. James Street",
+        "url": "http://www.JSON.org/",
+        "comment": "// /* <!-- --",
+        "# -- --> */": " ",
+        " s p a c e d " :[1,2 , 3
+
+,
+
+4 , 5        ,          6           ,7        ],"compact":[1,2,3,4,5,6,7],
+        "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+        "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+        "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
+: "A key can be any string"
+    },
+    0.5 ,98.6
+,
+99.44
+,
+
+1066,
+1e1,
+0.1e1,
+1e-1,
+1e00,2e+00,2e-00
+,"rosebud"]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/pass2.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,1 @@
+[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/json/pass3.json	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,6 @@
+{
+    "JSON Test Pattern pass3": {
+        "The outermost value": "must be an object or array.",
+        "In this test": "It is an object."
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/net_http_parser_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,52 @@
+local httpstreams = { [[
+GET / HTTP/1.1
+Host: example.com
+
+]], [[
+HTTP/1.1 200 OK
+Content-Length: 0
+
+]], [[
+HTTP/1.1 200 OK
+Content-Length: 7
+
+Hello
+HTTP/1.1 200 OK
+Transfer-Encoding: chunked
+
+1
+H
+1
+e
+2
+ll
+1
+o
+0
+
+
+]]
+}
+
+
+local http_parser = require "net.http.parser";
+
+describe("net.http.parser", function()
+	describe("#new()", function()
+		it("should work", function()
+			for _, stream in ipairs(httpstreams) do
+				local success;
+				local function success_cb(packet)
+					success = true;
+				end
+				stream = stream:gsub("\n", "\r\n");
+				local parser = http_parser.new(success_cb, error, stream:sub(1,4) == "HTTP" and "client" or "server")
+				for chunk in stream:gmatch("..?.?") do
+					parser:feed(chunk);
+				end
+
+				assert.is_true(success);
+			end
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/utf8_sequences.txt	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,52 @@
+Should pass: 41 42 43               # Simple ASCII - abc
+Should pass: 41 42 c3 87            # "ABÇ"
+Should pass: 41 42 e1 b8 88         # "ABḈ"
+Should pass: 41 42 f0 9d 9c 8d      # "AB𝜍"
+Should pass: F4 8F BF BF            # Last valid sequence (U+10FFFF)
+Should fail: F4 90 80 80            # First invalid sequence (U+110000)
+Should fail: 80 81 82 83            # Invalid sequence (invalid start byte)
+Should fail: C2 C3                  # Invalid sequence (invalid continuation byte)
+Should fail: C0 43                  # Overlong sequence
+Should fail: F5 80 80 80            # U+140000 (out of range)
+Should fail: ED A0 80               # U+D800 (forbidden by RFC 3629)
+Should fail: ED BF BF               # U+DFFF (forbidden by RFC 3629)
+Should pass: ED 9F BF               # U+D7FF (U+D800 minus 1: allowed)
+Should pass: EE 80 80               # U+E000 (U+D7FF plus 1: allowed)
+Should fail: C0                     # Invalid start byte
+Should fail: C1                     # Invalid start byte
+Should fail: C2                     # Incomplete sequence
+Should fail: F8 88 80 80 80         # 6-byte sequence
+Should pass: 7F                     # Last valid 1-byte sequence (U+00007F)
+Should pass: DF BF                  # Last valid 2-byte sequence (U+0007FF)
+Should pass: EF BF BF               # Last valid 3-byte sequence (U+00FFFF)
+Should pass: 00                     # First valid 1-byte sequence (U+000000)
+Should pass: C2 80                  # First valid 2-byte sequence (U+000080)
+Should pass: E0 A0 80               # First valid 3-byte sequence (U+000800)
+Should pass: F0 90 80 80            # First valid 4-byte sequence (U+000800)
+Should fail: F8 88 80 80 80         # First 5-byte sequence - invalid per RFC 3629
+Should fail: FC 84 80 80 80 80      # First 6-byte sequence - invalid per RFC 3629
+Should pass: EF BF BD               # U+00FFFD (replacement character)
+Should fail: 80                     # First continuation byte
+Should fail: BF                     # Last continuation byte
+Should fail: 80 BF                  # 2 continuation bytes
+Should fail: 80 BF 80               # 3 continuation bytes
+Should fail: 80 BF 80 BF            # 4 continuation bytes
+Should fail: 80 BF 80 BF 80         # 5 continuation bytes
+Should fail: 80 BF 80 BF 80 BF      # 6 continuation bytes
+Should fail: 80 BF 80 BF 80 BF 80   # 7 continuation bytes
+Should fail: FE                     # Impossible byte
+Should fail: FF                     # Impossible byte
+Should fail: FE FE FF FF            # Impossible bytes
+Should fail: C0 AF                  # Overlong "/"
+Should fail: E0 80 AF               # Overlong "/"
+Should fail: F0 80 80 AF            # Overlong "/"
+Should fail: F8 80 80 80 AF         # Overlong "/"
+Should fail: FC 80 80 80 80 AF      # Overlong "/"
+Should fail: C0 80 AF               # Overlong "/" (invalid)
+Should fail: C1 BF                  # Overlong
+Should fail: E0 9F BF               # Overlong
+Should fail: F0 8F BF BF            # Overlong
+Should fail: F8 87 BF BF BF         # Overlong
+Should fail: FC 83 BF BF BF BF      # Overlong
+Should pass: EF BF BE               # U+FFFE (invalid unicode, valid UTF-8)
+Should pass: EF BF BF               # U+FFFF (invalid unicode, valid UTF-8)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_cache_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,316 @@
+
+local cache = require "util.cache";
+
+describe("util.cache", function()
+	describe("#new()", function()
+		it("should work", function()
+
+			local c = cache.new(5);
+
+			local function expect_kv(key, value, actual_key, actual_value)
+				assert.are.equal(key, actual_key, "key incorrect");
+				assert.are.equal(value, actual_value, "value incorrect");
+			end
+
+			expect_kv(nil, nil, c:head());
+			expect_kv(nil, nil, c:tail());
+
+			assert.are.equal(c:count(), 0);
+
+			c:set("one", 1)
+			assert.are.equal(c:count(), 1);
+			expect_kv("one", 1, c:head());
+			expect_kv("one", 1, c:tail());
+
+			c:set("two", 2)
+			expect_kv("two", 2, c:head());
+			expect_kv("one", 1, c:tail());
+
+			c:set("three", 3)
+			expect_kv("three", 3, c:head());
+			expect_kv("one", 1, c:tail());
+
+			c:set("four", 4)
+			c:set("five", 5);
+			assert.are.equal(c:count(), 5);
+			expect_kv("five", 5, c:head());
+			expect_kv("one", 1, c:tail());
+
+			c:set("foo", nil);
+			assert.are.equal(c:count(), 5);
+			expect_kv("five", 5, c:head());
+			expect_kv("one", 1, c:tail());
+
+			assert.are.equal(c:get("one"), 1);
+			expect_kv("five", 5, c:head());
+			expect_kv("one", 1, c:tail());
+
+			assert.are.equal(c:get("two"), 2);
+			assert.are.equal(c:get("three"), 3);
+			assert.are.equal(c:get("four"), 4);
+			assert.are.equal(c:get("five"), 5);
+
+			assert.are.equal(c:get("foo"), nil);
+			assert.are.equal(c:get("bar"), nil);
+
+			c:set("six", 6);
+			assert.are.equal(c:count(), 5);
+			expect_kv("six", 6, c:head());
+			expect_kv("two", 2, c:tail());
+
+			assert.are.equal(c:get("one"), nil);
+			assert.are.equal(c:get("two"), 2);
+			assert.are.equal(c:get("three"), 3);
+			assert.are.equal(c:get("four"), 4);
+			assert.are.equal(c:get("five"), 5);
+			assert.are.equal(c:get("six"), 6);
+
+			c:set("three", nil);
+			assert.are.equal(c:count(), 4);
+
+			assert.are.equal(c:get("one"), nil);
+			assert.are.equal(c:get("two"), 2);
+			assert.are.equal(c:get("three"), nil);
+			assert.are.equal(c:get("four"), 4);
+			assert.are.equal(c:get("five"), 5);
+			assert.are.equal(c:get("six"), 6);
+
+			c:set("seven", 7);
+			assert.are.equal(c:count(), 5);
+
+			assert.are.equal(c:get("one"), nil);
+			assert.are.equal(c:get("two"), 2);
+			assert.are.equal(c:get("three"), nil);
+			assert.are.equal(c:get("four"), 4);
+			assert.are.equal(c:get("five"), 5);
+			assert.are.equal(c:get("six"), 6);
+			assert.are.equal(c:get("seven"), 7);
+
+			c:set("eight", 8);
+			assert.are.equal(c:count(), 5);
+
+			assert.are.equal(c:get("one"), nil);
+			assert.are.equal(c:get("two"), nil);
+			assert.are.equal(c:get("three"), nil);
+			assert.are.equal(c:get("four"), 4);
+			assert.are.equal(c:get("five"), 5);
+			assert.are.equal(c:get("six"), 6);
+			assert.are.equal(c:get("seven"), 7);
+			assert.are.equal(c:get("eight"), 8);
+
+			c:set("four", 4);
+			assert.are.equal(c:count(), 5);
+
+			assert.are.equal(c:get("one"), nil);
+			assert.are.equal(c:get("two"), nil);
+			assert.are.equal(c:get("three"), nil);
+			assert.are.equal(c:get("four"), 4);
+			assert.are.equal(c:get("five"), 5);
+			assert.are.equal(c:get("six"), 6);
+			assert.are.equal(c:get("seven"), 7);
+			assert.are.equal(c:get("eight"), 8);
+
+			c:set("nine", 9);
+			assert.are.equal(c:count(), 5);
+
+			assert.are.equal(c:get("one"), nil);
+			assert.are.equal(c:get("two"), nil);
+			assert.are.equal(c:get("three"), nil);
+			assert.are.equal(c:get("four"), 4);
+			assert.are.equal(c:get("five"), nil);
+			assert.are.equal(c:get("six"), 6);
+			assert.are.equal(c:get("seven"), 7);
+			assert.are.equal(c:get("eight"), 8);
+			assert.are.equal(c:get("nine"), 9);
+
+			do
+				local keys = { "nine", "four", "eight", "seven", "six" };
+				local values = { 9, 4, 8, 7, 6 };
+				local i = 0;
+				for k, v in c:items() do
+					i = i + 1;
+					assert.are.equal(k, keys[i]);
+					assert.are.equal(v, values[i]);
+				end
+				assert.are.equal(i, 5);
+
+				c:set("four", "2+2");
+				assert.are.equal(c:count(), 5);
+
+				assert.are.equal(c:get("one"), nil);
+				assert.are.equal(c:get("two"), nil);
+				assert.are.equal(c:get("three"), nil);
+				assert.are.equal(c:get("four"), "2+2");
+				assert.are.equal(c:get("five"), nil);
+				assert.are.equal(c:get("six"), 6);
+				assert.are.equal(c:get("seven"), 7);
+				assert.are.equal(c:get("eight"), 8);
+				assert.are.equal(c:get("nine"), 9);
+			end
+
+			do
+				local keys = { "four", "nine", "eight", "seven", "six" };
+				local values = { "2+2", 9, 8, 7, 6 };
+				local i = 0;
+				for k, v in c:items() do
+					i = i + 1;
+					assert.are.equal(k, keys[i]);
+					assert.are.equal(v, values[i]);
+				end
+				assert.are.equal(i, 5);
+
+				c:set("foo", nil);
+				assert.are.equal(c:count(), 5);
+
+				assert.are.equal(c:get("one"), nil);
+				assert.are.equal(c:get("two"), nil);
+				assert.are.equal(c:get("three"), nil);
+				assert.are.equal(c:get("four"), "2+2");
+				assert.are.equal(c:get("five"), nil);
+				assert.are.equal(c:get("six"), 6);
+				assert.are.equal(c:get("seven"), 7);
+				assert.are.equal(c:get("eight"), 8);
+				assert.are.equal(c:get("nine"), 9);
+			end
+
+			do
+				local keys = { "four", "nine", "eight", "seven", "six" };
+				local values = { "2+2", 9, 8, 7, 6 };
+				local i = 0;
+				for k, v in c:items() do
+					i = i + 1;
+					assert.are.equal(k, keys[i]);
+					assert.are.equal(v, values[i]);
+				end
+				assert.are.equal(i, 5);
+
+				c:set("four", nil);
+
+				assert.are.equal(c:get("one"), nil);
+				assert.are.equal(c:get("two"), nil);
+				assert.are.equal(c:get("three"), nil);
+				assert.are.equal(c:get("four"), nil);
+				assert.are.equal(c:get("five"), nil);
+				assert.are.equal(c:get("six"), 6);
+				assert.are.equal(c:get("seven"), 7);
+				assert.are.equal(c:get("eight"), 8);
+				assert.are.equal(c:get("nine"), 9);
+			end
+
+			do
+				local keys = { "nine", "eight", "seven", "six" };
+				local values = { 9, 8, 7, 6 };
+				local i = 0;
+				for k, v in c:items() do
+					i = i + 1;
+					assert.are.equal(k, keys[i]);
+					assert.are.equal(v, values[i]);
+				end
+				assert.are.equal(i, 4);
+			end
+
+			do
+				local evicted_key, evicted_value;
+				local c2 = cache.new(3, function (_key, _value)
+					evicted_key, evicted_value = _key, _value;
+				end);
+				local function set(k, v, should_evict_key, should_evict_value)
+					evicted_key, evicted_value = nil, nil;
+					c2:set(k, v);
+					assert.are.equal(evicted_key, should_evict_key);
+					assert.are.equal(evicted_value, should_evict_value);
+				end
+				set("a", 1)
+				set("a", 1)
+				set("a", 1)
+				set("a", 1)
+				set("a", 1)
+
+				set("b", 2)
+				set("c", 3)
+				set("b", 2)
+				set("d", 4, "a", 1)
+				set("e", 5, "c", 3)
+			end
+
+			do
+				local evicted_key, evicted_value;
+				local c3 = cache.new(1, function (_key, _value)
+					evicted_key, evicted_value = _key, _value;
+					if _key == "a" then
+						-- Sanity check for what we're evicting
+						assert.are.equal(_key, "a");
+						assert.are.equal(_value, 1);
+						-- We're going to block eviction of this key/value, so set to nil...
+						evicted_key, evicted_value = nil, nil;
+						-- Returning false to block eviction
+						return false
+					end
+				end);
+				local function set(k, v, should_evict_key, should_evict_value)
+					evicted_key, evicted_value = nil, nil;
+					local ret = c3:set(k, v);
+					assert.are.equal(evicted_key, should_evict_key);
+					assert.are.equal(evicted_value, should_evict_value);
+					return ret;
+				end
+				set("a", 1)
+				set("a", 1)
+				set("a", 1)
+				set("a", 1)
+				set("a", 1)
+
+				-- Our on_evict prevents "a" from being evicted, causing this to fail...
+				assert.are.equal(set("b", 2), false, "Failed to prevent eviction, or signal result");
+
+				expect_kv("a", 1, c3:head());
+				expect_kv("a", 1, c3:tail());
+
+				-- Check the final state is what we expect
+				assert.are.equal(c3:get("a"), 1);
+				assert.are.equal(c3:get("b"), nil);
+				assert.are.equal(c3:count(), 1);
+			end
+
+
+			local c4 = cache.new(3, false);
+
+			assert.are.equal(c4:set("a", 1), true);
+			assert.are.equal(c4:set("a", 1), true);
+			assert.are.equal(c4:set("a", 1), true);
+			assert.are.equal(c4:set("a", 1), true);
+			assert.are.equal(c4:set("b", 2), true);
+			assert.are.equal(c4:set("c", 3), true);
+			assert.are.equal(c4:set("d", 4), false);
+			assert.are.equal(c4:set("d", 4), false);
+			assert.are.equal(c4:set("d", 4), false);
+
+			expect_kv("c", 3, c4:head());
+			expect_kv("a", 1, c4:tail());
+
+			local c5 = cache.new(3, function (k, v)
+				if k == "a" then
+					return nil;
+				elseif k == "b" then
+					return true;
+				end
+				return false;
+			end);
+
+			assert.are.equal(c5:set("a", 1), true);
+			assert.are.equal(c5:set("a", 1), true);
+			assert.are.equal(c5:set("a", 1), true);
+			assert.are.equal(c5:set("a", 1), true);
+			assert.are.equal(c5:set("b", 2), true);
+			assert.are.equal(c5:set("c", 3), true);
+			assert.are.equal(c5:set("d", 4), true); -- "a" evicted (cb returned nil)
+			assert.are.equal(c5:set("d", 4), true); -- nop
+			assert.are.equal(c5:set("d", 4), true); -- nop
+			assert.are.equal(c5:set("e", 5), true); -- "b" evicted (cb returned true)
+			assert.are.equal(c5:set("f", 6), false); -- "c" won't evict (cb returned false)
+
+			expect_kv("e", 5, c5:head());
+			expect_kv("c", 3, c5:tail());
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_encodings_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,22 @@
+
+local encodings = require "util.encodings";
+local utf8 = assert(encodings.utf8, "no encodings.utf8 module");
+
+describe("util.encodings.utf8", function()
+	describe("#valid()", function()
+		it("should work", function()
+
+			for line in io.lines("spec/utf8_sequences.txt") do
+				local data = line:match(":%s*([^#]+)"):gsub("%s+", ""):gsub("..", function (c) return string.char(tonumber(c, 16)); end)
+				local expect = line:match("(%S+):");
+
+				assert(expect == "pass" or expect == "fail", "unknown expectation: "..line:match("^[^:]+"));
+
+				local valid = utf8.valid(data);
+				assert.is.equal(valid, utf8.valid(data.." "));
+				assert.is.equal(valid, expect == "pass", line);
+			end
+
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_http_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,64 @@
+
+local http = require "util.http";
+
+describe("util.http", function()
+	describe("#urlencode()", function()
+		it("should not change normal characters", function()
+			assert.are.equal(http.urlencode("helloworld123"), "helloworld123");
+		end);
+
+		it("should escape spaces", function()
+			assert.are.equal(http.urlencode("hello world"), "hello%20world");
+		end);
+
+		it("should escape important URL characters", function()
+			assert.are.equal(http.urlencode("This & that = something"), "This%20%26%20that%20%3d%20something");
+		end);
+	end);
+
+	describe("#urldecode()", function()
+		it("should not change normal characters", function()
+			assert.are.equal("helloworld123", http.urldecode("helloworld123"), "Normal characters not escaped");
+		end);
+
+		it("should decode spaces", function()
+			assert.are.equal("hello world", http.urldecode("hello%20world"), "Spaces escaped");
+		end);
+
+		it("should decode important URL characters", function()
+			assert.are.equal("This & that = something", http.urldecode("This%20%26%20that%20%3d%20something"), "Important URL chars escaped");
+		end);
+	end);
+
+	describe("#formencode()", function()
+		it("should encode basic data", function()
+			assert.are.equal(http.formencode({ { name = "one", value = "1"}, { name = "two", value = "2" } }), "one=1&two=2", "Form encoded");
+		end);
+
+		it("should encode special characters with escaping", function()
+			assert.are.equal(http.formencode({ { name = "one two", value = "1"}, { name = "two one&", value = "2" } }), "one+two=1&two+one%26=2", "Form encoded");
+		end);
+	end);
+
+	describe("#formdecode()", function()
+		it("should decode basic data", function()
+			local t = http.formdecode("one=1&two=2");
+			assert.are.same(t, {
+				{ name = "one", value = "1" };
+				{ name = "two", value = "2" };
+				one = "1";
+				two = "2";
+			});
+		end);
+
+		it("should decode special characters", function()
+			local t = http.formdecode("one+two=1&two+one%26=2");
+			assert.are.same(t, {
+				{ name = "one two", value = "1" };
+				{ name = "two one&", value = "2" };
+				["one two"] = "1";
+				["two one&"] = "2";
+			});
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_ip_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,103 @@
+
+local ip = require "util.ip";
+
+local new_ip = ip.new_ip;
+local match = ip.match;
+local parse_cidr = ip.parse_cidr;
+local commonPrefixLength = ip.commonPrefixLength;
+
+describe("util.ip", function()
+	describe("#match()", function()
+		it("should work", function()
+			local _ = new_ip;
+			local ip = _"10.20.30.40";
+			assert.are.equal(match(ip, _"10.0.0.0", 8), true);
+			assert.are.equal(match(ip, _"10.0.0.0", 16), false);
+			assert.are.equal(match(ip, _"10.0.0.0", 24), false);
+			assert.are.equal(match(ip, _"10.0.0.0", 32), false);
+
+			assert.are.equal(match(ip, _"10.20.0.0", 8), true);
+			assert.are.equal(match(ip, _"10.20.0.0", 16), true);
+			assert.are.equal(match(ip, _"10.20.0.0", 24), false);
+			assert.are.equal(match(ip, _"10.20.0.0", 32), false);
+
+			assert.are.equal(match(ip, _"0.0.0.0", 32), false);
+			assert.are.equal(match(ip, _"0.0.0.0", 0), true);
+			assert.are.equal(match(ip, _"0.0.0.0"), false);
+
+			assert.are.equal(match(ip, _"10.0.0.0", 255), false, "excessive number of bits");
+			assert.are.equal(match(ip, _"10.0.0.0", -8), true, "negative number of bits");
+			assert.are.equal(match(ip, _"10.0.0.0", -32), true, "negative number of bits");
+			assert.are.equal(match(ip, _"10.0.0.0", 0), true, "zero bits");
+			assert.are.equal(match(ip, _"10.0.0.0"), false, "no specified number of bits (differing ip)");
+			assert.are.equal(match(ip, _"10.20.30.40"), true, "no specified number of bits (same ip)");
+
+			assert.are.equal(match(_"127.0.0.1", _"127.0.0.1"), true, "simple ip");
+
+			assert.are.equal(match(_"8.8.8.8", _"8.8.0.0", 16), true);
+			assert.are.equal(match(_"8.8.4.4", _"8.8.0.0", 16), true);
+		end);
+	end);
+
+	describe("#parse_cidr()", function()
+		it("should work", function()
+			assert.are.equal(new_ip"0.0.0.0", new_ip"0.0.0.0")
+
+			local function assert_cidr(cidr, ip, bits)
+				local parsed_ip, parsed_bits = parse_cidr(cidr);
+				assert.are.equal(new_ip(ip), parsed_ip, cidr.." parsed ip is "..ip);
+				assert.are.equal(bits, parsed_bits, cidr.." parsed bits is "..tostring(bits));
+			end
+			assert_cidr("0.0.0.0", "0.0.0.0", nil);
+			assert_cidr("127.0.0.1", "127.0.0.1", nil);
+			assert_cidr("127.0.0.1/0", "127.0.0.1", 0);
+			assert_cidr("127.0.0.1/8", "127.0.0.1", 8);
+			assert_cidr("127.0.0.1/32", "127.0.0.1", 32);
+			assert_cidr("127.0.0.1/256", "127.0.0.1", 256);
+			assert_cidr("::/48", "::", 48);
+		end);
+	end);
+
+	describe("#new_ip()", function()
+		it("should work", function()
+			local v4, v6 = "IPv4", "IPv6";
+			local function assert_proto(s, proto)
+				local ip = new_ip(s);
+				if proto then
+					assert.are.equal(ip and ip.proto, proto, "protocol is correct for "..("%q"):format(s));
+				else
+					assert.are.equal(ip, nil, "address is invalid");
+				end
+			end
+			assert_proto("127.0.0.1", v4);
+			assert_proto("::1", v6);
+			assert_proto("", nil);
+			assert_proto("abc", nil);
+			assert_proto("   ", nil);
+		end);
+	end);
+
+	describe("#commonPrefixLength()", function()
+		it("should work", function()
+			local function assert_cpl6(a, b, len, v4)
+				local ipa, ipb = new_ip(a), new_ip(b);
+				if v4 then len = len+96; end
+				assert.are.equal(commonPrefixLength(ipa, ipb), len, "common prefix length of "..a.." and "..b.." is "..len);
+				assert.are.equal(commonPrefixLength(ipb, ipa), len, "common prefix length of "..b.." and "..a.." is "..len);
+			end
+			local function assert_cpl4(a, b, len)
+				return assert_cpl6(a, b, len, "IPv4");
+			end
+			assert_cpl4("0.0.0.0", "0.0.0.0", 32);
+			assert_cpl4("255.255.255.255", "0.0.0.0", 0);
+			assert_cpl4("255.255.255.255", "255.255.0.0", 16);
+			assert_cpl4("255.255.255.255", "255.255.255.255", 32);
+			assert_cpl4("255.255.255.255", "255.255.255.255", 32);
+
+			assert_cpl6("::1", "::1", 128);
+			assert_cpl6("abcd::1", "abcd::1", 128);
+			assert_cpl6("abcd::abcd", "abcd::", 112);
+			assert_cpl6("abcd::abcd", "abcd::abcd:abcd", 96);
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_jid_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,146 @@
+
+local jid = require "util.jid";
+
+describe("util.jid", function()
+	describe("#join()", function()
+		it("should work", function()
+			assert.are.equal(jid.join("a", "b", "c"), "a@b/c", "builds full JID");
+			assert.are.equal(jid.join("a", "b", nil), "a@b", "builds bare JID");
+			assert.are.equal(jid.join(nil, "b", "c"), "b/c", "builds full host JID");
+			assert.are.equal(jid.join(nil, "b", nil), "b", "builds bare host JID");
+			assert.are.equal(jid.join(nil, nil, nil), nil, "invalid JID is nil");
+			assert.are.equal(jid.join("a", nil, nil), nil, "invalid JID is nil");
+			assert.are.equal(jid.join(nil, nil, "c"), nil, "invalid JID is nil");
+			assert.are.equal(jid.join("a", nil, "c"), nil, "invalid JID is nil");
+		end);
+	end);
+	describe("#split()", function()
+		it("should work", function()
+			local function test(input_jid, expected_node, expected_server, expected_resource)
+				local rnode, rserver, rresource = jid.split(input_jid);
+				assert.are.equal(expected_node, rnode, "split("..tostring(input_jid)..") failed");
+				assert.are.equal(expected_server, rserver, "split("..tostring(input_jid)..") failed");
+				assert.are.equal(expected_resource, rresource, "split("..tostring(input_jid)..") failed");
+			end
+
+			-- Valid JIDs
+			test("node@server", 		"node", "server", nil		);
+			test("node@server/resource", 	"node", "server", "resource"        );
+			test("server", 			nil, 	"server", nil               );
+			test("server/resource", 	nil, 	"server", "resource"        );
+			test("server/resource@foo", 	nil, 	"server", "resource@foo"    );
+			test("server/resource@foo/bar",	nil, 	"server", "resource@foo/bar");
+
+			-- Always invalid JIDs
+			test(nil,                nil, nil, nil);
+			test("node@/server",     nil, nil, nil);
+			test("@server",          nil, nil, nil);
+			test("@server/resource", nil, nil, nil);
+			test("@/resource", nil, nil, nil);
+		end);
+	end);
+
+
+	describe("#bare()", function()
+		it("should work", function()
+			assert.are.equal(jid.bare("user@host"), "user@host", "bare JID remains bare");
+			assert.are.equal(jid.bare("host"), "host", "Host JID remains host");
+			assert.are.equal(jid.bare("host/resource"), "host", "Host JID with resource becomes host");
+			assert.are.equal(jid.bare("user@host/resource"), "user@host", "user@host JID with resource becomes user@host");
+			assert.are.equal(jid.bare("user@/resource"), nil, "invalid JID is nil");
+			assert.are.equal(jid.bare("@/resource"), nil, "invalid JID is nil");
+			assert.are.equal(jid.bare("@/"), nil, "invalid JID is nil");
+			assert.are.equal(jid.bare("/"), nil, "invalid JID is nil");
+			assert.are.equal(jid.bare(""), nil, "invalid JID is nil");
+			assert.are.equal(jid.bare("@"), nil, "invalid JID is nil");
+			assert.are.equal(jid.bare("user@"), nil, "invalid JID is nil");
+			assert.are.equal(jid.bare("user@@"), nil, "invalid JID is nil");
+			assert.are.equal(jid.bare("user@@host"), nil, "invalid JID is nil");
+			assert.are.equal(jid.bare("user@@host/resource"), nil, "invalid JID is nil");
+			assert.are.equal(jid.bare("user@host/"), nil, "invalid JID is nil");
+		end);
+	end);
+
+	describe("#compare()", function()
+		it("should work", function()
+			assert.are.equal(jid.compare("host", "host"), true, "host should match");
+			assert.are.equal(jid.compare("host", "other-host"), false, "host should not match");
+			assert.are.equal(jid.compare("other-user@host/resource", "host"), true, "host should match");
+			assert.are.equal(jid.compare("other-user@host", "user@host"), false, "user should not match");
+			assert.are.equal(jid.compare("user@host", "host"), true, "host should match");
+			assert.are.equal(jid.compare("user@host/resource", "host"), true, "host should match");
+			assert.are.equal(jid.compare("user@host/resource", "user@host"), true, "user and host should match");
+			assert.are.equal(jid.compare("user@other-host", "host"), false, "host should not match");
+			assert.are.equal(jid.compare("user@other-host", "user@host"), false, "host should not match");
+		end);
+	end);
+
+	it("should work with nodes", function()
+		local function test(_jid, expected_node)
+			assert.are.equal(jid.node(_jid), expected_node, "Unexpected node for "..tostring(_jid));
+		end
+
+		test("example.com", nil);
+		test("foo.example.com", nil);
+		test("foo.example.com/resource", nil);
+		test("foo.example.com/some resource", nil);
+		test("foo.example.com/some@resource", nil);
+
+		test("foo@foo.example.com/some@resource", "foo");
+		test("foo@example/some@resource", "foo");
+
+		test("foo@example/@resource", "foo");
+		test("foo@example@resource", nil);
+		test("foo@example", "foo");
+		test("foo", nil);
+
+		test(nil, nil);
+	end);
+
+	it("should work with hosts", function()
+		local function test(_jid, expected_host)
+			assert.are.equal(jid.host(_jid), expected_host, "Unexpected host for "..tostring(_jid));
+		end
+
+		test("example.com", "example.com");
+		test("foo.example.com", "foo.example.com");
+		test("foo.example.com/resource", "foo.example.com");
+		test("foo.example.com/some resource", "foo.example.com");
+		test("foo.example.com/some@resource", "foo.example.com");
+
+		test("foo@foo.example.com/some@resource", "foo.example.com");
+		test("foo@example/some@resource", "example");
+
+		test("foo@example/@resource", "example");
+		test("foo@example@resource", nil);
+		test("foo@example", "example");
+		test("foo", "foo");
+
+		test(nil, nil);
+	end);
+
+	it("should work with resources", function()
+		local function test(_jid, expected_resource)
+			assert.are.equal(jid.resource(_jid), expected_resource, "Unexpected resource for "..tostring(_jid));
+		end
+
+		test("example.com", nil);
+		test("foo.example.com", nil);
+		test("foo.example.com/resource", "resource");
+		test("foo.example.com/some resource", "some resource");
+		test("foo.example.com/some@resource", "some@resource");
+
+		test("foo@foo.example.com/some@resource", "some@resource");
+		test("foo@example/some@resource", "some@resource");
+
+		test("foo@example/@resource", "@resource");
+		test("foo@example@resource", nil);
+		test("foo@example", nil);
+		test("foo", nil);
+		test("/foo", nil);
+		test("@x/foo", nil);
+		test("@/foo", nil);
+
+		test(nil, nil);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_json_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,70 @@
+
+local json = require "util.json";
+
+describe("util.json", function()
+	describe("#encode()", function()
+		it("should work", function()
+			local function test(f, j, e)
+				if e then
+					assert.are.equal(f(j), e);
+				end
+				assert.are.equal(f(j), f(json.decode(f(j))));
+			end
+			test(json.encode, json.null, "null")
+			test(json.encode, {}, "{}")
+			test(json.encode, {a=1});
+			test(json.encode, {a={1,2,3}});
+			test(json.encode, {1}, "[1]");
+		end);
+	end);
+
+	describe("#decode()", function()
+		it("should work", function()
+			local empty_array = json.decode("[]");
+			assert.are.equal(type(empty_array), "table");
+			assert.are.equal(#empty_array, 0);
+			assert.are.equal(next(empty_array), nil);
+		end);
+	end);
+
+	describe("testcases", function()
+
+		local valid_data = {};
+		local invalid_data = {};
+
+		local skip = "fail1.json fail9.json fail18.json fail15.json fail13.json fail25.json fail26.json fail27.json fail28.json fail17.json pass1.json";
+
+		setup(function()
+			local lfs = require "lfs";
+			local path = "spec/json";
+			for name in lfs.dir(path) do
+				if name:match("%.json$") then
+					local f = assert(io.open(path.."/"..name));
+					local content = assert(f:read("*a"));
+					assert(f:close());
+					if skip:find(name) then
+						-- Skip
+					elseif name:match("^pass") then
+						valid_data[name] = content;
+					elseif name:match("^fail") then
+						invalid_data[name] = content;
+					end
+				end
+			end
+		end)
+
+		it("should pass valid testcases", function()
+			for name, content in pairs(valid_data) do
+				local parsed, err = json.decode(content);
+				assert(parsed, name..": "..tostring(err));
+			end
+		end);
+
+		it("should fail invalid testcases", function()
+			for name, content in pairs(invalid_data) do
+				local parsed, err = json.decode(content);
+				assert(not parsed, name..": "..tostring(err));
+			end			
+		end);
+	end)
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_multitable_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,60 @@
+
+local multitable = require "util.multitable";
+
+describe("util.multitable", function()
+	describe("#new()", function()
+		it("should create a multitable", function()
+			local mt = multitable.new();
+			assert.is_table(mt, "Multitable is a table");
+			assert.is_function(mt.add, "Multitable has method add");
+			assert.is_function(mt.get, "Multitable has method get");
+			assert.is_function(mt.remove, "Multitable has method remove");
+		end);
+	end);
+
+	describe("#get()", function()
+		it("should allow getting correctly", function()
+			local function has_items(list, ...)
+				local should_have = {};
+				if select('#', ...) > 0 then
+					assert.is_table(list, "has_items: list is table", 3);
+				else
+					assert.is.falsy(list and #list > 0, "No items, and no list");
+					return true, "has-all";
+				end
+				for n=1,select('#', ...) do should_have[select(n, ...)] = true; end
+				for _, item in ipairs(list) do
+					if not should_have[item] then return false, "too-many"; end
+					should_have[item] = nil;
+				end
+				if next(should_have) then
+					return false, "not-enough";
+				end
+				return true, "has-all";
+			end
+			local function assert_has_all(message, list, ...)
+				return assert.are.equal(select(2, has_items(list, ...)), "has-all", message or "List has all expected items, and no more", 2);
+			end
+
+			local mt = multitable.new();
+
+			local trigger1, trigger2, trigger3 = {}, {}, {};
+			local item1, item2, item3 = {}, {}, {};
+
+			assert_has_all("Has no items with trigger1", mt:get(trigger1));
+
+
+			mt:add(1, 2, 3, item1);
+
+			assert_has_all("Has item1 for 1, 2, 3", mt:get(1, 2, 3), item1);
+		end);
+	end);
+
+	-- Doesn't support nil
+	--[[	mt:add(nil, item1);
+		mt:add(nil, item2);
+		mt:add(nil, item3);
+
+		assert_has_all("Has all items with (nil)", mt:get(nil), item1, item2, item3);
+	]]
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_queue_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,82 @@
+
+local queue = require "util.queue";
+
+describe("util.queue", function()
+	describe("#new()", function()
+		it("should work", function()
+
+			do
+				local q = queue.new(10);
+
+				assert.are.equal(q.size, 10);
+				assert.are.equal(q:count(), 0);
+
+				assert.is_true(q:push("one"));
+				assert.is_true(q:push("two"));
+				assert.is_true(q:push("three"));
+
+				for i = 4, 10 do
+					assert.is_true(q:push("hello"));
+					assert.are.equal(q:count(), i, "count is not "..i.."("..q:count()..")");
+				end
+				assert.are.equal(q:push("hello"), nil, "queue overfull!");
+				assert.are.equal(q:push("hello"), nil, "queue overfull!");
+				assert.are.equal(q:pop(), "one", "queue item incorrect");
+				assert.are.equal(q:pop(), "two", "queue item incorrect");
+				assert.is_true(q:push("hello"));
+				assert.is_true(q:push("hello"));
+				assert.are.equal(q:pop(), "three", "queue item incorrect");
+				assert.is_true(q:push("hello"));
+				assert.are.equal(q:push("hello"), nil, "queue overfull!");
+				assert.are.equal(q:push("hello"), nil, "queue overfull!");
+
+				assert.are.equal(q:count(), 10, "queue count incorrect");
+
+				for _ = 1, 10 do
+					assert.are.equal(q:pop(), "hello", "queue item incorrect");
+				end
+
+				assert.are.equal(q:count(), 0, "queue count incorrect");
+
+				assert.is_true(q:push(1));
+				for i = 1, 1001 do
+					assert.are.equal(q:pop(), i);
+					assert.are.equal(q:count(), 0);
+					assert.is_true(q:push(i+1));
+					assert.are.equal(q:count(), 1);
+				end
+				assert.are.equal(q:pop(), 1002);
+				assert.is_true(q:push(1));
+				for i = 1, 1000 do
+					assert.are.equal(q:pop(), i);
+					assert.is_true(q:push(i+1));
+				end
+				assert.are.equal(q:pop(), 1001);
+				assert.are.equal(q:count(), 0);
+			end
+
+			do
+				-- Test queues that purge old items when pushing to a full queue
+				local q = queue.new(10, true);
+
+				for i = 1, 10 do
+					q:push(i);
+				end
+
+				assert.are.equal(q:count(), 10);
+
+				assert.is_true(q:push(11));
+				assert.are.equal(q:count(), 10);
+				assert.are.equal(q:pop(), 2); -- First item should have been purged
+
+				for i = 12, 32 do
+					assert.is_true(q:push(i));
+				end
+
+				assert.are.equal(q:count(), 10);
+				assert.are.equal(q:pop(), 23);
+			end
+
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_random_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,19 @@
+
+local random = require "util.random";
+
+describe("util.random", function()
+	describe("#bytes()", function()
+		it("should return a string", function()
+			assert.is_string(random.bytes(16));
+		end);
+
+		it("should return the requested number of bytes", function()
+			-- Makes no attempt at testing how random the bytes are,
+			-- just that it returns the number of bytes requested
+
+			for i = 1, 255 do
+				assert.are.equal(i, #random.bytes(i));
+			end
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_rfc6724_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,97 @@
+
+local rfc6724 = require "util.rfc6724";
+local new_ip = require"util.ip".new_ip;
+
+describe("util.rfc6724", function()
+	describe("#source()", function()
+		it("should work", function()
+			assert.are.equal(rfc6724.source(new_ip("2001:db8:1::1", "IPv6"),
+					{new_ip("2001:db8:3::1", "IPv6"), new_ip("fe80::1", "IPv6")}).addr,
+				"2001:db8:3::1",
+				"prefer appropriate scope");
+			assert.are.equal(rfc6724.source(new_ip("ff05::1", "IPv6"),
+					{new_ip("2001:db8:3::1", "IPv6"), new_ip("fe80::1", "IPv6")}).addr,
+				"2001:db8:3::1",
+				"prefer appropriate scope");
+			assert.are.equal(rfc6724.source(new_ip("2001:db8:1::1", "IPv6"),
+					{new_ip("2001:db8:1::1", "IPv6"), new_ip("2001:db8:2::1", "IPv6")}).addr,
+				"2001:db8:1::1",
+				"prefer same address"); -- "2001:db8:1::1" should be marked "deprecated" here, we don't handle that right now
+			assert.are.equal(rfc6724.source(new_ip("fe80::1", "IPv6"),
+					{new_ip("fe80::2", "IPv6"), new_ip("2001:db8:1::1", "IPv6")}).addr,
+				"fe80::2",
+				"prefer appropriate scope"); -- "fe80::2" should be marked "deprecated" here, we don't handle that right now
+			assert.are.equal(rfc6724.source(new_ip("2001:db8:1::1", "IPv6"),
+					{new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3::2", "IPv6")}).addr,
+				"2001:db8:1::2",
+				"longest matching prefix");
+		--[[ "2001:db8:1::2" should be a care-of address and "2001:db8:3::2" a home address, we can't handle this and would fail
+			assert.are.equal(rfc6724.source(new_ip("2001:db8:1::1", "IPv6"),
+					{new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3::2", "IPv6")}).addr,
+				"2001:db8:3::2",
+				"prefer home address");
+		]]
+			assert.are.equal(rfc6724.source(new_ip("2002:c633:6401::1", "IPv6"),
+					{new_ip("2002:c633:6401::d5e3:7953:13eb:22e8", "IPv6"), new_ip("2001:db8:1::2", "IPv6")}).addr,
+				"2002:c633:6401::d5e3:7953:13eb:22e8",
+				"prefer matching label"); -- "2002:c633:6401::d5e3:7953:13eb:22e8" should be marked "temporary" here, we don't handle that right now
+			assert.are.equal(rfc6724.source(new_ip("2001:db8:1::d5e3:0:0:1", "IPv6"),
+					{new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:1::d5e3:7953:13eb:22e8", "IPv6")}).addr,
+				"2001:db8:1::d5e3:7953:13eb:22e8",
+				"prefer temporary address") -- "2001:db8:1::2" should be marked "public" and "2001:db8:1::d5e3:7953:13eb:22e8" should be marked "temporary" here, we don't handle that right now
+		end);
+	end);
+	describe("#destination()", function()
+		it("should work", function()
+			local order;
+			order = rfc6724.destination({new_ip("2001:db8:1::1", "IPv6"), new_ip("198.51.100.121", "IPv4")},
+				{new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("169.254.13.78", "IPv4")})
+			assert.are.equal(order[1].addr, "2001:db8:1::1", "prefer matching scope");
+			assert.are.equal(order[2].addr, "198.51.100.121", "prefer matching scope");
+
+			order = rfc6724.destination({new_ip("2001:db8:1::1", "IPv6"), new_ip("198.51.100.121", "IPv4")},
+				{new_ip("fe80::1", "IPv6"), new_ip("198.51.100.117", "IPv4")})
+			assert.are.equal(order[1].addr, "198.51.100.121", "prefer matching scope");
+			assert.are.equal(order[2].addr, "2001:db8:1::1", "prefer matching scope");
+
+			order = rfc6724.destination({new_ip("2001:db8:1::1", "IPv6"), new_ip("10.1.2.3", "IPv4")},
+				{new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("10.1.2.4", "IPv4")})
+			assert.are.equal(order[1].addr, "2001:db8:1::1", "prefer higher precedence");
+			assert.are.equal(order[2].addr, "10.1.2.3", "prefer higher precedence");
+
+			order = rfc6724.destination({new_ip("2001:db8:1::1", "IPv6"), new_ip("fe80::1", "IPv6")},
+				{new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::2", "IPv6")})
+			assert.are.equal(order[1].addr, "fe80::1", "prefer smaller scope");
+			assert.are.equal(order[2].addr, "2001:db8:1::1", "prefer smaller scope");
+
+		--[[ "2001:db8:1::2" and "fe80::2" should be marked "care-of address", while "2001:db8:3::1" should be marked "home address", we can't currently handle this and would fail the test
+			order = rfc6724.destination({new_ip("2001:db8:1::1", "IPv6"), new_ip("fe80::1", "IPv6")},
+				{new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3::1", "IPv6"), new_ip("fe80::2", "IPv6")})
+			assert.are.equal(order[1].addr, "2001:db8:1::1", "prefer home address");
+			assert.are.equal(order[2].addr, "fe80::1", "prefer home address");
+		]]
+
+		--[[ "fe80::2" should be marked "deprecated", we can't currently handle this and would fail the test
+			order = rfc6724.destination({new_ip("2001:db8:1::1", "IPv6"), new_ip("fe80::1", "IPv6")},
+				{new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::2", "IPv6")})
+			assert.are.equal(order[1].addr, "2001:db8:1::1", "avoid deprecated addresses");
+			assert.are.equal(order[2].addr, "fe80::1", "avoid deprecated addresses");
+		]]
+
+			order = rfc6724.destination({new_ip("2001:db8:1::1", "IPv6"), new_ip("2001:db8:3ffe::1", "IPv6")},
+				{new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3f44::2", "IPv6"), new_ip("fe80::2", "IPv6")})
+			assert.are.equal(order[1].addr, "2001:db8:1::1", "longest matching prefix");
+			assert.are.equal(order[2].addr, "2001:db8:3ffe::1", "longest matching prefix");
+
+			order = rfc6724.destination({new_ip("2002:c633:6401::1", "IPv6"), new_ip("2001:db8:1::1", "IPv6")},
+				{new_ip("2002:c633:6401::2", "IPv6"), new_ip("fe80::2", "IPv6")})
+			assert.are.equal(order[1].addr, "2002:c633:6401::1", "prefer matching label");
+			assert.are.equal(order[2].addr, "2001:db8:1::1", "prefer matching label");
+
+			order = rfc6724.destination({new_ip("2002:c633:6401::1", "IPv6"), new_ip("2001:db8:1::1", "IPv6")},
+				{new_ip("2002:c633:6401::2", "IPv6"), new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::2", "IPv6")})
+			assert.are.equal(order[1].addr, "2001:db8:1::1", "prefer higher precedence");
+			assert.are.equal(order[2].addr, "2002:c633:6401::1", "prefer higher precedence");
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_stanza_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,159 @@
+
+local st = require "util.stanza";
+
+describe("util.stanza", function()
+	describe("#preserialize()", function()
+		it("should work", function()
+			local stanza = st.stanza("message", { a = "a" });
+			local stanza2 = st.preserialize(stanza);
+			assert.is_string(stanza2 and stanza.name, "preserialize returns a stanza");
+			assert.is_nil(stanza2.tags, "Preserialized stanza has no tag list");
+			assert.is_nil(stanza2.last_add, "Preserialized stanza has no last_add marker");
+			assert.is_nil(getmetatable(stanza2), "Preserialized stanza has no metatable");
+		end);
+	end);
+
+	describe("#preserialize()", function()
+		it("should work", function()
+			local stanza = st.stanza("message", { a = "a" });
+			local stanza2 = st.deserialize(st.preserialize(stanza));
+			assert.is_string(stanza2 and stanza.name, "deserialize returns a stanza");
+			assert.is_table(stanza2.attr, "Deserialized stanza has attributes");
+			assert.are.equal(stanza2.attr.a, "a", "Deserialized stanza retains attributes");
+			assert.is_table(getmetatable(stanza2), "Deserialized stanza has metatable");
+		end);
+	end);
+
+	describe("#stanza()", function()
+		it("should work", function()
+			local s = st.stanza("foo", { xmlns = "myxmlns", a = "attr-a" });
+			assert.are.equal(s.name, "foo");
+			assert.are.equal(s.attr.xmlns, "myxmlns");
+			assert.are.equal(s.attr.a, "attr-a");
+
+			local s1 = st.stanza("s1");
+			assert.are.equal(s1.name, "s1");
+			assert.are.equal(s1.attr.xmlns, nil);
+			assert.are.equal(#s1, 0);
+			assert.are.equal(#s1.tags, 0);
+
+			s1:tag("child1");
+			assert.are.equal(#s1.tags, 1);
+			assert.are.equal(s1.tags[1].name, "child1");
+
+			s1:tag("grandchild1"):up();
+			assert.are.equal(#s1.tags, 1);
+			assert.are.equal(s1.tags[1].name, "child1");
+			assert.are.equal(#s1.tags[1], 1);
+			assert.are.equal(s1.tags[1][1].name, "grandchild1");
+
+			s1:up():tag("child2");
+			assert.are.equal(#s1.tags, 2, tostring(s1));
+			assert.are.equal(s1.tags[1].name, "child1");
+			assert.are.equal(s1.tags[2].name, "child2");
+			assert.are.equal(#s1.tags[1], 1);
+			assert.are.equal(s1.tags[1][1].name, "grandchild1");
+
+			s1:up():text("Hello world");
+			assert.are.equal(#s1.tags, 2);
+			assert.are.equal(#s1, 3);
+			assert.are.equal(s1.tags[1].name, "child1");
+			assert.are.equal(s1.tags[2].name, "child2");
+			assert.are.equal(#s1.tags[1], 1);
+			assert.are.equal(s1.tags[1][1].name, "grandchild1");
+		end);
+	end);
+
+	describe("#message()", function()
+		it("should work", function()
+			local m = st.message();
+			assert.are.equal(m.name, "message");
+		end);
+	end);
+
+	describe("#iq()", function()
+		it("should work", function()
+			local i = st.iq();
+			assert.are.equal(i.name, "iq");
+		end);
+	end);
+
+	describe("#iq()", function()
+		it("should work", function()
+			local p = st.presence();
+			assert.are.equal(p.name, "presence");
+		end);
+	end);
+
+	describe("#reply()", function()
+		it("should work for <s>", function()
+			-- Test stanza
+			local s = st.stanza("s", { to = "touser", from = "fromuser", id = "123" })
+				:tag("child1");
+			-- Make reply stanza
+			local r = st.reply(s);
+			assert.are.equal(r.name, s.name);
+			assert.are.equal(r.id, s.id);
+			assert.are.equal(r.attr.to, s.attr.from);
+			assert.are.equal(r.attr.from, s.attr.to);
+			assert.are.equal(#r.tags, 0, "A reply should not include children of the original stanza");
+		end);
+
+		it("should work for <iq get>", function()
+			-- Test stanza
+			local s = st.stanza("iq", { to = "touser", from = "fromuser", id = "123", type = "get" })
+				:tag("child1");
+			-- Make reply stanza
+			local r = st.reply(s);
+			assert.are.equal(r.name, s.name);
+			assert.are.equal(r.id, s.id);
+			assert.are.equal(r.attr.to, s.attr.from);
+			assert.are.equal(r.attr.from, s.attr.to);
+			assert.are.equal(r.attr.type, "result");
+			assert.are.equal(#r.tags, 0, "A reply should not include children of the original stanza");
+		end);
+
+		it("should work for <iq set>", function()
+			-- Test stanza
+			local s = st.stanza("iq", { to = "touser", from = "fromuser", id = "123", type = "set" })
+				:tag("child1");
+			-- Make reply stanza
+			local r = st.reply(s);
+			assert.are.equal(r.name, s.name);
+			assert.are.equal(r.id, s.id);
+			assert.are.equal(r.attr.to, s.attr.from);
+			assert.are.equal(r.attr.from, s.attr.to);
+			assert.are.equal(r.attr.type, "result");
+			assert.are.equal(#r.tags, 0, "A reply should not include children of the original stanza");
+		end);
+	end);
+
+	describe("#error_reply()", function()
+		it("should work for <s>", function()
+			-- Test stanza
+			local s = st.stanza("s", { to = "touser", from = "fromuser", id = "123" })
+				:tag("child1");
+			-- Make reply stanza
+			local r = st.error_reply(s);
+			assert.are.equal(r.name, s.name);
+			assert.are.equal(r.id, s.id);
+			assert.are.equal(r.attr.to, s.attr.from);
+			assert.are.equal(r.attr.from, s.attr.to);
+			assert.are.equal(#r.tags, 1);
+		end);
+
+		it("should work for <iq get>", function()
+			-- Test stanza
+			local s = st.stanza("iq", { to = "touser", from = "fromuser", id = "123", type = "get" })
+				:tag("child1");
+			-- Make reply stanza
+			local r = st.error_reply(s);
+			assert.are.equal(r.name, s.name);
+			assert.are.equal(r.id, s.id);
+			assert.are.equal(r.attr.to, s.attr.from);
+			assert.are.equal(r.attr.from, s.attr.to);
+			assert.are.equal(r.attr.type, "error");
+			assert.are.equal(#r.tags, 1);
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_throttle_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,30 @@
+
+
+-- Mock util.time
+local now = 0; -- wibbly-wobbly... timey-wimey... stuff
+local function later(n)
+	now = now + n; -- time passes at a different rate
+end
+package.loaded["util.time"] = {
+	now = function() return now; end
+}
+
+
+local throttle = require "util.throttle";
+
+describe("util.sasl.scram", function()
+	describe("#Hi()", function()
+		it("should work", function()
+			local a = throttle.create(3, 10);
+
+			assert.are.equal(a:poll(1), true);  -- 3 -> 2
+			assert.are.equal(a:poll(1), true);  -- 2 -> 1
+			assert.are.equal(a:poll(1), true);  -- 1 -> 0
+			assert.are.equal(a:poll(1), false); -- MEEP, out of credits!
+			later(1);                       -- ... what about
+			assert.are.equal(a:poll(1), false); -- now? - Still no!
+			later(9);                       -- Later that day
+			assert.are.equal(a:poll(1), true);  -- Should be back at 3 credits ... 2
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_uuid_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,31 @@
+-- This tests the format, not the randomness
+
+local uuid = require "util.uuid";
+
+describe("util.uuid", function()
+	describe("#generate()", function()
+		it("should work follow the UUID pattern", function()
+			-- https://tools.ietf.org/html/rfc4122#section-4.4
+
+			local pattern = "^" .. table.concat({
+				string.rep("%x", 8),
+				string.rep("%x", 4),
+				"4" .. -- version
+				string.rep("%x", 3),
+				"[89ab]" .. -- reserved bits of 1 and 0
+				string.rep("%x", 3),
+				string.rep("%x", 12),
+			}, "%-") .. "$";
+
+			for _ = 1, 100 do
+				assert.is_string(uuid.generate():match(pattern));
+			end
+		end);
+	end);
+
+	describe("#seed()", function()
+		it("should return nothing", function()
+			assert.is_nil(uuid.seed("random string here"), "seed doesn't return anything");
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_xml_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,20 @@
+
+local xml = require "util.xml";
+
+describe("util.xml", function()
+	describe("#parse()", function()
+		it("should work", function()
+			local x =
+[[<x xmlns:a="b">
+	<y xmlns:a="c"> <!-- this overwrites 'a' -->
+	    <a:z/>
+	</y>
+	<a:z/> <!-- prefix 'a' is nil here, but should be 'b' -->
+</x>
+]]
+			local stanza = xml.parse(x);
+			assert.are.equal(stanza.tags[2].attr.xmlns, "b");
+			assert.are.equal(stanza.tags[2].namespaces["a"], "b");
+		end);
+	end);
+end);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_xmppstream_spec.lua	Fri Sep 15 17:07:57 2017 -0400
@@ -0,0 +1,90 @@
+
+local xmppstream = require "util.xmppstream";
+
+describe("util.xmppstream", function()
+	describe("#new()", function()
+		it("should work", function()
+			local function test(xml, expect_success, ex)
+				local stanzas = {};
+				local session = { notopen = true };
+				local callbacks = {
+					stream_ns = "streamns";
+					stream_tag = "stream";
+					default_ns = "stanzans";
+					streamopened = function (_session)
+						assert.are.equal(session, _session);
+						assert.are.equal(session.notopen, true);
+						_session.notopen = nil;
+						return true;
+					end;
+					handlestanza = function (_session, stanza)
+						assert.are.equal(session, _session);
+						assert.are.equal(_session.notopen, nil);
+						table.insert(stanzas, stanza);
+					end;
+					streamclosed = function (_session)
+						assert.are.equal(session, _session);
+						assert.are.equal(_session.notopen, nil);
+						_session.notopen = nil;
+					end;
+				}
+				if type(ex) == "table" then
+					for k, v in pairs(ex) do
+						if k ~= "_size_limit" then
+							callbacks[k] = v;
+						end
+					end
+				end
+				local stream = xmppstream.new(session, callbacks, size_limit);
+				local ok, err = pcall(function ()
+					assert(stream:feed(xml));
+				end);
+
+				if ok and type(expect_success) == "function" then
+					expect_success(stanzas);
+				end
+				assert.are.equal(not not ok, not not expect_success, "Expected "..(expect_success and ("success ("..tostring(err)..")") or "failure"));
+			end
+
+			local function test_stanza(stanza, expect_success, ex)
+				return test([[<stream:stream xmlns:stream="streamns" xmlns="stanzans">]]..stanza, expect_success, ex);
+			end
+
+			test([[<stream:stream xmlns:stream="streamns"/>]], true);
+			test([[<stream xmlns="streamns"/>]], true);
+
+			test([[<stream1 xmlns="streamns"/>]], false);
+			test([[<stream xmlns="streamns1"/>]], false);
+			test("<>", false);
+
+			test_stanza("<message/>", function (stanzas)
+				assert.are.equal(#stanzas, 1);
+				assert.are.equal(stanzas[1].name, "message");
+			end);
+			test_stanza("< message>>>>/>\n", false);
+
+			test_stanza([[<x xmlns:a="b">
+				<y xmlns:a="c">
+					<a:z/>
+				</y>
+				<a:z/>
+			</x>]], function (stanzas)
+				assert.are.equal(#stanzas, 1);
+				local s = stanzas[1];
+				assert.are.equal(s.name, "x");
+				assert.are.equal(#s.tags, 2);
+
+				assert.are.equal(s.tags[1].name, "y");
+				assert.are.equal(s.tags[1].attr.xmlns, nil);
+
+				assert.are.equal(s.tags[1].tags[1].name, "z");
+				assert.are.equal(s.tags[1].tags[1].attr.xmlns, "c");
+
+				assert.are.equal(s.tags[2].name, "z");
+				assert.are.equal(s.tags[2].attr.xmlns, "b");
+
+				assert.are.equal(s.namespaces, nil);
+			end);
+		end);
+	end);
+end);
--- a/tests/json/fail1.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-"A JSON payload should be an object or array, not a string."
\ No newline at end of file
--- a/tests/json/fail10.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-{"Extra value after close": true} "misplaced quoted value"
\ No newline at end of file
--- a/tests/json/fail11.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-{"Illegal expression": 1 + 2}
\ No newline at end of file
--- a/tests/json/fail12.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-{"Illegal invocation": alert()}
\ No newline at end of file
--- a/tests/json/fail13.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-{"Numbers cannot have leading zeroes": 013}
\ No newline at end of file
--- a/tests/json/fail14.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-{"Numbers cannot be hex": 0x14}
\ No newline at end of file
--- a/tests/json/fail15.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["Illegal backslash escape: \x15"]
\ No newline at end of file
--- a/tests/json/fail16.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-[\naked]
\ No newline at end of file
--- a/tests/json/fail17.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["Illegal backslash escape: \017"]
\ No newline at end of file
--- a/tests/json/fail18.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
\ No newline at end of file
--- a/tests/json/fail19.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-{"Missing colon" null}
\ No newline at end of file
--- a/tests/json/fail2.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["Unclosed array"
\ No newline at end of file
--- a/tests/json/fail20.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-{"Double colon":: null}
\ No newline at end of file
--- a/tests/json/fail21.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-{"Comma instead of colon", null}
\ No newline at end of file
--- a/tests/json/fail22.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["Colon instead of comma": false]
\ No newline at end of file
--- a/tests/json/fail23.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["Bad value", truth]
\ No newline at end of file
--- a/tests/json/fail24.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-['single quote']
\ No newline at end of file
--- a/tests/json/fail25.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["	tab	character	in	string	"]
\ No newline at end of file
--- a/tests/json/fail26.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["tab\   character\   in\  string\  "]
\ No newline at end of file
--- a/tests/json/fail27.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-["line
-break"]
\ No newline at end of file
--- a/tests/json/fail28.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-["line\
-break"]
\ No newline at end of file
--- a/tests/json/fail29.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-[0e]
\ No newline at end of file
--- a/tests/json/fail3.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-{unquoted_key: "keys must be quoted"}
\ No newline at end of file
--- a/tests/json/fail30.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-[0e+]
\ No newline at end of file
--- a/tests/json/fail31.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-[0e+-1]
\ No newline at end of file
--- a/tests/json/fail32.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-{"Comma instead if closing brace": true,
\ No newline at end of file
--- a/tests/json/fail33.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["mismatch"}
\ No newline at end of file
--- a/tests/json/fail4.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["extra comma",]
\ No newline at end of file
--- a/tests/json/fail5.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["double extra comma",,]
\ No newline at end of file
--- a/tests/json/fail6.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-[   , "<-- missing value"]
\ No newline at end of file
--- a/tests/json/fail7.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["Comma after the close"],
\ No newline at end of file
--- a/tests/json/fail8.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["Extra close"]]
\ No newline at end of file
--- a/tests/json/fail9.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-{"Extra comma": true,}
\ No newline at end of file
--- a/tests/json/pass1.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-[
-    "JSON Test Pattern pass1",
-    {"object with 1 member":["array with 1 element"]},
-    {},
-    [],
-    -42,
-    true,
-    false,
-    null,
-    {
-        "integer": 1234567890,
-        "real": -9876.543210,
-        "e": 0.123456789e-12,
-        "E": 1.234567890E+34,
-        "":  23456789012E66,
-        "zero": 0,
-        "one": 1,
-        "space": " ",
-        "quote": "\"",
-        "backslash": "\\",
-        "controls": "\b\f\n\r\t",
-        "slash": "/ & \/",
-        "alpha": "abcdefghijklmnopqrstuvwyz",
-        "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
-        "digit": "0123456789",
-        "0123456789": "digit",
-        "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
-        "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
-        "true": true,
-        "false": false,
-        "null": null,
-        "array":[  ],
-        "object":{  },
-        "address": "50 St. James Street",
-        "url": "http://www.JSON.org/",
-        "comment": "// /* <!-- --",
-        "# -- --> */": " ",
-        " s p a c e d " :[1,2 , 3
-
-,
-
-4 , 5        ,          6           ,7        ],"compact":[1,2,3,4,5,6,7],
-        "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
-        "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
-        "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
-: "A key can be any string"
-    },
-    0.5 ,98.6
-,
-99.44
-,
-
-1066,
-1e1,
-0.1e1,
-1e-1,
-1e00,2e+00,2e-00
-,"rosebud"]
\ No newline at end of file
--- a/tests/json/pass2.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
\ No newline at end of file
--- a/tests/json/pass3.json	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-{
-    "JSON Test Pattern pass3": {
-        "The outermost value": "must be an object or array.",
-        "In this test": "It is an object."
-    }
-}
--- a/tests/modulemanager_option_conversion.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-package.path = "../?.lua;"..package.path;
-
-local api = require "core.modulemanager".api;
-
-local module = setmetatable({}, {__index = api});
-local opt = nil;
-function module:log() end
-function module:get_option(name)
-	if name == "opt" then
-		return opt;
-	else
-		return nil;
-	end
-end
-
-function test_value(value, returns)
-	opt = value;
-	assert(module:get_option_number("opt") == returns.number, "number doesn't match");
-	assert(module:get_option_string("opt") == returns.string, "string doesn't match");
-	assert(module:get_option_boolean("opt") == returns.boolean, "boolean doesn't match");
-
-	if type(returns.array) == "table" then
-		local target_array, returned_array = returns.array, module:get_option_array("opt");
-		assert(#target_array == #returned_array, "array length doesn't match");
-		for i=1,#target_array do
-			assert(target_array[i] == returned_array[i], "array item doesn't match");
-		end
-	else
-		assert(module:get_option_array("opt") == returns.array, "array is returned (not nil)");
-	end
-
-	if type(returns.set) == "table" then
-		local target_items, returned_items = set.new(returns.set), module:get_option_set("opt");
-		assert(target_items == returned_items, "set doesn't match");
-	else
-		assert(module:get_option_set("opt") == returns.set, "set is returned (not nil)");
-	end
-end
-
-test_value(nil, {});
-
-test_value(true, { boolean = true, string = "true", array = {true}, set = {true} });
-test_value(false, { boolean = false, string = "false", array = {false}, set = {false} });
-test_value("true", { boolean = true, string = "true", array = {"true"}, set = {"true"} });
-test_value("false", { boolean = false, string = "false", array = {"false"}, set = {"false"} });
-test_value(1, { boolean = true, string = "1", array = {1}, set = {1}, number = 1 });
-test_value(0, { boolean = false, string = "0", array = {0}, set = {0}, number = 0 });
-
-test_value("hello world", { string = "hello world", array = {"hello world"}, set = {"hello world"} });
-test_value(1234, { string = "1234", number = 1234, array = {1234}, set = {1234} });
-
-test_value({1, 2, 3}, { boolean = true, string = "1", number = 1, array = {1, 2, 3}, set = {1, 2, 3} });
-test_value({1, 2, 3, 3, 4}, {boolean = true, string = "1", number = 1, array = {1, 2, 3, 3, 4}, set = {1, 2, 3, 4} });
-test_value({0, 1, 2, 3}, { boolean = false, string = "0", number = 0, array = {0, 1, 2, 3}, set = {0, 1, 2, 3} });
-
--- a/tests/reports/empty	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-This file was intentionally left blank.
--- a/tests/run_tests.bat	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-@echo off
-
-set oldpath=%path%
-set path=%path%;..;..\lualibs
-
-del reports\*.report
-lua test.lua %*
-
-set path=%oldpath%
-set oldpath=
\ No newline at end of file
--- a/tests/run_tests.sh	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/sh
-rm reports/*.report
-exec lua test.lua "$@"
--- a/tests/test.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,256 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2010 Matthew Wild
--- Copyright (C) 2008-2010 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-local tests_passed = true;
-
-function run_all_tests()
-	package.loaded["net.connlisteners"] = { get = function () return {} end };
-	dotest "util.jid"
-	dotest "util.multitable"
-	dotest "util.rfc6724"
-	dotest "util.http"
-	dotest "core.stanza_router"
-	dotest "core.s2smanager"
-	dotest "core.configmanager"
-	dotest "util.ip"
-	dotest "util.json"
-	dotest "util.stanza"
-	dotest "util.sasl.scram"
-	dotest "util.async"
-	dotest "util.cache"
-	dotest "util.throttle"
-	dotest "util.uuid"
-	dotest "util.random"
-	dotest "util.xml"
-	dotest "util.xmppstream"
-	dotest "util.queue"
-	dotest "net.http.parser"
-
-	dosingletest("test_sasl.lua", "latin1toutf8");
-	dosingletest("test_utf8.lua", "valid");
-end
-
-local verbosity = tonumber(arg[1]) or 2;
-
-if os.getenv("WINDIR") then
-	package.path = package.path..";..\\?.lua";
-	package.cpath = package.cpath..";..\\?.dll";
-else
-	package.path = package.path..";../?.lua";
-	package.cpath = package.cpath..";../?.so";
-end
-
-local _realG = _G;
-
-require "util.import"
-
-local envloadfile = require "util.envload".envloadfile;
-
-local env_mt = { __index = function (t,k) return rawget(_realG, k) or print("WARNING: Attempt to access nil global '"..tostring(k).."'"); end };
-function testlib_new_env(t)
-	return setmetatable(t or {}, env_mt);
-end
-
-function assert_equal(a, b, message, level)
-	if not (a == b) then
-		error("\n   assert_equal failed: "..tostring(a).." ~= "..tostring(b)..(message and ("\n   Message: "..message) or ""), (level or 1) + 1);
-	elseif verbosity >= 4 then
-		print("assert_equal succeeded: "..tostring(a).." == "..tostring(b));
-	end
-end
-
-function assert_table(a, message, level)
-	assert_equal(type(a), "table", message, (level or 1) + 1);
-end
-function assert_function(a, message, level)
-	assert_equal(type(a), "function", message, (level or 1) + 1);
-end
-function assert_string(a, message, level)
-	assert_equal(type(a), "string", message, (level or 1) + 1);
-end
-function assert_boolean(a, message)
-	assert_equal(type(a), "boolean", message);
-end
-function assert_is(a, message)
-	assert_equal(not not a, true, message);
-end
-function assert_is_not(a, message)
-	assert_equal(not not a, false, message);
-end
-
-
-function dosingletest(testname, fname)
-	local tests = setmetatable({}, { __index = _realG });
-	tests.__unit = testname;
-	tests.__test = fname;
-	local chunk, err = envloadfile(testname, tests);
-	if not chunk then
-		print("WARNING: ", "Failed to load tests for "..testname, err);
-		return;
-	end
-
-	local success, err = pcall(chunk);
-	if not success then
-		print("WARNING: ", "Failed to initialise tests for "..testname, err);
-		return;
-	end
-
-	if type(tests[fname]) ~= "function" then
-		error(testname.." has no test '"..fname.."'", 0);
-	end
-
-
-	local line_hook, line_info = new_line_coverage_monitor(testname);
-	debug.sethook(line_hook, "l")
-	local success, ret = pcall(tests[fname]);
-	debug.sethook();
-	if not success then
-		tests_passed = false;
-		print("TEST FAILED! Unit: ["..testname.."] Function: ["..fname.."]");
-		print("   Location: "..ret:gsub(":%s*\n", "\n"));
-		line_info(fname, false, report_file);
-	elseif verbosity >= 2 then
-		print("TEST SUCCEEDED: ", testname, fname);
-		print(string.format("TEST COVERED %d/%d lines", line_info(fname, true, report_file)));
-	else
-		line_info(name, success, report_file);
-	end
-end
-
-function dotest(unitname)
-	local _fakeG = setmetatable({}, {__index = _realG});
-	_fakeG._G = _fakeG;
-	local tests = setmetatable({}, { __index = _fakeG });
-	tests.__unit = unitname;
-	local chunk, err = envloadfile("test_"..unitname:gsub("%.", "_")..".lua", tests);
-	if not chunk then
-		print("WARNING: ", "Failed to load tests for "..unitname, err);
-		return;
-	end
-
-	local success, err = pcall(chunk);
-	if not success then
-		print("WARNING: ", "Failed to initialise tests for "..unitname, err);
-		return;
-	end
-	if tests.env then setmetatable(tests.env, { __index = _realG }); end
-	local unit = setmetatable({}, { __index = setmetatable({ _G = tests.env or _fakeG }, { __index = tests.env or _fakeG }) });
-	local fn = "../"..unitname:gsub("%.", "/")..".lua";
-	local chunk, err = envloadfile(fn, unit);
-	if not chunk then
-		print("WARNING: ", "Failed to load module: "..unitname, err);
-		return;
-	end
-
-	local oldmodule, old_M = _fakeG.module, _fakeG._M;
-	_fakeG.module = function ()
-		setmetatable(unit, nil);
-		unit._M = unit;
-	end
-	local success, ret = pcall(chunk);
-	_fakeG.module, _fakeG._M = oldmodule, old_M;
-	if not success then
-		print("WARNING: ", "Failed to initialise module: "..unitname, ret);
-		return;
-	end
-
-	if type(ret) == "table" then
-		for k,v in pairs(ret) do
-			unit[k] = v;
-		end
-	end
-
-	for name, f in pairs(unit) do
-		local test = rawget(tests, name);
-		if type(f) ~= "function" then
-			if verbosity >= 3 then
-				print("INFO: ", "Skipping "..unitname.."."..name.." because it is not a function");
-			end
-		elseif type(test) ~= "function" then
-			if verbosity >= 1 then
-				print("WARNING: ", unitname.."."..name.." has no test!");
-			end
-		else
-			if verbosity >= 4 then
-				print("INFO: ", "Testing "..unitname.."."..name);
-			end
-			local line_hook, line_info = new_line_coverage_monitor(fn);
-			debug.sethook(line_hook, "l")
-			local success, ret = pcall(test, f, unit);
-			debug.sethook();
-			if not success then
-				tests_passed = false;
-				print("TEST FAILED! Unit: ["..unitname.."] Function: ["..name.."]");
-				print("   Location: "..ret:gsub(":%s*\n", "\n"));
-				line_info(name, false, report_file);
-			elseif verbosity >= 2 then
-				print("TEST SUCCEEDED: ", unitname, name);
-				print(string.format("TEST COVERED %d/%d lines", line_info(name, true, report_file)));
-			else
-				line_info(name, success, report_file);
-			end
-		end
-	end
-end
-
-function runtest(f, msg)
-	if not f then print("SUBTEST NOT FOUND: "..(msg or "(no description)")); return; end
-	local success, ret = pcall(f);
-	if success and verbosity >= 2 then
-		print("SUBTEST PASSED: "..(msg or "(no description)"));
-	elseif (not success) and verbosity >= 0 then
-		tests_passed = false;
-		print("SUBTEST FAILED: "..(msg or "(no description)"));
-		error(ret, 0);
-	end
-end
-
-function new_line_coverage_monitor(file)
-	local lines_hit, funcs_hit = {}, {};
-	local total_lines, covered_lines = 0, 0;
-
-	for line in io.lines(file) do
-		total_lines = total_lines + 1;
-	end
-
-	return function (event, line) -- Line hook
-			if not lines_hit[line] then
-				local info = debug.getinfo(2, "fSL")
-				if not info.source:find(file) then return; end
-				if not funcs_hit[info.func] and info.activelines then
-					funcs_hit[info.func] = true;
-					for line in pairs(info.activelines) do
-						lines_hit[line] = false; -- Marks it as hittable, but not hit yet
-					end
-				end
-				if lines_hit[line] == false then
-					--print("New line hit: "..line.." in "..debug.getinfo(2, "S").source);
-					lines_hit[line] = true;
-					covered_lines = covered_lines + 1;
-				end
-			end
-		end,
-		function (test_name, success) -- Get info
-			local fn = file:gsub("^%W*", "");
-			local total_active_lines = 0;
-			local coverage_file = io.open("reports/coverage_"..fn:gsub("%W+", "_")..".report", "a+");
-			for line, active in pairs(lines_hit) do
-				if active ~= nil then total_active_lines = total_active_lines + 1; end
-				if coverage_file then
-					if active == false then coverage_file:write(fn, "|", line, "|", name or "", "|miss\n");
-					else coverage_file:write(fn, "|", line, "|", name or "", "|", tostring(success), "\n"); end
-				end
-			end
-			if coverage_file then coverage_file:close(); end
-			return covered_lines, total_active_lines, lines_hit;
-		end
-end
-
-run_all_tests()
-
-os.exit(tests_passed and 0 or 1);
--- a/tests/test_core_configmanager.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2010 Matthew Wild
--- Copyright (C) 2008-2010 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-
-
-function get(get, config)
-	config.set("example.com", "testkey", 123);
-	assert_equal(get("example.com", "testkey"), 123, "Retrieving a set key");
-
-	config.set("*", "testkey1", 321);
-	assert_equal(get("*", "testkey1"), 321, "Retrieving a set global key");
-	assert_equal(get("example.com", "testkey1"), 321, "Retrieving a set key of undefined host, of which only a globally set one exists");
-
-	config.set("example.com", ""); -- Creates example.com host in config
-	assert_equal(get("example.com", "testkey1"), 321, "Retrieving a set key, of which only a globally set one exists");
-
-	assert_equal(get(), nil, "No parameters to get()");
-	assert_equal(get("undefined host"), nil, "Getting for undefined host");
-	assert_equal(get("undefined host", "undefined key"), nil, "Getting for undefined host & key");
-end
-
-function set(set, u)
-	assert_equal(set("*"), false, "Set with no key");
-
-	assert_equal(set("*", "set_test", "testkey"), true, "Setting a nil global value");
-	assert_equal(set("*", "set_test", "testkey", 123), true, "Setting a global value");
-end
-
--- a/tests/test_core_s2smanager.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2010 Matthew Wild
--- Copyright (C) 2008-2010 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-env = {
-	prosody = { events = require "util.events".new() };
-};
-
-function compare_srv_priorities(csp)
-	local r1 = { priority = 10, weight = 0 }
-	local r2 = { priority = 100, weight = 0 }
-	local r3 = { priority = 1000, weight = 2 }
-	local r4 = { priority = 1000, weight = 2 }
-	local r5 = { priority = 1000, weight = 5 }
-
-	assert_equal(csp(r1, r1), false);
-	assert_equal(csp(r1, r2), true);
-	assert_equal(csp(r1, r3), true);
-	assert_equal(csp(r1, r4), true);
-	assert_equal(csp(r1, r5), true);
-
-	assert_equal(csp(r2, r1), false);
-	assert_equal(csp(r2, r2), false);
-	assert_equal(csp(r2, r3), true);
-	assert_equal(csp(r2, r4), true);
-	assert_equal(csp(r2, r5), true);
-
-	assert_equal(csp(r3, r1), false);
-	assert_equal(csp(r3, r2), false);
-	assert_equal(csp(r3, r3), false);
-	assert_equal(csp(r3, r4), false);
-	assert_equal(csp(r3, r5), false);
-
-	assert_equal(csp(r4, r1), false);
-	assert_equal(csp(r4, r2), false);
-	assert_equal(csp(r4, r3), false);
-	assert_equal(csp(r4, r4), false);
-	assert_equal(csp(r4, r5), false);
-
-	assert_equal(csp(r5, r1), false);
-	assert_equal(csp(r5, r2), false);
-	assert_equal(csp(r5, r3), true);
-	assert_equal(csp(r5, r4), true);
-	assert_equal(csp(r5, r5), false);
-
-end
--- a/tests/test_core_stanza_router.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,232 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2010 Matthew Wild
--- Copyright (C) 2008-2010 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-_G.prosody = { full_sessions = {}; bare_sessions = {}; hosts = {}; };
-
-function core_process_stanza(core_process_stanza, u)
-	local stanza = require "util.stanza";
-	local s2sout_session = { to_host = "remotehost", from_host = "localhost", type = "s2sout" }
-	local s2sin_session = { from_host = "remotehost", to_host = "localhost", type = "s2sin", hosts = { ["remotehost"] = { authed = true } } }
-	local local_host_session = { host = "localhost", type = "local", s2sout = { ["remotehost"] = s2sout_session } }
-	local local_user_session = { username = "user", host = "localhost", resource = "resource", full_jid = "user@localhost/resource", type = "c2s" }
-
-	_G.prosody.hosts["localhost"] = local_host_session;
-	_G.prosody.full_sessions["user@localhost/resource"] = local_user_session;
-	_G.prosody.bare_sessions["user@localhost"] = { sessions = { resource = local_user_session } };
-
-	-- Test message routing
-	local function test_message_full_jid()
-		local env = testlib_new_env();
-		local msg = stanza.stanza("message", { to = "user@localhost/resource", type = "chat" }):tag("body"):text("Hello world");
-
-		local target_routed;
-
-		function env.core_post_stanza(p_origin, p_stanza)
-			assert_equal(p_origin, local_user_session, "origin of routed stanza is not correct");
-			assert_equal(p_stanza, msg, "routed stanza is not correct one: "..p_stanza:pretty_print());
-			target_routed = true;
-		end
-
-		env.hosts = hosts;
-		env.prosody = { hosts = hosts };
-		setfenv(core_process_stanza, env);
-		assert_equal(core_process_stanza(local_user_session, msg), nil, "core_process_stanza returned incorrect value");
-		assert_equal(target_routed, true, "stanza was not routed successfully");
-	end
-
-	local function test_message_bare_jid()
-		local env = testlib_new_env();
-		local msg = stanza.stanza("message", { to = "user@localhost", type = "chat" }):tag("body"):text("Hello world");
-
-		local target_routed;
-
-		function env.core_post_stanza(p_origin, p_stanza)
-			assert_equal(p_origin, local_user_session, "origin of routed stanza is not correct");
-			assert_equal(p_stanza, msg, "routed stanza is not correct one: "..p_stanza:pretty_print());
-			target_routed = true;
-		end
-
-		env.hosts = hosts;
-		setfenv(core_process_stanza, env);
-		assert_equal(core_process_stanza(local_user_session, msg), nil, "core_process_stanza returned incorrect value");
-		assert_equal(target_routed, true, "stanza was not routed successfully");
-	end
-
-	local function test_message_no_to()
-		local env = testlib_new_env();
-		local msg = stanza.stanza("message", { type = "chat" }):tag("body"):text("Hello world");
-
-		local target_handled;
-
-		function env.core_post_stanza(p_origin, p_stanza)
-			assert_equal(p_origin, local_user_session, "origin of handled stanza is not correct");
-			assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print());
-			target_handled = true;
-		end
-
-		env.hosts = hosts;
-		setfenv(core_process_stanza, env);
-		assert_equal(core_process_stanza(local_user_session, msg), nil, "core_process_stanza returned incorrect value");
-		assert_equal(target_handled, true, "stanza was not handled successfully");
-	end
-
-	local function test_message_to_remote_bare()
-		local env = testlib_new_env();
-		local msg = stanza.stanza("message", { to = "user@remotehost", type = "chat" }):tag("body"):text("Hello world");
-
-		local target_routed;
-
-		function env.core_route_stanza(p_origin, p_stanza)
-			assert_equal(p_origin, local_user_session, "origin of handled stanza is not correct");
-			assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print());
-			target_routed = true;
-		end
-
-		function env.core_post_stanza(...) env.core_route_stanza(...); end
-
-		env.hosts = hosts;
-		setfenv(core_process_stanza, env);
-		assert_equal(core_process_stanza(local_user_session, msg), nil, "core_process_stanza returned incorrect value");
-		assert_equal(target_routed, true, "stanza was not routed successfully");
-	end
-
-	local function test_message_to_remote_server()
-		local env = testlib_new_env();
-		local msg = stanza.stanza("message", { to = "remotehost", type = "chat" }):tag("body"):text("Hello world");
-
-		local target_routed;
-
-		function env.core_route_stanza(p_origin, p_stanza)
-			assert_equal(p_origin, local_user_session, "origin of handled stanza is not correct");
-			assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print());
-			target_routed = true;
-		end
-
-		function env.core_post_stanza(...)
-			env.core_route_stanza(...);
-		end
-
-		env.hosts = hosts;
-		setfenv(core_process_stanza, env);
-		assert_equal(core_process_stanza(local_user_session, msg), nil, "core_process_stanza returned incorrect value");
-		assert_equal(target_routed, true, "stanza was not routed successfully");
-	end
-
-	--IQ tests
-
-
-	local function test_iq_to_remote_server()
-		local env = testlib_new_env();
-		local msg = stanza.stanza("iq", { to = "remotehost", type = "get", id = "id" }):tag("body"):text("Hello world");
-
-		local target_routed;
-
-		function env.core_route_stanza(p_origin, p_stanza)
-			assert_equal(p_origin, local_user_session, "origin of handled stanza is not correct");
-			assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print());
-			target_routed = true;
-		end
-
-		function env.core_post_stanza(...)
-			env.core_route_stanza(...);
-		end
-
-		env.hosts = hosts;
-		setfenv(core_process_stanza, env);
-		assert_equal(core_process_stanza(local_user_session, msg), nil, "core_process_stanza returned incorrect value");
-		assert_equal(target_routed, true, "stanza was not routed successfully");
-	end
-
-	local function test_iq_error_to_local_user()
-		local env = testlib_new_env();
-		local msg = stanza.stanza("iq", { to = "user@localhost/resource", from = "user@remotehost", type = "error", id = "id" }):tag("error", { type = 'cancel' }):tag("item-not-found", { xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' });
-
-		local target_routed;
-
-		function env.core_route_stanza(p_origin, p_stanza)
-			assert_equal(p_origin, s2sin_session, "origin of handled stanza is not correct");
-			assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print());
-			target_routed = true;
-		end
-
-		function env.core_post_stanza(...)
-			env.core_route_stanza(...);
-		end
-
-		env.hosts = hosts;
-		setfenv(core_process_stanza, env);
-		assert_equal(core_process_stanza(s2sin_session, msg), nil, "core_process_stanza returned incorrect value");
-		assert_equal(target_routed, true, "stanza was not routed successfully");
-	end
-
-	local function test_iq_to_local_bare()
-		local env = testlib_new_env();
-		local msg = stanza.stanza("iq", { to = "user@localhost", from = "user@localhost", type = "get", id = "id" }):tag("ping", { xmlns = "urn:xmpp:ping:0" });
-
-		local target_handled;
-
-		function env.core_post_stanza(p_origin, p_stanza)
-			assert_equal(p_origin, local_user_session, "origin of handled stanza is not correct");
-			assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print());
-			target_handled = true;
-		end
-
-		env.hosts = hosts;
-		setfenv(core_process_stanza, env);
-		assert_equal(core_process_stanza(local_user_session, msg), nil, "core_process_stanza returned incorrect value");
-		assert_equal(target_handled, true, "stanza was not handled successfully");
-	end
-
-	runtest(test_message_full_jid, "Messages with full JID destinations get routed");
-	runtest(test_message_bare_jid, "Messages with bare JID destinations get routed");
-	runtest(test_message_no_to, "Messages with no destination are handled by the server");
-	runtest(test_message_to_remote_bare, "Messages to a remote user are routed by the server");
-	runtest(test_message_to_remote_server, "Messages to a remote server's JID are routed");
-
-	runtest(test_iq_to_remote_server, "iq to a remote server's JID are routed");
-	runtest(test_iq_to_local_bare, "iq from a local user to a local user's bare JID are handled");
-	runtest(test_iq_error_to_local_user, "iq type=error to a local user's JID are routed");
-end
-
-function core_route_stanza(core_route_stanza)
-	local stanza = require "util.stanza";
-	local s2sout_session = { to_host = "remotehost", from_host = "localhost", type = "s2sout" }
-	local s2sin_session = { from_host = "remotehost", to_host = "localhost", type = "s2sin", hosts = { ["remotehost"] = { authed = true } } }
-	local local_host_session = { host = "localhost", type = "local", s2sout = { ["remotehost"] = s2sout_session }, sessions = {} }
-	local local_user_session = { username = "user", host = "localhost", resource = "resource", full_jid = "user@localhost/resource", type = "c2s" }
-	local hosts = {
-			["localhost"] = local_host_session;
-			}
-
-	local function test_iq_result_to_offline_user()
-		local env = testlib_new_env();
-		local msg = stanza.stanza("iq", { to = "user@localhost/foo", from = "user@localhost", type = "result" }):tag("ping", { xmlns = "urn:xmpp:ping:0" });
-		local msg2 = stanza.stanza("iq", { to = "user@localhost/foo", from = "user@localhost", type = "error" }):tag("ping", { xmlns = "urn:xmpp:ping:0" });
-		--package.loaded["core.usermanager"] = { user_exists = function (user, host) print("RAR!") return true or user == "user" and host == "localhost" and true; end };
-		local target_handled, target_replied;
-
-		function env.core_post_stanza(p_origin, p_stanza)
-			target_handled = true;
-		end
-
-		function local_user_session.send(data)
-			--print("Replying with: ", tostring(data));
-			--print(debug.traceback())
-			target_replied = true;
-		end
-
-		env.hosts = hosts;
-		setfenv(core_route_stanza, env);
-		assert_equal(core_route_stanza(local_user_session, msg), nil, "core_route_stanza returned incorrect value");
-		assert_equal(target_handled, nil, "stanza was handled and not dropped");
-		assert_equal(target_replied, nil, "stanza was replied to and not dropped");
-		package.loaded["core.usermanager"] = nil;
-	end
-
-	--runtest(test_iq_result_to_offline_user, "iq type=result|error to an offline user are not replied to");
-end
--- a/tests/test_net_http_parser.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-local httpstreams = { [[
-GET / HTTP/1.1
-Host: example.com
-
-]], [[
-HTTP/1.1 200 OK
-Content-Length: 0
-
-]], [[
-HTTP/1.1 200 OK
-Content-Length: 7
-
-Hello
-HTTP/1.1 200 OK
-Transfer-Encoding: chunked
-
-1
-H
-1
-e
-2
-ll
-1
-o
-0
-
-
-]]
-}
-
-function new(new)
-
-	for _, stream in ipairs(httpstreams) do
-		local success;
-		local function success_cb(packet)
-			success = true;
-		end
-		stream = stream:gsub("\n", "\r\n");
-		local parser = new(success_cb, error, stream:sub(1,4) == "HTTP" and "client" or "server")
-		for chunk in stream:gmatch("..?.?") do
-			parser:feed(chunk);
-		end
-
-		assert_is(success);
-	end
-
-end
--- a/tests/test_sasl.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2010 Matthew Wild
--- Copyright (C) 2008-2010 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-local gmatch = string.gmatch;
-local t_concat, t_insert = table.concat, table.insert;
-local to_byte, to_char = string.byte, string.char;
-
-local function _latin1toutf8(str)
-	if not str then return str; end
-	local p = {};
-	for ch in gmatch(str, ".") do
-		ch = to_byte(ch);
-		if (ch < 0x80) then
-			t_insert(p, to_char(ch));
-		elseif (ch < 0xC0) then
-			t_insert(p, to_char(0xC2, ch));
-		else
-			t_insert(p, to_char(0xC3, ch - 64));
-		end
-	end
-	return t_concat(p);
-end
-
-function latin1toutf8()
-	local function assert_utf8(latin, utf8)
-			assert_equal(_latin1toutf8(latin), utf8, "Incorrect UTF8 from Latin1: "..tostring(latin));
-	end
-
-	assert_utf8("", "")
-	assert_utf8("test", "test")
-	assert_utf8(nil, nil)
-	assert_utf8("foobar.r\229kat.se", "foobar.r\195\165kat.se")
-end
--- a/tests/test_utf8.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-package.cpath = "../?.so"
-package.path = "../?.lua";
-
-function valid()
-	local encodings = require "util.encodings";
-	local utf8 = assert(encodings.utf8, "no encodings.utf8 module");
-
-	for line in io.lines("utf8_sequences.txt") do
-		local data = line:match(":%s*([^#]+)"):gsub("%s+", ""):gsub("..", function (c) return string.char(tonumber(c, 16)); end)
-		local expect = line:match("(%S+):");
-		if expect ~= "pass" and expect ~= "fail" then
-			error("unknown expectation: "..line:match("^[^:]+"));
-		end
-		local valid = utf8.valid(data);
-		assert_equal(valid, utf8.valid(data.." "));
-		assert_equal(valid, expect == "pass", line);
-	end
-end
--- a/tests/test_util_async.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,301 +0,0 @@
-
--- Test passing nil to runner
--- Test runners work correctly after errors (coroutine gets recreated)
--- What happens if an error is thrown, but more items are in the queue? (I think runner might stall)
--- Test errors thrown halfway through a queue
--- Multiple runners
-
-function runner(new_runner, async)
-	local function new(func, name)
-		local log = {};
-		return new_runner(func, setmetatable({}, {
-			__index = function (_, event)
-				return function (runner, err)
-					print(name, "event", event, err)
-					table.insert(log, { event = event, err = err });
-				end;
-			end;
-		})), log;
-	end
-	
-	--------------------
-	local r, l = new(function (item) assert(type(item) == "number") end);
-	r:run(1);
-	r:run(2);
-	--for k, v in ipairs(l) do print(k,v) end
-
-	--------------------
-	local wait, done;
-
-	local r, l = new(function (item)
-		assert(type(item) == "number")
-		if item == 3 then
-			wait, done = async.waiter();
-			wait();
-		end
-	end);
-	
-	r:run(1);
-	assert(r.state == "ready");
-	r:run(2);
-	assert(r.state == "ready");
-	r:run(3);
-	assert(r.state == "waiting");
-	done();
-	assert(r.state == "ready");
-	--for k, v in ipairs(l) do print(k,v) end
-
-	--------------------
-	local wait, done;
-	local last_item = 0;
-	local r, l = new(function (item)
-		assert(type(item) == "number")
-		assert(item == last_item + 1);
-		last_item = item;
-		if item == 3 then
-			wait, done = async.waiter();
-			wait();
-		end
-	end);
-	
-	r:run(1);
-	assert(r.state == "ready");
-	r:run(2);
-	assert(r.state == "ready");
-	r:run(3);
-	assert(r.state == "waiting");
-	r:run(4);
-	assert(r.state == "waiting");
-	done();
-	assert(r.state == "ready");
-	--for k, v in ipairs(l) do print(k,v) end
-
-	--------------------
-	local wait, done;
-	local last_item = 0;
-	local r, l = new(function (item)
-		assert(type(item) == "number")
-		assert((item == last_item + 1) or item == 3);
-		last_item = item;
-		if item == 3 then
-			wait, done = async.waiter();
-			wait();
-		end
-	end);
-	
-	r:run(1);
-	assert(r.state == "ready");
-	r:run(2);
-	assert(r.state == "ready");
-	
-	local dones = {};
-	r:run(3);
-	assert(r.state == "waiting");
-	r:run(3);
-	assert(r.state == "waiting");
-	r:run(3);
-	assert(r.state == "waiting");
-	r:run(4);
-	assert(r.state == "waiting");
-
-	for i = 1, 3 do
-		done();
-		if i < 3 then
-			assert(r.state == "waiting");
-		end
-	end
-
-	assert(r.state == "ready");
-	--for k, v in ipairs(l) do print(k,v) end
-
-	--------------------
-	local wait, done;
-	local last_item = 0;
-	local r, l = new(function (item)
-		assert(type(item) == "number")
-		assert((item == last_item + 1) or item == 3);
-		last_item = item;
-		if item == 3 then
-			wait, done = async.waiter();
-			wait();
-		end
-	end);
-	
-	r:run(1);
-	assert(r.state == "ready");
-	r:run(2);
-	assert(r.state == "ready");
-	
-	local dones = {};
-	r:run(3);
-	assert(r.state == "waiting");
-	r:run(3);
-	assert(r.state == "waiting");
-
-	for i = 1, 2 do
-		done();
-		if i < 2 then
-			assert(r.state == "waiting");
-		end
-	end
-
-	assert(r.state == "ready");
-	r:run(4);
-	assert(r.state == "ready");
-
-	assert(r.state == "ready");
-	--for k, v in ipairs(l) do print(k,v) end
-
-	-- Now with multiple runners
-	--------------------
-	local wait1, done1;
-	local last_item1 = 0;
-	local r1, l1 = new(function (item)
-		assert(type(item) == "number")
-		assert((item == last_item1 + 1) or item == 3);
-		last_item1 = item;
-		if item == 3 then
-			wait1, done1 = async.waiter();
-			wait1();
-		end
-	end, "r1");
-
-	local wait2, done2;
-	local last_item2 = 0;
-	local r2, l2 = new(function (item)
-		assert(type(item) == "number")
-		assert((item == last_item2 + 1) or item == 3);
-		last_item2 = item;
-		if item == 3 then
-			wait2, done2 = async.waiter();
-			wait2();
-		end
-	end, "r2");
-	
-	r1:run(1);
-	assert(r1.state == "ready");
-	r1:run(2);
-	assert(r1.state == "ready");
-	
-	local dones = {};
-	r1:run(3);
-	assert(r1.state == "waiting");
-	r1:run(3);
-	assert(r1.state == "waiting");
-
-	r2:run(1);
-	assert(r1.state == "waiting");
-	assert(r2.state == "ready");
-
-	r2:run(2);
-	assert(r1.state == "waiting");
-	assert(r2.state == "ready");
-
-	r2:run(3);
-	assert(r1.state == "waiting");
-	assert(r2.state == "waiting");
-	done2();
-
-	r2:run(3);
-	assert(r1.state == "waiting");
-	assert(r2.state == "waiting");
-	done2();
-
-	r2:run(2);
-	assert(r1.state == "waiting");
-	assert(r2.state == "ready");
-
-	for i = 1, 2 do
-		done1();
-		if i < 2 then
-			assert(r1.state == "waiting");
-		end
-	end
-
-	assert(r1.state == "ready");
-	r1:run(4);
-	assert(r1.state == "ready");
-
-	assert(r1.state == "ready");
-	--for k, v in ipairs(l1) do print(k,v) end
-	
-
-	--------------------
-	local wait1, done1;
-	local last_item1 = 0;
-	local r1, l1 = new(function (item)
-		assert(type(item) == "number")
-		assert((item == last_item1 + 1) or item == 3);
-		last_item1 = item;
-		if item == 3 then
-			wait1, done1 = async.waiter();
-			wait1();
-		end
-	end, "r1");
-
-	local wait2, done2;
-	local last_item2 = 0;
-	local r2, l2 = new(function (item)
-		assert(type(item) == "number")
-		assert((item == last_item2 + 1) or item == 3);
-		last_item2 = item;
-		if item == 3 then
-			wait2, done2 = async.waiter();
-			wait2();
-		end
-	end, "r2");
-	
-	r1:run(1);
-	assert(r1.state == "ready");
-	r1:run(2);
-	assert(r1.state == "ready");
-	
-	r1:run(5);
-	assert(r1.state == "ready");
-
-	local dones = {};
-	r1:run(3);
-	assert(r1.state == "waiting");
-	r1:run(5); -- Will error, when we get to it
-	assert(r1.state == "waiting");
-	r1:run(3);
-	assert(r1.state == "waiting");
-
-	r2:run(1);
-	assert(r1.state == "waiting");
-	assert(r2.state == "ready");
-
-	r2:run(2);
-	assert(r1.state == "waiting");
-	assert(r2.state == "ready");
-
-	r2:run(3);
-	assert(r1.state == "waiting");
-	assert(r2.state == "waiting");
-	done2();
-
-	r2:run(3);
-	assert(r1.state == "waiting");
-	assert(r2.state == "waiting");
-	done2();
-
-	r2:run(2);
-	assert(r1.state == "waiting");
-	assert(r2.state == "ready");
-
-	for i = 1, 2 do
-		done1();
-		if i < 2 then
-			assert_equal(r1.state, "waiting");
-		end
-	end
-
-	assert(r1.state == "ready");
-	r1:run(4);
-	assert(r1.state == "ready");
-
-	assert(r1.state == "ready");
-	--for k, v in ipairs(l1) do print(k,v) end
-	
-	
-end
--- a/tests/test_util_cache.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,309 +0,0 @@
-function new(new)
-	local c = new(5);
-
-	local function expect_kv(key, value, actual_key, actual_value)
-		assert_equal(key, actual_key, "key incorrect");
-		assert_equal(value, actual_value, "value incorrect");
-	end
-
-	expect_kv(nil, nil, c:head());
-	expect_kv(nil, nil, c:tail());
-
-	assert_equal(c:count(), 0);
-
-	c:set("one", 1)
-	assert_equal(c:count(), 1);
-	expect_kv("one", 1, c:head());
-	expect_kv("one", 1, c:tail());
-
-	c:set("two", 2)
-	expect_kv("two", 2, c:head());
-	expect_kv("one", 1, c:tail());
-
-	c:set("three", 3)
-	expect_kv("three", 3, c:head());
-	expect_kv("one", 1, c:tail());
-
-	c:set("four", 4)
-	c:set("five", 5);
-	assert_equal(c:count(), 5);
-	expect_kv("five", 5, c:head());
-	expect_kv("one", 1, c:tail());
-
-	c:set("foo", nil);
-	assert_equal(c:count(), 5);
-	expect_kv("five", 5, c:head());
-	expect_kv("one", 1, c:tail());
-
-	assert_equal(c:get("one"), 1);
-	expect_kv("five", 5, c:head());
-	expect_kv("one", 1, c:tail());
-
-	assert_equal(c:get("two"), 2);
-	assert_equal(c:get("three"), 3);
-	assert_equal(c:get("four"), 4);
-	assert_equal(c:get("five"), 5);
-
-	assert_equal(c:get("foo"), nil);
-	assert_equal(c:get("bar"), nil);
-
-	c:set("six", 6);
-	assert_equal(c:count(), 5);
-	expect_kv("six", 6, c:head());
-	expect_kv("two", 2, c:tail());
-
-	assert_equal(c:get("one"), nil);
-	assert_equal(c:get("two"), 2);
-	assert_equal(c:get("three"), 3);
-	assert_equal(c:get("four"), 4);
-	assert_equal(c:get("five"), 5);
-	assert_equal(c:get("six"), 6);
-
-	c:set("three", nil);
-	assert_equal(c:count(), 4);
-
-	assert_equal(c:get("one"), nil);
-	assert_equal(c:get("two"), 2);
-	assert_equal(c:get("three"), nil);
-	assert_equal(c:get("four"), 4);
-	assert_equal(c:get("five"), 5);
-	assert_equal(c:get("six"), 6);
-
-	c:set("seven", 7);
-	assert_equal(c:count(), 5);
-
-	assert_equal(c:get("one"), nil);
-	assert_equal(c:get("two"), 2);
-	assert_equal(c:get("three"), nil);
-	assert_equal(c:get("four"), 4);
-	assert_equal(c:get("five"), 5);
-	assert_equal(c:get("six"), 6);
-	assert_equal(c:get("seven"), 7);
-
-	c:set("eight", 8);
-	assert_equal(c:count(), 5);
-
-	assert_equal(c:get("one"), nil);
-	assert_equal(c:get("two"), nil);
-	assert_equal(c:get("three"), nil);
-	assert_equal(c:get("four"), 4);
-	assert_equal(c:get("five"), 5);
-	assert_equal(c:get("six"), 6);
-	assert_equal(c:get("seven"), 7);
-	assert_equal(c:get("eight"), 8);
-
-	c:set("four", 4);
-	assert_equal(c:count(), 5);
-
-	assert_equal(c:get("one"), nil);
-	assert_equal(c:get("two"), nil);
-	assert_equal(c:get("three"), nil);
-	assert_equal(c:get("four"), 4);
-	assert_equal(c:get("five"), 5);
-	assert_equal(c:get("six"), 6);
-	assert_equal(c:get("seven"), 7);
-	assert_equal(c:get("eight"), 8);
-
-	c:set("nine", 9);
-	assert_equal(c:count(), 5);
-
-	assert_equal(c:get("one"), nil);
-	assert_equal(c:get("two"), nil);
-	assert_equal(c:get("three"), nil);
-	assert_equal(c:get("four"), 4);
-	assert_equal(c:get("five"), nil);
-	assert_equal(c:get("six"), 6);
-	assert_equal(c:get("seven"), 7);
-	assert_equal(c:get("eight"), 8);
-	assert_equal(c:get("nine"), 9);
-
-	do
-		local keys = { "nine", "four", "eight", "seven", "six" };
-		local values = { 9, 4, 8, 7, 6 };
-		local i = 0;
-		for k, v in c:items() do
-			i = i + 1;
-			assert_equal(k, keys[i]);
-			assert_equal(v, values[i]);
-		end
-		assert_equal(i, 5);
-
-		c:set("four", "2+2");
-		assert_equal(c:count(), 5);
-
-		assert_equal(c:get("one"), nil);
-		assert_equal(c:get("two"), nil);
-		assert_equal(c:get("three"), nil);
-		assert_equal(c:get("four"), "2+2");
-		assert_equal(c:get("five"), nil);
-		assert_equal(c:get("six"), 6);
-		assert_equal(c:get("seven"), 7);
-		assert_equal(c:get("eight"), 8);
-		assert_equal(c:get("nine"), 9);
-	end
-
-	do
-		local keys = { "four", "nine", "eight", "seven", "six" };
-		local values = { "2+2", 9, 8, 7, 6 };
-		local i = 0;
-		for k, v in c:items() do
-			i = i + 1;
-			assert_equal(k, keys[i]);
-			assert_equal(v, values[i]);
-		end
-		assert_equal(i, 5);
-
-		c:set("foo", nil);
-		assert_equal(c:count(), 5);
-
-		assert_equal(c:get("one"), nil);
-		assert_equal(c:get("two"), nil);
-		assert_equal(c:get("three"), nil);
-		assert_equal(c:get("four"), "2+2");
-		assert_equal(c:get("five"), nil);
-		assert_equal(c:get("six"), 6);
-		assert_equal(c:get("seven"), 7);
-		assert_equal(c:get("eight"), 8);
-		assert_equal(c:get("nine"), 9);
-	end
-
-	do
-		local keys = { "four", "nine", "eight", "seven", "six" };
-		local values = { "2+2", 9, 8, 7, 6 };
-		local i = 0;
-		for k, v in c:items() do
-			i = i + 1;
-			assert_equal(k, keys[i]);
-			assert_equal(v, values[i]);
-		end
-		assert_equal(i, 5);
-
-		c:set("four", nil);
-
-		assert_equal(c:get("one"), nil);
-		assert_equal(c:get("two"), nil);
-		assert_equal(c:get("three"), nil);
-		assert_equal(c:get("four"), nil);
-		assert_equal(c:get("five"), nil);
-		assert_equal(c:get("six"), 6);
-		assert_equal(c:get("seven"), 7);
-		assert_equal(c:get("eight"), 8);
-		assert_equal(c:get("nine"), 9);
-	end
-
-	do
-		local keys = { "nine", "eight", "seven", "six" };
-		local values = { 9, 8, 7, 6 };
-		local i = 0;
-		for k, v in c:items() do
-			i = i + 1;
-			assert_equal(k, keys[i]);
-			assert_equal(v, values[i]);
-		end
-		assert_equal(i, 4);
-	end
-
-	do
-		local evicted_key, evicted_value;
-		local c2 = new(3, function (_key, _value)
-			evicted_key, evicted_value = _key, _value;
-		end);
-		local function set(k, v, should_evict_key, should_evict_value)
-			evicted_key, evicted_value = nil, nil;
-			c2:set(k, v);
-			assert_equal(evicted_key, should_evict_key);
-			assert_equal(evicted_value, should_evict_value);
-		end
-		set("a", 1)
-		set("a", 1)
-		set("a", 1)
-		set("a", 1)
-		set("a", 1)
-
-		set("b", 2)
-		set("c", 3)
-		set("b", 2)
-		set("d", 4, "a", 1)
-		set("e", 5, "c", 3)
-	end
-
-	do
-		local evicted_key, evicted_value;
-		local c3 = new(1, function (_key, _value)
-			evicted_key, evicted_value = _key, _value;
-			if _key == "a" then
-				-- Sanity check for what we're evicting
-				assert_equal(_key, "a");
-				assert_equal(_value, 1);
-				-- We're going to block eviction of this key/value, so set to nil...
-				evicted_key, evicted_value = nil, nil;
-				-- Returning false to block eviction
-				return false
-			end
-		end);
-		local function set(k, v, should_evict_key, should_evict_value)
-			evicted_key, evicted_value = nil, nil;
-			local ret = c3:set(k, v);
-			assert_equal(evicted_key, should_evict_key);
-			assert_equal(evicted_value, should_evict_value);
-			return ret;
-		end
-		set("a", 1)
-		set("a", 1)
-		set("a", 1)
-		set("a", 1)
-		set("a", 1)
-
-		-- Our on_evict prevents "a" from being evicted, causing this to fail...
-		assert_equal(set("b", 2), false, "Failed to prevent eviction, or signal result");
-
-		expect_kv("a", 1, c3:head());
-		expect_kv("a", 1, c3:tail());
-
-		-- Check the final state is what we expect
-		assert_equal(c3:get("a"), 1);
-		assert_equal(c3:get("b"), nil);
-		assert_equal(c3:count(), 1);
-	end
-
-
-	local c4 = new(3, false);
-
-	assert_equal(c4:set("a", 1), true);
-	assert_equal(c4:set("a", 1), true);
-	assert_equal(c4:set("a", 1), true);
-	assert_equal(c4:set("a", 1), true);
-	assert_equal(c4:set("b", 2), true);
-	assert_equal(c4:set("c", 3), true);
-	assert_equal(c4:set("d", 4), false);
-	assert_equal(c4:set("d", 4), false);
-	assert_equal(c4:set("d", 4), false);
-
-	expect_kv("c", 3, c4:head());
-	expect_kv("a", 1, c4:tail());
-
-	local c5 = new(3, function (k, v)
-		if k == "a" then
-			return nil;
-		elseif k == "b" then
-			return true;
-		end
-		return false;
-	end);
-
-	assert_equal(c5:set("a", 1), true);
-	assert_equal(c5:set("a", 1), true);
-	assert_equal(c5:set("a", 1), true);
-	assert_equal(c5:set("a", 1), true);
-	assert_equal(c5:set("b", 2), true);
-	assert_equal(c5:set("c", 3), true);
-	assert_equal(c5:set("d", 4), true); -- "a" evicted (cb returned nil)
-	assert_equal(c5:set("d", 4), true); -- nop
-	assert_equal(c5:set("d", 4), true); -- nop
-	assert_equal(c5:set("e", 5), true); -- "b" evicted (cb returned true)
-	assert_equal(c5:set("f", 6), false); -- "c" won't evict (cb returned false)
-
-	expect_kv("e", 5, c5:head());
-	expect_kv("c", 3, c5:tail());
-
-end
--- a/tests/test_util_http.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2010 Matthew Wild
--- Copyright (C) 2008-2010 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-function urlencode(urlencode)
-	assert_equal(urlencode("helloworld123"), "helloworld123", "Normal characters not escaped");
-	assert_equal(urlencode("hello world"), "hello%20world", "Spaces escaped");
-	assert_equal(urlencode("This & that = something"), "This%20%26%20that%20%3d%20something", "Important URL chars escaped");
-end
-
-function urldecode(urldecode)
-	assert_equal("helloworld123", urldecode("helloworld123"), "Normal characters not escaped");
-	assert_equal("hello world", urldecode("hello%20world"), "Spaces escaped");
-	assert_equal("This & that = something", urldecode("This%20%26%20that%20%3d%20something"), "Important URL chars escaped");
-	assert_equal("This & that = something", urldecode("This%20%26%20that%20%3D%20something"), "Important URL chars escaped");
-end
-
-function formencode(formencode)
-	assert_equal(formencode({ { name = "one", value = "1"}, { name = "two", value = "2" } }), "one=1&two=2", "Form encoded");
-	assert_equal(formencode({ { name = "one two", value = "1"}, { name = "two one&", value = "2" } }), "one+two=1&two+one%26=2", "Form encoded");
-end
-
-function formdecode(formdecode)
-	do
-		local t = formdecode("one=1&two=2");
-		assert_table(t[1]);
-		assert_equal(t[1].name, "one"); assert_equal(t[1].value, "1");
-		assert_table(t[2]);
-		assert_equal(t[2].name, "two"); assert_equal(t[2].value, "2");
-	end
-
-	do
-		local t = formdecode("one+two=1&two+one%26=2");
-		assert_equal(t[1].name, "one two"); assert_equal(t[1].value, "1");
-		assert_equal(t[2].name, "two one&"); assert_equal(t[2].value, "2");
-	end
-end
--- a/tests/test_util_ip.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-
-function match(match, _M)
-	local _ = _M.new_ip;
-	local ip = _"10.20.30.40";
-	assert_equal(match(ip, _"10.0.0.0", 8), true);
-	assert_equal(match(ip, _"10.0.0.0", 16), false);
-	assert_equal(match(ip, _"10.0.0.0", 24), false);
-	assert_equal(match(ip, _"10.0.0.0", 32), false);
-
-	assert_equal(match(ip, _"10.20.0.0", 8), true);
-	assert_equal(match(ip, _"10.20.0.0", 16), true);
-	assert_equal(match(ip, _"10.20.0.0", 24), false);
-	assert_equal(match(ip, _"10.20.0.0", 32), false);
-
-	assert_equal(match(ip, _"0.0.0.0", 32), false);
-	assert_equal(match(ip, _"0.0.0.0", 0), true);
-	assert_equal(match(ip, _"0.0.0.0"), false);
-
-	assert_equal(match(ip, _"10.0.0.0", 255), false, "excessive number of bits");
-	assert_equal(match(ip, _"10.0.0.0", -8), true, "negative number of bits");
-	assert_equal(match(ip, _"10.0.0.0", -32), true, "negative number of bits");
-	assert_equal(match(ip, _"10.0.0.0", 0), true, "zero bits");
-	assert_equal(match(ip, _"10.0.0.0"), false, "no specified number of bits (differing ip)");
-	assert_equal(match(ip, _"10.20.30.40"), true, "no specified number of bits (same ip)");
-
-	assert_equal(match(_"127.0.0.1", _"127.0.0.1"), true, "simple ip");
-
-	assert_equal(match(_"8.8.8.8", _"8.8.0.0", 16), true);
-	assert_equal(match(_"8.8.4.4", _"8.8.0.0", 16), true);
-end
-
-function parse_cidr(parse_cidr, _M)
-	local new_ip = _M.new_ip;
-
-	assert_equal(new_ip"0.0.0.0", new_ip"0.0.0.0")
-
-	local function assert_cidr(cidr, ip, bits)
-		local parsed_ip, parsed_bits = parse_cidr(cidr);
-		assert_equal(new_ip(ip), parsed_ip, cidr.." parsed ip is "..ip);
-		assert_equal(bits, parsed_bits, cidr.." parsed bits is "..tostring(bits));
-	end
-	assert_cidr("0.0.0.0", "0.0.0.0", nil);
-	assert_cidr("127.0.0.1", "127.0.0.1", nil);
-	assert_cidr("127.0.0.1/0", "127.0.0.1", 0);
-	assert_cidr("127.0.0.1/8", "127.0.0.1", 8);
-	assert_cidr("127.0.0.1/32", "127.0.0.1", 32);
-	assert_cidr("127.0.0.1/256", "127.0.0.1", 256);
-	assert_cidr("::/48", "::", 48);
-end
-
-function new_ip(new_ip)
-	local v4, v6 = "IPv4", "IPv6";
-	local function assert_proto(s, proto)
-		local ip = new_ip(s);
-		if proto then
-			assert_equal(ip and ip.proto, proto, "protocol is correct for "..("%q"):format(s));
-		else
-			assert_equal(ip, nil, "address is invalid");
-		end
-	end
-	assert_proto("127.0.0.1", v4);
-	assert_proto("::1", v6);
-	assert_proto("", nil);
-	assert_proto("abc", nil);
-	assert_proto("   ", nil);
-end
-
-function commonPrefixLength(cpl, _M)
-	local new_ip = _M.new_ip;
-	local function assert_cpl6(a, b, len, v4)
-		local ipa, ipb = new_ip(a), new_ip(b);
-		if v4 then len = len+96; end
-		assert_equal(cpl(ipa, ipb), len, "common prefix length of "..a.." and "..b.." is "..len);
-		assert_equal(cpl(ipb, ipa), len, "common prefix length of "..b.." and "..a.." is "..len);
-	end
-	local function assert_cpl4(a, b, len)
-		return assert_cpl6(a, b, len, "IPv4");
-	end
-	assert_cpl4("0.0.0.0", "0.0.0.0", 32);
-	assert_cpl4("255.255.255.255", "0.0.0.0", 0);
-	assert_cpl4("255.255.255.255", "255.255.0.0", 16);
-	assert_cpl4("255.255.255.255", "255.255.255.255", 32);
-	assert_cpl4("255.255.255.255", "255.255.255.255", 32);
-
-	assert_cpl6("::1", "::1", 128);
-	assert_cpl6("abcd::1", "abcd::1", 128);
-	assert_cpl6("abcd::abcd", "abcd::", 112);
-	assert_cpl6("abcd::abcd", "abcd::abcd:abcd", 96);
-end
--- a/tests/test_util_jid.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2010 Matthew Wild
--- Copyright (C) 2008-2010 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-function join(join)
-	assert_equal(join("a", "b", "c"), "a@b/c", "builds full JID");
-	assert_equal(join("a", "b", nil), "a@b", "builds bare JID");
-	assert_equal(join(nil, "b", "c"), "b/c", "builds full host JID");
-	assert_equal(join(nil, "b", nil), "b", "builds bare host JID");
-	assert_equal(join(nil, nil, nil), nil, "invalid JID is nil");
-	assert_equal(join("a", nil, nil), nil, "invalid JID is nil");
-	assert_equal(join(nil, nil, "c"), nil, "invalid JID is nil");
-	assert_equal(join("a", nil, "c"), nil, "invalid JID is nil");
-end
-
-
-function split(split)
-	local function test(input_jid, expected_node, expected_server, expected_resource)
-		local rnode, rserver, rresource = split(input_jid);
-		assert_equal(expected_node, rnode, "split("..tostring(input_jid)..") failed");
-		assert_equal(expected_server, rserver, "split("..tostring(input_jid)..") failed");
-		assert_equal(expected_resource, rresource, "split("..tostring(input_jid)..") failed");
-	end
-
-	-- Valid JIDs
-	test("node@server", 		"node", "server", nil		);
-	test("node@server/resource", 	"node", "server", "resource"        );
-	test("server", 			nil, 	"server", nil               );
-	test("server/resource", 	nil, 	"server", "resource"        );
-	test("server/resource@foo", 	nil, 	"server", "resource@foo"    );
-	test("server/resource@foo/bar",	nil, 	"server", "resource@foo/bar");
-
-	-- Always invalid JIDs
-	test(nil,                nil, nil, nil);
-	test("node@/server",     nil, nil, nil);
-	test("@server",          nil, nil, nil);
-	test("@server/resource", nil, nil, nil);
-	test("@/resource", nil, nil, nil);
-end
-
-function bare(bare)
-	assert_equal(bare("user@host"), "user@host", "bare JID remains bare");
-	assert_equal(bare("host"), "host", "Host JID remains host");
-	assert_equal(bare("host/resource"), "host", "Host JID with resource becomes host");
-	assert_equal(bare("user@host/resource"), "user@host", "user@host JID with resource becomes user@host");
-	assert_equal(bare("user@/resource"), nil, "invalid JID is nil");
-	assert_equal(bare("@/resource"), nil, "invalid JID is nil");
-	assert_equal(bare("@/"), nil, "invalid JID is nil");
-	assert_equal(bare("/"), nil, "invalid JID is nil");
-	assert_equal(bare(""), nil, "invalid JID is nil");
-	assert_equal(bare("@"), nil, "invalid JID is nil");
-	assert_equal(bare("user@"), nil, "invalid JID is nil");
-	assert_equal(bare("user@@"), nil, "invalid JID is nil");
-	assert_equal(bare("user@@host"), nil, "invalid JID is nil");
-	assert_equal(bare("user@@host/resource"), nil, "invalid JID is nil");
-	assert_equal(bare("user@host/"), nil, "invalid JID is nil");
-end
-
-function compare(compare)
-	assert_equal(compare("host", "host"), true, "host should match");
-	assert_equal(compare("host", "other-host"), false, "host should not match");
-	assert_equal(compare("other-user@host/resource", "host"), true, "host should match");
-	assert_equal(compare("other-user@host", "user@host"), false, "user should not match");
-	assert_equal(compare("user@host", "host"), true, "host should match");
-	assert_equal(compare("user@host/resource", "host"), true, "host should match");
-	assert_equal(compare("user@host/resource", "user@host"), true, "user and host should match");
-	assert_equal(compare("user@other-host", "host"), false, "host should not match");
-	assert_equal(compare("user@other-host", "user@host"), false, "host should not match");
-end
-
-function node(node)
-	local function test(jid, expected_node)
-		assert_equal(node(jid), expected_node, "Unexpected node for "..tostring(jid));
-	end
-
-	test("example.com", nil);
-	test("foo.example.com", nil);
-	test("foo.example.com/resource", nil);
-	test("foo.example.com/some resource", nil);
-	test("foo.example.com/some@resource", nil);
-
-	test("foo@foo.example.com/some@resource", "foo");
-	test("foo@example/some@resource", "foo");
-
-	test("foo@example/@resource", "foo");
-	test("foo@example@resource", nil);
-	test("foo@example", "foo");
-	test("foo", nil);
-
-	test(nil, nil);
-end
-
-function host(host)
-	local function test(jid, expected_host)
-		assert_equal(host(jid), expected_host, "Unexpected host for "..tostring(jid));
-	end
-
-	test("example.com", "example.com");
-	test("foo.example.com", "foo.example.com");
-	test("foo.example.com/resource", "foo.example.com");
-	test("foo.example.com/some resource", "foo.example.com");
-	test("foo.example.com/some@resource", "foo.example.com");
-
-	test("foo@foo.example.com/some@resource", "foo.example.com");
-	test("foo@example/some@resource", "example");
-
-	test("foo@example/@resource", "example");
-	test("foo@example@resource", nil);
-	test("foo@example", "example");
-	test("foo", "foo");
-
-	test(nil, nil);
-end
-
-function resource(resource)
-	local function test(jid, expected_resource)
-		assert_equal(resource(jid), expected_resource, "Unexpected resource for "..tostring(jid));
-	end
-
-	test("example.com", nil);
-	test("foo.example.com", nil);
-	test("foo.example.com/resource", "resource");
-	test("foo.example.com/some resource", "some resource");
-	test("foo.example.com/some@resource", "some@resource");
-
-	test("foo@foo.example.com/some@resource", "some@resource");
-	test("foo@example/some@resource", "some@resource");
-
-	test("foo@example/@resource", "@resource");
-	test("foo@example@resource", nil);
-	test("foo@example", nil);
-	test("foo", nil);
-	test("/foo", nil);
-	test("@x/foo", nil);
-	test("@/foo", nil);
-
-	test(nil, nil);
-end
-
--- a/tests/test_util_json.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-
-function encode(encode, json)
-	local function test(f, j, e)
-		if e then
-			assert_equal(f(j), e);
-		end
-		assert_equal(f(j), f(json.decode(f(j))));
-	end
-	test(encode, json.null, "null")
-	test(encode, {}, "{}")
-	test(encode, {a=1});
-	test(encode, {a={1,2,3}});
-	test(encode, {1}, "[1]");
-end
-
-function decode(decode)
-	local empty_array = decode("[]");
-	assert_equal(type(empty_array), "table");
-	assert_equal(#empty_array, 0);
-	assert_equal(next(empty_array), nil);
-end
--- a/tests/test_util_json.sh	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-#!/bin/bash
-
-export LUA_PATH="../?.lua;;"
-export LUA_CPATH="../?.so;;"
-
-#set -x
-
-if ! which "$RUNWITH"; then
-	echo "Unable to find interpreter $RUNWITH";
-	exit 1;
-fi
-
-if ! $RUNWITH -e 'assert(require"util.json")' 2>/dev/null; then
-	echo "Unable to find util.json";
-	exit 1;
-fi
-
-FAIL=0
-
-for f in json/pass*.json; do
-	if ! $RUNWITH -e 'local j=require"util.json" assert(j.decode(io.read("*a"))~=nil)' <"$f" 2>/dev/null; then
-		echo "Failed to decode valid JSON: $f";
-		FAIL=1
-	fi
-done
-
-for f in json/fail*.json; do
-	if ! $RUNWITH -e 'local j=require"util.json" assert(j.decode(io.read("*a"))==nil)' <"$f" 2>/dev/null; then
-		echo "Invalid JSON decoded without error: $f";
-		FAIL=1
-	fi
-done
-
-if [ "$FAIL" == "1" ]; then
-	echo "JSON tests failed"
-	exit 1;
-fi
-
-exit 0;
--- a/tests/test_util_multitable.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2010 Matthew Wild
--- Copyright (C) 2008-2010 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-
-function new(new, multitable)
-	local mt = new();
-	assert_table(mt, "Multitable is a table");
-	assert_function(mt.add, "Multitable has method add");
-	assert_function(mt.get, "Multitable has method get");
-	assert_function(mt.remove, "Multitable has method remove");
-
-	get(mt.get, multitable);
-end
-
-function get(get, multitable)
-	local function has_items(list, ...)
-		local should_have = {};
-		if select('#', ...) > 0 then
-			assert_table(list, "has_items: list is table", 3);
-		else
-			assert_is_not(list and #list > 0, "No items, and no list");
-			return true, "has-all";
-		end
-		for n=1,select('#', ...) do should_have[select(n, ...)] = true; end
-		for _, item in ipairs(list) do
-			if not should_have[item] then return false, "too-many"; end
-			should_have[item] = nil;
-		end
-		if next(should_have) then
-			return false, "not-enough";
-		end
-		return true, "has-all";
-	end
-	local function assert_has_all(message, list, ...)
-		return assert_equal(select(2, has_items(list, ...)), "has-all", message or "List has all expected items, and no more", 2);
-	end
-
-	local mt = multitable.new();
-
-	local trigger1, trigger2, trigger3 = {}, {}, {};
-	local item1, item2, item3 = {}, {}, {};
-
-	assert_has_all("Has no items with trigger1", mt:get(trigger1));
-
-
-	mt:add(1, 2, 3, item1);
-
-	assert_has_all("Has item1 for 1, 2, 3", mt:get(1, 2, 3), item1);
-
--- Doesn't support nil
---[[	mt:add(nil, item1);
-	mt:add(nil, item2);
-	mt:add(nil, item3);
-
-	assert_has_all("Has all items with (nil)", mt:get(nil), item1, item2, item3);
-]]
-end
--- a/tests/test_util_queue.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-
-function new(new)
-	do
-		local q = new(10);
-
-		assert_equal(q.size, 10);
-		assert_equal(q:count(), 0);
-
-		assert_is(q:push("one"));
-		assert_is(q:push("two"));
-		assert_is(q:push("three"));
-
-		for i = 4, 10 do
-			assert_is(q:push("hello"));
-			assert_equal(q:count(), i, "count is not "..i.."("..q:count()..")");
-		end
-		assert_equal(q:push("hello"), nil, "queue overfull!");
-		assert_equal(q:push("hello"), nil, "queue overfull!");
-		assert_equal(q:pop(), "one", "queue item incorrect");
-		assert_equal(q:pop(), "two", "queue item incorrect");
-		assert_is(q:push("hello"));
-		assert_is(q:push("hello"));
-		assert_equal(q:pop(), "three", "queue item incorrect");
-		assert_is(q:push("hello"));
-		assert_equal(q:push("hello"), nil, "queue overfull!");
-		assert_equal(q:push("hello"), nil, "queue overfull!");
-
-		assert_equal(q:count(), 10, "queue count incorrect");
-
-		for _ = 1, 10 do
-			assert_equal(q:pop(), "hello", "queue item incorrect");
-		end
-
-		assert_equal(q:count(), 0, "queue count incorrect");
-
-		assert_is(q:push(1));
-		for i = 1, 1001 do
-			assert_equal(q:pop(), i);
-			assert_equal(q:count(), 0);
-			assert_is(q:push(i+1));
-			assert_equal(q:count(), 1);
-		end
-		assert_equal(q:pop(), 1002);
-		assert_is(q:push(1));
-		for i = 1, 1000 do
-			assert_equal(q:pop(), i);
-			assert_is(q:push(i+1));
-		end
-		assert_equal(q:pop(), 1001);
-		assert_equal(q:count(), 0);
-	end
-
-	do
-		-- Test queues that purge old items when pushing to a full queue
-		local q = new(10, true);
-
-		for i = 1, 10 do
-			q:push(i);
-		end
-
-		assert_equal(q:count(), 10);
-
-		assert_is(q:push(11));
-		assert_equal(q:count(), 10);
-		assert_equal(q:pop(), 2); -- First item should have been purged
-
-		for i = 12, 32 do
-			assert_is(q:push(i));
-		end
-
-		assert_equal(q:count(), 10);
-		assert_equal(q:pop(), 23);
-	end
-end
--- a/tests/test_util_random.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
--- Makes no attempt at testing how random the bytes are,
--- just that it returns the number of bytes requested
-
-function bytes(bytes)
-	assert_is(bytes(16));
-
-	for i = 1, 255 do
-		assert_equal(i, #bytes(i));
-	end
-end
--- a/tests/test_util_rfc6724.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
--- Prosody IM
--- Copyright (C) 2011-2013 Florian Zeitz
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-function source(source)
-	local new_ip = require"util.ip".new_ip;
-	assert_equal(source(new_ip("2001:db8:1::1", "IPv6"),
-			{new_ip("2001:db8:3::1", "IPv6"), new_ip("fe80::1", "IPv6")}).addr,
-		"2001:db8:3::1",
-		"prefer appropriate scope");
-	assert_equal(source(new_ip("ff05::1", "IPv6"),
-			{new_ip("2001:db8:3::1", "IPv6"), new_ip("fe80::1", "IPv6")}).addr,
-		"2001:db8:3::1",
-		"prefer appropriate scope");
-	assert_equal(source(new_ip("2001:db8:1::1", "IPv6"),
-			{new_ip("2001:db8:1::1", "IPv6"), new_ip("2001:db8:2::1", "IPv6")}).addr,
-		"2001:db8:1::1",
-		"prefer same address"); -- "2001:db8:1::1" should be marked "deprecated" here, we don't handle that right now
-	assert_equal(source(new_ip("fe80::1", "IPv6"),
-			{new_ip("fe80::2", "IPv6"), new_ip("2001:db8:1::1", "IPv6")}).addr,
-		"fe80::2",
-		"prefer appropriate scope"); -- "fe80::2" should be marked "deprecated" here, we don't handle that right now
-	assert_equal(source(new_ip("2001:db8:1::1", "IPv6"),
-			{new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3::2", "IPv6")}).addr,
-		"2001:db8:1::2",
-		"longest matching prefix");
---[[ "2001:db8:1::2" should be a care-of address and "2001:db8:3::2" a home address, we can't handle this and would fail
-	assert_equal(source(new_ip("2001:db8:1::1", "IPv6"),
-			{new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3::2", "IPv6")}).addr,
-		"2001:db8:3::2",
-		"prefer home address");
-]]
-	assert_equal(source(new_ip("2002:c633:6401::1", "IPv6"),
-			{new_ip("2002:c633:6401::d5e3:7953:13eb:22e8", "IPv6"), new_ip("2001:db8:1::2", "IPv6")}).addr,
-		"2002:c633:6401::d5e3:7953:13eb:22e8",
-		"prefer matching label"); -- "2002:c633:6401::d5e3:7953:13eb:22e8" should be marked "temporary" here, we don't handle that right now
-	assert_equal(source(new_ip("2001:db8:1::d5e3:0:0:1", "IPv6"),
-			{new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:1::d5e3:7953:13eb:22e8", "IPv6")}).addr,
-		"2001:db8:1::d5e3:7953:13eb:22e8",
-		"prefer temporary address") -- "2001:db8:1::2" should be marked "public" and "2001:db8:1::d5e3:7953:13eb:22e8" should be marked "temporary" here, we don't handle that right now
-end
-
-function destination(dest)
-	local order;
-	local new_ip = require"util.ip".new_ip;
-	order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("198.51.100.121", "IPv4")},
-		{new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("169.254.13.78", "IPv4")})
-	assert_equal(order[1].addr, "2001:db8:1::1", "prefer matching scope");
-	assert_equal(order[2].addr, "198.51.100.121", "prefer matching scope");
-
-	order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("198.51.100.121", "IPv4")},
-		{new_ip("fe80::1", "IPv6"), new_ip("198.51.100.117", "IPv4")})
-	assert_equal(order[1].addr, "198.51.100.121", "prefer matching scope");
-	assert_equal(order[2].addr, "2001:db8:1::1", "prefer matching scope");
-
-	order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("10.1.2.3", "IPv4")},
-		{new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("10.1.2.4", "IPv4")})
-	assert_equal(order[1].addr, "2001:db8:1::1", "prefer higher precedence");
-	assert_equal(order[2].addr, "10.1.2.3", "prefer higher precedence");
-
-	order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("fe80::1", "IPv6")},
-		{new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::2", "IPv6")})
-	assert_equal(order[1].addr, "fe80::1", "prefer smaller scope");
-	assert_equal(order[2].addr, "2001:db8:1::1", "prefer smaller scope");
-
---[[ "2001:db8:1::2" and "fe80::2" should be marked "care-of address", while "2001:db8:3::1" should be marked "home address", we can't currently handle this and would fail the test
-	order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("fe80::1", "IPv6")},
-		{new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3::1", "IPv6"), new_ip("fe80::2", "IPv6")})
-	assert_equal(order[1].addr, "2001:db8:1::1", "prefer home address");
-	assert_equal(order[2].addr, "fe80::1", "prefer home address");
-]]
-
---[[ "fe80::2" should be marked "deprecated", we can't currently handle this and would fail the test
-	order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("fe80::1", "IPv6")},
-		{new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::2", "IPv6")})
-	assert_equal(order[1].addr, "2001:db8:1::1", "avoid deprecated addresses");
-	assert_equal(order[2].addr, "fe80::1", "avoid deprecated addresses");
-]]
-
-	order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("2001:db8:3ffe::1", "IPv6")},
-		{new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3f44::2", "IPv6"), new_ip("fe80::2", "IPv6")})
-	assert_equal(order[1].addr, "2001:db8:1::1", "longest matching prefix");
-	assert_equal(order[2].addr, "2001:db8:3ffe::1", "longest matching prefix");
-
-	order = dest({new_ip("2002:c633:6401::1", "IPv6"), new_ip("2001:db8:1::1", "IPv6")},
-		{new_ip("2002:c633:6401::2", "IPv6"), new_ip("fe80::2", "IPv6")})
-	assert_equal(order[1].addr, "2002:c633:6401::1", "prefer matching label");
-	assert_equal(order[2].addr, "2001:db8:1::1", "prefer matching label");
-
-	order = dest({new_ip("2002:c633:6401::1", "IPv6"), new_ip("2001:db8:1::1", "IPv6")},
-		{new_ip("2002:c633:6401::2", "IPv6"), new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::2", "IPv6")})
-	assert_equal(order[1].addr, "2001:db8:1::1", "prefer higher precedence");
-	assert_equal(order[2].addr, "2002:c633:6401::1", "prefer higher precedence");
-end
--- a/tests/test_util_sasl_scram.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-
-
-local hmac_sha1 = require "util.hashes".hmac_sha1;
-local function toHex(s)
-	return s and (s:gsub(".", function (c) return ("%02x"):format(c:byte()); end));
-end
-
-function Hi(Hi)
-	assert( toHex(Hi(hmac_sha1, "password", "salt", 1)) == "0c60c80f961f0e71f3a9b524af6012062fe037a6",
-	[[FAIL: toHex(Hi(hmac_sha1, "password", "salt", 1)) == "0c60c80f961f0e71f3a9b524af6012062fe037a6"]])
-	assert( toHex(Hi(hmac_sha1, "password", "salt", 2)) == "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957",
-	[[FAIL: toHex(Hi(hmac_sha1, "password", "salt", 2)) == "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"]])
-	assert( toHex(Hi(hmac_sha1, "password", "salt", 64)) == "a7bc9b6efea2cbd717da72d83bfcc4e17d0b6280",
-	[[FAIL: toHex(Hi(hmac_sha1, "password", "salt", 64)) == "a7bc9b6efea2cbd717da72d83bfcc4e17d0b6280"]])
-	assert( toHex(Hi(hmac_sha1, "password", "salt", 4096)) == "4b007901b765489abead49d926f721d065a429c1",
-	[[FAIL: toHex(Hi(hmac_sha1, "password", "salt", 4096)) == "4b007901b765489abead49d926f721d065a429c1"]])
-	-- assert( toHex(Hi(hmac_sha1, "password", "salt", 16777216)) == "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984",
-	-- [[FAIL: toHex(Hi(hmac_sha1, "password", "salt", 16777216)) == "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"]])
-end
-
-function init(init)
-	-- no tests
-end
--- a/tests/test_util_stanza.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2010 Matthew Wild
--- Copyright (C) 2008-2010 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-
-function preserialize(preserialize, st)
-	local stanza = st.stanza("message", { a = "a" });
-	local stanza2 = preserialize(stanza);
-	assert_is(stanza2 and stanza.name, "preserialize returns a stanza");
-	assert_is_not(stanza2.tags, "Preserialized stanza has no tag list");
-	assert_is_not(stanza2.last_add, "Preserialized stanza has no last_add marker");
-	assert_is_not(getmetatable(stanza2), "Preserialized stanza has no metatable");
-end
-
-function deserialize(deserialize, st)
-	local stanza = st.stanza("message", { a = "a" });
-
-	local stanza2 = deserialize(st.preserialize(stanza));
-	assert_is(stanza2 and stanza.name, "deserialize returns a stanza");
-	assert_table(stanza2.attr, "Deserialized stanza has attributes");
-	assert_equal(stanza2.attr.a, "a", "Deserialized stanza retains attributes");
-	assert_table(getmetatable(stanza2), "Deserialized stanza has metatable");
-end
-
-function stanza(stanza)
-	local s = stanza("foo", { xmlns = "myxmlns", a = "attr-a" });
-	assert_equal(s.name, "foo");
-	assert_equal(s.attr.xmlns, "myxmlns");
-	assert_equal(s.attr.a, "attr-a");
-
-	local s1 = stanza("s1");
-	assert_equal(s1.name, "s1");
-	assert_equal(s1.attr.xmlns, nil);
-	assert_equal(#s1, 0);
-	assert_equal(#s1.tags, 0);
-
-	s1:tag("child1");
-	assert_equal(#s1.tags, 1);
-	assert_equal(s1.tags[1].name, "child1");
-
-	s1:tag("grandchild1"):up();
-	assert_equal(#s1.tags, 1);
-	assert_equal(s1.tags[1].name, "child1");
-	assert_equal(#s1.tags[1], 1);
-	assert_equal(s1.tags[1][1].name, "grandchild1");
-
-	s1:up():tag("child2");
-	assert_equal(#s1.tags, 2, tostring(s1));
-	assert_equal(s1.tags[1].name, "child1");
-	assert_equal(s1.tags[2].name, "child2");
-	assert_equal(#s1.tags[1], 1);
-	assert_equal(s1.tags[1][1].name, "grandchild1");
-
-	s1:up():text("Hello world");
-	assert_equal(#s1.tags, 2);
-	assert_equal(#s1, 3);
-	assert_equal(s1.tags[1].name, "child1");
-	assert_equal(s1.tags[2].name, "child2");
-	assert_equal(#s1.tags[1], 1);
-	assert_equal(s1.tags[1][1].name, "grandchild1");
-end
-
-function message(message)
-	local m = message();
-	assert_equal(m.name, "message");
-end
-
-function iq(iq)
-	local i = iq();
-	assert_equal(i.name, "iq");
-end
-
-function presence(presence)
-	local p = presence();
-	assert_equal(p.name, "presence");
-end
-
-function reply(reply, _M)
-	do
-		-- Test stanza
-		local s = _M.stanza("s", { to = "touser", from = "fromuser", id = "123" })
-			:tag("child1");
-		-- Make reply stanza
-		local r = reply(s);
-		assert_equal(r.name, s.name);
-		assert_equal(r.id, s.id);
-		assert_equal(r.attr.to, s.attr.from);
-		assert_equal(r.attr.from, s.attr.to);
-		assert_equal(#r.tags, 0, "A reply should not include children of the original stanza");
-	end
-
-	do
-		-- Test stanza
-		local s = _M.stanza("iq", { to = "touser", from = "fromuser", id = "123", type = "get" })
-			:tag("child1");
-		-- Make reply stanza
-		local r = reply(s);
-		assert_equal(r.name, s.name);
-		assert_equal(r.id, s.id);
-		assert_equal(r.attr.to, s.attr.from);
-		assert_equal(r.attr.from, s.attr.to);
-		assert_equal(r.attr.type, "result");
-		assert_equal(#r.tags, 0, "A reply should not include children of the original stanza");
-	end
-
-	do
-		-- Test stanza
-		local s = _M.stanza("iq", { to = "touser", from = "fromuser", id = "123", type = "set" })
-			:tag("child1");
-		-- Make reply stanza
-		local r = reply(s);
-		assert_equal(r.name, s.name);
-		assert_equal(r.id, s.id);
-		assert_equal(r.attr.to, s.attr.from);
-		assert_equal(r.attr.from, s.attr.to);
-		assert_equal(r.attr.type, "result");
-		assert_equal(#r.tags, 0, "A reply should not include children of the original stanza");
-	end
-end
-
-function error_reply(error_reply, _M)
-	do
-		-- Test stanza
-		local s = _M.stanza("s", { to = "touser", from = "fromuser", id = "123" })
-			:tag("child1");
-		-- Make reply stanza
-		local r = error_reply(s);
-		assert_equal(r.name, s.name);
-		assert_equal(r.id, s.id);
-		assert_equal(r.attr.to, s.attr.from);
-		assert_equal(r.attr.from, s.attr.to);
-		assert_equal(#r.tags, 1);
-	end
-
-	do
-		-- Test stanza
-		local s = _M.stanza("iq", { to = "touser", from = "fromuser", id = "123", type = "get" })
-			:tag("child1");
-		-- Make reply stanza
-		local r = error_reply(s);
-		assert_equal(r.name, s.name);
-		assert_equal(r.id, s.id);
-		assert_equal(r.attr.to, s.attr.from);
-		assert_equal(r.attr.from, s.attr.to);
-		assert_equal(r.attr.type, "error");
-		assert_equal(#r.tags, 1);
-	end
-end
--- a/tests/test_util_throttle.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-
-local now = 0; -- wibbly-wobbly... timey-wimey... stuff
-local function predictable_gettime()
-	return now;
-end
-local function later(n)
-	now = now + n; -- time passes at a different rate
-end
-
-local function override_gettime(throttle)
-	local i = 0;
-	repeat
-		i = i + 1;
-		local name = debug.getupvalue(throttle.update, i);
-		if name then
-			debug.setupvalue(throttle.update, i, predictable_gettime);
-			return throttle;
-		end
-	until not name;
-end
-
-function create(create)
-	local a = override_gettime( create(3, 10) );
-
-	assert_equal(a:poll(1), true);  -- 3 -> 2
-	assert_equal(a:poll(1), true);  -- 2 -> 1
-	assert_equal(a:poll(1), true);  -- 1 -> 0
-	assert_equal(a:poll(1), false); -- MEEP, out of credits!
-	later(1);                       -- ... what about
-	assert_equal(a:poll(1), false); -- now? - Still no!
-	later(9);                       -- Later that day
-	assert_equal(a:poll(1), true);  -- Should be back at 3 credits ... 2
-end
-
--- a/tests/test_util_uuid.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
--- This tests the format, not the randomness
-
--- https://tools.ietf.org/html/rfc4122#section-4.4
-
-local pattern = "^" .. table.concat({
-	string.rep("%x", 8),
-	string.rep("%x", 4),
-	"4" .. -- version
-	string.rep("%x", 3),
-	"[89ab]" .. -- reserved bits of 1 and 0
-	string.rep("%x", 3),
-	string.rep("%x", 12),
-}, "%-") .. "$";
-
-function generate(generate)
-	for _ = 1, 100 do
-		assert_is(generate():match(pattern));
-	end
-end
-
-function seed(seed)
-	assert_equal(seed("random string here"), nil, "seed doesn't return anything");
-end
-
--- a/tests/test_util_xml.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-function parse(parse)
-	local x =
-[[<x xmlns:a="b">
-	<y xmlns:a="c"> <!-- this overwrites 'a' -->
-	    <a:z/>
-	</y>
-	<a:z/> <!-- prefix 'a' is nil here, but should be 'b' -->
-</x>
-]]
-	local stanza = parse(x);
-	assert_equal(stanza.tags[2].attr.xmlns, "b");
-	assert_equal(stanza.tags[2].namespaces["a"], "b");
-end
--- a/tests/test_util_xmppstream.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-function new(new_stream, _M)
-	local function test(xml, expect_success, ex)
-		local stanzas = {};
-		local session = { notopen = true };
-		local callbacks = {
-			stream_ns = "streamns";
-			stream_tag = "stream";
-			default_ns = "stanzans";
-			streamopened = function (_session)
-				assert_equal(session, _session);
-				assert_equal(session.notopen, true);
-				_session.notopen = nil;
-				return true;
-			end;
-			handlestanza = function (_session, stanza)
-				assert_equal(session, _session);
-				assert_equal(_session.notopen, nil);
-				table.insert(stanzas, stanza);
-			end;
-			streamclosed = function (_session)
-				assert_equal(session, _session);
-				assert_equal(_session.notopen, nil);
-				_session.notopen = nil;
-			end;
-		}
-		if type(ex) == "table" then
-			for k, v in pairs(ex) do
-				if k ~= "_size_limit" then
-					callbacks[k] = v;
-				end
-			end
-		end
-		local stream = new_stream(session, callbacks, size_limit);
-		local ok, err = pcall(function ()
-			assert(stream:feed(xml));
-		end);
-
-		if ok and type(expect_success) == "function" then
-			expect_success(stanzas);
-		end
-		assert_equal(not not ok, not not expect_success, "Expected "..(expect_success and ("success ("..tostring(err)..")") or "failure"));
-	end
-
-	local function test_stanza(stanza, expect_success, ex)
-		return test([[<stream:stream xmlns:stream="streamns" xmlns="stanzans">]]..stanza, expect_success, ex);
-	end
-
-	test([[<stream:stream xmlns:stream="streamns"/>]], true);
-	test([[<stream xmlns="streamns"/>]], true);
-
-	test([[<stream1 xmlns="streamns"/>]], false);
-	test([[<stream xmlns="streamns1"/>]], false);
-	test("<>", false);
-
-	test_stanza("<message/>", function (stanzas)
-		assert_equal(#stanzas, 1);
-		assert_equal(stanzas[1].name, "message");
-	end);
-	test_stanza("< message>>>>/>\n", false);
-
-	test_stanza([[<x xmlns:a="b">
-		<y xmlns:a="c">
-			<a:z/>
-		</y>
-		<a:z/>
-	</x>]], function (stanzas)
-		assert_equal(#stanzas, 1);
-		local s = stanzas[1];
-		assert_equal(s.name, "x");
-		assert_equal(#s.tags, 2);
-
-		assert_equal(s.tags[1].name, "y");
-		assert_equal(s.tags[1].attr.xmlns, nil);
-
-		assert_equal(s.tags[1].tags[1].name, "z");
-		assert_equal(s.tags[1].tags[1].attr.xmlns, "c");
-
-		assert_equal(s.tags[2].name, "z");
-		assert_equal(s.tags[2].attr.xmlns, "b");
-
-		assert_equal(s.namespaces, nil);
-	end);
-end
--- a/tests/utf8_sequences.txt	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-Should pass: 41 42 43               # Simple ASCII - abc
-Should pass: 41 42 c3 87            # "ABÇ"
-Should pass: 41 42 e1 b8 88         # "ABḈ"
-Should pass: 41 42 f0 9d 9c 8d      # "AB𝜍"
-Should pass: F4 8F BF BF            # Last valid sequence (U+10FFFF)
-Should fail: F4 90 80 80            # First invalid sequence (U+110000)
-Should fail: 80 81 82 83            # Invalid sequence (invalid start byte)
-Should fail: C2 C3                  # Invalid sequence (invalid continuation byte)
-Should fail: C0 43                  # Overlong sequence
-Should fail: F5 80 80 80            # U+140000 (out of range)
-Should fail: ED A0 80               # U+D800 (forbidden by RFC 3629)
-Should fail: ED BF BF               # U+DFFF (forbidden by RFC 3629)
-Should pass: ED 9F BF               # U+D7FF (U+D800 minus 1: allowed)
-Should pass: EE 80 80               # U+E000 (U+D7FF plus 1: allowed)
-Should fail: C0                     # Invalid start byte
-Should fail: C1                     # Invalid start byte
-Should fail: C2                     # Incomplete sequence
-Should fail: F8 88 80 80 80         # 6-byte sequence
-Should pass: 7F                     # Last valid 1-byte sequence (U+00007F)
-Should pass: DF BF                  # Last valid 2-byte sequence (U+0007FF)
-Should pass: EF BF BF               # Last valid 3-byte sequence (U+00FFFF)
-Should pass: 00                     # First valid 1-byte sequence (U+000000)
-Should pass: C2 80                  # First valid 2-byte sequence (U+000080)
-Should pass: E0 A0 80               # First valid 3-byte sequence (U+000800)
-Should pass: F0 90 80 80            # First valid 4-byte sequence (U+000800)
-Should fail: F8 88 80 80 80         # First 5-byte sequence - invalid per RFC 3629
-Should fail: FC 84 80 80 80 80      # First 6-byte sequence - invalid per RFC 3629
-Should pass: EF BF BD               # U+00FFFD (replacement character)
-Should fail: 80                     # First continuation byte
-Should fail: BF                     # Last continuation byte
-Should fail: 80 BF                  # 2 continuation bytes
-Should fail: 80 BF 80               # 3 continuation bytes
-Should fail: 80 BF 80 BF            # 4 continuation bytes
-Should fail: 80 BF 80 BF 80         # 5 continuation bytes
-Should fail: 80 BF 80 BF 80 BF      # 6 continuation bytes
-Should fail: 80 BF 80 BF 80 BF 80   # 7 continuation bytes
-Should fail: FE                     # Impossible byte
-Should fail: FF                     # Impossible byte
-Should fail: FE FE FF FF            # Impossible bytes
-Should fail: C0 AF                  # Overlong "/"
-Should fail: E0 80 AF               # Overlong "/"
-Should fail: F0 80 80 AF            # Overlong "/"
-Should fail: F8 80 80 80 AF         # Overlong "/"
-Should fail: FC 80 80 80 80 AF      # Overlong "/"
-Should fail: C0 80 AF               # Overlong "/" (invalid)
-Should fail: C1 BF                  # Overlong
-Should fail: E0 9F BF               # Overlong
-Should fail: F0 8F BF BF            # Overlong
-Should fail: F8 87 BF BF BF         # Overlong
-Should fail: FC 83 BF BF BF BF      # Overlong
-Should pass: EF BF BE               # U+FFFE (invalid unicode, valid UTF-8)
-Should pass: EF BF BF               # U+FFFF (invalid unicode, valid UTF-8)
--- a/tests/util/logger.lua	Thu Sep 14 02:48:34 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2010 Matthew Wild
--- Copyright (C) 2008-2010 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-local format = string.format;
-local print = print;
-local debug = debug;
-local tostring = tostring;
-
-local getstyle, getstring = require "util.termcolours".getstyle, require "util.termcolours".getstring;
-local do_pretty_printing = not os.getenv("WINDIR");
-
-local _ENV = nil
-local _M = {}
-
-local logstyles = {};
-
---TODO: This should be done in config, but we don't have proper config yet
-if do_pretty_printing then
-	logstyles["info"] = getstyle("bold");
-	logstyles["warn"] = getstyle("bold", "yellow");
-	logstyles["error"] = getstyle("bold", "red");
-end
-
-function _M.init(name)
-	--name = nil; -- While this line is not commented, will automatically fill in file/line number info
-	return 	function (level, message, ...)
-				if level == "debug" or level == "info" then return; end
-				if not name then
-					local inf = debug.getinfo(3, 'Snl');
-					level = level .. ","..tostring(inf.short_src):match("[^/]*$")..":"..inf.currentline;
-				end
-				if ... then
-					print(name, getstring(logstyles[level], level), format(message, ...));
-				else
-					print(name, getstring(logstyles[level], level), message);
-				end
-			end
-end
-
-return _M;