From d007771f8da390816640fa3839b29dcbaa5862d2 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Wed, 28 Nov 2018 20:36:53 +0100
Subject: util.format: Tweak how nil values are handled

Because [<nil>] seems exsessive
---
 spec/util_format_spec.lua | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'spec')

diff --git a/spec/util_format_spec.lua b/spec/util_format_spec.lua
index 7e6a0c6e..8a2e9312 100644
--- a/spec/util_format_spec.lua
+++ b/spec/util_format_spec.lua
@@ -5,6 +5,8 @@ describe("util.format", function()
 		it("should work", function()
 			assert.equal("hello", format("%s", "hello"));
 			assert.equal("<nil>", format("%s"));
+			assert.equal("<nil>", format("%d"));
+			assert.equal("<nil>", format("%q"));
 			assert.equal(" [<nil>]", format("", nil));
 			assert.equal("true", format("%s", true));
 			assert.equal("[true]", format("%d", true));
-- 
cgit v1.2.3


From e999fee5c39278f767f7f508a2c0c964ec964cd1 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Fri, 30 Nov 2018 23:58:55 +0100
Subject: tests: Add scansion test for #689 about keeping the full subscription
 request stanza

---
 spec/scansion/keep_full_sub_req.scs | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 spec/scansion/keep_full_sub_req.scs

(limited to 'spec')

diff --git a/spec/scansion/keep_full_sub_req.scs b/spec/scansion/keep_full_sub_req.scs
new file mode 100644
index 00000000..318bbb60
--- /dev/null
+++ b/spec/scansion/keep_full_sub_req.scs
@@ -0,0 +1,37 @@
+# server MUST keep a record of the complete presence stanza comprising the subscription request (#689)
+
+[Client] Alice
+	jid: pars-a@localhost
+	password: password
+
+[Client] Bob
+	jid: pars-b@localhost
+	password: password
+
+---------
+
+Alice connects
+
+Alice sends:
+	<presence to="${Bob's JID}" type="subscribe">
+		<preauth xmlns="urn:xmpp:pars:0" token="1tMFqYDdKhfe2pwp" />
+	</presence>
+
+Alice disconnects
+
+Bob connects
+
+Bob sends:
+	<presence/>
+
+Bob receives:
+	<presence from="${Bob's full JID}"/>
+	
+
+Bob receives:
+	<presence from="${Alice's JID}">
+		<preauth xmlns="urn:xmpp:pars:0" token="1tMFqYDdKhfe2pwp" />
+	</presence>
+
+Bob disconnects
+
-- 
cgit v1.2.3


From 296555762ed5a515998d4b85d6d7fd4d9bfb62e5 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 1 Dec 2018 18:02:58 +0100
Subject: spec/keep_full_sub_req: Add missing type attribute

---
 spec/scansion/keep_full_sub_req.scs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/scansion/keep_full_sub_req.scs b/spec/scansion/keep_full_sub_req.scs
index 318bbb60..3b80b8b2 100644
--- a/spec/scansion/keep_full_sub_req.scs
+++ b/spec/scansion/keep_full_sub_req.scs
@@ -29,7 +29,7 @@ Bob receives:
 	
 
 Bob receives:
-	<presence from="${Alice's JID}">
+	<presence from="${Alice's JID}" type="subscribe">
 		<preauth xmlns="urn:xmpp:pars:0" token="1tMFqYDdKhfe2pwp" />
 	</presence>
 
-- 
cgit v1.2.3


From 8aac387431c7dad47c6afffc4bfcc024d3147950 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 1 Dec 2018 18:07:56 +0100
Subject: spec/keep_full_sub_req: Verify that the presence subscription stays
 the same after a reconnect

---
 spec/scansion/keep_full_sub_req.scs | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

(limited to 'spec')

diff --git a/spec/scansion/keep_full_sub_req.scs b/spec/scansion/keep_full_sub_req.scs
index 3b80b8b2..5a5e1fdf 100644
--- a/spec/scansion/keep_full_sub_req.scs
+++ b/spec/scansion/keep_full_sub_req.scs
@@ -27,6 +27,23 @@ Bob sends:
 Bob receives:
 	<presence from="${Bob's full JID}"/>
 	
+Bob receives:
+	<presence from="${Alice's JID}" type="subscribe">
+		<preauth xmlns="urn:xmpp:pars:0" token="1tMFqYDdKhfe2pwp" />
+	</presence>
+
+Bob disconnects
+
+# Works if they reconnect too
+
+Bob connects
+
+Bob sends:
+	<presence/>
+
+Bob receives:
+	<presence from="${Bob's full JID}"/>
+
 
 Bob receives:
 	<presence from="${Alice's JID}" type="subscribe">
-- 
cgit v1.2.3


From c295aedbfeeab6ebacb9b5bece085b8a532a7e9d Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 1 Dec 2018 18:12:01 +0100
Subject: spec/keep_full_sub_req: Make the second connect a differenct device
 (workaround for scansion issue)

scansion threw an error when a client connected again
---
 spec/scansion/keep_full_sub_req.scs | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

(limited to 'spec')

diff --git a/spec/scansion/keep_full_sub_req.scs b/spec/scansion/keep_full_sub_req.scs
index 5a5e1fdf..244c1d55 100644
--- a/spec/scansion/keep_full_sub_req.scs
+++ b/spec/scansion/keep_full_sub_req.scs
@@ -8,6 +8,10 @@
 	jid: pars-b@localhost
 	password: password
 
+[Client] Bob's phone
+	jid: pars-b@localhost/phone
+	password: password
+
 ---------
 
 Alice connects
@@ -36,19 +40,19 @@ Bob disconnects
 
 # Works if they reconnect too
 
-Bob connects
+Bob's phone connects
 
-Bob sends:
+Bob's phone sends:
 	<presence/>
 
-Bob receives:
-	<presence from="${Bob's full JID}"/>
+Bob's phone receives:
+	<presence from="${Bob's phone's full JID}"/>
 
 
-Bob receives:
+Bob's phone receives:
 	<presence from="${Alice's JID}" type="subscribe">
 		<preauth xmlns="urn:xmpp:pars:0" token="1tMFqYDdKhfe2pwp" />
 	</presence>
 
-Bob disconnects
+Bob's phone disconnects
 
-- 
cgit v1.2.3


From c28be4a630e1e6872438a5822de098295b55b925 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Thu, 6 Dec 2018 17:54:50 +0100
Subject: MUC: Add test case for #667

---
 spec/scansion/muc_subject_issue_667.scs | 79 +++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 spec/scansion/muc_subject_issue_667.scs

(limited to 'spec')

diff --git a/spec/scansion/muc_subject_issue_667.scs b/spec/scansion/muc_subject_issue_667.scs
new file mode 100644
index 00000000..68f4c17a
--- /dev/null
+++ b/spec/scansion/muc_subject_issue_667.scs
@@ -0,0 +1,79 @@
+# #667 MUC message with subject and body SHALL NOT be interpreted as a subject change
+
+[Client] Romeo
+	password: password
+	jid: romeo@localhost
+
+-----
+
+Romeo connects
+
+# and creates a room
+Romeo sends:
+	<presence to="issue667@conference.localhost/Romeo">
+		<x xmlns="http://jabber.org/protocol/muc"/>
+	</presence>
+
+Romeo receives:
+	<presence from="issue667@conference.localhost/Romeo">
+		<x xmlns="http://jabber.org/protocol/muc#user">
+			<status code="201"/>
+			<item affiliation="owner" role="moderator" jid="${Romeo's full JID}"/>
+			<status code="110"/>
+		</x>
+	</presence>
+
+Romeo receives:
+	<message type="groupchat" from="issue667@conference.localhost">
+		<subject/>
+	</message>
+
+Romeo sends:
+	<message to="issue667@conference.localhost" type="groupchat">
+		<subject>Greetings</subject>
+		<body>Hello everyone</body>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" from="issue667@conference.localhost/Romeo">
+		<subject>Greetings</subject>
+		<body>Hello everyone</body>
+	</message>
+
+Romeo sends:
+	<message to="issue667@conference.localhost" type="groupchat">
+		<subject>Something to talk about</subject>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" from="issue667@conference.localhost/Romeo">
+		<subject>Something to talk about</subject>
+	</message>
+
+Romeo sends:
+	<presence to="issue667@conference.localhost/Romeo">
+		<x xmlns="http://jabber.org/protocol/muc"/>
+	</presence>
+
+Romeo receives:
+	<presence from="issue667@conference.localhost/Romeo">
+		<x xmlns="http://jabber.org/protocol/muc#user">
+			<item affiliation="owner" role="moderator" jid="${Romeo's full JID}"/>
+			<status code="110"/>
+		</x>
+	</presence>
+
+# These have delay tags but we ignore those for now
+Romeo receives:
+	<message type="groupchat" from="issue667@conference.localhost/Romeo">
+		<subject>Greetings</subject>
+		<body>Hello everyone</body>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" from="issue667@conference.localhost/Romeo">
+		<subject>Something to talk about</subject>
+	</message>
+
+Romeo disconnects
+
-- 
cgit v1.2.3


From 2b289f34f929a69424a22bb0de3b668a58ba80cd Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 8 Dec 2018 17:09:55 +0100
Subject: various: Don't rely on _G.unpack existing

---
 spec/core_storagemanager_spec.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/core_storagemanager_spec.lua b/spec/core_storagemanager_spec.lua
index a0a8b5ef..fd2f8742 100644
--- a/spec/core_storagemanager_spec.lua
+++ b/spec/core_storagemanager_spec.lua
@@ -1,4 +1,4 @@
-local unpack = table.unpack or unpack;
+local unpack = table.unpack or unpack; -- luacheck: ignore 113
 local server = require "net.server_select";
 package.loaded["net.server"] = server;
 
-- 
cgit v1.2.3


From 177420df39c60de47eb47bc5ed574e2ccf082ec4 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Fri, 12 Oct 2018 01:29:34 +0200
Subject: util.format: Serialize values for the %q format

Improves eg debug logs
---
 spec/util_format_spec.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'spec')

diff --git a/spec/util_format_spec.lua b/spec/util_format_spec.lua
index 8a2e9312..b9652d19 100644
--- a/spec/util_format_spec.lua
+++ b/spec/util_format_spec.lua
@@ -11,6 +11,7 @@ describe("util.format", function()
 			assert.equal("true", format("%s", true));
 			assert.equal("[true]", format("%d", true));
 			assert.equal("% [true]", format("%%", true));
+			assert.equal("{ }", format("%q", { }));
 		end);
 	end);
 end);
-- 
cgit v1.2.3


From b1c3c4bc382df869fab3783a1ba35261e81420a6 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Tue, 11 Dec 2018 23:24:14 +0100
Subject: spec/scansion/prosody.cfg.lua: Update a comment from
 prosody.cfg.lua.dist for easier comparisons

---
 spec/scansion/prosody.cfg.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/scansion/prosody.cfg.lua b/spec/scansion/prosody.cfg.lua
index 94861449..170371e1 100644
--- a/spec/scansion/prosody.cfg.lua
+++ b/spec/scansion/prosody.cfg.lua
@@ -14,7 +14,7 @@ modules_enabled = {
 
 	-- Not essential, but recommended
 		"carbons"; -- Keep multiple clients in sync
-		"pep"; -- Enables users to publish their mood, activity, playing music and more
+		"pep"; -- Enables users to publish their avatar, mood, activity, playing music and more
 		"private"; -- Private XML storage (for room bookmarks, etc.)
 		"blocklist"; -- Allow users to block communications with other users
 		"vcard"; -- Allow users to set vCards
-- 
cgit v1.2.3


From 35c3393bca3c7ce6f64ef22f0c2bfa133e4367e1 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Tue, 11 Dec 2018 23:25:16 +0100
Subject: spec/scansion/prosody.cfg.lua: Replace mod_vcard with mod_vcard4 and
 mod_vcard_legacy as in default config

---
 spec/scansion/prosody.cfg.lua | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/scansion/prosody.cfg.lua b/spec/scansion/prosody.cfg.lua
index 170371e1..e8872bff 100644
--- a/spec/scansion/prosody.cfg.lua
+++ b/spec/scansion/prosody.cfg.lua
@@ -17,7 +17,8 @@ modules_enabled = {
 		"pep"; -- Enables users to publish their avatar, mood, activity, playing music and more
 		"private"; -- Private XML storage (for room bookmarks, etc.)
 		"blocklist"; -- Allow users to block communications with other users
-		"vcard"; -- Allow users to set vCards
+		"vcard4"; -- User profiles (stored in PEP)
+		"vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard
 
 	-- Nice to have
 		"version"; -- Replies to server version requests
-- 
cgit v1.2.3


From a270e6d5c8798dfad2fcd624f7ebb34ec72238a2 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Tue, 11 Dec 2018 23:26:16 +0100
Subject: spec/scansion/prosody.cfg.lua: Add remaining modules listened in
 prosody.cfg.lua.dist for easier comparisons

---
 spec/scansion/prosody.cfg.lua | 5 +++++
 1 file changed, 5 insertions(+)

(limited to 'spec')

diff --git a/spec/scansion/prosody.cfg.lua b/spec/scansion/prosody.cfg.lua
index e8872bff..8d6e7c0a 100644
--- a/spec/scansion/prosody.cfg.lua
+++ b/spec/scansion/prosody.cfg.lua
@@ -27,6 +27,11 @@ modules_enabled = {
 		"ping"; -- Replies to XMPP pings with pongs
 		"register"; -- Allow users to register on this server using a client and change passwords
 		--"mam"; -- Store messages in an archive and allow users to access it
+		--"csi_simple"; -- Simple Mobile optimizations
+
+	-- Admin interfaces
+		--"admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
+		--"admin_telnet"; -- Opens telnet console interface on localhost port 5582
 
 	-- HTTP modules
 		--"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
-- 
cgit v1.2.3


From 09d88cefa5738c1ec7a60c50c73685c2378335d4 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 16 Dec 2018 22:49:58 +0100
Subject: MUC: Add another message to #667 test

---
 spec/scansion/muc_subject_issue_667.scs | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

(limited to 'spec')

diff --git a/spec/scansion/muc_subject_issue_667.scs b/spec/scansion/muc_subject_issue_667.scs
index 68f4c17a..859a0bfd 100644
--- a/spec/scansion/muc_subject_issue_667.scs
+++ b/spec/scansion/muc_subject_issue_667.scs
@@ -50,6 +50,16 @@ Romeo receives:
 		<subject>Something to talk about</subject>
 	</message>
 
+Romeo sends:
+	<message to="issue667@conference.localhost" type="groupchat">
+		<body>Lorem ipsum dolor sit amet</body>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" from="issue667@conference.localhost/Romeo">
+		<body>Lorem ipsum dolor sit amet</body>
+	</message>
+
 Romeo sends:
 	<presence to="issue667@conference.localhost/Romeo">
 		<x xmlns="http://jabber.org/protocol/muc"/>
@@ -70,6 +80,11 @@ Romeo receives:
 		<body>Hello everyone</body>
 	</message>
 
+Romeo receives:
+	<message type="groupchat" from="issue667@conference.localhost/Romeo">
+		<body>Lorem ipsum dolor sit amet</body>
+	</message>
+
 Romeo receives:
 	<message type="groupchat" from="issue667@conference.localhost/Romeo">
 		<subject>Something to talk about</subject>
-- 
cgit v1.2.3


From 826c511cac78d521e6f336a658f50d66cb10d78a Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 16 Dec 2018 22:53:56 +0100
Subject: MUC: Add descriptive comments to #667 test

---
 spec/scansion/muc_subject_issue_667.scs | 8 ++++++++
 1 file changed, 8 insertions(+)

(limited to 'spec')

diff --git a/spec/scansion/muc_subject_issue_667.scs b/spec/scansion/muc_subject_issue_667.scs
index 859a0bfd..417f957a 100644
--- a/spec/scansion/muc_subject_issue_667.scs
+++ b/spec/scansion/muc_subject_issue_667.scs
@@ -23,11 +23,13 @@ Romeo receives:
 		</x>
 	</presence>
 
+# the default (empty) subject
 Romeo receives:
 	<message type="groupchat" from="issue667@conference.localhost">
 		<subject/>
 	</message>
 
+# this should be treated as a normal message
 Romeo sends:
 	<message to="issue667@conference.localhost" type="groupchat">
 		<subject>Greetings</subject>
@@ -40,6 +42,7 @@ Romeo receives:
 		<body>Hello everyone</body>
 	</message>
 
+# this is a subject change
 Romeo sends:
 	<message to="issue667@conference.localhost" type="groupchat">
 		<subject>Something to talk about</subject>
@@ -50,6 +53,7 @@ Romeo receives:
 		<subject>Something to talk about</subject>
 	</message>
 
+# a message without <subject>
 Romeo sends:
 	<message to="issue667@conference.localhost" type="groupchat">
 		<body>Lorem ipsum dolor sit amet</body>
@@ -60,11 +64,13 @@ Romeo receives:
 		<body>Lorem ipsum dolor sit amet</body>
 	</message>
 
+# Resync
 Romeo sends:
 	<presence to="issue667@conference.localhost/Romeo">
 		<x xmlns="http://jabber.org/protocol/muc"/>
 	</presence>
 
+# Presences
 Romeo receives:
 	<presence from="issue667@conference.localhost/Romeo">
 		<x xmlns="http://jabber.org/protocol/muc#user">
@@ -73,6 +79,7 @@ Romeo receives:
 		</x>
 	</presence>
 
+# History
 # These have delay tags but we ignore those for now
 Romeo receives:
 	<message type="groupchat" from="issue667@conference.localhost/Romeo">
@@ -85,6 +92,7 @@ Romeo receives:
 		<body>Lorem ipsum dolor sit amet</body>
 	</message>
 
+# Finally, the topic
 Romeo receives:
 	<message type="groupchat" from="issue667@conference.localhost/Romeo">
 		<subject>Something to talk about</subject>
-- 
cgit v1.2.3


From 24a020bbaa7d9d99d26330e2639f9249511f84cd Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 16 Dec 2018 22:59:14 +0100
Subject: MUC: Test that subject is still empty after sending a non-subject
 change message with a subject (#667)

---
 spec/scansion/muc_subject_issue_667.scs | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

(limited to 'spec')

diff --git a/spec/scansion/muc_subject_issue_667.scs b/spec/scansion/muc_subject_issue_667.scs
index 417f957a..74980073 100644
--- a/spec/scansion/muc_subject_issue_667.scs
+++ b/spec/scansion/muc_subject_issue_667.scs
@@ -42,6 +42,33 @@ Romeo receives:
 		<body>Hello everyone</body>
 	</message>
 
+# Resync
+Romeo sends:
+	<presence to="issue667@conference.localhost/Romeo">
+		<x xmlns="http://jabber.org/protocol/muc"/>
+	</presence>
+
+# Presences
+Romeo receives:
+	<presence from="issue667@conference.localhost/Romeo">
+		<x xmlns="http://jabber.org/protocol/muc#user">
+			<item affiliation="owner" role="moderator" jid="${Romeo's full JID}"/>
+			<status code="110"/>
+		</x>
+	</presence>
+
+Romeo receives:
+	<message type="groupchat" from="issue667@conference.localhost/Romeo">
+		<subject>Greetings</subject>
+		<body>Hello everyone</body>
+	</message>
+
+# the still empty subject
+Romeo receives:
+	<message type="groupchat" from="issue667@conference.localhost">
+		<subject/>
+	</message>
+
 # this is a subject change
 Romeo sends:
 	<message to="issue667@conference.localhost" type="groupchat">
-- 
cgit v1.2.3


From b90dce4c204a7fd58ec00361cd75546ea32d585b Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 23 Dec 2018 14:52:52 +0100
Subject: util.table: Add test for pack()

---
 spec/util_table_spec.lua | 10 ++++++++++
 1 file changed, 10 insertions(+)
 create mode 100644 spec/util_table_spec.lua

(limited to 'spec')

diff --git a/spec/util_table_spec.lua b/spec/util_table_spec.lua
new file mode 100644
index 00000000..97266fe2
--- /dev/null
+++ b/spec/util_table_spec.lua
@@ -0,0 +1,10 @@
+local u_table = require "util.table";
+describe("util.table", function ()
+	describe("pack()", function ()
+		it("works", function ()
+			assert.same({ "lorem", "ipsum", "dolor", "sit", "amet", n = 5 }, u_table.pack("lorem", "ipsum", "dolor", "sit", "amet"));
+		end);
+	end);
+end);
+
+
-- 
cgit v1.2.3


From 9ff2b47bcc4a5c1c026ecdba8fc3b6c818af183e Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 23 Dec 2018 15:01:37 +0100
Subject: util.table: Add test for create()

---
 spec/util_table_spec.lua | 7 +++++++
 1 file changed, 7 insertions(+)

(limited to 'spec')

diff --git a/spec/util_table_spec.lua b/spec/util_table_spec.lua
index 97266fe2..76f54b69 100644
--- a/spec/util_table_spec.lua
+++ b/spec/util_table_spec.lua
@@ -1,5 +1,12 @@
 local u_table = require "util.table";
 describe("util.table", function ()
+	describe("create()", function ()
+		it("works", function ()
+			-- Can't test the allocated sizes of the table, so what you gonna do?
+			assert.is.table(u_table.create(1,1));
+		end);
+	end);
+
 	describe("pack()", function ()
 		it("works", function ()
 			assert.same({ "lorem", "ipsum", "dolor", "sit", "amet", n = 5 }, u_table.pack("lorem", "ipsum", "dolor", "sit", "amet"));
-- 
cgit v1.2.3


From 20429527b1c455e2c6784d717c48d69e80b1138b Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Fri, 28 Dec 2018 20:49:01 +0100
Subject: util.stanza: Require a type attribute for iq stanzas

---
 spec/util_stanza_spec.lua | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

(limited to 'spec')

diff --git a/spec/util_stanza_spec.lua b/spec/util_stanza_spec.lua
index 6fbae41a..18e39554 100644
--- a/spec/util_stanza_spec.lua
+++ b/spec/util_stanza_spec.lua
@@ -95,20 +95,31 @@ describe("util.stanza", function()
 
 	describe("#iq()", function()
 		it("should create an iq stanza", function()
-			local i = st.iq({ id = "foo" });
+			local i = st.iq({ type = "get", id = "foo" });
 			assert.are.equal("iq", i.name);
 			assert.are.equal("foo", i.attr.id);
+			assert.are.equal("get", i.attr.type);
 		end);
 
-		it("should reject stanzas with no id", function ()
+		it("should reject stanzas with no attributes", function ()
 			assert.has.error_match(function ()
 				st.iq();
-			end, "id attribute");
+			end, "attributes");
+		end);
 
+
+		it("should reject stanzas with no id", function ()
 			assert.has.error_match(function ()
-				st.iq({ foo = "bar" });
+				st.iq({ type = "get" });
 			end, "id attribute");
 		end);
+
+		it("should reject stanzas with no type", function ()
+			assert.has.error_match(function ()
+				st.iq({ id = "foo" });
+			end, "type attribute");
+
+		end);
 	end);
 
 	describe("#presence()", function ()
-- 
cgit v1.2.3


From 15d5dffa63b71c75bcba23046ac20e4a7f0e3a58 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 10 Mar 2018 19:58:41 +0100
Subject: spec: Stub tests for util.interpolation

---
 spec/util_interpolation_spec.lua | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 spec/util_interpolation_spec.lua

(limited to 'spec')

diff --git a/spec/util_interpolation_spec.lua b/spec/util_interpolation_spec.lua
new file mode 100644
index 00000000..88d9f844
--- /dev/null
+++ b/spec/util_interpolation_spec.lua
@@ -0,0 +1,17 @@
+local template = [[
+{greet!}, {name?world}!
+]];
+local expect1 = [[
+Hello, WORLD!
+]];
+local expect2 = [[
+Hello, world!
+]];
+
+describe("util.interpolation", function ()
+	it("renders", function ()
+		local render = require "util.interpolation".new("%b{}", string.upper);
+		assert.equal(expect1, render(template, { greet = "Hello", name = "world" }));
+		assert.equal(expect2, render(template, { greet = "Hello" }));
+	end);
+end);
-- 
cgit v1.2.3


From 3e30870220e8c617cda3a06b1c9d9054b346283c Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Wed, 16 Jan 2019 13:53:04 +0100
Subject: util.http: Fix decoding of uppercase URL encoded chars

Broken in 1af5106a2c34
---
 spec/util_http_spec.lua | 5 +++++
 1 file changed, 5 insertions(+)

(limited to 'spec')

diff --git a/spec/util_http_spec.lua b/spec/util_http_spec.lua
index 0f51a86c..d38645f7 100644
--- a/spec/util_http_spec.lua
+++ b/spec/util_http_spec.lua
@@ -28,6 +28,11 @@ describe("util.http", function()
 		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);
+
+		it("should decode both lower and uppercase", function ()
+			assert.are.equal("This & that = {something}.", http.urldecode("This%20%26%20that%20%3D%20%7Bsomething%7D%2E"), "Important URL chars escaped");
+		end);
+
 	end);
 
 	describe("#formencode()", function()
-- 
cgit v1.2.3


From a274eacbbc62164a6567faeaa8d18ea5993a133f Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Sat, 23 Mar 2019 08:47:55 +0000
Subject: util.queue: Add 'consume()' convenience iterator

---
 spec/util_queue_spec.lua | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

(limited to 'spec')

diff --git a/spec/util_queue_spec.lua b/spec/util_queue_spec.lua
index 7cd3d695..d73f523d 100644
--- a/spec/util_queue_spec.lua
+++ b/spec/util_queue_spec.lua
@@ -100,4 +100,41 @@ describe("util.queue", function()
 
 		end);
 	end);
+	describe("consume()", function ()
+		it("should work", function ()
+			local q = queue.new(10);
+			for i = 1, 5 do
+				q:push(i);
+			end
+			local c = 0;
+			for i in q:consume() do
+				assert(i == c + 1);
+				assert(q:count() == (5-i));
+				c = i;
+			end
+		end);
+
+		it("should work even if items are pushed in the loop", function ()
+			local q = queue.new(10);
+			for i = 1, 5 do
+				q:push(i);
+			end
+			local c = 0;
+			for i in q:consume() do
+				assert(i == c + 1);
+				if c < 3 then
+					assert(q:count() == (5-i));
+				else
+					assert(q:count() == (6-i));
+				end
+
+				c = i;
+
+				if c == 3 then
+					q:push(6);
+				end
+			end
+			assert.equal(c, 6);
+		end);
+	end);
 end);
-- 
cgit v1.2.3


From e1b559853fb0f6e0967124a135e1d380d02316d9 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Mon, 25 Mar 2019 14:37:43 +0000
Subject: util.stanza: Fix :top_tag() handling of namespaced attributes

---
 spec/util_stanza_spec.lua | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

(limited to 'spec')

diff --git a/spec/util_stanza_spec.lua b/spec/util_stanza_spec.lua
index 18e39554..38503ab7 100644
--- a/spec/util_stanza_spec.lua
+++ b/spec/util_stanza_spec.lua
@@ -381,4 +381,35 @@ describe("util.stanza", function()
 			end);
 		end);
 	end);
+
+	describe("top_tag", function ()
+		local xml_parse = require "util.xml".parse;
+		it("works", function ()
+			local s = st.message({type="chat"}, "Hello");
+			local top_tag = s:top_tag();
+			assert.is_string(top_tag);
+			assert.not_equal("/>", top_tag:sub(-2, -1));
+			assert.equal(">", top_tag:sub(-1, -1));
+			local s2 = xml_parse(top_tag.."</message>");
+			assert(st.is_stanza(s2));
+			assert.equal("message", s2.name);
+			assert.equal(0, #s2);
+			assert.equal(0, #s2.tags);
+			assert.equal("chat", s2.attr.type);
+		end);
+
+		it("works with namespaced attributes", function ()
+			local s = xml_parse[[<message foo:bar='true' xmlns:foo='my-awesome-ns'/>]];
+			local top_tag = s:top_tag();
+			assert.is_string(top_tag);
+			assert.not_equal("/>", top_tag:sub(-2, -1));
+			assert.equal(">", top_tag:sub(-1, -1));
+			local s2 = xml_parse(top_tag.."</message>");
+			assert(st.is_stanza(s2));
+			assert.equal("message", s2.name);
+			assert.equal(0, #s2);
+			assert.equal(0, #s2.tags);
+			assert.equal("true", s2.attr["my-awesome-ns\1bar"]);
+		end);
+	end);
 end);
-- 
cgit v1.2.3


From d00874434414a06801a3b8d0be756176d1eb778b Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Thu, 11 Apr 2019 00:41:48 +0200
Subject: util.hmac: Generate test cases from RFC 4231

---
 spec/util_hmac_spec.lua | 103 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)
 create mode 100644 spec/util_hmac_spec.lua

(limited to 'spec')

diff --git a/spec/util_hmac_spec.lua b/spec/util_hmac_spec.lua
new file mode 100644
index 00000000..abcc92f1
--- /dev/null
+++ b/spec/util_hmac_spec.lua
@@ -0,0 +1,103 @@
+-- Test cases from RFC 4231
+
+local hmac = require "util.hmac";
+local hex = require "util.hex";
+
+describe("Test case 1", function ()
+	local Key  = hex.from("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
+	local Data = hex.from("4869205468657265");
+	describe("HMAC-SHA-256", function ()
+		it("works", function()
+			assert.equal("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", hmac.sha256(Key, Data, true))
+		end);
+	end);
+	describe("HMAC-SHA-512", function ()
+		it("works", function()
+			assert.equal("87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854", hmac.sha512(Key, Data, true))
+		end);
+	end);
+end);
+describe("Test case 2", function ()
+	local Key  = hex.from("4a656665");
+	local Data = hex.from("7768617420646f2079612077616e7420666f72206e6f7468696e673f");
+	describe("HMAC-SHA-256", function ()
+		it("works", function()
+			assert.equal("5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", hmac.sha256(Key, Data, true))
+		end);
+	end);
+	describe("HMAC-SHA-512", function ()
+		it("works", function()
+			assert.equal("164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737", hmac.sha512(Key, Data, true))
+		end);
+	end);
+end);
+describe("Test case 3", function ()
+	local Key  = hex.from("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+	local Data = hex.from("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");
+	describe("HMAC-SHA-256", function ()
+		it("works", function()
+			assert.equal("773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", hmac.sha256(Key, Data, true))
+		end);
+	end);
+	describe("HMAC-SHA-512", function ()
+		it("works", function()
+			assert.equal("fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb", hmac.sha512(Key, Data, true))
+		end);
+	end);
+end);
+describe("Test case 4", function ()
+	local Key  = hex.from("0102030405060708090a0b0c0d0e0f10111213141516171819");
+	local Data = hex.from("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd");
+	describe("HMAC-SHA-256", function ()
+		it("works", function()
+			assert.equal("82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b", hmac.sha256(Key, Data, true))
+		end);
+	end);
+	describe("HMAC-SHA-512", function ()
+		it("works", function()
+			assert.equal("b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd", hmac.sha512(Key, Data, true))
+		end);
+	end);
+end);
+describe("Test case 5", function ()
+	local Key  = hex.from("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c");
+	local Data = hex.from("546573742057697468205472756e636174696f6e");
+	describe("HMAC-SHA-256", function ()
+		it("works", function()
+			assert.equal("a3b6167473100ee06e0c796c2955552b", hmac.sha256(Key, Data, true):sub(1,128/4))
+		end);
+	end);
+	describe("HMAC-SHA-512", function ()
+		it("works", function()
+			assert.equal("415fad6271580a531d4179bc891d87a6", hmac.sha512(Key, Data, true):sub(1,128/4))
+		end);
+	end);
+end);
+describe("Test case 6", function ()
+	local Key  = hex.from("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+	local Data = hex.from("54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374");
+	describe("HMAC-SHA-256", function ()
+		it("works", function()
+			assert.equal("60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54", hmac.sha256(Key, Data, true))
+		end);
+	end);
+	describe("HMAC-SHA-512", function ()
+		it("works", function()
+			assert.equal("80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598", hmac.sha512(Key, Data, true))
+		end);
+	end);
+end);
+describe("Test case 7", function ()
+	local Key  = hex.from("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+	local Data = hex.from("5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e");
+	describe("HMAC-SHA-256", function ()
+		it("works", function()
+			assert.equal("9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2", hmac.sha256(Key, Data, true))
+		end);
+	end);
+	describe("HMAC-SHA-512", function ()
+		it("works", function()
+			assert.equal("e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58", hmac.sha512(Key, Data, true))
+		end);
+	end);
+end);
-- 
cgit v1.2.3


From 53f4351d9a70341bfa9083be3552b7f0d1f7ffbe Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Fri, 19 Apr 2019 13:17:49 +0200
Subject: util.hmac: Ignore long hex lines in tests

---
 spec/util_hmac_spec.lua | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'spec')

diff --git a/spec/util_hmac_spec.lua b/spec/util_hmac_spec.lua
index abcc92f1..a2125c3a 100644
--- a/spec/util_hmac_spec.lua
+++ b/spec/util_hmac_spec.lua
@@ -1,5 +1,8 @@
 -- Test cases from RFC 4231
 
+-- Yes, the lines are long, it's annoying to split the long hex things.
+-- luacheck: ignore 631
+
 local hmac = require "util.hmac";
 local hex = require "util.hex";
 
-- 
cgit v1.2.3


From 43bb3d5756a77f7d67a470ca1c69c979a2dba612 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Fri, 19 Apr 2019 14:12:28 +0200
Subject: util.hashes: Add test vectors from RFC 6070 for PBKDF2 (aka SCRAM
 Hi())

Number 4 is disabled by default beacuse of how long time it takes
---
 spec/util_hashes_spec.lua | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 spec/util_hashes_spec.lua

(limited to 'spec')

diff --git a/spec/util_hashes_spec.lua b/spec/util_hashes_spec.lua
new file mode 100644
index 00000000..1e6187bb
--- /dev/null
+++ b/spec/util_hashes_spec.lua
@@ -0,0 +1,37 @@
+-- Test vectors from RFC 6070
+local hashes = require "util.hashes";
+local hex = require "util.hex";
+
+-- Also see spec for util.hmac where HMAC test cases reside
+
+describe("PBKDF2-SHA1", function ()
+	it("test vector 1", function ()
+		local P = "password"
+		local S = "salt"
+		local c = 1
+		local DK = "0c60c80f961f0e71f3a9b524af6012062fe037a6";
+		assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c)));
+	end);
+	it("test vector 2", function ()
+		local P = "password"
+		local S = "salt"
+		local c = 2
+		local DK = "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957";
+		assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c)));
+	end);
+	it("test vector 3", function ()
+		local P = "password"
+		local S = "salt"
+		local c = 4096
+		local DK = "4b007901b765489abead49d926f721d065a429c1";
+		assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c)));
+	end);
+	it("test vector 4 #SLOW", function ()
+		local P = "password"
+		local S = "salt"
+		local c = 16777216
+		local DK = "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984";
+		assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c)));
+	end);
+end);
+
-- 
cgit v1.2.3


From 165ee3a5ef1247468e98d0d4cba6fc43e15f92d7 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 20 Apr 2019 15:11:04 +0200
Subject: util.hashes: Allow specifying output key length

This is not needed for SCRAM but PBKDF2 takes this argument.
---
 spec/util_hashes_spec.lua | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

(limited to 'spec')

diff --git a/spec/util_hashes_spec.lua b/spec/util_hashes_spec.lua
index 1e6187bb..9099145a 100644
--- a/spec/util_hashes_spec.lua
+++ b/spec/util_hashes_spec.lua
@@ -33,5 +33,21 @@ describe("PBKDF2-SHA1", function ()
 		local DK = "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984";
 		assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c)));
 	end);
+	it("test vector 5", function ()
+		local P = "passwordPASSWORDpassword"
+		local S = "saltSALTsaltSALTsaltSALTsaltSALTsalt"
+		local c = 4096
+		local dkLen = 25
+		local DK = "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"
+		assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c, dkLen)));
+	end);
+	it("works", function ()
+		local P = "pass\0word"
+		local S = "sa\0lt"
+		local c = 4096
+		local dkLen = 16
+		local DK = "56fa6aa75548099dcc37d7f03425e0c3"
+		assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c, dkLen)));
+	end);
 end);
 
-- 
cgit v1.2.3


From 90d4d6bda8161d7fdc730f822db13a1a8639aee4 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 21 Apr 2019 00:59:36 +0200
Subject: Backed out changeset 61bc5c52c941

luaL_buffinitsize is only available in Lua 5.2+
---
 spec/util_hashes_spec.lua | 16 ----------------
 1 file changed, 16 deletions(-)

(limited to 'spec')

diff --git a/spec/util_hashes_spec.lua b/spec/util_hashes_spec.lua
index 9099145a..1e6187bb 100644
--- a/spec/util_hashes_spec.lua
+++ b/spec/util_hashes_spec.lua
@@ -33,21 +33,5 @@ describe("PBKDF2-SHA1", function ()
 		local DK = "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984";
 		assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c)));
 	end);
-	it("test vector 5", function ()
-		local P = "passwordPASSWORDpassword"
-		local S = "saltSALTsaltSALTsaltSALTsaltSALTsalt"
-		local c = 4096
-		local dkLen = 25
-		local DK = "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"
-		assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c, dkLen)));
-	end);
-	it("works", function ()
-		local P = "pass\0word"
-		local S = "sa\0lt"
-		local c = 4096
-		local dkLen = 16
-		local DK = "56fa6aa75548099dcc37d7f03425e0c3"
-		assert.equal(DK, hex.to(hashes.scram_Hi_sha1(P, S, c, dkLen)));
-	end);
 end);
 
-- 
cgit v1.2.3


From f65c017ee107f86b353d5931e85a70e8c6067f1f Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Fri, 3 May 2019 20:54:24 +0200
Subject: Fix various spelling mistakes [codespell]

---
 spec/util_throttle_spec.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/util_throttle_spec.lua b/spec/util_throttle_spec.lua
index 75daf1b9..985afae8 100644
--- a/spec/util_throttle_spec.lua
+++ b/spec/util_throttle_spec.lua
@@ -88,7 +88,7 @@ describe("util.throttle", function()
 				later(0.1);
 				a:update();
 			end
-			assert(math.abs(a.balance - 1) < 0.0001); -- incremental updates cause rouding errors
+			assert(math.abs(a.balance - 1) < 0.0001); -- incremental updates cause rounding errors
 		end);
 	end);
 
-- 
cgit v1.2.3


From 46822c54b1e6ba4e37b88e7184147fbf57f99782 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Mon, 13 May 2019 10:36:03 +0100
Subject: util.hashring: Add tests

---
 spec/util_hashring_spec.lua | 85 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)
 create mode 100644 spec/util_hashring_spec.lua

(limited to 'spec')

diff --git a/spec/util_hashring_spec.lua b/spec/util_hashring_spec.lua
new file mode 100644
index 00000000..d8801774
--- /dev/null
+++ b/spec/util_hashring_spec.lua
@@ -0,0 +1,85 @@
+local hashring = require "util.hashring";
+
+describe("util.hashring", function ()
+
+	local sha256 = require "util.hashes".sha256;
+
+	local ring = hashring.new(128, sha256);
+
+	it("should fail to get a node that does not exist", function ()
+		assert.is_nil(ring:get_node("foo"))
+	end);
+
+	it("should support adding nodes", function ()
+		ring:add_node("node1");
+	end);
+
+	it("should return a single node for all keys if only one node exists", function ()
+		for i = 1, 100 do
+			assert.is_equal("node1", ring:get_node(tostring(i)))
+		end
+	end);
+
+	it("should support adding a second node", function ()
+		ring:add_node("node2");
+	end);
+
+	it("should fail to remove a non-existent node", function ()
+		assert.is_falsy(ring:remove_node("node3"));
+	end);
+
+	it("should succeed to remove a node", function ()
+		assert.is_truthy(ring:remove_node("node1"));
+	end);
+
+	it("should return the only node for all keys", function ()
+		for i = 1, 100 do
+			assert.is_equal("node2", ring:get_node(tostring(i)))
+		end
+	end);
+
+	it("should support adding multiple nodes", function ()
+		ring:add_nodes({ "node1", "node3", "node4", "node5" });
+	end);
+
+	it("should disrupt a minimal number of keys on node removal", function ()
+		local orig_ring = ring:clone();
+		local node_tallies = {};
+
+		local n = 1000;
+
+		for i = 1, n do
+			local key = tostring(i);
+			local node = ring:get_node(key);
+			node_tallies[node] = (node_tallies[node] or 0) + 1;
+		end
+
+		--[[
+		for node, key_count in pairs(node_tallies) do
+			print(node, key_count, ("%.2f%%"):format((key_count/n)*100));
+		end
+		]]
+
+		ring:remove_node("node5");
+
+		local disrupted_keys = 0;
+		for i = 1, n do
+			local key = tostring(i);
+			if orig_ring:get_node(key) ~= ring:get_node(key) then
+				disrupted_keys = disrupted_keys + 1;
+			end
+		end
+		assert.is_equal(node_tallies["node5"], disrupted_keys);
+	end);
+
+	it("should support removing multiple nodes", function ()
+		ring:remove_nodes({"node2", "node3", "node4", "node5"});
+	end);
+
+	it("should return a single node for all keys if only one node remains", function ()
+		for i = 1, 100 do
+			assert.is_equal("node1", ring:get_node(tostring(i)))
+		end
+	end);
+
+end);
-- 
cgit v1.2.3


From 236abc4afed5321e0da406e369a8b23dac6fef83 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Thu, 30 May 2019 13:41:05 +0200
Subject: util.format: Handle formats expecting an integer in Lua 5.3+ (fixes
 #1371)

---
 spec/util_format_spec.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'spec')

diff --git a/spec/util_format_spec.lua b/spec/util_format_spec.lua
index b9652d19..82b70205 100644
--- a/spec/util_format_spec.lua
+++ b/spec/util_format_spec.lua
@@ -12,6 +12,7 @@ describe("util.format", function()
 			assert.equal("[true]", format("%d", true));
 			assert.equal("% [true]", format("%%", true));
 			assert.equal("{ }", format("%q", { }));
+			assert.equal("[1.5]", format("%d", 1.5));
 		end);
 	end);
 end);
-- 
cgit v1.2.3


From 2661a6f5a32731100287df9564c45cbe2406e0f0 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Thu, 30 May 2019 13:54:11 +0200
Subject: util.format: Handle integer formats the same way on Lua versions
 without integer support

---
 spec/util_format_spec.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'spec')

diff --git a/spec/util_format_spec.lua b/spec/util_format_spec.lua
index 82b70205..50509630 100644
--- a/spec/util_format_spec.lua
+++ b/spec/util_format_spec.lua
@@ -13,6 +13,7 @@ describe("util.format", function()
 			assert.equal("% [true]", format("%%", true));
 			assert.equal("{ }", format("%q", { }));
 			assert.equal("[1.5]", format("%d", 1.5));
+			assert.equal("[7.3786976294838e+19]", format("%d", 73786976294838206464));
 		end);
 	end);
 end);
-- 
cgit v1.2.3


From 56b07603dd018dc6cfd67bf0b34bb5539455a761 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Mon, 29 Jul 2019 00:51:03 +0200
Subject: util.array: Add tests

---
 spec/util_array_spec.lua | 154 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 154 insertions(+)
 create mode 100644 spec/util_array_spec.lua

(limited to 'spec')

diff --git a/spec/util_array_spec.lua b/spec/util_array_spec.lua
new file mode 100644
index 00000000..acd2e882
--- /dev/null
+++ b/spec/util_array_spec.lua
@@ -0,0 +1,154 @@
+local array = require "util.array";
+describe("util.array", function ()
+	describe("creation", function ()
+		describe("from tablle", function ()
+			it("works", function ()
+				local a = array({"a", "b", "c"});
+				assert.same({"a", "b", "c"}, a);
+			end);
+		end);
+
+		describe("from iterator", function ()
+			it("works", function ()
+				-- collects the first value, ie the keys
+				local a = array(ipairs({true, true, true}));
+				assert.same({1, 2, 3}, a);
+			end);
+		end);
+
+		describe("collect", function ()
+			it("works", function ()
+				-- collects the first value, ie the keys
+				local a = array.collect(ipairs({true, true, true}));
+				assert.same({1, 2, 3}, a);
+			end);
+		end);
+
+	end);
+
+	describe("metatable", function ()
+		describe("operator", function ()
+			describe("addition", function ()
+				it("works", function ()
+					local a = array({ "a", "b" });
+					local b = array({ "c", "d" });
+					assert.same({"a", "b", "c", "d"}, a + b);
+				end);
+			end);
+
+			describe("equality", function ()
+				it("works", function ()
+					local a1 = array({ "a", "b" });
+					local a2 = array({ "a", "b" });
+					local b = array({ "c", "d" });
+					assert.truthy(a1 == a2);
+					assert.falsy(a1 == b);
+				end);
+			end);
+
+			describe("division", function ()
+				it("works", function ()
+					local a = array({ "a", "b", "c" });
+					local b = a / function (i) if i ~= "b" then return i .. "x" end end;
+					assert.same({ "ax", "cx" }, b);
+				end);
+			end);
+
+		end);
+	end);
+
+	describe("methods", function ()
+		describe("map", function ()
+			it("works", function ()
+				local a = array({ "a", "b", "c" });
+				local b = a:map(string.upper);
+				assert.same({ "A", "B", "C" }, b);
+			end);
+		end);
+
+		describe("filter", function ()
+			it("works", function ()
+				local a = array({ "a", "b", "c" });
+				a:filter(function (i) return i ~= "b" end);
+				assert.same({ "a", "c" }, a);
+			end);
+		end);
+
+		describe("sort", function ()
+			it("works", function ()
+				local a = array({ 5, 4, 3, 1, 2, });
+				a:sort();
+				assert.same({ 1, 2, 3, 4, 5, }, a);
+			end);
+		end);
+
+		describe("unique", function ()
+			it("works", function ()
+				local a = array({ "a", "b", "c", "c", "a", "b" });
+				a:unique();
+				assert.same({ "a", "b", "c" }, a);
+			end);
+		end);
+
+		describe("pluck", function ()
+			it("works", function ()
+				local a = array({ { a = 1, b = -1 }, { a = 2, b = -2 }, });
+				a:pluck("a");
+				assert.same({ 1, 2 }, a);
+			end);
+		end);
+
+
+		describe("reverse", function ()
+			it("works", function ()
+				local a = array({ "a", "b", "c" });
+				a:reverse();
+				assert.same({ "c", "b", "a" }, a);
+			end);
+		end);
+
+		-- TODO :shuffle
+
+		describe("append", function ()
+			it("works", function ()
+				local a = array({ "a", "b", "c" });
+				a:append(array({ "d", "e", }));
+				assert.same({ "a", "b", "c", "d", "e" }, a);
+			end);
+		end);
+
+		describe("push", function ()
+			it("works", function ()
+				local a = array({ "a", "b", "c" });
+				a:push("d"):push("e");
+				assert.same({ "a", "b", "c", "d", "e" }, a);
+			end);
+		end);
+
+		describe("pop", function ()
+			it("works", function ()
+				local a = array({ "a", "b", "c" });
+				assert.equal("c", a:pop());
+				assert.same({ "a", "b", }, a);
+			end);
+		end);
+
+		describe("concat", function ()
+			it("works", function ()
+				local a = array({ "a", "b", "c" });
+				assert.equal("a,b,c", a:concat(","));
+			end);
+		end);
+
+		describe("length", function ()
+			it("works", function ()
+				local a = array({ "a", "b", "c" });
+				assert.equal(3, a:length());
+			end);
+		end);
+
+	end);
+
+	-- TODO The various array.foo(array ina, array outa) functions
+end);
+
-- 
cgit v1.2.3


From ab82920e54c61272770c93051deeb29396171228 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Mon, 29 Jul 2019 17:26:03 +0200
Subject: util.error: Add tests

---
 spec/util_error_spec.lua | 68 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100644 spec/util_error_spec.lua

(limited to 'spec')

diff --git a/spec/util_error_spec.lua b/spec/util_error_spec.lua
new file mode 100644
index 00000000..d8534c2b
--- /dev/null
+++ b/spec/util_error_spec.lua
@@ -0,0 +1,68 @@
+local errors = require "util.error"
+
+describe("util.error", function ()
+	describe("new()", function ()
+		it("works", function ()
+			local err = errors.new("bork", "bork bork");
+			assert.not_nil(err);
+			assert.equal("cancel", err.type);
+			assert.equal("undefined-condition", err.condition);
+			assert.same("bork bork", err.context);
+		end);
+
+		describe("templates", function ()
+			it("works", function ()
+				local templates = {
+					["fail"] = {
+						type = "wait",
+						condition = "internal-server-error",
+					};
+				};
+				local err = errors.new("fail", { traceback = "in some file, somewhere" }, templates);
+				assert.equal("wait", err.type);
+				assert.equal("internal-server-error", err.condition);
+				assert.same({ traceback = "in some file, somewhere" }, err.context);
+			end);
+		end);
+
+	end);
+
+	describe("is_err()", function ()
+		it("works", function ()
+			assert.truthy(errors.is_err(errors.new()));
+			assert.falsy(errors.is_err("not an error"));
+		end);
+	end);
+
+	describe("coerce", function ()
+		it("works", function ()
+			local ok, err = errors.coerce(nil, "it dun goofed");
+			assert.is_nil(ok);
+			assert.truthy(errors.is_err(err))
+		end);
+	end);
+
+	describe("from_stanza", function ()
+		it("works", function ()
+			local st = require "util.stanza";
+			local m = st.message({ type = "chat" });
+			local e = st.error_reply(m, "modify", "bad-request");
+			local err = errors.from_stanza(e);
+			assert.truthy(errors.is_err(err));
+			assert.equal("modify", err.type);
+			assert.equal("bad-request", err.condition);
+			assert.equal(e, err.context.stanza);
+		end);
+	end);
+
+	describe("__tostring", function ()
+		it("doesn't throw", function ()
+			assert.has_no.errors(function ()
+				-- See 6f317e51544d
+				tostring(errors.new());
+			end);
+		end);
+	end);
+
+end);
+
-- 
cgit v1.2.3


From 59c1712dfe1ba856aa8c3bd3e0dfa5c8db7ccec1 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 31 Aug 2019 16:04:50 +0200
Subject: MUC: Add a test covering basic room creation, messages and
 destruction

---
 spec/scansion/muc_create_destroy.scs | 242 +++++++++++++++++++++++++++++++++++
 1 file changed, 242 insertions(+)
 create mode 100644 spec/scansion/muc_create_destroy.scs

(limited to 'spec')

diff --git a/spec/scansion/muc_create_destroy.scs b/spec/scansion/muc_create_destroy.scs
new file mode 100644
index 00000000..b24ef4a2
--- /dev/null
+++ b/spec/scansion/muc_create_destroy.scs
@@ -0,0 +1,242 @@
+# MUC creation, basic messages and destruction
+
+[Client] Romeo
+	jid: romeo@localhost/mK0dD6Ha
+	password: password
+
+[Client] Juliet
+	jid: juliet@localhost/lVwkim_k
+	password: password
+
+-----
+
+Romeo connects
+
+Romeo sends:
+	<presence to="garden@conference.localhost/romeo">
+		<x xmlns="http://jabber.org/protocol/muc"/>
+	</presence>
+
+Romeo receives:
+	<presence from="garden@conference.localhost/romeo">
+		<x xmlns="vcard-temp:x:update"/>
+		<x xmlns="http://jabber.org/protocol/muc#user">
+			<status code="201"/>
+			<item affiliation="owner" jid="${Romeo's full JID}" role="moderator"/>
+			<status code="110"/>
+		</x>
+	</presence>
+
+Romeo receives:
+	<message from="garden@conference.localhost" type="groupchat">
+		<subject/>
+	</message>
+
+Romeo sends:
+	<iq to="garden@conference.localhost" id="lx3" type="set">
+		<query xmlns="http://jabber.org/protocol/muc#owner">
+			<x type="submit" xmlns="jabber:x:data"/>
+		</query>
+	</iq>
+
+Romeo receives:
+	<iq id="lx3" type="result" from="garden@conference.localhost"/>
+
+Juliet connects
+
+Romeo sends:
+	<message to="garden@conference.localhost" type="groupchat" id="rm1">
+		<body>Where are thou my Juliet?</body>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" from="garden@conference.localhost/romeo" id="rm1">
+		<body>Where are thou my Juliet?</body>
+	</message>
+
+Juliet sends:
+	<presence to="garden@conference.localhost/juliet">
+		<x xmlns="http://jabber.org/protocol/muc"/>
+	</presence>
+
+Juliet receives:
+	<presence from="garden@conference.localhost/romeo">
+		<x xmlns="vcard-temp:x:update"/>
+		<x xmlns="http://jabber.org/protocol/muc#user">
+			<item affiliation="owner" role="moderator"/>
+		</x>
+	</presence>
+
+Juliet receives:
+	<presence from="garden@conference.localhost/juliet">
+		<x xmlns="vcard-temp:x:update"/>
+		<x xmlns="http://jabber.org/protocol/muc#user">
+			<item affiliation="none" jid="${Juliet's full JID}" role="participant"/>
+			<status code="110"/>
+		</x>
+	</presence>
+
+Juliet receives:
+	<message from="garden@conference.localhost/romeo" id="rm1" type="groupchat">
+		<body>Where are thou my Juliet?</body>
+		<delay stamp="{scansion:any}" xmlns="urn:xmpp:delay" from="conference.localhost"/>
+		<x stamp="{scansion:any}" xmlns="jabber:x:delay" from="conference.localhost"/>
+	</message>
+
+Juliet receives:
+	<message from="garden@conference.localhost" type="groupchat">
+		<subject/>
+	</message>
+
+Romeo receives:
+	<presence from="garden@conference.localhost/juliet">
+		<x xmlns="vcard-temp:x:update"/>
+		<x xmlns="http://jabber.org/protocol/muc#user">
+			<item affiliation="none" jid="${Juliet's full JID}" role="participant"/>
+		</x>
+	</presence>
+
+Juliet sends:
+	<message to="garden@conference.localhost" type="groupchat" id="jm1">
+		<body>/me jumps out from behind a tree</body>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" id="jm1" from="garden@conference.localhost/juliet">
+		<body>/me jumps out from behind a tree</body>
+	</message>
+
+Juliet receives:
+	<message type="groupchat" id="jm1" from="garden@conference.localhost/juliet">
+		<body>/me jumps out from behind a tree</body>
+	</message>
+
+Juliet sends:
+	<message to="garden@conference.localhost" type="groupchat" id="jm2">
+		<body>Here I am!</body>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" id="jm2" from="garden@conference.localhost/juliet">
+		<body>Here I am!</body>
+	</message>
+
+Juliet receives:
+	<message type="groupchat" id="jm2" from="garden@conference.localhost/juliet">
+		<body>Here I am!</body>
+	</message>
+
+Romeo sends:
+	<message to="garden@conference.localhost" type="groupchat" id="rm2">
+		<body>What is this place?</body>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" id="rm2" from="garden@conference.localhost/romeo">
+		<body>What is this place?</body>
+	</message>
+
+Juliet receives:
+	<message type="groupchat" id="rm2" from="garden@conference.localhost/romeo">
+		<body>What is this place?</body>
+	</message>
+
+Juliet sends:
+	<message to="garden@conference.localhost" type="groupchat" id="jm3">
+		<body>I think we&apos;re in a script!</body>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" id="jm3" from="garden@conference.localhost/juliet">
+		<body>I think we&apos;re in a script!</body>
+	</message>
+
+Juliet receives:
+	<message type="groupchat" id="jm3" from="garden@conference.localhost/juliet">
+		<body>I think we&apos;re in a script!</body>
+	</message>
+
+Romeo sends:
+	<message to="garden@conference.localhost" type="groupchat" id="rm3">
+		<body>Oh no! Does that mean our love is not real?!</body>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" id="rm3" from="garden@conference.localhost/romeo">
+		<body>Oh no! Does that mean our love is not real?!</body>
+	</message>
+
+Juliet receives:
+	<message type="groupchat" id="rm3" from="garden@conference.localhost/romeo">
+		<body>Oh no! Does that mean our love is not real?!</body>
+	</message>
+
+Juliet sends:
+	<message to="garden@conference.localhost" type="groupchat" id="jm4">
+		<body>I refuse to accept this! Let&apos;s burn this place to the ground!</body>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" id="jm4" from="garden@conference.localhost/juliet">
+		<body>I refuse to accept this! Let&apos;s burn this place to the ground!</body>
+	</message>
+
+Juliet receives:
+	<message type="groupchat" id="jm4" from="garden@conference.localhost/juliet">
+		<body>I refuse to accept this! Let&apos;s burn this place to the ground!</body>
+	</message>
+
+Romeo sends:
+	<message to="garden@conference.localhost" type="groupchat" id="rm4">
+		<body>Yes!</body>
+	</message>
+
+Romeo receives:
+	<message type="groupchat" id="rm4" from="garden@conference.localhost/romeo">
+		<body>Yes!</body>
+	</message>
+
+Juliet receives:
+	<message type="groupchat" id="rm4" from="garden@conference.localhost/romeo">
+		<body>Yes!</body>
+	</message>
+
+Romeo sends:
+	<iq to="garden@conference.localhost" id="lx4" type="set">
+		<query xmlns="http://jabber.org/protocol/muc#owner">
+			<destroy>
+				<reason>We refuse to live in this fantasy!</reason>
+			</destroy>
+		</query>
+	</iq>
+
+Juliet receives:
+	<presence from="garden@conference.localhost/juliet" type="unavailable">
+		<x xmlns="http://jabber.org/protocol/muc#user">
+			<destroy>
+				<reason>We refuse to live in this fantasy!</reason>
+			</destroy>
+			<item affiliation="none" jid="${Juliet's full JID}" role="none"/>
+			<status code="110"/>
+		</x>
+	</presence>
+
+Romeo receives:
+	<presence from="garden@conference.localhost/romeo" type="unavailable">
+		<x xmlns="http://jabber.org/protocol/muc#user">
+			<destroy>
+				<reason>We refuse to live in this fantasy!</reason>
+			</destroy>
+			<item affiliation="owner" jid="${Romeo's full JID}" role="none"/>
+			<status code="110"/>
+		</x>
+	</presence>
+
+Romeo receives:
+	<iq id="lx4" type="result" from="garden@conference.localhost"/>
+
+Juliet disconnects
+
+Romeo disconnects
+
+# recording ended on 2019-08-31T13:45:32Z
-- 
cgit v1.2.3


From 887ccb25c5a26f7d645e626b3ad915cf84793dde Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 31 Aug 2019 16:15:51 +0200
Subject: MUC: Fix delay tag @from in test to be the room JID (#1054 came back)

---
 spec/scansion/muc_create_destroy.scs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/scansion/muc_create_destroy.scs b/spec/scansion/muc_create_destroy.scs
index b24ef4a2..4b16fbf2 100644
--- a/spec/scansion/muc_create_destroy.scs
+++ b/spec/scansion/muc_create_destroy.scs
@@ -79,8 +79,8 @@ Juliet receives:
 Juliet receives:
 	<message from="garden@conference.localhost/romeo" id="rm1" type="groupchat">
 		<body>Where are thou my Juliet?</body>
-		<delay stamp="{scansion:any}" xmlns="urn:xmpp:delay" from="conference.localhost"/>
-		<x stamp="{scansion:any}" xmlns="jabber:x:delay" from="conference.localhost"/>
+		<delay stamp="{scansion:any}" xmlns="urn:xmpp:delay" from="garden@conference.localhost"/>
+		<x stamp="{scansion:any}" xmlns="jabber:x:delay" from="garden@conference.localhost"/>
 	</message>
 
 Juliet receives:
-- 
cgit v1.2.3


From f724d890d28484d3c6d818b93c348019ce1256fb Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 7 Sep 2019 00:46:06 +0200
Subject: tests: Disable TLS in scansion tests

They were not using TLS before. With a36af4570b39 TLS context creation
will succeed even without a certificate, so TLS will be offered, but
since there is no certificate it does not work.
---
 spec/scansion/prosody.cfg.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/scansion/prosody.cfg.lua b/spec/scansion/prosody.cfg.lua
index fd742db6..1c359b27 100644
--- a/spec/scansion/prosody.cfg.lua
+++ b/spec/scansion/prosody.cfg.lua
@@ -8,7 +8,7 @@ modules_enabled = {
 	-- Generally required
 		"roster"; -- Allow users to have a roster. Recommended ;)
 		"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
-		"tls"; -- Add support for secure TLS on c2s/s2s connections
+		--"tls"; -- Add support for secure TLS on c2s/s2s connections
 		"dialback"; -- s2s dialback support
 		"disco"; -- Service discovery
 
-- 
cgit v1.2.3


From 52198503001e9e701fc89036972d7374ca14b249 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 21 Sep 2019 17:52:07 +0200
Subject: MUC: Update test for vcard-temp changes

Should this XEP-0398 behavior even be covered here?

The original lines came from a recording.
---
 spec/scansion/muc_create_destroy.scs | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

(limited to 'spec')

diff --git a/spec/scansion/muc_create_destroy.scs b/spec/scansion/muc_create_destroy.scs
index 4b16fbf2..9a66c160 100644
--- a/spec/scansion/muc_create_destroy.scs
+++ b/spec/scansion/muc_create_destroy.scs
@@ -19,7 +19,8 @@ Romeo sends:
 
 Romeo receives:
 	<presence from="garden@conference.localhost/romeo">
-		<x xmlns="vcard-temp:x:update"/>
+			<photo/>
+		</x>
 		<x xmlns="http://jabber.org/protocol/muc#user">
 			<status code="201"/>
 			<item affiliation="owner" jid="${Romeo's full JID}" role="moderator"/>
@@ -61,7 +62,9 @@ Juliet sends:
 
 Juliet receives:
 	<presence from="garden@conference.localhost/romeo">
-		<x xmlns="vcard-temp:x:update"/>
+		<x xmlns="vcard-temp:x:update">
+			<photo/>
+		</x>
 		<x xmlns="http://jabber.org/protocol/muc#user">
 			<item affiliation="owner" role="moderator"/>
 		</x>
@@ -69,7 +72,9 @@ Juliet receives:
 
 Juliet receives:
 	<presence from="garden@conference.localhost/juliet">
-		<x xmlns="vcard-temp:x:update"/>
+		<x xmlns="vcard-temp:x:update">
+			<photo/>
+		</x>
 		<x xmlns="http://jabber.org/protocol/muc#user">
 			<item affiliation="none" jid="${Juliet's full JID}" role="participant"/>
 			<status code="110"/>
@@ -90,7 +95,9 @@ Juliet receives:
 
 Romeo receives:
 	<presence from="garden@conference.localhost/juliet">
-		<x xmlns="vcard-temp:x:update"/>
+		<x xmlns="vcard-temp:x:update">
+			<photo/>
+		</x>
 		<x xmlns="http://jabber.org/protocol/muc#user">
 			<item affiliation="none" jid="${Juliet's full JID}" role="participant"/>
 		</x>
-- 
cgit v1.2.3


From 9f70749716ef88e9fa5017e41d6dfb7b177f6cea Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 21 Sep 2019 18:16:45 +0200
Subject: MUC: Fix XML syntax error in test

How did this even happen?
---
 spec/scansion/muc_create_destroy.scs | 1 +
 1 file changed, 1 insertion(+)

(limited to 'spec')

diff --git a/spec/scansion/muc_create_destroy.scs b/spec/scansion/muc_create_destroy.scs
index 9a66c160..fea759a3 100644
--- a/spec/scansion/muc_create_destroy.scs
+++ b/spec/scansion/muc_create_destroy.scs
@@ -19,6 +19,7 @@ Romeo sends:
 
 Romeo receives:
 	<presence from="garden@conference.localhost/romeo">
+		<x xmlns="vcard-temp:x:update">
 			<photo/>
 		</x>
 		<x xmlns="http://jabber.org/protocol/muc#user">
-- 
cgit v1.2.3


From 843104372c0ec065a89d09f25079f68b98314c31 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Mon, 30 Sep 2019 08:22:30 +0100
Subject: util.promise: Add some additional tests to cover callback return
 values

---
 spec/util_promise_spec.lua | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

(limited to 'spec')

diff --git a/spec/util_promise_spec.lua b/spec/util_promise_spec.lua
index 65d252f6..0008c6a2 100644
--- a/spec/util_promise_spec.lua
+++ b/spec/util_promise_spec.lua
@@ -248,6 +248,30 @@ describe("util.promise", function ()
 			assert.spy(cb3).was_called(1);
 			assert.spy(cb3).was_called_with("goodbye");
 		end);
+
+		it("ordinary values", function ()
+			local p = promise.resolve()
+			local cb = spy.new(function ()
+				return "hello"
+			end);
+			local cb2 = spy.new(function () end);
+			p:next(cb):next(cb2);
+			assert.spy(cb).was_called(1);
+			assert.spy(cb2).was_called(1);
+			assert.spy(cb2).was_called_with("hello");
+		end);
+
+		it("nil", function ()
+			local p = promise.resolve()
+			local cb = spy.new(function ()
+				return
+			end);
+			local cb2 = spy.new(function () end);
+			p:next(cb):next(cb2);
+			assert.spy(cb).was_called(1);
+			assert.spy(cb2).was_called(1);
+			assert.spy(cb2).was_called_with(nil);
+		end);
 	end);
 
 	describe("race()", function ()
-- 
cgit v1.2.3


From 8b19b4435f6feded2bfffa4ee5a11716579ec7ea Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 20 Oct 2019 20:53:41 +0200
Subject: util.interpolation: Test #1452

---
 spec/util_interpolation_spec.lua | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/util_interpolation_spec.lua b/spec/util_interpolation_spec.lua
index 88d9f844..9fcad469 100644
--- a/spec/util_interpolation_spec.lua
+++ b/spec/util_interpolation_spec.lua
@@ -1,5 +1,5 @@
 local template = [[
-{greet!}, {name?world}!
+{greet!?Hi}, {name?world}!
 ]];
 local expect1 = [[
 Hello, WORLD!
@@ -7,11 +7,15 @@ Hello, WORLD!
 local expect2 = [[
 Hello, world!
 ]];
+local expect3 = [[
+Hi, YOU!
+]];
 
 describe("util.interpolation", function ()
 	it("renders", function ()
 		local render = require "util.interpolation".new("%b{}", string.upper);
 		assert.equal(expect1, render(template, { greet = "Hello", name = "world" }));
 		assert.equal(expect2, render(template, { greet = "Hello" }));
+		assert.equal(expect3, render(template, { name = "you" }));
 	end);
 end);
-- 
cgit v1.2.3


From c0a72783661d8008519a0283ac7f107661f89c6b Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 20 Oct 2019 20:56:29 +0200
Subject: util.interpolation: Test array syntax

---
 spec/util_interpolation_spec.lua | 8 ++++++++
 1 file changed, 8 insertions(+)

(limited to 'spec')

diff --git a/spec/util_interpolation_spec.lua b/spec/util_interpolation_spec.lua
index 9fcad469..4106e10b 100644
--- a/spec/util_interpolation_spec.lua
+++ b/spec/util_interpolation_spec.lua
@@ -10,6 +10,13 @@ Hello, world!
 local expect3 = [[
 Hi, YOU!
 ]];
+local template_array = [[
+{foo#{idx}. {item}
+}]]
+local expect_array = [[
+1. HELLO
+2. WORLD
+]]
 
 describe("util.interpolation", function ()
 	it("renders", function ()
@@ -17,5 +24,6 @@ describe("util.interpolation", function ()
 		assert.equal(expect1, render(template, { greet = "Hello", name = "world" }));
 		assert.equal(expect2, render(template, { greet = "Hello" }));
 		assert.equal(expect3, render(template, { name = "you" }));
+		assert.equal(expect_array, render(template_array, { foo = { "Hello", "World" } }));
 	end);
 end);
-- 
cgit v1.2.3


From 9889cb8bb4c614939a4a82624b0e7e3539b80b63 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 20 Oct 2019 20:58:19 +0200
Subject: util.interpolation: Test map syntax

---
 spec/util_interpolation_spec.lua | 7 +++++++
 1 file changed, 7 insertions(+)

(limited to 'spec')

diff --git a/spec/util_interpolation_spec.lua b/spec/util_interpolation_spec.lua
index 4106e10b..eb49e53b 100644
--- a/spec/util_interpolation_spec.lua
+++ b/spec/util_interpolation_spec.lua
@@ -17,6 +17,12 @@ local expect_array = [[
 1. HELLO
 2. WORLD
 ]]
+local template_map = [[
+{foo%{idx}: {item!}
+}]]
+local expect_map = [[
+FOO: bar
+]]
 
 describe("util.interpolation", function ()
 	it("renders", function ()
@@ -25,5 +31,6 @@ describe("util.interpolation", function ()
 		assert.equal(expect2, render(template, { greet = "Hello" }));
 		assert.equal(expect3, render(template, { name = "you" }));
 		assert.equal(expect_array, render(template_array, { foo = { "Hello", "World" } }));
+		assert.equal(expect_map, render(template_map, { foo = { foo = "bar" } }));
 	end);
 end);
-- 
cgit v1.2.3


From b5b9b70c88a1287f034bceccdd953fe805bc78c6 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Sun, 27 Oct 2019 14:45:57 +0000
Subject: util.pubsub, pubsub.lib and tests: Add text to precondition-not-met
 error (fixes #1455)

---
 spec/scansion/pubsub_preconditions.scs | 234 +++++++++++++++++++++++++++++++++
 spec/util_pubsub_spec.lua              |   2 +-
 2 files changed, 235 insertions(+), 1 deletion(-)
 create mode 100644 spec/scansion/pubsub_preconditions.scs

(limited to 'spec')

diff --git a/spec/scansion/pubsub_preconditions.scs b/spec/scansion/pubsub_preconditions.scs
new file mode 100644
index 00000000..25afaa8d
--- /dev/null
+++ b/spec/scansion/pubsub_preconditions.scs
@@ -0,0 +1,234 @@
+# Pubsub preconditions are enforced
+
+[Client] Romeo
+	password: password
+	jid: jqpcrbq2@localhost
+
+-----
+
+Romeo connects
+
+Romeo sends:
+	<iq id="67eb1f47-1e69-4cb3-91e2-4d5943e72d4c" type="set">
+		<pubsub xmlns="http://jabber.org/protocol/pubsub">
+			<publish node="http://jabber.org/protocol/tune">
+				<item id="current">
+					<tune xmlns="http://jabber.org/protocol/tune"/>
+				</item>
+			</publish>
+		</pubsub>
+	</iq>
+
+Romeo receives:
+	<iq id="67eb1f47-1e69-4cb3-91e2-4d5943e72d4c" type="result">
+		<pubsub xmlns="http://jabber.org/protocol/pubsub">
+			<publish node="http://jabber.org/protocol/tune">
+				<item id="current"/>
+			</publish>
+		</pubsub>
+	</iq>
+
+Romeo sends:
+	<iq id="52d74a36-afb0-4028-87ed-b25b988b049e" type="get">
+		<pubsub xmlns="http://jabber.org/protocol/pubsub#owner">
+			<configure node="http://jabber.org/protocol/tune"/>
+		</pubsub>
+	</iq>
+
+Romeo receives:
+	<iq id="52d74a36-afb0-4028-87ed-b25b988b049e" type="result">
+		<pubsub xmlns="http://jabber.org/protocol/pubsub#owner">
+			<configure node="http://jabber.org/protocol/tune">
+				<x xmlns="jabber:x:data" type="form">
+					<field var="FORM_TYPE" type="hidden">
+						<value>http://jabber.org/protocol/pubsub#node_config</value>
+					</field>
+					<field var="pubsub#title" label="Title" type="text-single"/>
+					<field var="pubsub#description" label="Description" type="text-single"/>
+					<field var="pubsub#type" label="The type of node data, usually specified by the namespace of the payload (if any)" type="text-single"/>
+					<field var="pubsub#max_items" label="Max # of items to persist" type="text-single">
+						<validate xmlns="http://jabber.org/protocol/xdata-validate" datatype="xs:integer"/>
+						<value>1</value>
+					</field>
+					<field var="pubsub#persist_items" label="Persist items to storage" type="boolean">
+						<value>1</value>
+					</field>
+					<field var="pubsub#access_model" label="Specify the subscriber model" type="list-single">
+						<option label="authorize">
+							<value>authorize</value>
+						</option>
+						<option label="open">
+							<value>open</value>
+						</option>
+						<option label="presence">
+							<value>presence</value>
+						</option>
+						<option label="roster">
+							<value>roster</value>
+						</option>
+						<option label="whitelist">
+							<value>whitelist</value>
+						</option>
+						<value>presence</value>
+					</field>
+					<field var="pubsub#publish_model" label="Specify the publisher model" type="list-single">
+						<option label="publishers">
+							<value>publishers</value>
+						</option>
+						<option label="subscribers">
+							<value>subscribers</value>
+						</option>
+						<option label="open">
+							<value>open</value>
+						</option>
+						<value>publishers</value>
+					</field>
+					<field var="pubsub#deliver_notifications" label="Whether to deliver event notifications" type="boolean">
+						<value>1</value>
+					</field>
+					<field var="pubsub#deliver_payloads" label="Whether to deliver payloads with event notifications" type="boolean">
+						<value>1</value>
+					</field>
+					<field var="pubsub#notification_type" label="Specify the delivery style for notifications" type="list-single">
+						<option label="Messages of type normal">
+							<value>normal</value>
+						</option>
+						<option label="Messages of type headline">
+							<value>headline</value>
+						</option>
+						<value>headline</value>
+					</field>
+					<field var="pubsub#notify_delete" label="Whether to notify subscribers when the node is deleted" type="boolean">
+						<value>1</value>
+					</field>
+					<field var="pubsub#notify_retract" label="Whether to notify subscribers when items are removed from the node" type="boolean">
+						<value>1</value>
+					</field>
+				</x>
+			</configure>
+		</pubsub>
+	</iq>
+
+Romeo sends:
+	<iq id="a73aac09-74be-4ee2-97e5-571bbdbcd956" type="set">
+		<pubsub xmlns="http://jabber.org/protocol/pubsub#owner">
+			<configure node="http://jabber.org/protocol/tune">
+				<x xmlns="jabber:x:data" type="submit">
+					<field var="FORM_TYPE" type="hidden">
+						<value>http://jabber.org/protocol/pubsub#node_config</value>
+					</field>
+					<field var="pubsub#title" type="text-single" label="Title">
+						<value>Nice tunes</value>
+					</field>
+					<field var="pubsub#description" type="text-single" label="Description"/>
+					<field var="pubsub#type" type="text-single" label="The type of node data, usually specified by the namespace of the payload (if any)"/>
+					<field var="pubsub#max_items" type="text-single" label="Max # of items to persist">
+						<validate xmlns="http://jabber.org/protocol/xdata-validate" datatype="xs:integer"/>
+						<value>1</value>
+					</field>
+					<field var="pubsub#persist_items" type="boolean" label="Persist items to storage">
+						<value>1</value>
+					</field>
+					<field var="pubsub#access_model" type="list-single" label="Specify the subscriber model">
+						<option label="authorize">
+							<value>authorize</value>
+						</option>
+						<option label="open">
+							<value>open</value>
+						</option>
+						<option label="presence">
+							<value>presence</value>
+						</option>
+						<option label="roster">
+							<value>roster</value>
+						</option>
+						<option label="whitelist">
+							<value>whitelist</value>
+						</option>
+						<value>presence</value>
+					</field>
+					<field var="pubsub#publish_model" type="list-single" label="Specify the publisher model">
+						<option label="publishers">
+							<value>publishers</value>
+						</option>
+						<option label="subscribers">
+							<value>subscribers</value>
+						</option>
+						<option label="open">
+							<value>open</value>
+						</option>
+						<value>publishers</value>
+					</field>
+					<field var="pubsub#deliver_notifications" type="boolean" label="Whether to deliver event notifications">
+						<value>1</value>
+					</field>
+					<field var="pubsub#deliver_payloads" type="boolean" label="Whether to deliver payloads with event notifications">
+						<value>1</value>
+					</field>
+					<field var="pubsub#notification_type" type="list-single" label="Specify the delivery style for notifications">
+						<option label="Messages of type normal">
+							<value>normal</value>
+						</option>
+						<option label="Messages of type headline">
+							<value>headline</value>
+						</option>
+						<value>headline</value>
+					</field>
+					<field var="pubsub#notify_delete" type="boolean" label="Whether to notify subscribers when the node is deleted">
+						<value>1</value>
+					</field>
+					<field var="pubsub#notify_retract" type="boolean" label="Whether to notify subscribers when items are removed from the node">
+						<value>1</value>
+					</field>
+				</x>
+			</configure>
+		</pubsub>
+	</iq>
+
+Romeo receives:
+	<iq id="a73aac09-74be-4ee2-97e5-571bbdbcd956" type="result"/>
+
+Romeo sends:
+	<iq id="ab0e92d2-c06b-4987-9d45-f9f9e7721709" type="get">
+		<query xmlns="http://jabber.org/protocol/disco#items"/>
+	</iq>
+
+Romeo receives:
+	<iq id="ab0e92d2-c06b-4987-9d45-f9f9e7721709" type="result">
+		<query xmlns="http://jabber.org/protocol/disco#items">
+			<item name="Nice tunes" node="http://jabber.org/protocol/tune" jid="${Romeo's JID}"/>
+		</query>
+	</iq>
+
+Romeo sends:
+	<iq id="67eb1f47-1e69-4cb3-91e2-4d5943e72d4c" type="set">
+		<pubsub xmlns="http://jabber.org/protocol/pubsub">
+			<publish node="http://jabber.org/protocol/tune">
+				<item id="current">
+					<tune xmlns="http://jabber.org/protocol/tune"/>
+				</item>
+			</publish>
+			<publish-options>
+				<x xmlns="jabber:x:data">
+					<field var="FORM_TYPE" type="hidden">
+						<value>http://jabber.org/protocol/pubsub#publish-options</value>
+					</field>
+					<field var="pubsub#access_model">
+						<value>whitelist</value>
+					</field>
+				</x>
+			</publish-options>
+		</pubsub>
+	</iq>
+
+Romeo receives:
+	<iq type='error' id='67eb1f47-1e69-4cb3-91e2-4d5943e72d4c'>
+		<error type='cancel'>
+			<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
+			<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>Field does not match: access_model</text>
+			<precondition-not-met xmlns='http://jabber.org/protocol/pubsub#errors'/>
+		</error>
+	</iq>
+
+Romeo disconnects
+
diff --git a/spec/util_pubsub_spec.lua b/spec/util_pubsub_spec.lua
index c982fb36..a48bd400 100644
--- a/spec/util_pubsub_spec.lua
+++ b/spec/util_pubsub_spec.lua
@@ -107,7 +107,7 @@ describe("util.pubsub", function ()
 		it("fails to publish to a node with differing config", function ()
 			local ok, err = service:publish("node", true, "1", "item 2", { myoption = false });
 			assert.falsy(ok);
-			assert.equals("precondition-not-met", err);
+			assert.equals("precondition-not-met", err.pubsub_condition);
 		end);
 
 		it("allows to publish to a node with differing config when only defaults are suggested", function ()
-- 
cgit v1.2.3


From 03adb505558555cd2449bea0ae83c0a89c82a399 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Fri, 1 Nov 2019 18:31:12 +0100
Subject: util.error: Add well-known field 'code' in error templates

Intended to be for HTTP-ish numeric status codes
---
 spec/util_error_spec.lua | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'spec')

diff --git a/spec/util_error_spec.lua b/spec/util_error_spec.lua
index d8534c2b..ca053285 100644
--- a/spec/util_error_spec.lua
+++ b/spec/util_error_spec.lua
@@ -16,11 +16,13 @@ describe("util.error", function ()
 					["fail"] = {
 						type = "wait",
 						condition = "internal-server-error",
+						code = 555;
 					};
 				};
 				local err = errors.new("fail", { traceback = "in some file, somewhere" }, templates);
 				assert.equal("wait", err.type);
 				assert.equal("internal-server-error", err.condition);
+				assert.equal(555, err.code);
 				assert.same({ traceback = "in some file, somewhere" }, err.context);
 			end);
 		end);
-- 
cgit v1.2.3


From fb0fee842496d9cf89464479406352161f2888bd Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 2 Nov 2019 14:22:06 +0100
Subject: MUC: Make nickname field in registration form required

Prevents traceback from resourceprep(nil)

muc#register_roomnick is also required in XEP-0045
---
 spec/scansion/muc_register.scs | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/scansion/muc_register.scs b/spec/scansion/muc_register.scs
index e1eaf4e0..a077cd76 100644
--- a/spec/scansion/muc_register.scs
+++ b/spec/scansion/muc_register.scs
@@ -100,7 +100,9 @@ Juliet receives:
 				<field type='hidden' var='FORM_TYPE'>
 					<value>http://jabber.org/protocol/muc#register</value>
 				</field>
-				<field type='text-single' label='Nickname' var='muc#register_roomnick'/>
+				<field type='text-single' label='Nickname' var='muc#register_roomnick'>
+					<required/>
+				</field>
 			</x>
 		</query>
 	</iq>
@@ -339,7 +341,9 @@ Romeo receives:
 				<field type='hidden' var='FORM_TYPE'>
 					<value>http://jabber.org/protocol/muc#register</value>
 				</field>
-				<field type='text-single' label='Nickname' var='muc#register_roomnick'/>
+				<field type='text-single' label='Nickname' var='muc#register_roomnick'>
+					<required/>
+				</field>
 			</x>
 		</query>
 	</iq>
-- 
cgit v1.2.3


From a9980f81fadf325ed8f609ae3787c061dba63f94 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Thu, 7 Nov 2019 00:20:54 +0100
Subject: util.array: Fix typo in test

---
 spec/util_array_spec.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/util_array_spec.lua b/spec/util_array_spec.lua
index acd2e882..04d0cc28 100644
--- a/spec/util_array_spec.lua
+++ b/spec/util_array_spec.lua
@@ -1,7 +1,7 @@
 local array = require "util.array";
 describe("util.array", function ()
 	describe("creation", function ()
-		describe("from tablle", function ()
+		describe("from table", function ()
 			it("works", function ()
 				local a = array({"a", "b", "c"});
 				assert.same({"a", "b", "c"}, a);
-- 
cgit v1.2.3


From e0e0b24f003bcebc564fcebeb745717a4e08b5b7 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 17 Nov 2019 15:06:22 +0100
Subject: util.interpolation: Test template filters

---
 spec/util_interpolation_spec.lua | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/util_interpolation_spec.lua b/spec/util_interpolation_spec.lua
index eb49e53b..21d1abe0 100644
--- a/spec/util_interpolation_spec.lua
+++ b/spec/util_interpolation_spec.lua
@@ -17,6 +17,15 @@ local expect_array = [[
 1. HELLO
 2. WORLD
 ]]
+local template_func_pipe = [[
+{foo|sort#{idx}. {item}
+}]]
+local expect_func_pipe = [[
+1. A
+2. B
+3. C
+4. D
+]]
 local template_map = [[
 {foo%{idx}: {item!}
 }]]
@@ -26,11 +35,12 @@ FOO: bar
 
 describe("util.interpolation", function ()
 	it("renders", function ()
-		local render = require "util.interpolation".new("%b{}", string.upper);
+		local render = require "util.interpolation".new("%b{}", string.upper, { sort = function (t) table.sort(t) return t end });
 		assert.equal(expect1, render(template, { greet = "Hello", name = "world" }));
 		assert.equal(expect2, render(template, { greet = "Hello" }));
 		assert.equal(expect3, render(template, { name = "you" }));
 		assert.equal(expect_array, render(template_array, { foo = { "Hello", "World" } }));
+		assert.equal(expect_func_pipe, render(template_func_pipe, { foo = { "c", "a", "d", "b", } }));
 		assert.equal(expect_map, render(template_map, { foo = { foo = "bar" } }));
 	end);
 end);
-- 
cgit v1.2.3


From a7579e93f5833154aef8d67f068064d71b5dc731 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 17 Nov 2019 15:32:28 +0100
Subject: util.interpolation: Add commented test case for passing nil to filter

---
 spec/util_interpolation_spec.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'spec')

diff --git a/spec/util_interpolation_spec.lua b/spec/util_interpolation_spec.lua
index 21d1abe0..76000d94 100644
--- a/spec/util_interpolation_spec.lua
+++ b/spec/util_interpolation_spec.lua
@@ -41,6 +41,7 @@ describe("util.interpolation", function ()
 		assert.equal(expect3, render(template, { name = "you" }));
 		assert.equal(expect_array, render(template_array, { foo = { "Hello", "World" } }));
 		assert.equal(expect_func_pipe, render(template_func_pipe, { foo = { "c", "a", "d", "b", } }));
+		-- assert.equal("", render(template_func_pipe, { foo = nil })); -- FIXME
 		assert.equal(expect_map, render(template_map, { foo = { foo = "bar" } }));
 	end);
 end);
-- 
cgit v1.2.3


From 7ed435c0548a7c735c74234f081e267302970be6 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sun, 24 Nov 2019 00:02:48 +0100
Subject: MUC: Add testcase for #1466

---
 spec/scansion/muc_nickname_change.scs | 127 ++++++++++++++++++++++++++++++++++
 1 file changed, 127 insertions(+)
 create mode 100644 spec/scansion/muc_nickname_change.scs

(limited to 'spec')

diff --git a/spec/scansion/muc_nickname_change.scs b/spec/scansion/muc_nickname_change.scs
new file mode 100644
index 00000000..73f81203
--- /dev/null
+++ b/spec/scansion/muc_nickname_change.scs
@@ -0,0 +1,127 @@
+# MUC: Change nickname
+# Make sure a role is not reset, see #1466
+
+[Client] Romeo
+	jid: user@localhost
+	password: password
+
+[Client] Juliet
+	jid: user2@localhost
+	password: password
+
+-----
+
+Romeo connects
+
+Romeo sends:
+	<presence to="room@conference.localhost/Romeo">
+		<x xmlns="http://jabber.org/protocol/muc"/>
+	</presence>
+
+Romeo receives:
+	<presence from='room@conference.localhost/Romeo'>
+		<x xmlns='http://jabber.org/protocol/muc#user'>
+			<status code='201'/>
+			<item jid="${Romeo's full JID}" affiliation='owner' role='moderator'/>
+			<status code='110'/>
+		</x>
+	</presence>
+
+Romeo receives:
+	<message type='groupchat' from='room@conference.localhost'><subject/></message>
+
+Romeo sends:
+	<iq id='config1' to='room@conference.localhost' type='set'>
+		<query xmlns='http://jabber.org/protocol/muc#owner'>
+			<x xmlns='jabber:x:data' type='submit'>
+				<field var='FORM_TYPE'>
+					<value>http://jabber.org/protocol/muc#roomconfig</value>
+				</field>
+				<field var='muc#roomconfig_moderatedroom'>
+					<value>1</value>
+				</field>
+			</x>
+		</query>
+	</iq>
+
+Romeo receives:
+	<iq id="config1" from="room@conference.localhost" type="result"/>
+
+Juliet connects
+
+Juliet sends:
+	<presence to="room@conference.localhost/Juliet">
+		<x xmlns="http://jabber.org/protocol/muc"/>
+	</presence>
+
+Juliet receives:
+	<presence from='room@conference.localhost/Romeo'>
+		<x xmlns='http://jabber.org/protocol/muc#user'>
+			<item role='moderator' xmlns='http://jabber.org/protocol/muc#user' affiliation='owner'/>
+		</x>
+	</presence>
+
+Juliet receives:
+	<presence from='room@conference.localhost/Juliet'>
+		<x xmlns='http://jabber.org/protocol/muc#user'>
+			<item jid="${Juliet's full JID}" affiliation='none' role='visitor'/>
+			<status code='110'/>
+		</x>
+	</presence>
+
+
+Juliet receives:
+	<message type='groupchat' from='room@conference.localhost'><subject/></message>
+
+Romeo receives:
+	<presence from='room@conference.localhost/Juliet'>
+		<x xmlns='http://jabber.org/protocol/muc#user'>
+			<item affiliation="none" role="visitor" jid="${Juliet's full JID}"/>
+		</x>
+	</presence>
+
+Romeo sends:
+	<iq id='config1' to='room@conference.localhost' type='set'>
+		<query xmlns='http://jabber.org/protocol/muc#owner'>
+			<x xmlns='jabber:x:data' type='submit'>
+				<field var='FORM_TYPE'>
+					<value>http://jabber.org/protocol/muc#roomconfig</value>
+				</field>
+				<field var='muc#roomconfig_moderatedroom'>
+					<value>0</value>
+				</field>
+			</x>
+		</query>
+	</iq>
+
+Romeo receives:
+	<iq id="config1" from="room@conference.localhost" type="result"/>
+
+Juliet receives:
+	<message type='groupchat' from='room@conference.localhost'>
+		<x xmlns='http://jabber.org/protocol/muc#user'>
+			<status xmlns='http://jabber.org/protocol/muc#user' code='104'/>
+		</x>
+	</message>
+
+Juliet sends:
+	<presence to="room@conference.localhost/Juliet2">
+	</presence>
+
+Juliet receives:
+	<presence from='room@conference.localhost/Juliet' type='unavailable'>
+		<x xmlns='http://jabber.org/protocol/muc#user'>
+			<status code='303'/>
+			<item nick='Juliet2' jid="${Juliet's full JID}" affiliation='none' role='visitor'/>
+			<status code='110'/>
+		</x>
+	</presence>
+
+Juliet receives:
+	<presence from='room@conference.localhost/Juliet2'>
+		<x xmlns='http://jabber.org/protocol/muc#user'>
+			<item jid="${Juliet's full JID}" affiliation='none' role='visitor'/>
+			<status code='110'/>
+		</x>
+	</presence>
+
-- 
cgit v1.2.3


From b340e5e4628e2f5c136fe1f4300821d89ed4cb94 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Mon, 25 Nov 2019 20:44:05 +0100
Subject: util.stanza: Check that argument to reply is a stanza

---
 spec/util_stanza_spec.lua | 6 ++++++
 1 file changed, 6 insertions(+)

(limited to 'spec')

diff --git a/spec/util_stanza_spec.lua b/spec/util_stanza_spec.lua
index 38503ab7..7d710888 100644
--- a/spec/util_stanza_spec.lua
+++ b/spec/util_stanza_spec.lua
@@ -170,6 +170,12 @@ describe("util.stanza", function()
 			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 reject not-stanzas", function ()
+			assert.has.error_match(function ()
+				st.reply(not "a stanza");
+			end, "expected stanza");
+		end);
 	end);
 
 	describe("#error_reply()", function()
-- 
cgit v1.2.3


From 11095184a53cc144e37560b7bbbf4de19ce669c7 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Mon, 25 Nov 2019 20:46:55 +0100
Subject: util.stanza: Remove redundant check for attrs

A stanza can't not have attrs if created the correct way
---
 spec/util_stanza_spec.lua | 7 +++++++
 1 file changed, 7 insertions(+)

(limited to 'spec')

diff --git a/spec/util_stanza_spec.lua b/spec/util_stanza_spec.lua
index 7d710888..3b9084fa 100644
--- a/spec/util_stanza_spec.lua
+++ b/spec/util_stanza_spec.lua
@@ -176,6 +176,13 @@ describe("util.stanza", function()
 				st.reply(not "a stanza");
 			end, "expected stanza");
 		end);
+
+		it("should reject not-stanzas", function ()
+			assert.has.error_match(function ()
+				st.reply({name="x"});
+			end, "expected stanza");
+		end);
+
 	end);
 
 	describe("#error_reply()", function()
-- 
cgit v1.2.3


From 52b7181979bcee9000acf1c90e85934976e4da6a Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Mon, 25 Nov 2019 20:52:01 +0100
Subject: util.stanza: Check that argument to error_reply is a stanza

---
 spec/util_stanza_spec.lua | 6 ++++++
 1 file changed, 6 insertions(+)

(limited to 'spec')

diff --git a/spec/util_stanza_spec.lua b/spec/util_stanza_spec.lua
index 3b9084fa..23cdbeb9 100644
--- a/spec/util_stanza_spec.lua
+++ b/spec/util_stanza_spec.lua
@@ -214,6 +214,12 @@ describe("util.stanza", function()
 			assert.are.equal(#r.tags, 1);
 			assert.are.equal(r.tags[1].tags[1].name, "service-unavailable");
 		end);
+
+		it("should reject not-stanzas", function ()
+			assert.has.error_match(function ()
+				st.error_reply(not "a stanza", "modify", "bad-request");
+			end, "expected stanza");
+		end);
 	end);
 
 	describe("should reject #invalid", function ()
-- 
cgit v1.2.3


From 54da2ab6f7fec145d05ac8682c50a776bb993880 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Mon, 25 Nov 2019 20:52:03 +0100
Subject: util.stanza: Check that argument to error_reply is NOT a stanza of
 type error

Replying to an error is Very Bad
---
 spec/util_stanza_spec.lua | 10 ++++++++++
 1 file changed, 10 insertions(+)

(limited to 'spec')

diff --git a/spec/util_stanza_spec.lua b/spec/util_stanza_spec.lua
index 23cdbeb9..04458303 100644
--- a/spec/util_stanza_spec.lua
+++ b/spec/util_stanza_spec.lua
@@ -220,6 +220,16 @@ describe("util.stanza", function()
 				st.error_reply(not "a stanza", "modify", "bad-request");
 			end, "expected stanza");
 		end);
+
+		it("should reject stanzas of type error", function ()
+			assert.has.error_match(function ()
+				st.error_reply(st.message({type="error"}), "cancel", "conflict");
+			end, "got stanza of type error");
+			assert.has.error_match(function ()
+				st.error_reply(st.error_reply(st.message({type="chat"}), "modify", "forbidden"), "cancel", "service-unavailable");
+			end, "got stanza of type error");
+		end);
+
 	end);
 
 	describe("should reject #invalid", function ()
-- 
cgit v1.2.3


From be23b274f685f5eac73b79231491f4f0141f1c1c Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Mon, 25 Nov 2019 20:59:36 +0100
Subject: util.stanza: Support the 'by' attribute on errors

This is to be used when the entity generating the error is not the same
as the one the stanza was directed to, e.g. an intermediate server.
---
 spec/util_stanza_spec.lua | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/util_stanza_spec.lua b/spec/util_stanza_spec.lua
index 04458303..b754f59d 100644
--- a/spec/util_stanza_spec.lua
+++ b/spec/util_stanza_spec.lua
@@ -191,13 +191,14 @@ describe("util.stanza", function()
 			local s = st.stanza("s", { to = "touser", from = "fromuser", id = "123" })
 				:tag("child1");
 			-- Make reply stanza
-			local r = st.error_reply(s, "cancel", "service-unavailable");
+			local r = st.error_reply(s, "cancel", "service-unavailable", nil, "host");
 			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);
 			assert.are.equal(r.tags[1].tags[1].name, "service-unavailable");
+			assert.are.equal(r.tags[1].attr.by, "host");
 		end);
 
 		it("should work for <iq get>", function()
-- 
cgit v1.2.3


From 057fbeaf06876cfbfbba24bbc317de313fa9e84b Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Mon, 25 Nov 2019 23:47:49 +0100
Subject: MUC: Indicate origin of password related errors

---
 spec/scansion/muc_password.scs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/scansion/muc_password.scs b/spec/scansion/muc_password.scs
index 82611183..63c821e0 100644
--- a/spec/scansion/muc_password.scs
+++ b/spec/scansion/muc_password.scs
@@ -58,7 +58,7 @@ Juliet sends:
 
 Juliet receives:
 	<presence from="room@conference.localhost/Juliet" type="error">
-		<error type="auth" code="401">
+		<error type="auth" code="401" by="room@conference.localhost">
 			<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
 		</error>
 	</presence>
-- 
cgit v1.2.3


From c26f8beac4075c8d031ed9a620fac77653d1bb07 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Mon, 25 Nov 2019 23:51:41 +0100
Subject: MUC: Indicate origin of registration related errors

---
 spec/scansion/muc_register.scs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/scansion/muc_register.scs b/spec/scansion/muc_register.scs
index a077cd76..5d1f5f3e 100644
--- a/spec/scansion/muc_register.scs
+++ b/spec/scansion/muc_register.scs
@@ -177,7 +177,7 @@ Rosaline sends:
 
 Rosaline receives:
 	<presence type='error' from='room@conference.localhost/Juliet'>
-		<error type='cancel'>
+		<error type='cancel' by='room@conference.localhost'>
 			<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
 		</error>
 		<x xmlns='http://jabber.org/protocol/muc'/>
@@ -288,7 +288,7 @@ Rosaline sends:
 
 Rosaline receives:
 	<presence type='error' from='room@conference.localhost/Juliet'>
-		<error type='cancel'>
+		<error type='cancel' by='room@conference.localhost'>
 			<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
 		</error>
 		<x xmlns='http://jabber.org/protocol/muc'/>
-- 
cgit v1.2.3


From b1aadaced9b8012b55c8b9ee158bfaf6f24ea147 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 30 Nov 2019 14:00:13 +0100
Subject: tests: Disable s2s in scansion tests

These are all c2s tests, no need to have s2s enabled.
---
 spec/scansion/prosody.cfg.lua | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/scansion/prosody.cfg.lua b/spec/scansion/prosody.cfg.lua
index 1c359b27..3f804c4e 100644
--- a/spec/scansion/prosody.cfg.lua
+++ b/spec/scansion/prosody.cfg.lua
@@ -9,7 +9,7 @@ modules_enabled = {
 		"roster"; -- Allow users to have a roster. Recommended ;)
 		"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
 		--"tls"; -- Add support for secure TLS on c2s/s2s connections
-		"dialback"; -- s2s dialback support
+		--"dialback"; -- s2s dialback support
 		"disco"; -- Service discovery
 
 	-- Not essential, but recommended
@@ -53,6 +53,9 @@ modules_enabled = {
 		--"scansion_record"; -- Records things that happen in scansion test case format
 }
 
+modules_disabled = {
+	"s2s";
+}
 certificate = "certs"
 
 allow_registration = false
-- 
cgit v1.2.3


From 8d23fdfc77ff7ba88e749662dd3eaeefbf951f47 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Mon, 9 Dec 2019 11:57:10 +0000
Subject: configmanager tests: Split long line

---
 spec/core_configmanager_spec.lua | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/core_configmanager_spec.lua b/spec/core_configmanager_spec.lua
index afb7d492..7958ec6b 100644
--- a/spec/core_configmanager_spec.lua
+++ b/spec/core_configmanager_spec.lua
@@ -9,7 +9,9 @@ describe("core.configmanager", function()
 
 			configmanager.set("*", "testkey1", 321);
 			assert.are.equal(321, configmanager.get("*", "testkey1"), "Retrieving a set global key");
-			assert.are.equal(321, configmanager.get("example.com", "testkey1"), "Retrieving a set key of undefined host, of which only a globally set one exists");
+			assert.are.equal(321, configmanager.get("example.com", "testkey1"),
+				"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(321, configmanager.get("example.com", "testkey1"), "Retrieving a set key, of which only a globally set one exists");
-- 
cgit v1.2.3


From 75ff6ee528124979ae6a5a3b2f12d6f3d76eadd3 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Mon, 9 Dec 2019 12:43:32 +0000
Subject: net.http.parser tests: Expand tests to include validation of results

---
 spec/net_http_parser_spec.lua | 108 +++++++++++++++++++++++++++++++++---------
 1 file changed, 86 insertions(+), 22 deletions(-)

(limited to 'spec')

diff --git a/spec/net_http_parser_spec.lua b/spec/net_http_parser_spec.lua
index 6bba087c..8310a451 100644
--- a/spec/net_http_parser_spec.lua
+++ b/spec/net_http_parser_spec.lua
@@ -1,16 +1,68 @@
-local httpstreams = { [[
+local http_parser = require "net.http.parser";
+
+local function test_stream(stream, expect)
+	local success_cb = spy.new(function (packet)
+		assert.is_table(packet);
+		assert.is_equal(expect.body, packet.body);
+	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.spy(success_cb).was_called(expect.count or 1);
+end
+
+
+describe("net.http.parser", function()
+	describe("parser", function()
+		it("should handle requests with no content-length or body", function ()
+			test_stream(
+[[
 GET / HTTP/1.1
 Host: example.com
 
-]], [[
+]],
+				{
+					body = "";
+				}
+			);
+		end);
+
+		it("should handle responses with empty body", function ()
+			test_stream(
+[[
 HTTP/1.1 200 OK
 Content-Length: 0
 
-]], [[
+]],
+				{
+					body = "";
+				}
+			);
+		end);
+
+		it("should handle simple responses", function ()
+			test_stream(
+
+[[
 HTTP/1.1 200 OK
 Content-Length: 7
 
 Hello
+]],
+				{
+					body = "Hello\r\n", count = 1;
+				}
+			);
+		end);
+
+		it("should handle chunked encoding in responses", function ()
+			test_stream(
+
+[[
 HTTP/1.1 200 OK
 Transfer-Encoding: chunked
 
@@ -25,28 +77,40 @@ o
 0
 
 
-]]
-}
+]],
+				{
+					body = "Hello", count = 1;
+				}
+			);
+		end);
 
+		it("should handle a stream of responses", function ()
+			test_stream(
 
-local http_parser = require "net.http.parser";
+[[
+HTTP/1.1 200 OK
+Content-Length: 5
 
-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
+Hello
+HTTP/1.1 200 OK
+Transfer-Encoding: chunked
+
+1
+H
+1
+e
+2
+ll
+1
+o
+0
+
+
+]],
+				{
+					body = "Hello", count = 2;
+				}
+			);
 		end);
 	end);
 end);
-- 
cgit v1.2.3


From 71d99b65fa50afebb0241199d4000a8a7c50e1d1 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 14 Dec 2019 22:43:12 +0100
Subject: util.sasl: Add stub tests

Random uncommitted file I found when cleaning out my work dir
---
 spec/util_sasl_spec.lua | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 spec/util_sasl_spec.lua

(limited to 'spec')

diff --git a/spec/util_sasl_spec.lua b/spec/util_sasl_spec.lua
new file mode 100644
index 00000000..368291b3
--- /dev/null
+++ b/spec/util_sasl_spec.lua
@@ -0,0 +1,43 @@
+local sasl = require "util.sasl";
+
+-- profile * mechanism
+-- callbacks could use spies instead
+
+describe("util.sasl", function ()
+	describe("plain_test profile", function ()
+		local profile = {
+			plain_test = function (_, username, password, realm)
+				assert.equals("user", username)
+				assert.equals("pencil", password)
+				assert.equals("sasl.test", realm)
+				return true, true;
+			end;
+		};
+		it("works with PLAIN", function ()
+			local plain = sasl.new("sasl.test", profile);
+			assert.truthy(plain:select("PLAIN"));
+			assert.truthy(plain:process("\000user\000pencil"));
+			assert.equals("user", plain.username);
+		end);
+	end);
+
+	describe("plain profile", function ()
+		local profile = {
+			plain = function (_, username, realm)
+				assert.equals("user", username)
+				assert.equals("sasl.test", realm)
+				return "pencil", true;
+			end;
+		};
+
+		it("works with PLAIN", function ()
+			local plain = sasl.new("sasl.test", profile);
+			assert.truthy(plain:select("PLAIN"));
+			assert.truthy(plain:process("\000user\000pencil"));
+			assert.equals("user", plain.username);
+		end);
+
+		-- TODO SCRAM
+	end);
+end);
+
-- 
cgit v1.2.3


From 4e34c40ece0eb19f85720d63b1b0372f59e5616d Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Sat, 14 Dec 2019 22:47:41 +0100
Subject: util.stanza: Accept util.error object to error_reply

If we're moving towards util.error as the standard error container then
this makes sense.

This may allow for future extensibility without needing a lot of
optional arguments.
---
 spec/util_stanza_spec.lua | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

(limited to 'spec')

diff --git a/spec/util_stanza_spec.lua b/spec/util_stanza_spec.lua
index b754f59d..d38a609f 100644
--- a/spec/util_stanza_spec.lua
+++ b/spec/util_stanza_spec.lua
@@ -1,5 +1,6 @@
 
 local st = require "util.stanza";
+local errors = require "util.error";
 
 describe("util.stanza", function()
 	describe("#preserialize()", function()
@@ -231,6 +232,22 @@ describe("util.stanza", function()
 			end, "got stanza of type error");
 		end);
 
+		it("should accept util.error objects", function ()
+			local s = st.message({ to = "touser", from = "fromuser", id = "123", type = "chat" }, "Hello");
+			local e = errors.new({ type = "modify", condition = "not-acceptable", text = "Bork bork bork" });
+			local r = st.error_reply(s, e);
+
+			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].name, "error");
+			assert.are.equal(r.tags[1].attr.type, e.type);
+			assert.are.equal(r.tags[1].tags[1].name, e.condition);
+			assert.are.equal(r.tags[1].tags[2]:get_text(), e.text);
+		end);
+
 	end);
 
 	describe("should reject #invalid", function ()
-- 
cgit v1.2.3


From 6b533ad772fb32d00a2f87cb53a87ee9f3a6d689 Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Mon, 16 Dec 2019 02:02:47 +0100
Subject: util.dataforms: Improve descriptions in tests

---
 spec/util_dataforms_spec.lua | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

(limited to 'spec')

diff --git a/spec/util_dataforms_spec.lua b/spec/util_dataforms_spec.lua
index 89759035..085128d1 100644
--- a/spec/util_dataforms_spec.lua
+++ b/spec/util_dataforms_spec.lua
@@ -110,7 +110,7 @@ describe("util.dataforms", function ()
 		xform = some_form:form();
 	end);
 
-	it("works", function ()
+	it("XML serialization looks like it should", function ()
 		assert.truthy(xform);
 		assert.truthy(st.is_stanza(xform));
 		assert.equal("x", xform.name);
@@ -316,7 +316,7 @@ describe("util.dataforms", function ()
 	end);
 
 	describe(":data", function ()
-		it("works", function ()
+		it("returns something", function ()
 			assert.truthy(some_form:data(xform));
 		end);
 	end);
@@ -402,7 +402,7 @@ describe("util.dataforms", function ()
 		end);
 	end);
 
-	describe("validation", function ()
+	describe("datatype validation", function ()
 		local f = dataforms.new {
 			{
 				name = "number",
@@ -411,12 +411,12 @@ describe("util.dataforms", function ()
 			},
 		};
 
-		it("works", function ()
+		it("integer roundtrip works", function ()
 			local d = f:data(f:form({number = 1}));
 			assert.equal(1, d.number);
 		end);
 
-		it("works", function ()
+		it("integer error handling works", function ()
 			local d,e = f:data(f:form({number = "nan"}));
 			assert.not_equal(1, d.number);
 			assert.table(e);
-- 
cgit v1.2.3


From 173990157fad6d4507e8ce2dc214e7bf35a17822 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Thu, 19 Dec 2019 10:03:16 +0000
Subject: rostermanager, mod_presence: Support for subscription preapproval
 (fixes #686)

---
 spec/scansion/presence_preapproval.scs | 74 ++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 spec/scansion/presence_preapproval.scs

(limited to 'spec')

diff --git a/spec/scansion/presence_preapproval.scs b/spec/scansion/presence_preapproval.scs
new file mode 100644
index 00000000..ce6158d2
--- /dev/null
+++ b/spec/scansion/presence_preapproval.scs
@@ -0,0 +1,74 @@
+# server supports contact subscription pre-approval (RFC 6121 3.4)
+
+[Client] Alice
+	jid: preappove-a@localhost
+	password: password
+
+[Client] Bob
+	jid: preapprove-b@localhost
+	password: password
+
+---------
+
+Alice connects
+
+Alice sends:
+	<presence/>
+
+Alice receives:
+	<presence/>
+
+Alice sends:
+	<presence to="${Bob's JID}" type="subscribed"/>
+
+Bob connects
+
+Bob sends:
+	<iq type="get" id="roster1">
+		<query xmlns="jabber:iq:roster"/>
+	</iq>
+
+Bob receives:
+	<iq type="result" id="roster1">
+		<query xmlns="jabber:iq:roster" ver="{scansion:any}">
+		</query>
+	</iq>
+
+Bob sends:
+	<presence/>
+
+Bob receives:
+	<presence from="${Bob's full JID}"/>
+	
+Bob sends:
+	<presence to="${Alice's JID}" type="subscribe" />
+
+Bob receives:
+	<iq type='set' id='{scansion:any}'>
+		<query ver='1' xmlns='jabber:iq:roster'>
+			<item jid="${Alice's JID}" subscription='none' ask='subscribe' />
+		</query>
+	</iq>
+
+	                                                    
+
+Bob receives:
+	<presence from="${Alice's JID}" type="subscribed" />
+
+Bob disconnects
+
+Alice sends:
+	<iq type="get" id="roster1">
+		<query xmlns="jabber:iq:roster"/>
+	</iq>
+
+Alice receives:
+	<iq type="result" id="roster1">
+		<query xmlns="jabber:iq:roster" ver="{scansion:any}">
+			<item jid="${Bob's JID}" subscription="from" />
+		</query>
+	</iq>
+
+Alice disconnects
+
+Bob disconnects
-- 
cgit v1.2.3


From 228ec67d9790822defd4cf7d64bb1de6f479f0aa Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Thu, 19 Dec 2019 16:22:12 +0100
Subject: scansion: Trim trailing whitespace in tests

---
 spec/scansion/basic_message.scs           | 6 +++---
 spec/scansion/keep_full_sub_req.scs       | 2 +-
 spec/scansion/muc_members_only_change.scs | 2 +-
 spec/scansion/muc_register.scs            | 2 +-
 spec/scansion/presence_preapproval.scs    | 4 ++--
 spec/scansion/pubsub_basic.scs            | 2 +-
 6 files changed, 9 insertions(+), 9 deletions(-)

(limited to 'spec')

diff --git a/spec/scansion/basic_message.scs b/spec/scansion/basic_message.scs
index fb21c465..1258dbf5 100644
--- a/spec/scansion/basic_message.scs
+++ b/spec/scansion/basic_message.scs
@@ -79,7 +79,7 @@ Juliet's phone receives:
 	<message from="${Romeo's full JID}" type="chat">
 		<body>Hello Juliet, are you there?</body>
 		<delay xmlns='urn:xmpp:delay' from='localhost' stamp='{scansion:any}' />
-	</message>	
+	</message>
 
 # Romeo sends another bare-JID message, it should be delivered
 # instantly to Juliet's phone
@@ -92,7 +92,7 @@ Romeo sends:
 Juliet's phone receives:
 	<message from="${Romeo's full JID}" type="chat">
 		<body>Oh, hi!</body>
-	</message>	
+	</message>
 
 # Juliet's laptop goes online, but with a negative priority
 
@@ -122,7 +122,7 @@ Romeo sends:
 Juliet's phone receives:
 	<message from="${Romeo's full JID}" type="chat">
 		<body>How are you?</body>
-	</message>	
+	</message>
 
 # Romeo sends direct to Juliet's full JID, and she should receive it
 
diff --git a/spec/scansion/keep_full_sub_req.scs b/spec/scansion/keep_full_sub_req.scs
index 244c1d55..41ffec0d 100644
--- a/spec/scansion/keep_full_sub_req.scs
+++ b/spec/scansion/keep_full_sub_req.scs
@@ -30,7 +30,7 @@ Bob sends:
 
 Bob receives:
 	<presence from="${Bob's full JID}"/>
-	
+
 Bob receives:
 	<presence from="${Alice's JID}" type="subscribe">
 		<preauth xmlns="urn:xmpp:pars:0" token="1tMFqYDdKhfe2pwp" />
diff --git a/spec/scansion/muc_members_only_change.scs b/spec/scansion/muc_members_only_change.scs
index dc40b5a0..a708dbfb 100644
--- a/spec/scansion/muc_members_only_change.scs
+++ b/spec/scansion/muc_members_only_change.scs
@@ -94,7 +94,7 @@ Romeo sends:
 			<item affiliation='none' jid="${Juliet's JID}" />
 		</query>
 	</iq>
-	
+
 # As a non-member, Juliet must now be removed from the room
 Romeo receives:
 	<presence type='unavailable' from='room@conference.localhost/Juliet'>
diff --git a/spec/scansion/muc_register.scs b/spec/scansion/muc_register.scs
index 5d1f5f3e..81612829 100644
--- a/spec/scansion/muc_register.scs
+++ b/spec/scansion/muc_register.scs
@@ -328,7 +328,7 @@ Romeo receives:
 	</iq>
 
 # Romeo updates his own registration
-	
+
 Romeo sends:
 	<iq id='jw81b36f' to='room@conference.localhost' type='get'>
 		<query xmlns='jabber:iq:register'/>
diff --git a/spec/scansion/presence_preapproval.scs b/spec/scansion/presence_preapproval.scs
index ce6158d2..e34ac7cf 100644
--- a/spec/scansion/presence_preapproval.scs
+++ b/spec/scansion/presence_preapproval.scs
@@ -39,7 +39,7 @@ Bob sends:
 
 Bob receives:
 	<presence from="${Bob's full JID}"/>
-	
+
 Bob sends:
 	<presence to="${Alice's JID}" type="subscribe" />
 
@@ -50,7 +50,7 @@ Bob receives:
 		</query>
 	</iq>
 
-	                                                    
+
 
 Bob receives:
 	<presence from="${Alice's JID}" type="subscribed" />
diff --git a/spec/scansion/pubsub_basic.scs b/spec/scansion/pubsub_basic.scs
index d983ff66..0adf6857 100644
--- a/spec/scansion/pubsub_basic.scs
+++ b/spec/scansion/pubsub_basic.scs
@@ -32,7 +32,7 @@ Juliet connects
 -- 			<subscribe node="princely_musings" jid="${Romeo's full JID}"/>
 -- 		</pubsub>
 -- 	</iq>
--- 
+--
 -- Juliet receives:
 -- 	<iq type="error"/>
 
-- 
cgit v1.2.3


From e0bcb4d7d43745ce677edabc1cebe6a53644723d Mon Sep 17 00:00:00 2001
From: Kim Alvefur <zash@zash.se>
Date: Mon, 23 Dec 2019 21:33:10 +0100
Subject: tests: Silence [luacheck] warnings

---
 spec/core_storagemanager_spec.lua | 6 ++++++
 spec/util_async_spec.lua          | 2 ++
 spec/util_pubsub_spec.lua         | 6 ++++++
 3 files changed, 14 insertions(+)

(limited to 'spec')

diff --git a/spec/core_storagemanager_spec.lua b/spec/core_storagemanager_spec.lua
index fd2f8742..c3534cd5 100644
--- a/spec/core_storagemanager_spec.lua
+++ b/spec/core_storagemanager_spec.lua
@@ -119,6 +119,7 @@ describe("storagemanager", function ()
 
 				describe("can be queried", function ()
 					it("for all items", function ()
+						-- luacheck: ignore 211/err
 						local data, err = archive:find("user", {});
 						assert.truthy(data);
 						local count = 0;
@@ -135,6 +136,7 @@ describe("storagemanager", function ()
 					end);
 
 					it("by JID", function ()
+						-- luacheck: ignore 211/err
 						local data, err = archive:find("user", {
 							with = "contact@example.com";
 						});
@@ -153,6 +155,7 @@ describe("storagemanager", function ()
 					end);
 
 					it("by time (end)", function ()
+						-- luacheck: ignore 211/err
 						local data, err = archive:find("user", {
 							["end"] = test_time;
 						});
@@ -171,6 +174,7 @@ describe("storagemanager", function ()
 					end);
 
 					it("by time (start)", function ()
+						-- luacheck: ignore 211/err
 						local data, err = archive:find("user", {
 							["start"] = test_time;
 						});
@@ -189,6 +193,7 @@ describe("storagemanager", function ()
 					end);
 
 					it("by time (start+end)", function ()
+						-- luacheck: ignore 211/err
 						local data, err = archive:find("user", {
 							["start"] = test_time;
 							["end"] = test_time+1;
@@ -239,6 +244,7 @@ describe("storagemanager", function ()
 				end);
 
 				it("can be purged", function ()
+					-- luacheck: ignore 211/err
 					local ok, err = archive:delete("user");
 					assert.truthy(ok);
 					local data, err = archive:find("user", {
diff --git a/spec/util_async_spec.lua b/spec/util_async_spec.lua
index d2de8c94..8123503b 100644
--- a/spec/util_async_spec.lua
+++ b/spec/util_async_spec.lua
@@ -544,6 +544,8 @@ describe("util.async", function()
 			assert.equal(r1.state, "ready");
 		end);
 
+		-- luacheck: ignore 211/rf
+		-- FIXME what's rf?
 		it("should support multiple done() calls", function ()
 			local processed_item;
 			local wait, done;
diff --git a/spec/util_pubsub_spec.lua b/spec/util_pubsub_spec.lua
index a48bd400..75f893e3 100644
--- a/spec/util_pubsub_spec.lua
+++ b/spec/util_pubsub_spec.lua
@@ -101,6 +101,7 @@ describe("util.pubsub", function ()
 			assert(service:publish("node", true, "1", "item 1", { myoption = true }));
 
 			local ok, config = assert(service:get_node_config("node", true));
+			assert.truthy(ok);
 			assert.equals(true, config.myoption);
 		end);
 
@@ -229,6 +230,7 @@ describe("util.pubsub", function ()
 			end);
 			it("should be the default", function ()
 				local ok, config = service:get_node_config("test", true);
+				assert.truthy(ok);
 				assert.equal("open", config.access_model);
 			end);
 			it("should allow anyone to subscribe", function ()
@@ -250,6 +252,7 @@ describe("util.pubsub", function ()
 			end);
 			it("should be present in the configuration", function ()
 				local ok, config = service:get_node_config("test", true);
+				assert.truthy(ok);
 				assert.equal("whitelist", config.access_model);
 			end);
 			it("should not allow anyone to subscribe", function ()
@@ -294,6 +297,7 @@ describe("util.pubsub", function ()
 			end);
 			it("should be the default", function ()
 				local ok, config = service:get_node_config("test", true);
+				assert.truthy(ok);
 				assert.equal("publishers", config.publish_model);
 			end);
 			it("should not allow anyone to publish", function ()
@@ -304,6 +308,7 @@ describe("util.pubsub", function ()
 			end);
 			it("should allow publishers to publish", function ()
 				assert(service:set_affiliation("test", true, "mypublisher", "publisher"));
+				-- luacheck: ignore 211/err
 				local ok, err = service:publish("test", "mypublisher", "item1", "foo");
 				assert.is_true(ok);
 			end);
@@ -342,6 +347,7 @@ describe("util.pubsub", function ()
 			end);
 			it("should allow publishers to publish without a subscription", function ()
 				assert(service:set_affiliation("test", true, "mypublisher", "publisher"));
+				-- luacheck: ignore 211/err
 				local ok, err = service:publish("test", "mypublisher", "item1", "foo");
 				assert.is_true(ok);
 			end);
-- 
cgit v1.2.3