diff --git a/NEWS b/NEWS
index e69ac155..7eebca04 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,9 @@
In Development:
# Mentioning Check 0.10.0 for now, to fix distcheck target until next release
+* Emit only valid XML characters in XML logging (assumes ASCII encoding).
+ Bug #103
+
* Add LGPL header to files where it was missing; update FSF address in LGPL headers
Bug #110
diff --git a/src/check_print.c b/src/check_print.c
index d56e1707..35f13b64 100644
--- a/src/check_print.c
+++ b/src/check_print.c
@@ -95,34 +95,53 @@ static void srunner_fprint_results(FILE * file, SRunner * sr,
void fprint_xml_esc(FILE * file, const char *str)
{
+ /* The valid XML characters are as follows:
+ * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+ * Characters that are outside of ASCII must be encoded. Further, the
+ * following special characters:
+ * " ' < > &
+ * must be encoded. We assume that the incoming string may be a multibyte
+ * character.
+ */
+
for(; *str != '\0'; str++)
{
+ char next = *str;
- switch (*str)
+ /* handle special characters that must be escaped */
+ if(next == '"' || next == '\'' || next == '<' || next == '>' || next == '&')
{
-
- /* handle special characters that must be escaped */
- case '"':
- fputs(""", file);
- break;
- case '\'':
- fputs("'", file);
- break;
- case '<':
- fputs("<", file);
- break;
- case '>':
- fputs(">", file);
- break;
- case '&':
- fputs("&", file);
- break;
-
- /* regular characters, print as is */
- default:
- fputc(*str, file);
- break;
+ switch (next)
+ {
+ case '"':
+ fputs(""", file);
+ break;
+ case '\'':
+ fputs("'", file);
+ break;
+ case '<':
+ fputs("<", file);
+ break;
+ case '>':
+ fputs(">", file);
+ break;
+ case '&':
+ fputs("&", file);
+ break;
+ }
+ }
+ /* printable ASCII */
+ else if(next >= ' ' && next <= '~')
+ {
+ fputc(next, file);
+ }
+ /* Non-printable character */
+ else if(next == 0x9 || next == 0xA || next == 0xD ||
+ next >= 0x20)
+ {
+ fprintf(file, "%X;", next);
}
+ /* If it did not get printed, it is not a valid XML character*/
}
}
diff --git a/tests/ex_output.c b/tests/ex_output.c
index 6d0aad27..9e4e7467 100644
--- a/tests/ex_output.c
+++ b/tests/ex_output.c
@@ -75,7 +75,7 @@ END_TEST
START_TEST(test_xml_esc_fail_msg)
{
- ck_abort_msg("fail \" ' < > & message");
+ ck_abort_msg("fail \" ' < > & \x9 \xA" "X""\x08"" message"); /* backspace char \x08 deletes the X */
}
END_TEST
@@ -120,8 +120,8 @@ static Suite *make_xml_esc_suite(void)
Suite *s;
TCase *tc;
- s = suite_create("XML escape \" ' < > & tests");
- tc = tcase_create("description \" ' < > &");
+ s = suite_create("XML escape \" ' < > & \x9 \xA" "X""\x08"" tests"); /* backspace char \x08 deletes the X */
+ tc = tcase_create("description \" ' < > & \x9 \xA" "X""\x08"" end"); /* backspace char \x08 deletes the X */
suite_add_tcase(s, tc);
tcase_add_test(tc, test_xml_esc_fail_msg);
diff --git a/tests/test_output_strings b/tests/test_output_strings
index b23da03f..ccb3861f 100644
--- a/tests/test_output_strings
+++ b/tests/test_output_strings
@@ -2,12 +2,17 @@
. ./test_vars
+# Set the 'internal field separator' character to
+# something besides whitespace so that the string
+# comparisons will work
+IFS="~"
+
##################
# stdout output
##################
-suite_output="Running suite(s): S1
+suite_output=`printf "Running suite(s): S1
S2
- XML escape \" ' < > & tests"
+ XML escape \" ' < > & \x9 \x0AX\x08 tests"`
exp_silent=""
@@ -20,25 +25,25 @@ exp_minimal="$suite_output
$exp_minimal_result"
if [ $HAVE_FORK -eq 1 ]; then
-exp_normal_result="37%: Checks: 8, Failures: 4, Errors: 1
+exp_normal_result=`printf "37%%: Checks: 8, Failures: 4, Errors: 1
${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure
${SRCDIR}ex_output.c:46:E:Core:test_exit:0: (after this point) Early exit with return value 1
${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed
${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed
-${SRCDIR}ex_output.c:78:F:description \" ' < > &:test_xml_esc_fail_msg:0: fail \" ' < > & message"
+${SRCDIR}ex_output.c:78:F:description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg:0: fail \" ' < > & \x9 \x0AX\x08 message"`
else
-exp_normal_result="42%: Checks: 7, Failures: 4, Errors: 0
+exp_normal_result=`printf "42%%: Checks: 7, Failures: 4, Errors: 0
${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure
${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed
${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed
-${SRCDIR}ex_output.c:78:F:description \" ' < > &:test_xml_esc_fail_msg:0: fail \" ' < > & message"
+${SRCDIR}ex_output.c:78:F:description \" ' < > &\x9 \xA end:test_xml_esc_fail_msg:0: fail \" ' < > & \x9 \x0AX\x08 message"`
fi
exp_normal="$suite_output
$exp_normal_result"
if [ $HAVE_FORK -eq 1 ]; then
-exp_verbose_result="37%: Checks: 8, Failures: 4, Errors: 1
+exp_verbose_result=`printf "37%%: Checks: 8, Failures: 4, Errors: 1
${SRCDIR}ex_output.c:31:P:Core:test_pass:0: Passed
${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure
${SRCDIR}ex_output.c:46:E:Core:test_exit:0: (after this point) Early exit with return value 1
@@ -46,22 +51,22 @@ ${SRCDIR}ex_output.c:66:P:Core:test_pass2:0: Passed
${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed
${SRCDIR}ex_output.c:72:P:Core:test_loop:1: Passed
${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed
-${SRCDIR}ex_output.c:78:F:description \" ' < > &:test_xml_esc_fail_msg:0: fail \" ' < > & message"
+${SRCDIR}ex_output.c:78:F:description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg:0: fail \" ' < > & \x9 \x0AX\x08 message"`
else
-exp_verbose_result="42%: Checks: 7, Failures: 4, Errors: 0
+exp_verbose_result=`printf "42%%: Checks: 7, Failures: 4, Errors: 0
${SRCDIR}ex_output.c:31:P:Core:test_pass:0: Passed
${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure
${SRCDIR}ex_output.c:66:P:Core:test_pass2:0: Passed
${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed
${SRCDIR}ex_output.c:72:P:Core:test_loop:1: Passed
${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed
-${SRCDIR}ex_output.c:78:F:description \" ' < > &:test_xml_esc_fail_msg:0: fail \" ' < > & message"
+${SRCDIR}ex_output.c:78:F:description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg:0: fail \" ' < > & \x9 \x0AX\x08 message"`
fi
exp_verbose="$suite_output
$exp_verbose_result"
if [ $HAVE_FORK -eq 1 ]; then
-exp_subunit="test: Core:test_pass
+exp_subunit=`printf "test: Core:test_pass
success: Core:test_pass
test: Core:test_fail
failure: Core:test_fail [
@@ -83,12 +88,12 @@ test: Core:test_loop
failure: Core:test_loop [
${SRCDIR}ex_output.c:72: Iteration 2 failed
]
-test: description \" ' < > &:test_xml_esc_fail_msg
-failure: description \" ' < > &:test_xml_esc_fail_msg [
-${SRCDIR}ex_output.c:78: fail \" ' < > & message
-]"
+test: description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg
+failure: description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg [
+${SRCDIR}ex_output.c:78: fail \" ' < > & \x9 \x0AX\x08 message
+]"`
else
-exp_subunit="test: Core:test_pass
+exp_subunit=`printf "test: Core:test_pass
success: Core:test_pass
test: Core:test_fail
failure: Core:test_fail [
@@ -106,17 +111,17 @@ test: Core:test_loop
failure: Core:test_loop [
${SRCDIR}ex_output.c:72: Iteration 2 failed
]
-test: description \" ' < > &:test_xml_esc_fail_msg
-failure: description \" ' < > &:test_xml_esc_fail_msg [
-${SRCDIR}ex_output.c:78: fail \" ' < > & message
-]"
+test: description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg
+failure: description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg [
+${SRCDIR}ex_output.c:78: fail \" ' < > & \x9 \x0AX\x08 message
+]"`
fi
##################
# log output
##################
if [ $HAVE_FORK -eq 1 ]; then
-expected_log_log="Running suite S1
+expected_log_log=`printf "Running suite S1
${SRCDIR}ex_output.c:31:P:Core:test_pass:0: Passed
${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure
${SRCDIR}ex_output.c:46:E:Core:test_exit:0: (after this point) Early exit with return value 1
@@ -125,12 +130,12 @@ ${SRCDIR}ex_output.c:66:P:Core:test_pass2:0: Passed
${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed
${SRCDIR}ex_output.c:72:P:Core:test_loop:1: Passed
${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed
-Running suite XML escape \" ' < > & tests
-${SRCDIR}ex_output.c:78:F:description \" ' < > &:test_xml_esc_fail_msg:0: fail \" ' < > & message
+Running suite XML escape \" ' < > & \x9 \x0AX\x08 tests
+${SRCDIR}ex_output.c:78:F:description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg:0: fail \" ' < > & \x9 \x0AX\x08 message
Results for all suites run:
-37%: Checks: 8, Failures: 4, Errors: 1"
+37%%: Checks: 8, Failures: 4, Errors: 1"`
else
-expected_log_log="Running suite S1
+expected_log_log=`printf "Running suite S1
${SRCDIR}ex_output.c:31:P:Core:test_pass:0: Passed
${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure
Running suite S2
@@ -138,10 +143,10 @@ ${SRCDIR}ex_output.c:66:P:Core:test_pass2:0: Passed
${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed
${SRCDIR}ex_output.c:72:P:Core:test_loop:1: Passed
${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed
-Running suite XML escape \" ' < > & tests
-${SRCDIR}ex_output.c:78:F:description \" ' < > &:test_xml_esc_fail_msg:0: fail \" ' < > & message
+Running suite XML escape \" ' < > & \x9 \x0AX\x08 tests
+${SRCDIR}ex_output.c:78:F:description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg:0: fail \" ' < > & \x9 \x0AX\x08 message
Results for all suites run:
-42%: Checks: 7, Failures: 4, Errors: 0"
+42%%: Checks: 7, Failures: 4, Errors: 0"`
fi
##################
@@ -207,19 +212,19 @@ expected_xml="
- XML escape " ' < > & tests
+ XML escape " ' < > &
X tests
ex_output.c:78
test_xml_esc_fail_msg
0
- description " ' < > &
- fail " ' < > & message
+ description " ' < > &
X end
+ fail " ' < > &
X message
"
expected_duration_count=9
else
-expected_xml="
+expected_xml="
@@ -271,13 +276,13 @@ expected_xml="
- XML escape " ' < > & tests
+ XML escape " ' < > &
X tests
ex_output.c:78
test_xml_esc_fail_msg
0
- description " ' < > &
- fail " ' < > & message
+ description " ' < > &
X end
+ fail " ' < > &
X message
"
@@ -288,16 +293,16 @@ fi
# tap output
##################
if [ $HAVE_FORK -eq 1 ]; then
-expected_normal_tap="ok 1 - ${SRCDIR}ex_output.c:Core:test_pass: Passed
+expected_normal_tap=`printf "ok 1 - ${SRCDIR}ex_output.c:Core:test_pass: Passed
not ok 2 - ${SRCDIR}ex_output.c:Core:test_fail: Failure
not ok 3 - ${SRCDIR}ex_output.c:Core:test_exit: Early exit with return value 1
ok 4 - ${SRCDIR}ex_output.c:Core:test_pass2: Passed
not ok 5 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 0 failed
ok 6 - ${SRCDIR}ex_output.c:Core:test_loop: Passed
not ok 7 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 2 failed
-not ok 8 - ${SRCDIR}ex_output.c:description \" ' < > &:test_xml_esc_fail_msg: fail \" ' < > & message
-1..8"
-expected_aborted_tap="ok 1 - ${SRCDIR}ex_output.c:Core:test_pass: Passed
+not ok 8 - ${SRCDIR}ex_output.c:description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg: fail \" ' < > & \x9 \x0AX\x08 message
+1..8"`
+expected_aborted_tap=`printf "ok 1 - ${SRCDIR}ex_output.c:Core:test_pass: Passed
not ok 2 - ${SRCDIR}ex_output.c:Core:test_fail: Failure
not ok 3 - ${SRCDIR}ex_output.c:Core:test_exit: Early exit with return value 1
not ok 4 - ${SRCDIR}ex_output.c:Core:test_abort: Early exit with return value 1
@@ -305,17 +310,17 @@ ok 5 - ${SRCDIR}ex_output.c:Core:test_pass2: Passed
not ok 6 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 0 failed
ok 7 - ${SRCDIR}ex_output.c:Core:test_loop: Passed
not ok 8 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 2 failed
-not ok 9 - ${SRCDIR}ex_output.c:description \" ' < > &:test_xml_esc_fail_msg: fail \" ' < > & message
-1..9"
+not ok 9 - ${SRCDIR}ex_output.c:description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg: fail \" ' < > & \x9 \x0AX\x08 message
+1..9"`
else
-expected_normal_tap="ok 1 - ${SRCDIR}ex_output.c:Core:test_pass: Passed
+expected_normal_tap=`printf "ok 1 - ${SRCDIR}ex_output.c:Core:test_pass: Passed
not ok 2 - ${SRCDIR}ex_output.c:Core:test_fail: Failure
ok 3 - ${SRCDIR}ex_output.c:Core:test_pass2: Passed
not ok 4 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 0 failed
ok 5 - ${SRCDIR}ex_output.c:Core:test_loop: Passed
not ok 6 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 2 failed
-not ok 7 - ${SRCDIR}ex_output.c:description \" ' < > &:test_xml_esc_fail_msg: fail \" ' < > & message
-1..7"
+not ok 7 - ${SRCDIR}ex_output.c:description \" ' < > & \x9 \x0AX\x08 end:test_xml_esc_fail_msg: fail \" ' < > & \x9 \x0AX\x08 message
+1..7"`
# When fork() is unavailable, one of the tests
# will invoke exit() which will terminate the
# unit testing program. In that case, the tap
diff --git a/tests/test_xml_output.sh b/tests/test_xml_output.sh
index 7497f376..11bb77ad 100755
--- a/tests/test_xml_output.sh
+++ b/tests/test_xml_output.sh
@@ -25,12 +25,18 @@ if [ x"${expected_duration_count}" != x"${actual_duration_count}" ]; then
exit 1;
fi
-for duration in `grep "\" ${OUTPUT_FILE} | cut -d ">" -f 2 | cut -d "<" -f 1`; do
-int_duration=`echo $duration | cut -d "." -f 1`
-if [ "${int_duration}" -ne "-1" ] && [ "${int_duration}" -gt "${CK_DEFAULT_TIMEOUT}" ]; then
- echo "Problem with duration ${duration}; is not valid. Should be -1 or in [0, ${CK_DEFAULT_TIMEOUT}]"
- exit 1
-fi
+num_durations=`grep "\" ${OUTPUT_FILE} | wc -l`
+
+i=1
+while [ ${i} -le ${num_durations} ]; do
+ duration=`grep "\" ${OUTPUT_FILE} | head -n ${i} | tail -n 1 | cut -d ">" -f 2 | cut -d "<" -f 1`
+ int_duration=`echo $duration | cut -d "." -f 1`
+ if [ "${int_duration}" -ne "-1" ] && [ "${int_duration}" -gt "${CK_DEFAULT_TIMEOUT}" ]; then
+ echo "Problem with duration ${duration}; is not valid. Should be -1 or in [0, ${CK_DEFAULT_TIMEOUT}]"
+ exit 1
+ fi
+
+ i=$((i+1))
done