add program to test XML entities and coverage for it - sfeed_tests - sfeed tests and RSS and Atom files
(HTM) git clone git://git.codemadness.org/sfeed_tests
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
(DIR) commit 6eca9afe6aebc7c3f32f341272b1ac7734085e45
(DIR) parent e415995086723ab71dbf59368780681dd6ec7b91
(HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Thu, 11 Dec 2025 20:19:35 +0100
add program to test XML entities and coverage for it
This tests some of the xml_entitytostr() functions from the application-use side.
Some paths cannot happen because of how sfeed works.
This increases test coverage from 98% to 100%.
Diffstat:
A xml_test_entities/build_coverage.sh | 21 +++++++++++++++++++++
A xml_test_entities/main.c | 144 +++++++++++++++++++++++++++++++
2 files changed, 165 insertions(+), 0 deletions(-)
---
(DIR) diff --git a/xml_test_entities/build_coverage.sh b/xml_test_entities/build_coverage.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+# NOTE: make sure to disable pledge on OpenBSD, gcov needs rpath.
+
+XMLO="$HOME/p/sfeed/xml.o"
+SFEEDDIR="$HOME/p/sfeed"
+
+header="$(readlink -f "$0")"
+header="$(dirname "$header")/../gcov_dump.h"
+
+CC="gcc"
+CFLAGS="-include $header -fprofile-arcs -ftest-coverage"
+LDFLAGS="-fprofile-arcs"
+
+BIN="${SFEEDDIR}/test_xml_entities"
+
+rm -f *.gcda *.gcno *.o
+rm -f main
+
+${CC} -o main.o -c main.c ${CFLAGS} ${LDFLAGS} "-I${SFEEDDIR}"
+
+${CC} -o "${BIN}" "$XMLO" main.o ${CFLAGS} ${LDFLAGS}
(DIR) diff --git a/xml_test_entities/main.c b/xml_test_entities/main.c
@@ -0,0 +1,144 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "xml.h"
+
+int count, ok, failed;
+
+int
+test(char *buf, size_t bufsiz,
+ const char *input, int ret, const char *expect, int expectret)
+{
+ count++;
+
+ ret = xml_entitytostr(input, buf, bufsiz);
+ if (ret != expectret) {
+ printf("[%d] FAILED: input=%s, status=%d, expected status=%d\n",
+ count, input, ret, expectret);
+ failed++;
+ return 0;
+ }
+ /* if return status is -1 the result in buf should not be used */
+ if (ret == -1) {
+ ok++;
+ return 0;
+ }
+
+ if (strcmp(expect, buf)) {
+ printf("[%d] FAILED: input=%s, expected=%s, got=%s\n",
+ count, input, expect, buf);
+ failed++;
+ return 0;
+ }
+ ok++;
+
+ return 1;
+}
+
+int
+main(void)
+{
+ char buf[8];
+
+ /* named entities */
+ test(buf, sizeof(buf), "&", 1, "&", 1);
+ test(buf, sizeof(buf), "<", 1, "<", 1);
+ test(buf, sizeof(buf), ">", 1, ">", 1);
+ test(buf, sizeof(buf), "'", 1, "'", 1);
+ test(buf, sizeof(buf), """, 1, "\"", 1);
+
+ /* case-sensitivity of named entities (should not match) */
+ test(buf, sizeof(buf), "&", -1, "&", -1);
+ test(buf, sizeof(buf), "<", -1, "<", -1);
+ test(buf, sizeof(buf), ">", -1, ">", -1);
+ test(buf, sizeof(buf), "&APOS;", -1, "'", -1);
+ test(buf, sizeof(buf), """, -1, "\"", -1);
+
+ /* HTML entities (should not match) */
+ test(buf, sizeof(buf), "€", -1, "&", -1);
+ test(buf, sizeof(buf), "&EURO;", -1, "&", -1);
+
+ /* numeric entities */
+ test(buf, sizeof(buf), "A", 1, "A", 1);
+ test(buf, sizeof(buf), "A", 1, "A", 1);
+
+ /* numeric entities rare characters */
+ /* The XML specification doesn't recommend this. But we allow it */
+ test(buf, sizeof(buf), "�", 0, "", 0); /* NUL */
+ test(buf, sizeof(buf), "", 1, "\x01", 1);
+
+ /* surrogate range */
+ test(buf, sizeof(buf), "�", -1, "", -1); /* start range >= */
+ test(buf, sizeof(buf), "�", -1, "", -1); /* end range <= */
+ test(buf, sizeof(buf), "�", -1, "\xed\xb0\x80", -1);
+ /* near range */
+ test(buf, sizeof(buf), "󠀀", 4, "\xf3\xa0\x80\x80", 4);
+ test(buf, sizeof(buf), "퟿", 3, "\xed\x9f\xbf", 3);
+ test(buf, sizeof(buf), "ퟻ", 3, "\xed\x9f\xbb", 3);
+
+ test(buf, sizeof(buf), "&#x-1;", -1, "", -1);
+ test(buf, sizeof(buf), "&#-1;", -1, "", -1);
+ test(buf, sizeof(buf), "&#x-0;", -1, "", -1);
+ test(buf, sizeof(buf), "&#-0;", -1, "", -1);
+ test(buf, sizeof(buf), "&#+1;", -1, "", -1);
+ test(buf, sizeof(buf), "&;", -1, "", -1);
+ test(buf, sizeof(buf), "& ;", -1, "", -1);
+ test(buf, sizeof(buf), "&;", -1, "", -1);
+ test(buf, sizeof(buf), "A;", -1, "", -1);
+ test(buf, sizeof(buf), "&;a", -1, "", -1);
+ test(buf, sizeof(buf), "A;a", -1, "", -1);
+ test(buf, sizeof(buf), "&# 65;", -1, "", -1);
+ test(buf, sizeof(buf), "A", -1, "", -1);
+ test(buf, sizeof(buf), "&", -1, "", -1);
+ test(buf, sizeof(buf), "&#", -1, "", -1);
+ test(buf, sizeof(buf), "&#x", -1, "", -1);
+
+ /* just in range (limit) */
+ test(buf, sizeof(buf), "", 4, "\xf4\x8f\xbf\xbf", 4);
+ test(buf, sizeof(buf), "", 4, "\xf4\x8f\xbf\xbf", 4);
+ /* outside range (range + 1) */
+ test(buf, sizeof(buf), "�", -1, "", -1);
+ test(buf, sizeof(buf), "�", -1, "", -1);
+
+ /* 2 bytes */
+ test(buf, sizeof(buf), "Ͱ", 2, "\xcd\xb0", 2);
+ test(buf, sizeof(buf), "Ͱ", 2, "\xcd\xb0", 2);
+ test(buf, sizeof(buf), "Ͱ", 2, "\xcd\xb0", 2);
+ /* 3 bytes */
+ test(buf, sizeof(buf), "᚛", 3, "\xe1\x9a\x9b", 3);
+ test(buf, sizeof(buf), "᚛", 3, "\xe1\x9a\x9b", 3);
+ test(buf, sizeof(buf), "᚛", 3, "\xe1\x9a\x9b", 3);
+ test(buf, sizeof(buf), "᚛", 3, "\xe1\x9a\x9b", 3);
+ /* 4 bytes */
+ test(buf, sizeof(buf), "𐌀", 4, "\xf0\x90\x8c\x80", 4);
+ test(buf, sizeof(buf), "𐌀", 4, "\xf0\x90\x8c\x80", 4);
+ test(buf, sizeof(buf), "𐌀", 4, "\xf0\x90\x8c\x80", 4);
+ test(buf, sizeof(buf), "🫰", 4, "\xf0\x9f\xab\xb0", 4);
+ test(buf, sizeof(buf), "🫰", 4, "\xf0\x9f\xab\xb0", 4);
+
+ /* --- */
+
+ /* does not start with "&" */
+ test(buf, sizeof(buf), " &", -1, "", -1);
+ test(buf, sizeof(buf), "#65;", -1, "", -1);
+ test(buf, sizeof(buf), "#x65;", -1, "", -1);
+
+ /* --- */
+
+ /* test buffer size checks */
+ /* named entities must have bufsiz >= 2 */
+ test(buf, 0, "&", -1, "", -1);
+ test(buf, 1, "&", -1, "", -1);
+ test(buf, 2, "&", 1, "&", 1);
+
+ /* numeric entities must have bufsiz >= 5 */
+ test(buf, 0, "A", -1, "", -1);
+ test(buf, 1, "A", -1, "", -1);
+ test(buf, 4, "A", -1, "", -1);
+ test(buf, 5, "A", 1, "A", 1);
+
+ printf("%s (%d tested, %d OK, %d failed)\n",
+ failed == 0 ? "OK" : "FAILED", count, ok, failed);
+
+ return failed != 0;
+}