2 * Copyright © 2012 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38 #include "weston-test-runner.h"
39 #include "weston-testsuite-data.h"
40 #include "shared/string-helpers.h"
43 * \defgroup testharness Test harness
44 * \defgroup testharness_private Test harness private
47 extern const struct weston_test_entry __start_test_section, __stop_test_section;
49 struct weston_test_run_info {
54 static const struct weston_test_run_info *test_run_info_;
56 /** Get the test name string with counter
58 * \return The test name with fixture number \c -f%%d added. For an array
59 * driven test, e.g. defined with TEST_P(), the name has also a \c -e%%d
60 * suffix to indicate the array element number.
62 * This is only usable from code paths inside TEST(), TEST_P(), PLUGIN_TEST()
63 * etc. defined functions.
65 * \ingroup testharness
70 return test_run_info_->name;
73 /** Get the current fixture index
75 * Returns the current fixture index which can be used directly as an index
76 * into the array passed as an argument to DECLARE_FIXTURE_SETUP_WITH_ARG().
78 * This is only usable from code paths inside TEST(), TEST_P(), PLUGIN_TEST()
79 * etc. defined functions.
81 * \ingroup testharness
84 get_test_fixture_index(void)
86 return test_run_info_->fixture_nr - 1;
89 /** Print into test log
91 * This is exactly like printf() except the output goes to the test log,
94 * \param fmt printf format string
96 * \ingroup testharness
99 testlog(const char *fmt, ...)
104 vfprintf(stderr, fmt, argp);
108 static const struct weston_test_entry *
109 find_test(const char *name)
111 const struct weston_test_entry *t;
113 for (t = &__start_test_section; t < &__stop_test_section; t++)
114 if (strcmp(t->name, name) == 0)
120 static enum test_result_code
121 run_test(int fixture_nr, const struct weston_test_entry *t, void *data,
124 struct weston_test_run_info info;
127 snprintf(info.name, sizeof(info.name), "%s-f%02d-e%02d",
128 t->name, fixture_nr, iteration);
130 snprintf(info.name, sizeof(info.name), "%s-f%02d",
131 t->name, fixture_nr);
133 info.fixture_nr = fixture_nr;
135 test_run_info_ = &info;
137 test_run_info_ = NULL;
140 * XXX: We should return t->run(data); but that requires changing
141 * the function signature and stop using assert() in tests.
142 * https://gitlab.freedesktop.org/wayland/weston/issues/311
150 const struct fixture_setup_array *fsa;
151 const struct weston_test_entry *t;
153 fsa = fixture_setup_array_get_();
155 printf("Fixture setups: %d\n", fsa->n_elements);
157 for (t = &__start_test_section; t < &__stop_test_section; t++) {
158 printf(" %s\n", t->name);
159 if (t->n_elements > 1)
160 printf(" with array of %d cases\n", t->n_elements);
164 struct weston_test_harness {
166 char *chosen_testname;
169 struct wet_testsuite_data data;
172 typedef void (*weston_test_cb)(struct wet_testsuite_data *suite_data,
173 const struct weston_test_entry *t,
174 const void *test_data,
178 for_each_test_case(struct wet_testsuite_data *data, weston_test_cb cb)
182 for (i = 0; i < data->tests_count; i++) {
183 const struct weston_test_entry *t = &data->tests[i];
184 const void *current_test_data = t->table_data;
188 if (data->case_index == -1) {
190 elem_end = t->n_elements;
192 elem = data->case_index;
196 for (; elem < elem_end; elem++) {
197 current_test_data = (char *)t->table_data +
198 elem * t->element_size;
199 cb(data, t, current_test_data, elem);
205 result_to_str(enum test_result_code ret)
207 static const char *names[] = {
208 [RESULT_FAIL] = "fail",
209 [RESULT_HARD_ERROR] = "hard error",
211 [RESULT_SKIP] = "skip",
214 assert(ret >= 0 && ret < ARRAY_LENGTH(names));
219 run_case(struct wet_testsuite_data *suite_data,
220 const struct weston_test_entry *t,
221 const void *test_data,
224 enum test_result_code ret;
225 const char *fail = "";
226 const char *skip = "";
227 int fixture_nr = suite_data->fixture_iteration + 1;
228 int iteration_nr = iteration + 1;
230 testlog("*** Run fixture %d, %s/%d\n",
231 fixture_nr, t->name, iteration_nr);
233 if (suite_data->type == TEST_TYPE_PLUGIN) {
234 ret = run_test(fixture_nr, t, suite_data->compositor,
237 ret = run_test(fixture_nr, t, (void *)test_data, iteration);
242 suite_data->passed++;
245 case RESULT_HARD_ERROR:
246 suite_data->failed++;
250 suite_data->skipped++;
255 testlog("*** Result fixture %d, %s/%d: %s\n",
256 fixture_nr, t->name, iteration_nr, result_to_str(ret));
258 suite_data->counter++;
259 printf("%sok %d fixture %d %s/%d%s\n", fail, suite_data->counter,
260 fixture_nr, t->name, iteration_nr, skip);
263 /* This function might run in a new thread */
265 testsuite_run(struct wet_testsuite_data *data)
267 for_each_test_case(data, run_case);
271 count_case(struct wet_testsuite_data *suite_data,
272 const struct weston_test_entry *t,
273 const void *test_data,
280 tap_plan(struct wet_testsuite_data *data, int count_fixtures)
283 for_each_test_case(data, count_case);
285 printf("1..%d\n", data->total * count_fixtures);
289 skip_case(struct wet_testsuite_data *suite_data,
290 const struct weston_test_entry *t,
291 const void *test_data,
294 int fixture_nr = suite_data->fixture_iteration + 1;
295 int iteration_nr = iteration + 1;
297 suite_data->counter++;
298 printf("ok %d fixture %d %s/%d # SKIP fixture\n", suite_data->counter,
299 fixture_nr, t->name, iteration_nr);
303 tap_skip_fixture(struct wet_testsuite_data *data)
305 for_each_test_case(data, skip_case);
309 help(const char *exe)
312 "Usage: %s [options] [testname [index]]\n"
314 "This is a Weston test suite executable that runs some tests.\n"
316 " -f, --fixture N Run only fixture index N. Indices start from 1.\n"
317 " -h, --help Print this help and exit with success.\n"
318 " -l, --list List all tests in this executable and exit with success.\n"
319 "testname: Optional; name of the test to execute instead of all tests.\n"
320 "index: Optional; for a multi-case test, run the given case only.\n",
325 parse_command_line(struct weston_test_harness *harness, int argc, char **argv)
328 static const struct option opts[] = {
329 { "fixture", required_argument, NULL, 'f' },
330 { "help", no_argument, NULL, 'h' },
331 { "list", no_argument, NULL, 'l' },
335 while ((c = getopt_long(argc, argv, "f:hl", opts, NULL)) != -1) {
338 if (!safe_strtoint(optarg, &harness->fixt_ind)) {
340 "Error: '%s' does not look like a number (command line).\n",
342 exit(RESULT_HARD_ERROR);
344 harness->fixt_ind--; /* convert base-1 to base 0 */
355 exit(RESULT_HARD_ERROR);
360 harness->chosen_testname = argv[optind++];
363 if (!safe_strtoint(argv[optind], &harness->case_ind)) {
365 "Error: '%s' does not look like a number (command line).\n",
367 exit(RESULT_HARD_ERROR);
369 harness->case_ind--; /* convert base-1 to base 0 */
374 fprintf(stderr, "Unexpected extra arguments given (command line).\n\n");
376 exit(RESULT_HARD_ERROR);
380 static struct weston_test_harness *
381 weston_test_harness_create(int argc, char **argv)
383 const struct fixture_setup_array *fsa;
384 struct weston_test_harness *harness;
386 harness = zalloc(sizeof(*harness));
389 harness->fixt_ind = -1;
390 harness->case_ind = -1;
391 parse_command_line(harness, argc, argv);
393 fsa = fixture_setup_array_get_();
394 if (harness->fixt_ind < -1 || harness->fixt_ind >= fsa->n_elements) {
396 "Error: fixture index %d (command line) is invalid for this program.\n",
397 harness->fixt_ind + 1);
398 exit(RESULT_HARD_ERROR);
401 if (harness->chosen_testname) {
402 const struct weston_test_entry *t;
404 t = find_test(harness->chosen_testname);
407 "Error: test '%s' not found (command line).\n",
408 harness->chosen_testname);
409 exit(RESULT_HARD_ERROR);
412 if (harness->case_ind < -1 ||
413 harness->case_ind >= t->n_elements) {
415 "Error: case index %d (command line) is invalid for this test.\n",
416 harness->case_ind + 1);
417 exit(RESULT_HARD_ERROR);
420 harness->data.tests = t;
421 harness->data.tests_count = 1;
422 harness->data.case_index = harness->case_ind;
424 harness->data.tests = &__start_test_section;
425 harness->data.tests_count =
426 &__stop_test_section - &__start_test_section;
427 harness->data.case_index = -1;
430 harness->data.run = testsuite_run;
436 weston_test_harness_destroy(struct weston_test_harness *harness)
441 static enum test_result_code
442 counts_to_result(const struct wet_testsuite_data *data)
444 /* RESULT_SKIP is reserved for fixture setup itself skipping everything */
445 if (data->total == data->passed + data->skipped)
450 /** Execute all tests as client tests
452 * \param harness The test harness context.
453 * \param setup The compositor configuration.
455 * Initializes the compositor with the given setup and executes the compositor.
456 * The compositor creates a new thread where all tests in the test program are
457 * serially executed. Once the thread finishes, the compositor returns from its
458 * event loop and cleans up.
460 * Returns RESULT_SKIP if the requested compositor features, e.g. GL-renderer,
463 * \sa DECLARE_FIXTURE_SETUP(), DECLARE_FIXTURE_SETUP_WITH_ARG()
464 * \ingroup testharness
466 enum test_result_code
467 weston_test_harness_execute_as_client(struct weston_test_harness *harness,
468 const struct compositor_setup *setup)
470 struct wet_testsuite_data *data = &harness->data;
472 data->type = TEST_TYPE_CLIENT;
473 return execute_compositor(setup, data);
476 /** Execute all tests as plugin tests
478 * \param harness The test harness context.
479 * \param setup The compositor configuration.
481 * Initializes the compositor with the given setup and executes the compositor.
482 * The compositor executes all tests in the test program serially from an idle
483 * handler, then returns from its event loop and cleans up.
485 * Returns RESULT_SKIP if the requested compositor features, e.g. GL-renderer,
488 * \sa DECLARE_FIXTURE_SETUP(), DECLARE_FIXTURE_SETUP_WITH_ARG()
489 * \ingroup testharness
491 enum test_result_code
492 weston_test_harness_execute_as_plugin(struct weston_test_harness *harness,
493 const struct compositor_setup *setup)
495 struct wet_testsuite_data *data = &harness->data;
497 data->type = TEST_TYPE_PLUGIN;
498 return execute_compositor(setup, data);
501 /** Execute all tests as standalone tests
503 * \param harness The test harness context.
505 * Executes all tests in the test program serially without any further setup,
506 * particularly without any compositor instance created.
508 * \sa DECLARE_FIXTURE_SETUP(), DECLARE_FIXTURE_SETUP_WITH_ARG()
509 * \ingroup testharness
511 enum test_result_code
512 weston_test_harness_execute_standalone(struct weston_test_harness *harness)
514 struct wet_testsuite_data *data = &harness->data;
516 data->type = TEST_TYPE_STANDALONE;
522 /** Fixture data array getter method
524 * DECLARE_FIXTURE_SETUP_WITH_ARG() overrides this in test programs.
525 * The default implementation has no data and makes the tests run once.
527 * \ingroup testharness
529 __attribute__((weak)) const struct fixture_setup_array *
530 fixture_setup_array_get_(void)
532 /* A dummy fixture without a data array. */
533 static const struct fixture_setup_array default_fsa = {
542 /** Fixture setup function
544 * DECLARE_FIXTURE_SETUP() and DECLARE_FIXTURE_SETUP_WITH_ARG() override
545 * this in test programs.
546 * The default implementation just calls
547 * weston_test_harness_execute_standalone().
549 * \ingroup testharness
551 __attribute__((weak)) enum test_result_code
552 fixture_setup_run_(struct weston_test_harness *harness, const void *arg_)
554 return weston_test_harness_execute_standalone(harness);
558 fixture_report(const struct wet_testsuite_data *d, enum test_result_code ret)
560 int fixture_nr = d->fixture_iteration + 1;
562 testlog("--- Fixture %d %s: passed %d, skipped %d, failed %d, total %d\n",
563 fixture_nr, result_to_str(ret),
564 d->passed, d->skipped, d->failed, d->total);
568 main(int argc, char *argv[])
570 struct weston_test_harness *harness;
571 enum test_result_code ret;
572 enum test_result_code result = RESULT_OK;
573 const struct fixture_setup_array *fsa;
574 const char *array_data;
578 harness = weston_test_harness_create(argc, argv);
580 fsa = fixture_setup_array_get_();
581 array_data = fsa->array;
583 if (harness->fixt_ind == -1) {
585 fi_end = fsa->n_elements;
587 fi = harness->fixt_ind;
591 tap_plan(&harness->data, fi_end - fi);
592 testlog("Iterating through %d fixtures.\n", fi_end - fi);
594 for (; fi < fi_end; fi++) {
595 const void *arg = array_data + fi * fsa->element_size;
597 testlog("--- Fixture %d...\n", fi + 1);
598 harness->data.fixture_iteration = fi;
599 harness->data.passed = 0;
600 harness->data.skipped = 0;
601 harness->data.failed = 0;
603 ret = fixture_setup_run_(harness, arg);
604 fixture_report(&harness->data, ret);
606 if (ret == RESULT_SKIP) {
607 tap_skip_fixture(&harness->data);
611 if (ret != RESULT_OK && result != RESULT_HARD_ERROR)
613 else if (counts_to_result(&harness->data) != RESULT_OK)
614 result = RESULT_FAIL;
617 weston_test_harness_destroy(harness);