| author | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-03-26 02:34:43 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-03-26 02:59:40 UTC |
| parent | 2d22bbc6945837598ff8a34aa7916a875b567712 |
| test/TestAll.hx | +4 | -0 |
| test/TestClient.hx | +71 | -0 |
| test/TestJID.hx | +77 | -0 |
| test/TestReaction.hx | +30 | -0 |
| test/TestStanza.hx | +51 | -1 |
| test/TestStringUtil.hx | +20 | -0 |
| test/TestUtil.hx | +36 | -0 |
diff --git a/test/TestAll.hx b/test/TestAll.hx index 83f46de..a7c6805 100644 --- a/test/TestAll.hx +++ b/test/TestAll.hx @@ -13,6 +13,10 @@ class TestAll { new TestClient(), new TestXEP0393(), new TestEmojiUtil(), + new TestJID(), + new TestStringUtil(), + new TestUtil(), + new TestReaction(), ]); } } diff --git a/test/TestClient.hx b/test/TestClient.hx index 61f3d97..f0cf8f6 100644 --- a/test/TestClient.hx +++ b/test/TestClient.hx @@ -5,8 +5,11 @@ import utest.Async; import borogove.Client; import borogove.Stanza; +import borogove.Chat; import borogove.persistence.Dummy; +using Lambda; + @:access(borogove) class TestClient extends utest.Test { public function testAccountId() { @@ -191,4 +194,72 @@ class TestClient extends utest.Test { client.stream.onStanza(new Stanza("message", { xmlns: "jabber:client", from: "test2@example.com", id: "localid"}).textTag("body", "hi")); } + + public function testEmptyAccountId() { + final persistence = new Dummy(); + Assert.raises(() -> new Client("", persistence), String); + Assert.raises(() -> new Client(null, persistence), String); + } + + public function testGetChatsFilter() { + final persistence = new Dummy(); + final client = new Client("test@example.com", persistence); + final chat1 = client.getDirectChat("test1@example.com"); + final chat2 = client.getDirectChat("test2@example.com"); + + Assert.equals(2, client.getChats().length); + + chat1.close(); + Assert.equals(1, client.getChats().length); + Assert.equals("test2@example.com", client.getChats()[0].chatId); + } + + public function testChatsUpdateEvent(async: Async) { + final persistence = new Dummy(); + final client = new Client("test@example.com", persistence); + client.on("chats/update", (chats: Array<Chat>) -> { + final friendChat = chats.find(c -> c.chatId == "friend@example.com"); + if (friendChat != null) { + Assert.equals("friend@example.com", friendChat.chatId); + async.done(); + } + return EventHandled; + }); + + client.getDirectChat("friend@example.com"); + } + + public function testPresenceSubscription(async: Async) { + final persistence = new Dummy(); + final client = new Client("test@example.com", persistence); + client.inSync = true; + + client.stream.on("sendStanza", (stanza: Stanza) -> { + if (stanza.name == "iq" && stanza.findChild("{http://jabber.org/protocol/disco#info}query") != null) { + client.stream.onStanza( + new Stanza("iq", { type: "result", to: "test@example.com", id: stanza.attr.get("id"), from: "stranger@example.com", xmlns: "jabber:client" }) + .tag("query", { xmlns: "http://jabber.org/protocol/disco#info" }) + .tag("identity", { category: "client", type: "pc", name: "Stranger" }).up() + .up() + ); + } + return EventHandled; + }); + + client.on("chats/update", (chats: Array<Chat>) -> { + final strangerChat = chats.find(c -> c.chatId == "stranger@example.com"); + if (strangerChat != null && strangerChat.uiState == Invited) { + Assert.equals("stranger@example.com", strangerChat.chatId); + Assert.equals("Stranger (stranger@example.com)", strangerChat.getDisplayName()); + Assert.equals(Invited, strangerChat.uiState); + async.done(); + } + return EventHandled; + }); + + client.stream.onStanza( + new Stanza("presence", { from: "stranger@example.com", type: "subscribe", xmlns: "jabber:client" }) + .textTag("nick", "Stranger", { xmlns: "http://jabber.org/protocol/nick" }) + ); + } } diff --git a/test/TestJID.hx b/test/TestJID.hx new file mode 100644 index 0000000..37a1a1a --- /dev/null +++ b/test/TestJID.hx @@ -0,0 +1,77 @@ +package test; + +import utest.Assert; +import borogove.JID; + +class TestJID extends utest.Test { + public function testParse() { + var jid = JID.parse("user@example.com"); + Assert.equals("user", jid.node); + Assert.equals("example.com", jid.domain); + Assert.isNull(jid.resource); + + jid = JID.parse("user@example.com/mobile"); + Assert.equals("user", jid.node); + Assert.equals("example.com", jid.domain); + Assert.equals("mobile", jid.resource); + + jid = JID.parse("example.com"); + Assert.isNull(jid.node); + Assert.equals("example.com", jid.domain); + Assert.isNull(jid.resource); + + jid = JID.parse("example.com/resource"); + Assert.isNull(jid.node); + Assert.equals("example.com", jid.domain); + Assert.equals("resource", jid.resource); + } + + public function testEscape() { + // Test that escaping works in constructor + var jid = new JID("node with space", "example.com"); + Assert.equals("node\\20with\\20space", jid.node); + Assert.equals("node\\20with\\20space@example.com", jid.asString()); + + jid = new JID("d'artagnan", "example.com"); + Assert.equals("d\\27artagnan", jid.node); + + jid = new JID("alice@wonderland", "example.com"); + Assert.equals("alice\\40wonderland", jid.node); + + // Test parsing escaped JIDs + jid = JID.parse("node\\20with\\20space@example.com"); + Assert.equals("node\\20with\\20space", jid.node); + } + + public function testUtilityMethods() { + var jid = new JID("user", "example.com", "resource", true); + Assert.isFalse(jid.isBare()); + Assert.isFalse(jid.isDomain()); + Assert.isTrue(jid.isValid()); + + var bare = jid.asBare(); + Assert.isTrue(bare.isBare()); + Assert.equals("user@example.com", bare.asString()); + + var withNewResource = bare.withResource("new"); + Assert.equals("new", withNewResource.resource); + Assert.equals("user@example.com/new", withNewResource.asString()); + + var domainOnly = new JID(null, "example.com"); + Assert.isTrue(domainOnly.isDomain()); + Assert.isTrue(domainOnly.isBare()); + Assert.equals("example.com", domainOnly.asString()); + + var invalid = new JID(null, "localhost"); + Assert.isFalse(invalid.isValid()); + } + + public function testEquals() { + var jid1 = new JID("user", "example.com", "res", true); + var jid2 = new JID("user", "example.com", "res", true); + var jid3 = new JID("user", "example.com", "other", true); + + Assert.isTrue(jid1.equals(jid2)); + Assert.isFalse(jid1.equals(jid3)); + } +} diff --git a/test/TestReaction.hx b/test/TestReaction.hx new file mode 100644 index 0000000..b9eacf5 --- /dev/null +++ b/test/TestReaction.hx @@ -0,0 +1,30 @@ +package test; + +import utest.Assert; +import borogove.Reaction; + +@:access(borogove.Reaction) +class TestReaction extends utest.Test { + public function testNormalization() { + // 👍 with variation selector 16 (\u{fe0f}) + var r = Reaction.unicode("👍\u{fe0f}"); + + // Internal text should have it stripped + Assert.equals("👍", r.text); + + // Render should add it back + var rendered = r.render((text) -> text, (name, uri) -> ""); + Assert.equals("👍\u{fe0f}", rendered); + } + + public function testCustomEmoji() { + var r = CustomEmojiReaction.custom("tada", "https://example.com/tada.png"); + + var rendered = r.render( + (text) -> "text:" + text, + (name, uri) -> "image:" + name + ":" + uri + ); + + Assert.equals("image:tada:https://example.com/tada.png", rendered); + } +} diff --git a/test/TestStanza.hx b/test/TestStanza.hx index 7ca0289..d905cb7 100644 --- a/test/TestStanza.hx +++ b/test/TestStanza.hx @@ -1,10 +1,10 @@ package test; - import utest.Assert; import utest.Async; import borogove.Stanza; +@:access(borogove.Stanza) class TestStanza extends utest.Test { public function testRemoveChildren() { final s = new Stanza("test", { xmlns: "urn:example:foo" }) @@ -29,4 +29,54 @@ class TestStanza extends utest.Test { Assert.equals(false, Stanza.parseXmlBool("false")); Assert.equals(false, Stanza.parseXmlBool("0")); } + + public function testFluentApi() { + final s = new Stanza("root") + .tag("child", { id: "1" }) + .text("hello") + .up() + .tag("child", { id: "2" }) + .tag("grandchild") + .text("world") + .up() + .up(); + + Assert.equals(2, s.allTags("child").length); + var secondChild = s.allTags("child")[1]; + Assert.equals("2", secondChild.attr.get("id")); + Assert.equals("world", secondChild.getChildText("grandchild")); + } + + public function testFind() { + final s = new Stanza("root") + .tag("person", { name: "Alice" }) + .textTag("email", "alice@example.com") + .up() + .tag("person", { name: "Bob" }) + .textTag("email", "bob@example.com") + .up(); + + Assert.equals("Alice", s.findText("person@name")); + Assert.equals("alice@example.com", s.findText("person/email#")); + + var person = s.findChild("person"); + Assert.equals("Alice", person.attr.get("name")); + } + + public function testClone() { + final s = new Stanza("root") + .tag("child") + .text("original") + .up(); + + final cloned = s.clone(); + Assert.equals(s.serialize(), cloned.serialize()); + + // Modify original + s.allTags("child")[0].children = []; + s.allTags("child")[0].text("modified"); + + Assert.equals("modified", s.getChildText("child")); + Assert.equals("original", cloned.getChildText("child")); + } } diff --git a/test/TestStringUtil.hx b/test/TestStringUtil.hx new file mode 100644 index 0000000..9ad7697 --- /dev/null +++ b/test/TestStringUtil.hx @@ -0,0 +1,20 @@ +package test; + +import utest.Assert; +import borogove.StringUtil; + +class TestStringUtil extends utest.Test { + public function testCodepointArray() { + Assert.same(["a", "b", "c"], StringUtil.codepointArray("abc")); + Assert.same(["👍", "!", "👋"], StringUtil.codepointArray("👍!👋")); + Assert.same(["\u{1F601}", "\u{1F602}"], StringUtil.codepointArray("\u{1F601}\u{1F602}")); + Assert.same([], StringUtil.codepointArray("")); + } + + public function testRawCodepointArray() { + Assert.same([97, 98, 99], StringUtil.rawCodepointArray("abc")); + // 👍 is 0x1F44D (128077 decimal), 👋 is 0x1F44B (128075 decimal) + Assert.same([128077, 33, 128075], StringUtil.rawCodepointArray("👍!👋")); + Assert.same([], StringUtil.rawCodepointArray("")); + } +} diff --git a/test/TestUtil.hx b/test/TestUtil.hx new file mode 100644 index 0000000..c3bcd44 --- /dev/null +++ b/test/TestUtil.hx @@ -0,0 +1,36 @@ +package test; + +import utest.Assert; +import borogove.Util; + +class TestUtil extends utest.Test { + public function testXmlEscape() { + Assert.equals("foo & bar < baz >", borogove.Util.xmlEscape("foo & bar < baz >")); + Assert.equals("nothing", borogove.Util.xmlEscape("nothing")); + Assert.equals("", borogove.Util.xmlEscape("")); + } + + public function testUriDecode() { + Assert.equals("a b", borogove.Util.uriDecode("a%20b")); + Assert.equals("a+b", borogove.Util.uriDecode("a+b")); // Should NOT decode + as space + Assert.equals("!", borogove.Util.uriDecode("%21")); + Assert.equals("hello", borogove.Util.uriDecode("hello")); + } + + public function testCapitalize() { + Assert.equals("Hello", Util.capitalize("hello")); + Assert.equals("Hello", Util.capitalize("Hello")); + Assert.equals("A", Util.capitalize("a")); + Assert.equals("", Util.capitalize("")); + Assert.isNull(Util.capitalize(null)); + } + + public function testSearchHelpers() { + final arr = [1, 2, 3, 4, 5]; + Assert.isTrue(borogove.Util.existsFast(arr, (x) -> x == 3)); + Assert.isFalse(borogove.Util.existsFast(arr, (x) -> x == 10)); + + Assert.equals(4, borogove.Util.findFast(arr, (x) -> x > 3)); + Assert.isNull(borogove.Util.findFast(arr, (x) -> x > 10)); + } +}