git » sdk » commit 440bc7d

Tests for XEP0393 and autolink

author Stephen Paul Weber
2025-11-12 21:00:52 UTC
committer Stephen Paul Weber
2025-11-12 21:00:52 UTC
parent 98d964e02f6fe8d1a973e2bd296a9d5b367ce317

Tests for XEP0393 and autolink

borogove/Util.hx +6 -0
borogove/XEP0393.hx +1 -1
test/TestAll.hx +1 -0
test/TestXEP0393.hx +210 -0

diff --git a/borogove/Util.hx b/borogove/Util.hx
index 7697a94..5670463 100644
--- a/borogove/Util.hx
+++ b/borogove/Util.hx
@@ -171,6 +171,7 @@ class Util {
 	/**
 		Convert a String index to a UnicodeString index
 	**/
+	#if utf16
 	@:access(StringTools.utf16CodePointAt)
 	@:access(StringTools.MIN_SURROGATE_CODE_POINT)
 	static public function convertIndex(u: UnicodeString, index: Int) {
@@ -194,4 +195,9 @@ class Util {
 
 		throw "No matching index";
 	}
+	#else
+	static public function convertIndex(u: UnicodeString, index: Int) {
+		return index;
+	}
+	#end
 }
diff --git a/borogove/XEP0393.hx b/borogove/XEP0393.hx
index 24c4910..a391a96 100644
--- a/borogove/XEP0393.hx
+++ b/borogove/XEP0393.hx
@@ -5,7 +5,7 @@ import borogove.Stanza;
 using borogove.Util;
 
 class XEP0393 {
-	public static function parse(styled: UnicodeString) {
+	public static function parse(styled: UnicodeString): Array<Stanza> {
 		final blocks = [];
 		while (styled.length > 0) {
 			final result = parseBlock(styled);
diff --git a/test/TestAll.hx b/test/TestAll.hx
index 6d7c949..03d93a5 100644
--- a/test/TestAll.hx
+++ b/test/TestAll.hx
@@ -10,6 +10,7 @@ class TestAll {
 			new TestChatMessageBuilder(),
 			new TestStanza(),
 			new TestCaps(),
+			new TestXEP0393(),
 		]);
 	}
 }
diff --git a/test/TestXEP0393.hx b/test/TestXEP0393.hx
new file mode 100644
index 0000000..75870af
--- /dev/null
+++ b/test/TestXEP0393.hx
@@ -0,0 +1,210 @@
+package test;
+
+import utest.Assert;
+import utest.Async;
+import borogove.XEP0393;
+
+class TestXEP0393 extends utest.Test {
+	function toHtml(s: String) {
+		return XEP0393.parse(s).map(b -> b.toString()).join("");
+	}
+
+	public function testSpansDoNotEscapeBlocks() {
+		Assert.equals(
+			"<div>There are three blocks in this body, one per line,
+</div><div>but there is no *formatting
+</div><div>as spans* may not escape blocks.</div>",
+			toHtml("There are three blocks in this body, one per line,
+but there is no *formatting
+as spans* may not escape blocks.")
+		);
+	}
+
+	public function testPreformattedBlock() {
+		Assert.equals(
+			"<pre>(println \"Hello, world!\")
+</pre><div>
+</div><div>This should show up as monospace, preformatted text ⤴</div>",
+			toHtml("```ignored
+(println \"Hello, world!\")
+```
+
+This should show up as monospace, preformatted text ⤴")
+		);
+	}
+
+	public function testPreformattedBlockUnterminated() {
+		Assert.equals(
+			"<blockquote><pre>(println \"Hello, world!\")
+</pre></blockquote><div>
+</div><div>The entire blockquote is a preformatted text block, but this line
+</div><div>is plaintext!</div>",
+			toHtml("> ```ignored
+> (println \"Hello, world!\")
+
+The entire blockquote is a preformatted text block, but this line
+is plaintext!")
+		);
+	}
+
+	public function testQuotation() {
+		Assert.equals(
+			"<blockquote><div>That that is, is.
+</div></blockquote><div>
+</div><div>Said the old hermit of Prague.</div>",
+			toHtml("> That that is, is.
+
+Said the old hermit of Prague.")
+		);
+	}
+
+	public function testNestedQuotation() {
+		Assert.equals(
+			"<blockquote><blockquote><div>That that is, is.
+</div></blockquote><div>Said the old hermit of Prague.
+</div></blockquote><div>
+</div><div>Who?</div>",
+			toHtml(">> That that is, is.
+> Said the old hermit of Prague.
+
+Who?")
+		);
+	}
+
+	public function testPlainSpan() {
+		Assert.equals(
+			"<div>plain span</div>",
+			toHtml("plain span")
+		);
+	}
+
+	public function testStrongSpan() {
+		Assert.equals(
+			"<div><strong>strong span</strong></div>",
+			toHtml("*strong span*")
+		);
+	}
+
+	public function testPlainEmphasisPlain() {
+		Assert.equals(
+			"<div>plain <em>emphasis</em> plain</div>",
+			toHtml("plain _emphasis_ plain")
+		);
+	}
+
+	public function testPrePlainStrong() {
+		Assert.equals(
+			"<div><tt>pre</tt> plain <strong>strong</strong></div>",
+			toHtml("`pre` plain *strong*")
+		);
+	}
+
+	public function testStrongPlain() {
+		Assert.equals(
+			"<div><strong>strong</strong>plain*</div>",
+			toHtml("*strong*plain*")
+		);
+	}
+
+	public function testPlainStrong() {
+		Assert.equals(
+			"<div>* plain <strong>strong</strong></div>",
+			toHtml("* plain *strong*")
+		);
+	}
+
+	public function testNotStrong1() {
+		Assert.equals(
+			"<div>not strong*</div>",
+			toHtml("not strong*")
+		);
+	}
+
+	public function testNotStrong2() {
+		Assert.equals(
+			"<div>*not strong</div>",
+			toHtml("*not strong")
+		);
+	}
+
+	public function testNotStrong3() {
+		Assert.equals(
+			"<div>*not \n</div><div> strong</div>",
+			toHtml("*not \n strong")
+		);
+	}
+
+	public function testNotStrong4() {
+		Assert.equals(
+			"<div>**</div>",
+			toHtml("**")
+		);
+	}
+
+	public function testNotStrong5() {
+		Assert.equals(
+			"<div>***</div>",
+			toHtml("***")
+		);
+	}
+
+	public function testNotStrong6() {
+		Assert.equals(
+			"<div>****</div>",
+			toHtml("****")
+		);
+	}
+
+	public function testStrike() {
+		Assert.equals(
+			"<div>Everyone <s>dis</s>likes cake.</div>",
+			toHtml("Everyone ~dis~likes cake.")
+		);
+	}
+
+	public function testThisIsMonospace() {
+		Assert.equals(
+			"<div>This is <tt>*monospace*</tt></div>",
+			toHtml("This is `*monospace*`")
+		);
+	}
+
+	public function testThisIsMonospaceAndBold() {
+		Assert.equals(
+			"<div>This is <strong><tt>monospace and bold</tt></strong></div>",
+			toHtml("This is *`monospace and bold`*")
+		);
+	}
+
+	// NOTE: autolink is not part of the XEP, but we process it within blocks
+	// for consistency with the rest of the XEP rules
+
+	public function testAutolink() {
+		Assert.equals(
+			"<blockquote><div><a href=\"https://example.com\">example.com</a>
+</div></blockquote>",
+			toHtml("> example.com")
+		);
+	}
+
+	public function testNoAutolink() {
+		Assert.equals(
+			"<div><tt>example.com</tt></div>",
+			toHtml("`example.com`")
+		);
+	}
+
+	public function testAutolinkXMPP() {
+		Assert.equals(
+			"<div>hello <a href=\"xmpp:alice@example.com\">xmpp:alice@example.com</a></div>",
+			toHtml("hello xmpp:alice@example.com")
+		);
+	}
+
+	public function testAutolinkAfterEmoji() {
+		Assert.equals(
+			"<div>📞 icon <a href=\"https://example.com\">example.com</a></div>",
+			toHtml("📞 icon example.com")
+		);
+	}
+}