Skip to content

Commit

Permalink
Emit only valid XML characters
Browse files Browse the repository at this point in the history
Previously output XML files could contain illegal characters.
Some of these characters could be encoded, and others should
not be output at all.

This change will attempt to encode characters if they are not
printable or are special. Note that if a test contains a UTF-8
charater it will not be printed out accurately.

In order to get the tests for encoding XML characters to work,
the characters separating fields in a shell variable needed to
be changed. Originally white space would separate fields,
meaning shell would eat the extra whitespace in the tests.
Because of the change, the xml output test needed to be
reworked to not rely on white space field separators.
Additionally, the printf program is used to properly un-escape
strings used in the tests.

git-svn-id: svn+ssh://svn.code.sf.net/p/check/code/trunk@1225 64e312b2-a51f-0410-8e61-82d0ca0eb02a
  • Loading branch information
brarcher committed Sep 14, 2015
1 parent f21438f commit e18f163
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 76 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -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

Expand Down
65 changes: 42 additions & 23 deletions src/check_print.c
Original file line number Diff line number Diff line change
Expand Up @@ -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("&quot;", file);
break;
case '\'':
fputs("&apos;", file);
break;
case '<':
fputs("&lt;", file);
break;
case '>':
fputs("&gt;", file);
break;
case '&':
fputs("&amp;", file);
break;

/* regular characters, print as is */
default:
fputc(*str, file);
break;
switch (next)
{
case '"':
fputs("&quot;", file);
break;
case '\'':
fputs("&apos;", file);
break;
case '<':
fputs("&lt;", file);
break;
case '>':
fputs("&gt;", file);
break;
case '&':
fputs("&amp;", 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%X;", next);
}
/* If it did not get printed, it is not a valid XML character*/
}
}

Expand Down
6 changes: 3 additions & 3 deletions tests/ex_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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);
Expand Down
93 changes: 49 additions & 44 deletions tests/test_output_strings
Original file line number Diff line number Diff line change
Expand Up @@ -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=""

Expand All @@ -20,48 +25,48 @@ 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
${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 [
Expand All @@ -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 [
Expand All @@ -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
Expand All @@ -125,23 +130,23 @@ ${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
${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

##################
Expand Down Expand Up @@ -207,19 +212,19 @@ expected_xml="<?xml version=\"1.0\"?>
</test>
</suite>
<suite>
<title>XML escape &quot; &apos; &lt; &gt; &amp; tests</title>
<title>XML escape &quot; &apos; &lt; &gt; &amp; &#x9; &#xA;X tests</title>
<test result=\"failure\">
<fn>ex_output.c:78</fn>
<id>test_xml_esc_fail_msg</id>
<iteration>0</iteration>
<description>description &quot; &apos; &lt; &gt; &amp;</description>
<message>fail &quot; &apos; &lt; &gt; &amp; message</message>
<description>description &quot; &apos; &lt; &gt; &amp; &#x9; &#xA;X end</description>
<message>fail &quot; &apos; &lt; &gt; &amp; &#x9; &#xA;X message</message>
</test>
</suite>
</testsuites>"
expected_duration_count=9
else
expected_xml="<?xml version=\"1.0\"?>
expected_xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<?xml-stylesheet type=\"text/xsl\" href=\"http://check.sourceforge.net/xml/check_unittest.xslt\"?>
<testsuites xmlns=\"http://check.sourceforge.net/ns\">
<suite>
Expand Down Expand Up @@ -271,13 +276,13 @@ expected_xml="<?xml version=\"1.0\"?>
</test>
</suite>
<suite>
<title>XML escape &quot; &apos; &lt; &gt; &amp; tests</title>
<title>XML escape &quot; &apos; &lt; &gt; &amp; &#x9; &#xA;X tests</title>
<test result=\"failure\">
<fn>ex_output.c:78</fn>
<id>test_xml_esc_fail_msg</id>
<iteration>0</iteration>
<description>description &quot; &apos; &lt; &gt; &amp;</description>
<message>fail &quot; &apos; &lt; &gt; &amp; message</message>
<description>description &quot; &apos; &lt; &gt; &amp; &#x9; &#xA;X end</description>
<message>fail &quot; &apos; &lt; &gt; &amp; &#x9; &#xA;X message</message>
</test>
</suite>
</testsuites>"
Expand All @@ -288,34 +293,34 @@ 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
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
Expand Down
18 changes: 12 additions & 6 deletions tests/test_xml_output.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@ if [ x"${expected_duration_count}" != x"${actual_duration_count}" ]; then
exit 1;
fi

for duration in `grep "\<duration\>" ${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 "\<duration\>" ${OUTPUT_FILE} | wc -l`

i=1
while [ ${i} -le ${num_durations} ]; do
duration=`grep "\<duration\>" ${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


Expand Down

0 comments on commit e18f163

Please sign in to comment.