mirror of
https://github.com/bjc/prosody.git
synced 2025-04-01 20:27:39 +03:00
Sometimes you only care about a single attribute, but the child tag itself may be optional, leading to needing `tag and tag.attr.foo` or `stanza:find("tag@foo")`. The `:find()` method is fairly complex, so avoiding it for this kind of simpler use case is a win.
512 lines
14 KiB
Lua
512 lines
14 KiB
Lua
local dataforms = require "util.dataforms";
|
|
local st = require "util.stanza";
|
|
local jid = require "util.jid";
|
|
local iter = require "util.iterators";
|
|
|
|
describe("util.dataforms", function ()
|
|
local some_form, xform;
|
|
setup(function ()
|
|
some_form = dataforms.new({
|
|
title = "form-title",
|
|
instructions = "form-instructions",
|
|
{
|
|
type = "hidden",
|
|
name = "FORM_TYPE",
|
|
value = "xmpp:prosody.im/spec/util.dataforms#1",
|
|
};
|
|
{
|
|
type = "fixed";
|
|
value = "Fixed field";
|
|
},
|
|
{
|
|
type = "boolean",
|
|
label = "boolean-label",
|
|
name = "boolean-field",
|
|
value = true,
|
|
},
|
|
{
|
|
type = "fixed",
|
|
label = "fixed-label",
|
|
name = "fixed-field",
|
|
value = "fixed-value",
|
|
},
|
|
{
|
|
type = "hidden",
|
|
label = "hidden-label",
|
|
name = "hidden-field",
|
|
value = "hidden-value",
|
|
},
|
|
{
|
|
type = "jid-multi",
|
|
label = "jid-multi-label",
|
|
name = "jid-multi-field",
|
|
value = {
|
|
"jid@multi/value#1",
|
|
"jid@multi/value#2",
|
|
},
|
|
},
|
|
{
|
|
type = "jid-single",
|
|
label = "jid-single-label",
|
|
name = "jid-single-field",
|
|
value = "jid@single/value",
|
|
},
|
|
{
|
|
type = "list-multi",
|
|
label = "list-multi-label",
|
|
name = "list-multi-field",
|
|
value = {
|
|
"list-multi-option-value#1",
|
|
"list-multi-option-value#3",
|
|
},
|
|
options = {
|
|
{
|
|
label = "list-multi-option-label#1",
|
|
value = "list-multi-option-value#1",
|
|
default = true,
|
|
},
|
|
{
|
|
label = "list-multi-option-label#2",
|
|
value = "list-multi-option-value#2",
|
|
default = false,
|
|
},
|
|
{
|
|
label = "list-multi-option-label#3",
|
|
value = "list-multi-option-value#3",
|
|
default = true,
|
|
},
|
|
}
|
|
},
|
|
{
|
|
type = "list-single",
|
|
label = "list-single-label",
|
|
name = "list-single-field",
|
|
value = "list-single-value",
|
|
options = {
|
|
"list-single-value",
|
|
"list-single-value#2",
|
|
"list-single-value#3",
|
|
}
|
|
},
|
|
{
|
|
type = "text-multi",
|
|
label = "text-multi-label",
|
|
name = "text-multi-field",
|
|
value = "text\nmulti\nvalue",
|
|
},
|
|
{
|
|
type = "text-private",
|
|
label = "text-private-label",
|
|
name = "text-private-field",
|
|
value = "text-private-value",
|
|
},
|
|
{
|
|
type = "text-single",
|
|
label = "text-single-label",
|
|
name = "text-single-field",
|
|
value = "text-single-value",
|
|
},
|
|
{
|
|
-- XEP-0221
|
|
-- TODO Validate the XML produced by this.
|
|
type = "text-single",
|
|
label = "text-single-with-media-label",
|
|
name = "text-single-with-media-field",
|
|
media = {
|
|
height = 24,
|
|
width = 32,
|
|
{
|
|
type = "image/png",
|
|
uri = "data:",
|
|
},
|
|
},
|
|
},
|
|
});
|
|
xform = some_form:form();
|
|
end);
|
|
|
|
it("XML serialization looks like it should", function ()
|
|
assert.truthy(xform);
|
|
assert.truthy(st.is_stanza(xform));
|
|
assert.equal("x", xform.name);
|
|
assert.equal("jabber:x:data", xform.attr.xmlns);
|
|
assert.equal("FORM_TYPE", xform:get_child_attr("field", nil, "var"));
|
|
assert.equal("xmpp:prosody.im/spec/util.dataforms#1", xform:find("field/value#"));
|
|
local allowed_direct_children = {
|
|
title = true,
|
|
instructions = true,
|
|
field = true,
|
|
}
|
|
for tag in xform:childtags() do
|
|
assert.truthy(allowed_direct_children[tag.name], "unknown direct child");
|
|
end
|
|
end);
|
|
|
|
it("produced boolean field correctly", function ()
|
|
local f;
|
|
for field in xform:childtags("field") do
|
|
if field.attr.var == "boolean-field" then
|
|
f = field;
|
|
break;
|
|
end
|
|
end
|
|
|
|
assert.truthy(st.is_stanza(f));
|
|
assert.equal("boolean-field", f.attr.var);
|
|
assert.equal("boolean", f.attr.type);
|
|
assert.equal("boolean-label", f.attr.label);
|
|
assert.equal(1, iter.count(f:childtags("value")));
|
|
local val = f:get_child_text("value");
|
|
assert.truthy(val == "true" or val == "1");
|
|
end);
|
|
|
|
it("produced fixed field correctly", function ()
|
|
local f;
|
|
for field in xform:childtags("field") do
|
|
if field.attr.var == "fixed-field" then
|
|
f = field;
|
|
break;
|
|
end
|
|
end
|
|
|
|
assert.truthy(st.is_stanza(f));
|
|
assert.equal("fixed-field", f.attr.var);
|
|
assert.equal("fixed", f.attr.type);
|
|
assert.equal("fixed-label", f.attr.label);
|
|
assert.equal(1, iter.count(f:childtags("value")));
|
|
assert.equal("fixed-value", f:get_child_text("value"));
|
|
end);
|
|
|
|
it("produced hidden field correctly", function ()
|
|
local f;
|
|
for field in xform:childtags("field") do
|
|
if field.attr.var == "hidden-field" then
|
|
f = field;
|
|
break;
|
|
end
|
|
end
|
|
|
|
assert.truthy(st.is_stanza(f));
|
|
assert.equal("hidden-field", f.attr.var);
|
|
assert.equal("hidden", f.attr.type);
|
|
assert.equal("hidden-label", f.attr.label);
|
|
assert.equal(1, iter.count(f:childtags("value")));
|
|
assert.equal("hidden-value", f:get_child_text("value"));
|
|
end);
|
|
|
|
it("produced jid-multi field correctly", function ()
|
|
local f;
|
|
for field in xform:childtags("field") do
|
|
if field.attr.var == "jid-multi-field" then
|
|
f = field;
|
|
break;
|
|
end
|
|
end
|
|
|
|
assert.truthy(st.is_stanza(f));
|
|
assert.equal("jid-multi-field", f.attr.var);
|
|
assert.equal("jid-multi", f.attr.type);
|
|
assert.equal("jid-multi-label", f.attr.label);
|
|
assert.equal(2, iter.count(f:childtags("value")));
|
|
|
|
local i = 0;
|
|
for value in f:childtags("value") do
|
|
i = i + 1;
|
|
assert.equal(("jid@multi/value#%d"):format(i), value:get_text());
|
|
end
|
|
end);
|
|
|
|
it("produced jid-single field correctly", function ()
|
|
local f;
|
|
for field in xform:childtags("field") do
|
|
if field.attr.var == "jid-single-field" then
|
|
f = field;
|
|
break;
|
|
end
|
|
end
|
|
|
|
assert.truthy(st.is_stanza(f));
|
|
assert.equal("jid-single-field", f.attr.var);
|
|
assert.equal("jid-single", f.attr.type);
|
|
assert.equal("jid-single-label", f.attr.label);
|
|
assert.equal(1, iter.count(f:childtags("value")));
|
|
assert.equal("jid@single/value", f:get_child_text("value"));
|
|
assert.truthy(jid.prep(f:get_child_text("value")));
|
|
end);
|
|
|
|
it("produced list-multi field correctly", function ()
|
|
local f;
|
|
for field in xform:childtags("field") do
|
|
if field.attr.var == "list-multi-field" then
|
|
f = field;
|
|
break;
|
|
end
|
|
end
|
|
|
|
assert.truthy(st.is_stanza(f));
|
|
assert.equal("list-multi-field", f.attr.var);
|
|
assert.equal("list-multi", f.attr.type);
|
|
assert.equal("list-multi-label", f.attr.label);
|
|
assert.equal(2, iter.count(f:childtags("value")));
|
|
assert.equal("list-multi-option-value#1", f:get_child_text("value"));
|
|
assert.equal(3, iter.count(f:childtags("option")));
|
|
end);
|
|
|
|
it("produced list-single field correctly", function ()
|
|
local f;
|
|
for field in xform:childtags("field") do
|
|
if field.attr.var == "list-single-field" then
|
|
f = field;
|
|
break;
|
|
end
|
|
end
|
|
|
|
assert.truthy(st.is_stanza(f));
|
|
assert.equal("list-single-field", f.attr.var);
|
|
assert.equal("list-single", f.attr.type);
|
|
assert.equal("list-single-label", f.attr.label);
|
|
assert.equal(1, iter.count(f:childtags("value")));
|
|
assert.equal("list-single-value", f:get_child_text("value"));
|
|
assert.equal(3, iter.count(f:childtags("option")));
|
|
end);
|
|
|
|
it("produced text-multi field correctly", function ()
|
|
local f;
|
|
for field in xform:childtags("field") do
|
|
if field.attr.var == "text-multi-field" then
|
|
f = field;
|
|
break;
|
|
end
|
|
end
|
|
|
|
assert.truthy(st.is_stanza(f));
|
|
assert.equal("text-multi-field", f.attr.var);
|
|
assert.equal("text-multi", f.attr.type);
|
|
assert.equal("text-multi-label", f.attr.label);
|
|
assert.equal(3, iter.count(f:childtags("value")));
|
|
end);
|
|
|
|
it("produced text-private field correctly", function ()
|
|
local f;
|
|
for field in xform:childtags("field") do
|
|
if field.attr.var == "text-private-field" then
|
|
f = field;
|
|
break;
|
|
end
|
|
end
|
|
|
|
assert.truthy(st.is_stanza(f));
|
|
assert.equal("text-private-field", f.attr.var);
|
|
assert.equal("text-private", f.attr.type);
|
|
assert.equal("text-private-label", f.attr.label);
|
|
assert.equal(1, iter.count(f:childtags("value")));
|
|
assert.equal("text-private-value", f:get_child_text("value"));
|
|
end);
|
|
|
|
it("produced text-single field correctly", function ()
|
|
local f;
|
|
for field in xform:childtags("field") do
|
|
if field.attr.var == "text-single-field" then
|
|
f = field;
|
|
break;
|
|
end
|
|
end
|
|
|
|
assert.truthy(st.is_stanza(f));
|
|
assert.equal("text-single-field", f.attr.var);
|
|
assert.equal("text-single", f.attr.type);
|
|
assert.equal("text-single-label", f.attr.label);
|
|
assert.equal(1, iter.count(f:childtags("value")));
|
|
assert.equal("text-single-value", f:get_child_text("value"));
|
|
end);
|
|
|
|
describe("get_type()", function ()
|
|
it("identifes dataforms", function ()
|
|
assert.equal(nil, dataforms.get_type(nil));
|
|
assert.equal(nil, dataforms.get_type(""));
|
|
assert.equal(nil, dataforms.get_type({}));
|
|
assert.equal(nil, dataforms.get_type(st.stanza("no-a-form")));
|
|
assert.equal("xmpp:prosody.im/spec/util.dataforms#1", dataforms.get_type(xform));
|
|
end);
|
|
end);
|
|
|
|
describe(":data", function ()
|
|
it("returns something", function ()
|
|
assert.truthy(some_form:data(xform));
|
|
end);
|
|
end);
|
|
|
|
describe("issue1177", function ()
|
|
local form_with_stuff;
|
|
setup(function ()
|
|
form_with_stuff = dataforms.new({
|
|
{
|
|
type = "list-single";
|
|
name = "abtest";
|
|
label = "A or B?";
|
|
options = {
|
|
{ label = "A", value = "a", default = true },
|
|
{ label = "B", value = "b" },
|
|
};
|
|
},
|
|
});
|
|
end);
|
|
|
|
it("includes options when value is included", function ()
|
|
local f = form_with_stuff:form({ abtest = "a" });
|
|
assert.truthy(f:find("field/option"));
|
|
end);
|
|
|
|
it("includes options when value is excluded", function ()
|
|
local f = form_with_stuff:form({});
|
|
assert.truthy(f:find("field/option"));
|
|
end);
|
|
end);
|
|
|
|
describe("using current values in place of missing fields", function ()
|
|
it("gets back the previous values when given an empty form", function ()
|
|
local current = {
|
|
["list-multi-field"] = {
|
|
"list-multi-option-value#2";
|
|
};
|
|
["list-single-field"] = "list-single-value#2";
|
|
["hidden-field"] = "hidden-value";
|
|
["boolean-field"] = false;
|
|
["text-multi-field"] = "words\ngo\nhere";
|
|
["jid-single-field"] = "alice@example.com";
|
|
["text-private-field"] = "hunter2";
|
|
["text-single-field"] = "text-single-value";
|
|
["jid-multi-field"] = {
|
|
"bob@example.net";
|
|
};
|
|
};
|
|
local expect = {
|
|
-- FORM_TYPE = "xmpp:prosody.im/spec/util.dataforms#1"; -- does this need to be included?
|
|
["list-multi-field"] = {
|
|
"list-multi-option-value#2";
|
|
};
|
|
["list-single-field"] = "list-single-value#2";
|
|
["hidden-field"] = "hidden-value";
|
|
["boolean-field"] = false;
|
|
["text-multi-field"] = "words\ngo\nhere";
|
|
["jid-single-field"] = "alice@example.com";
|
|
["text-private-field"] = "hunter2";
|
|
["text-single-field"] = "text-single-value";
|
|
["jid-multi-field"] = {
|
|
"bob@example.net";
|
|
};
|
|
};
|
|
local data, err = some_form:data(st.stanza("x", {xmlns="jabber:x:data"}), current);
|
|
assert.is.table(data, err);
|
|
assert.same(expect, data, "got back the same data");
|
|
end);
|
|
end);
|
|
|
|
describe("field 'var' property", function ()
|
|
it("works as expected", function ()
|
|
local f = dataforms.new {
|
|
{
|
|
var = "someprefix#the-field",
|
|
name = "the_field",
|
|
type = "text-single",
|
|
}
|
|
};
|
|
local x = f:form({the_field = "hello"});
|
|
assert.equal("someprefix#the-field", x:find"field@var");
|
|
assert.equal("hello", x:find"field/value#");
|
|
end);
|
|
end);
|
|
|
|
describe("number handling", function()
|
|
it("handles numbers as booleans", function()
|
|
local f = dataforms.new { { name = "boolean"; type = "boolean" } };
|
|
local x = f:form({ boolean = 0 });
|
|
assert.equal("0", x:find "field/value#");
|
|
x = f:form({ boolean = 1 });
|
|
assert.equal("1", x:find "field/value#");
|
|
end);
|
|
end)
|
|
|
|
describe("datatype validation", function ()
|
|
describe("integer", function ()
|
|
|
|
local f = dataforms.new {
|
|
{
|
|
name = "number",
|
|
type = "text-single",
|
|
datatype = "xs:integer",
|
|
range_min = -10,
|
|
range_max = 10,
|
|
},
|
|
};
|
|
|
|
it("roundtrip works", function ()
|
|
local d = f:data(f:form({number = 1}));
|
|
assert.equal(1, d.number);
|
|
end);
|
|
|
|
it("error handling works", function ()
|
|
local d,e = f:data(f:form({number = "nan"}));
|
|
assert.not_equal(1, d.number);
|
|
assert.table(e);
|
|
assert.string(e.number);
|
|
end);
|
|
|
|
it("bounds-checking work works", function ()
|
|
local d,e = f:data(f:form({number = 100}));
|
|
assert.not_equal(100, d.number);
|
|
assert.table(e);
|
|
assert.string(e.number);
|
|
end);
|
|
|
|
it("serializes larger ints okay", function ()
|
|
local x = f:form{number=1125899906842624}
|
|
assert.equal("1125899906842624", x:find("field/value#"))
|
|
end);
|
|
|
|
end)
|
|
|
|
describe("datetime", function ()
|
|
local f = dataforms.new { { name = "when"; type = "text-single"; datatype = "xs:dateTime" } }
|
|
|
|
it("works", function ()
|
|
local x = f:form({ when = 1219439340 });
|
|
assert.equal("2008-08-22T21:09:00Z", x:find("field/value#"))
|
|
local d, e = f:data(x);
|
|
assert.is_nil(e);
|
|
assert.same({ when = 1219439340 }, d);
|
|
end);
|
|
|
|
end)
|
|
|
|
end);
|
|
describe("media element", function ()
|
|
it("produced media element correctly", function ()
|
|
local f;
|
|
for field in xform:childtags("field") do
|
|
if field.attr.var == "text-single-with-media-field" then
|
|
f = field;
|
|
break;
|
|
end
|
|
end
|
|
|
|
assert.truthy(st.is_stanza(f));
|
|
assert.equal("text-single-with-media-field", f.attr.var);
|
|
assert.equal("text-single", f.attr.type);
|
|
assert.equal("text-single-with-media-label", f.attr.label);
|
|
assert.equal(0, iter.count(f:childtags("value")));
|
|
|
|
local m = f:get_child("media", "urn:xmpp:media-element");
|
|
assert.truthy(st.is_stanza(m));
|
|
assert.equal("24", m.attr.height);
|
|
assert.equal("32", m.attr.width);
|
|
assert.equal(1, iter.count(m:childtags("uri")));
|
|
|
|
local u = m:get_child("uri");
|
|
assert.truthy(st.is_stanza(u));
|
|
assert.equal("image/png", u.attr.type);
|
|
assert.equal("data:", u:get_text());
|
|
end);
|
|
end);
|
|
end);
|
|
|