mirror of
https://github.com/libexpat/libexpat.git
synced 2025-04-06 13:45:00 +00:00
tests: Run SINGLE_BYTES with variously-sized chunks
The _XML_Parse_SINGLE_BYTES function currently calls XML_Parse() one byte at a time. This is useful to detect possible parsing bugs related to having to exit parsing, wait for more data, and resume. This commit makes SINGLE_BYTES even more useful by repeating all tests, changing the chunk size every time. So instead of just one byte at a time, we now also test two bytes at a time, and so on. Tests that don't use the SINGLE_BYTES also run multiple times, but are otherwise not affected. This uncovered some issues, which have been fixed in preceding commits. On failure, the chunk size is included in the "FAIL" log prints.
This commit is contained in:
parent
4978d285d2
commit
1d8ceb26aa
5 changed files with 40 additions and 22 deletions
|
@ -18,6 +18,7 @@
|
|||
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
|
||||
Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
|
||||
Copyright (c) 2021 Donghee Na <donghee.na@python.org>
|
||||
Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -137,6 +138,9 @@ XML_Bool g_resumable = XML_FALSE;
|
|||
/* Used to control abort checks in some tests */
|
||||
XML_Bool g_abortable = XML_FALSE;
|
||||
|
||||
/* Used to control _XML_Parse_SINGLE_BYTES() chunk size */
|
||||
int g_chunkSize = 1;
|
||||
|
||||
/* Common test functions */
|
||||
|
||||
void
|
||||
|
@ -176,22 +180,19 @@ _xml_failure(XML_Parser parser, const char *file, int line) {
|
|||
enum XML_Status
|
||||
_XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len,
|
||||
int isFinal) {
|
||||
enum XML_Status res = XML_STATUS_ERROR;
|
||||
const int chunksize = g_chunkSize;
|
||||
int offset = 0;
|
||||
|
||||
if (len == 0) {
|
||||
return XML_Parse(parser, s, len, isFinal);
|
||||
}
|
||||
|
||||
for (; offset < len; offset++) {
|
||||
const int innerIsFinal = (offset == len - 1) && isFinal;
|
||||
const char c = s[offset]; /* to help out-of-bounds detection */
|
||||
res = XML_Parse(parser, &c, sizeof(char), innerIsFinal);
|
||||
if (res != XML_STATUS_OK) {
|
||||
return res;
|
||||
if (chunksize > 0) {
|
||||
// parse in chunks of `chunksize` bytes as long as possible
|
||||
for (; offset + chunksize < len; offset += chunksize) {
|
||||
enum XML_Status res = XML_Parse(parser, s + offset, chunksize, XML_FALSE);
|
||||
if (res != XML_STATUS_OK) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
// parse the final chunk, the size of which will be <= chunksize
|
||||
return XML_Parse(parser, s + offset, len - offset, isFinal);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
|
||||
Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
|
||||
Copyright (c) 2021 Donghee Na <donghee.na@python.org>
|
||||
Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -82,6 +83,8 @@ extern XML_Parser g_parser;
|
|||
extern XML_Bool g_resumable;
|
||||
extern XML_Bool g_abortable;
|
||||
|
||||
extern int g_chunkSize;
|
||||
|
||||
extern const char *long_character_data_text;
|
||||
extern const char *long_cdata_text;
|
||||
extern const char *get_buffer_test_text;
|
||||
|
|
|
@ -176,19 +176,20 @@ handle_success(int verbosity) {
|
|||
}
|
||||
|
||||
static void
|
||||
handle_failure(SRunner *runner, int verbosity, const char *phase_info) {
|
||||
handle_failure(SRunner *runner, int verbosity, const char *context,
|
||||
const char *phase_info) {
|
||||
runner->nfailures++;
|
||||
if (verbosity != CK_SILENT) {
|
||||
if (strlen(_check_current_subtest) != 0) {
|
||||
phase_info = _check_current_subtest;
|
||||
}
|
||||
printf("FAIL: %s (%s at %s:%d)\n", _check_current_function, phase_info,
|
||||
_check_current_filename, _check_current_lineno);
|
||||
printf("FAIL [%s]: %s (%s at %s:%d)\n", context, _check_current_function,
|
||||
phase_info, _check_current_filename, _check_current_lineno);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
srunner_run_all(SRunner *runner, int verbosity) {
|
||||
srunner_run_all(SRunner *runner, const char *context, int verbosity) {
|
||||
Suite *suite;
|
||||
TCase *volatile tc;
|
||||
assert(runner != NULL);
|
||||
|
@ -203,14 +204,14 @@ srunner_run_all(SRunner *runner, int verbosity) {
|
|||
if (tc->setup != NULL) {
|
||||
/* setup */
|
||||
if (setjmp(env)) {
|
||||
handle_failure(runner, verbosity, "during setup");
|
||||
handle_failure(runner, verbosity, context, "during setup");
|
||||
continue;
|
||||
}
|
||||
tc->setup();
|
||||
}
|
||||
/* test */
|
||||
if (setjmp(env)) {
|
||||
handle_failure(runner, verbosity, "during actual test");
|
||||
handle_failure(runner, verbosity, context, "during actual test");
|
||||
continue;
|
||||
}
|
||||
(tc->tests[i])();
|
||||
|
@ -219,7 +220,7 @@ srunner_run_all(SRunner *runner, int verbosity) {
|
|||
/* teardown */
|
||||
if (tc->teardown != NULL) {
|
||||
if (setjmp(env)) {
|
||||
handle_failure(runner, verbosity, "during teardown");
|
||||
handle_failure(runner, verbosity, context, "during teardown");
|
||||
continue;
|
||||
}
|
||||
tc->teardown();
|
||||
|
@ -229,6 +230,10 @@ srunner_run_all(SRunner *runner, int verbosity) {
|
|||
}
|
||||
tc = tc->next_tcase;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
srunner_summarize(SRunner *runner, int verbosity) {
|
||||
if (verbosity != CK_SILENT) {
|
||||
int passed = runner->nchecks - runner->nfailures;
|
||||
double percentage = ((double)passed) / runner->nchecks;
|
||||
|
|
|
@ -132,7 +132,8 @@ void tcase_add_checked_fixture(TCase *, tcase_setup_function,
|
|||
tcase_teardown_function);
|
||||
void tcase_add_test(TCase *tc, tcase_test_function test);
|
||||
SRunner *srunner_create(Suite *suite);
|
||||
void srunner_run_all(SRunner *runner, int verbosity);
|
||||
void srunner_run_all(SRunner *runner, const char *context, int verbosity);
|
||||
void srunner_summarize(SRunner *runner, int verbosity);
|
||||
int srunner_ntests_failed(SRunner *runner);
|
||||
void srunner_free(SRunner *runner);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
|
||||
Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
|
||||
Copyright (c) 2021 Donghee Na <donghee.na@python.org>
|
||||
Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -95,7 +96,14 @@ main(int argc, char *argv[]) {
|
|||
}
|
||||
if (verbosity != CK_SILENT)
|
||||
printf("Expat version: %" XML_FMT_STR "\n", XML_ExpatVersion());
|
||||
srunner_run_all(sr, verbosity);
|
||||
|
||||
for (g_chunkSize = 1; g_chunkSize <= 5; g_chunkSize++) {
|
||||
char context[100];
|
||||
snprintf(context, sizeof(context), "chunksize=%d", g_chunkSize);
|
||||
context[sizeof(context) - 1] = '\0';
|
||||
srunner_run_all(sr, context, verbosity);
|
||||
}
|
||||
srunner_summarize(sr, verbosity);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue