IMPORTANT: due to a drive failure, as of 13-Mar-2021, the Mercurial repository had to be re-mirrored, which changed every commit SHA. The old SHAs and trees are backed up in the vault branches. Please migrate to the new branches as soon as you can.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
prosody/spec/util_datamapper_spec.lua

244 lines
6.8 KiB

local st
local xml
local map
setup(function()
st = require "util.stanza";
xml = require "util.xml";
map = require "util.datamapper";
end);
describe("util.datamapper", function()
local s, x, d
local disco, disco_info, disco_schema
setup(function()
-- a convenience function for simple attributes, there's a few of them
local attr = {["$ref"]="#/$defs/attr"};
s = {
["$defs"] = { attr = { type = "string"; xml = { attribute = true } } };
type = "object";
xml = {name = "message"; namespace = "jabber:client"};
properties = {
to = attr;
from = attr;
type = attr;
id = attr;
body = true; -- should be assumed to be a string
lang = {type = "string"; xml = {attribute = true; prefix = "xml"}};
delay = {
type = "object";
xml = {namespace = "urn:xmpp:delay"; name = "delay"};
properties = {stamp = attr; from = attr; reason = {type = "string"; xml = {text = true}}};
};
state = {
type = "string";
enum = {
"active",
"inactive",
"gone",
"composing",
"paused",
};
xml = {x_name_is_value = true; namespace = "http://jabber.org/protocol/chatstates"};
};
fallback = {
type = "boolean";
xml = {x_name_is_value = true; name = "fallback"; namespace = "urn:xmpp:fallback:0"};
};
origin_id = {
type = "string";
xml = {name = "origin-id"; namespace = "urn:xmpp:sid:0"; x_single_attribute = "id"};
};
react = {
type = "object";
xml = {namespace = "urn:xmpp:reactions:0"; name = "reactions"};
properties = {
to = {type = "string"; xml = {attribute = true; name = "id"}};
-- should be assumed to be array since it has 'items'
reactions = { items = { xml = { name = "reaction" } } };
};
};
stanza_ids = {
type = "array";
items = {
xml = {name = "stanza-id"; namespace = "urn:xmpp:sid:0"};
type = "object";
properties = {
id = attr;
by = attr;
};
};
};
};
};
x = xml.parse [[
<message xmlns="jabber:client" xml:lang="en" to="a@test" from="b@test" type="chat" id="1">
<body>Hello</body>
<delay xmlns='urn:xmpp:delay' from='test' stamp='2021-03-07T15:59:08+00:00'>Because</delay>
<UNRELATED xmlns='http://jabber.org/protocol/chatstates'/>
<active xmlns='http://jabber.org/protocol/chatstates'/>
<fallback xmlns='urn:xmpp:fallback:0'/>
<origin-id xmlns='urn:xmpp:sid:0' id='qgkmMdPB'/>
<stanza-id xmlns='urn:xmpp:sid:0' id='abc1' by='muc'/>
<stanza-id xmlns='urn:xmpp:sid:0' id='xyz2' by='host'/>
<reactions id='744f6e18-a57a-11e9-a656-4889e7820c76' xmlns='urn:xmpp:reactions:0'>
<reaction>👋</reaction>
<reaction>🐢</reaction>
</reactions>
</message>
]];
d = {
to = "a@test";
from = "b@test";
type = "chat";
id = "1";
lang = "en";
body = "Hello";
delay = {from = "test"; stamp = "2021-03-07T15:59:08+00:00"; reason = "Because"};
state = "active";
fallback = true;
origin_id = "qgkmMdPB";
stanza_ids = {{id = "abc1"; by = "muc"}; {id = "xyz2"; by = "host"}};
react = {
to = "744f6e18-a57a-11e9-a656-4889e7820c76";
reactions = {
"👋",
"🐢",
};
};
};
disco_schema = {
["$defs"] = { attr = { type = "string"; xml = { attribute = true } } };
type = "object";
xml = {
name = "iq";
namespace = "jabber:client"
};
properties = {
to = attr;
from = attr;
type = attr;
id = attr;
disco = {
type = "object";
xml = {
name = "query";
namespace = "http://jabber.org/protocol/disco#info"
};
properties = {
features = {
type = "array";
items = {
type = "string";
xml = {
name = "feature";
x_single_attribute = "var";
};
};
};
};
};
};
};
disco_info = xml.parse[[
<iq type="result" id="disco1" from="example.com">
<query xmlns="http://jabber.org/protocol/disco#info">
<feature var="urn:example:feature:1">wrong</feature>
<feature var="urn:example:feature:2"/>
<feature var="urn:example:feature:3"/>
<unrelated var="urn:example:feature:not"/>
</query>
</iq>
]];
disco = {
type="result";
id="disco1";
from="example.com";
disco = {
features = {
"urn:example:feature:1";
"urn:example:feature:2";
"urn:example:feature:3";
};
};
};
end);
describe("parse", function()
it("works", function()
assert.same(d, map.parse(s, x));
end);
it("handles arrays", function ()
assert.same(disco, map.parse(disco_schema, disco_info));
end);
it("deals with locally built stanzas", function()
-- FIXME this could also be argued to be a util.stanza problem
local ver_schema = {
type = "object";
xml = {name = "iq"};
properties = {
type = {type = "string"; xml = {attribute = true}};
id = {type = "string"; xml = {attribute = true}};
version = {
type = "object";
xml = {name = "query"; namespace = "jabber:iq:version"};
-- properties should be assumed to be strings
properties = {name = true; version = {}; os = {}};
};
};
};
local ver_st = st.iq({type = "result"; id = "v1"})
:query("jabber:iq:version")
:text_tag("name", "Prosody")
:text_tag("version", "trunk")
:text_tag("os", "Lua 5.3")
:reset();
local data = {type = "result"; id = "v1"; version = {name = "Prosody"; version = "trunk"; os = "Lua 5.3"}}
assert.same(data, map.parse(ver_schema, ver_st));
end);
end);
describe("unparse", function()
it("works", function()
local u = map.unparse(s, d);
assert.equal("message", u.name);
assert.same(x.attr, u.attr);
assert.equal(x:get_child_text("body"), u:get_child_text("body"));
assert.equal(x:get_child_text("delay", "urn:xmpp:delay"), u:get_child_text("delay", "urn:xmpp:delay"));
assert.same(x:get_child("delay", "urn:xmpp:delay").attr, u:get_child("delay", "urn:xmpp:delay").attr);
assert.same(x:get_child("origin-id", "urn:xmpp:sid:0").attr, u:get_child("origin-id", "urn:xmpp:sid:0").attr);
assert.same(x:get_child("reactions", "urn:xmpp:reactions:0").attr, u:get_child("reactions", "urn:xmpp:reactions:0").attr);
assert.same(2, #u:get_child("reactions", "urn:xmpp:reactions:0").tags);
for _, tag in ipairs(x.tags) do
if tag.name ~= "UNRELATED" then
assert.truthy(u:get_child(tag.name, tag.attr.xmlns) or u:get_child(tag.name), tag:top_tag())
end
end
assert.equal(#x.tags-1, #u.tags)
end);
it("handles arrays", function ()
local u = map.unparse(disco_schema, disco);
assert.equal("urn:example:feature:1", u:find("{http://jabber.org/protocol/disco#info}query/feature/@var"))
local n = 0;
for child in u:get_child("query", "http://jabber.org/protocol/disco#info"):childtags("feature") do
n = n + 1;
assert.equal(string.format("urn:example:feature:%d", n), child.attr.var);
end
end);
end);
end)