You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							682 lines
						
					
					
						
							17 KiB
						
					
					
				
			
		
		
	
	
							682 lines
						
					
					
						
							17 KiB
						
					
					
				/*
 | 
						|
 * Copyright © 2012 Intel Corporation
 | 
						|
 *
 | 
						|
 * Permission is hereby granted, free of charge, to any person obtaining
 | 
						|
 * a copy of this software and associated documentation files (the
 | 
						|
 * "Software"), to deal in the Software without restriction, including
 | 
						|
 * without limitation the rights to use, copy, modify, merge, publish,
 | 
						|
 * distribute, sublicense, and/or sell copies of the Software, and to
 | 
						|
 * permit persons to whom the Software is furnished to do so, subject to
 | 
						|
 * the following conditions:
 | 
						|
 *
 | 
						|
 * The above copyright notice and this permission notice (including the
 | 
						|
 * next paragraph) shall be included in all copies or substantial
 | 
						|
 * portions of the Software.
 | 
						|
 *
 | 
						|
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
						|
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
						|
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
						|
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 | 
						|
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 | 
						|
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
						|
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
						|
 * SOFTWARE.
 | 
						|
 */
 | 
						|
 | 
						|
#include "config.h"
 | 
						|
 | 
						|
#include <unistd.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <sys/wait.h>
 | 
						|
#include <string.h>
 | 
						|
#include <assert.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <getopt.h>
 | 
						|
 | 
						|
#include "test-config.h"
 | 
						|
#include "weston-test-runner.h"
 | 
						|
#include "weston-testsuite-data.h"
 | 
						|
#include "shared/string-helpers.h"
 | 
						|
 | 
						|
/**
 | 
						|
 * \defgroup testharness Test harness
 | 
						|
 * \defgroup testharness_private Test harness private
 | 
						|
 */
 | 
						|
 | 
						|
extern const struct weston_test_entry __start_test_section, __stop_test_section;
 | 
						|
 | 
						|
struct weston_test_run_info {
 | 
						|
	char name[512];
 | 
						|
	int fixture_nr;
 | 
						|
};
 | 
						|
 | 
						|
static const struct weston_test_run_info *test_run_info_;
 | 
						|
 | 
						|
/** Get the test name string with counter
 | 
						|
 *
 | 
						|
 * \return The test name with fixture number \c -f%%d added. For an array
 | 
						|
 * driven test, e.g. defined with TEST_P(), the name has also a \c -e%%d
 | 
						|
 * suffix to indicate the array element number.
 | 
						|
 *
 | 
						|
 * This is only usable from code paths inside TEST(), TEST_P(), PLUGIN_TEST()
 | 
						|
 * etc. defined functions.
 | 
						|
 *
 | 
						|
 * \ingroup testharness
 | 
						|
 */
 | 
						|
const char *
 | 
						|
get_test_name(void)
 | 
						|
{
 | 
						|
	return test_run_info_->name;
 | 
						|
}
 | 
						|
 | 
						|
/** Get the current fixture index
 | 
						|
 *
 | 
						|
 * Returns the current fixture index which can be used directly as an index
 | 
						|
 * into the array passed as an argument to DECLARE_FIXTURE_SETUP_WITH_ARG().
 | 
						|
 *
 | 
						|
 * This is only usable from code paths inside TEST(), TEST_P(), PLUGIN_TEST()
 | 
						|
 * etc. defined functions.
 | 
						|
 *
 | 
						|
 * \ingroup testharness
 | 
						|
 */
 | 
						|
int
 | 
						|
get_test_fixture_index(void)
 | 
						|
{
 | 
						|
	return test_run_info_->fixture_nr - 1;
 | 
						|
}
 | 
						|
 | 
						|
/** Print into test log
 | 
						|
 *
 | 
						|
 * This is exactly like printf() except the output goes to the test log,
 | 
						|
 * which is at stderr.
 | 
						|
 *
 | 
						|
 * \param fmt printf format string
 | 
						|
 *
 | 
						|
 * \ingroup testharness
 | 
						|
 */
 | 
						|
void
 | 
						|
testlog(const char *fmt, ...)
 | 
						|
{
 | 
						|
	va_list argp;
 | 
						|
 | 
						|
	va_start(argp, fmt);
 | 
						|
	vfprintf(stderr, fmt, argp);
 | 
						|
	va_end(argp);
 | 
						|
}
 | 
						|
 | 
						|
static const void *
 | 
						|
fixture_setup_array_get_arg(const struct fixture_setup_array *fsa, int findex)
 | 
						|
{
 | 
						|
	const char *array_data = fsa->array;
 | 
						|
 | 
						|
	if (array_data)
 | 
						|
		return array_data + findex * fsa->element_size;
 | 
						|
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static const char *
 | 
						|
fixture_setup_array_get_name(const struct fixture_setup_array *fsa, int findex)
 | 
						|
{
 | 
						|
	const char *element_data = fixture_setup_array_get_arg(fsa, findex);
 | 
						|
	const struct fixture_metadata *meta;
 | 
						|
 | 
						|
	if (!element_data)
 | 
						|
		return "";
 | 
						|
 | 
						|
	meta = (const void *)(element_data + fsa->meta_offset);
 | 
						|
 | 
						|
	return meta->name;
 | 
						|
}
 | 
						|
 | 
						|
static const struct weston_test_entry *
 | 
						|
find_test(const char *name)
 | 
						|
{
 | 
						|
	const struct weston_test_entry *t;
 | 
						|
 | 
						|
	for (t = &__start_test_section; t < &__stop_test_section; t++)
 | 
						|
		if (strcmp(t->name, name) == 0)
 | 
						|
			return t;
 | 
						|
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static enum test_result_code
 | 
						|
run_test(int fixture_nr, const struct weston_test_entry *t, void *data,
 | 
						|
	 int iteration)
 | 
						|
{
 | 
						|
	struct weston_test_run_info info;
 | 
						|
 | 
						|
	if (data) {
 | 
						|
		snprintf(info.name, sizeof(info.name), "%s-f%02d-e%02d",
 | 
						|
			 t->name, fixture_nr, iteration);
 | 
						|
	} else {
 | 
						|
		snprintf(info.name, sizeof(info.name), "%s-f%02d",
 | 
						|
			 t->name, fixture_nr);
 | 
						|
	}
 | 
						|
	info.fixture_nr = fixture_nr;
 | 
						|
 | 
						|
	test_run_info_ = &info;
 | 
						|
	t->run(data);
 | 
						|
	test_run_info_ = NULL;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * XXX: We should return t->run(data); but that requires changing
 | 
						|
	 * the function signature and stop using assert() in tests.
 | 
						|
	 * https://gitlab.freedesktop.org/wayland/weston/issues/311
 | 
						|
	 */
 | 
						|
	return RESULT_OK;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
list_tests(void)
 | 
						|
{
 | 
						|
	const struct fixture_setup_array *fsa;
 | 
						|
	const struct weston_test_entry *t;
 | 
						|
	int i;
 | 
						|
 | 
						|
	fsa = fixture_setup_array_get_();
 | 
						|
 | 
						|
	if (fsa->n_elements > 1) {
 | 
						|
		printf("Fixture setups:\n");
 | 
						|
		for (i = 0; i < fsa->n_elements; i++) {
 | 
						|
			printf("%2d: %s\n", i + 1,
 | 
						|
			       fixture_setup_array_get_name(fsa, i));
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		printf("One fixture setup.\n");
 | 
						|
	}
 | 
						|
 | 
						|
	printf("Test names:\n");
 | 
						|
	for (t = &__start_test_section; t < &__stop_test_section; t++) {
 | 
						|
		printf("  %s\n", t->name);
 | 
						|
		if (t->n_elements > 1)
 | 
						|
			printf("    with array of %d cases\n", t->n_elements);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
struct weston_test_harness {
 | 
						|
	int32_t fixt_ind;
 | 
						|
	char *chosen_testname;
 | 
						|
	int32_t case_ind;
 | 
						|
 | 
						|
	struct wet_testsuite_data data;
 | 
						|
};
 | 
						|
 | 
						|
typedef void (*weston_test_cb)(struct wet_testsuite_data *suite_data,
 | 
						|
			       const struct weston_test_entry *t,
 | 
						|
			       const void *test_data,
 | 
						|
			       int iteration);
 | 
						|
 | 
						|
static void
 | 
						|
for_each_test_case(struct wet_testsuite_data *data, weston_test_cb cb)
 | 
						|
{
 | 
						|
	unsigned i;
 | 
						|
 | 
						|
	for (i = 0; i < data->tests_count; i++) {
 | 
						|
		const struct weston_test_entry *t = &data->tests[i];
 | 
						|
		const void *current_test_data = t->table_data;
 | 
						|
		int elem;
 | 
						|
		int elem_end;
 | 
						|
 | 
						|
		if (data->case_index == -1) {
 | 
						|
			elem = 0;
 | 
						|
			elem_end = t->n_elements;
 | 
						|
		} else {
 | 
						|
			elem = data->case_index;
 | 
						|
			elem_end = elem + 1;
 | 
						|
		}
 | 
						|
 | 
						|
		for (; elem < elem_end; elem++) {
 | 
						|
			current_test_data = (char *)t->table_data +
 | 
						|
					    elem * t->element_size;
 | 
						|
			cb(data, t, current_test_data, elem);
 | 
						|
		 }
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static const char *
 | 
						|
result_to_str(enum test_result_code ret)
 | 
						|
{
 | 
						|
	static const char *names[] = {
 | 
						|
		[RESULT_FAIL] = "fail",
 | 
						|
		[RESULT_HARD_ERROR] = "hard error",
 | 
						|
		[RESULT_OK] = "ok",
 | 
						|
#if WESTON_TEST_SKIP_IS_FAILURE
 | 
						|
		[RESULT_SKIP] = "skip error",
 | 
						|
#else
 | 
						|
		[RESULT_SKIP] = "skip",
 | 
						|
#endif
 | 
						|
	};
 | 
						|
 | 
						|
	assert(ret >= 0 && ret < ARRAY_LENGTH(names));
 | 
						|
	return names[ret];
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
run_case(struct wet_testsuite_data *suite_data,
 | 
						|
	 const struct weston_test_entry *t,
 | 
						|
	 const void *test_data,
 | 
						|
	 int iteration)
 | 
						|
{
 | 
						|
	enum test_result_code ret;
 | 
						|
	const char *fail = "";
 | 
						|
	const char *skip = "";
 | 
						|
	int fixture_nr = suite_data->fixture_iteration + 1;
 | 
						|
	int iteration_nr = iteration + 1;
 | 
						|
 | 
						|
	testlog("*** Run %s %s/%d\n",
 | 
						|
		suite_data->fixture_name, t->name, iteration_nr);
 | 
						|
 | 
						|
	if (suite_data->type == TEST_TYPE_PLUGIN) {
 | 
						|
		ret = run_test(fixture_nr, t, suite_data->compositor,
 | 
						|
			       iteration);
 | 
						|
	} else {
 | 
						|
		ret = run_test(fixture_nr, t, (void *)test_data, iteration);
 | 
						|
	}
 | 
						|
 | 
						|
	switch (ret) {
 | 
						|
	case RESULT_OK:
 | 
						|
		suite_data->passed++;
 | 
						|
		break;
 | 
						|
	case RESULT_FAIL:
 | 
						|
	case RESULT_HARD_ERROR:
 | 
						|
		suite_data->failed++;
 | 
						|
		fail = "not ";
 | 
						|
		break;
 | 
						|
	case RESULT_SKIP:
 | 
						|
		suite_data->skipped++;
 | 
						|
		skip = " # SKIP";
 | 
						|
#if WESTON_TEST_SKIP_IS_FAILURE
 | 
						|
		fail = "not ";
 | 
						|
#endif
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	testlog("*** Result %s %s/%d: %s\n",
 | 
						|
		suite_data->fixture_name, t->name, iteration_nr,
 | 
						|
		result_to_str(ret));
 | 
						|
 | 
						|
	suite_data->counter++;
 | 
						|
	printf("%sok %d %s %s/%d%s\n", fail, suite_data->counter,
 | 
						|
	       suite_data->fixture_name, t->name, iteration_nr, skip);
 | 
						|
}
 | 
						|
 | 
						|
/* This function might run in a new thread */
 | 
						|
static void
 | 
						|
testsuite_run(struct wet_testsuite_data *data)
 | 
						|
{
 | 
						|
	for_each_test_case(data, run_case);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
count_case(struct wet_testsuite_data *suite_data,
 | 
						|
	   const struct weston_test_entry *t,
 | 
						|
	   const void *test_data,
 | 
						|
	   int iteration)
 | 
						|
{
 | 
						|
	suite_data->total++;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
tap_plan(struct wet_testsuite_data *data, int count_fixtures)
 | 
						|
{
 | 
						|
	data->total = 0;
 | 
						|
	for_each_test_case(data, count_case);
 | 
						|
 | 
						|
	printf("1..%d\n", data->total * count_fixtures);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
skip_case(struct wet_testsuite_data *suite_data,
 | 
						|
	  const struct weston_test_entry *t,
 | 
						|
	  const void *test_data,
 | 
						|
	  int iteration)
 | 
						|
{
 | 
						|
	const char *skip_error = "";
 | 
						|
	int iteration_nr = iteration + 1;
 | 
						|
 | 
						|
#if WESTON_TEST_SKIP_IS_FAILURE
 | 
						|
	skip_error = "not ";
 | 
						|
#endif
 | 
						|
 | 
						|
	suite_data->counter++;
 | 
						|
	printf("%sok %d %s %s/%d # SKIP fixture\n",
 | 
						|
	       skip_error, suite_data->counter,
 | 
						|
	       suite_data->fixture_name, t->name, iteration_nr);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
tap_skip_fixture(struct wet_testsuite_data *data)
 | 
						|
{
 | 
						|
	for_each_test_case(data, skip_case);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
help(const char *exe)
 | 
						|
{
 | 
						|
	printf(
 | 
						|
		"Usage: %s [options] [testname [number]]\n"
 | 
						|
		"\n"
 | 
						|
		"This is a Weston test suite executable that runs some tests.\n"
 | 
						|
		"Options:\n"
 | 
						|
		"  -f, --fixture N  Run only fixture number N. 0 runs all (default).\n"
 | 
						|
		"  -h, --help       Print this help and exit with success.\n"
 | 
						|
		"  -l, --list       List all tests in this executable and exit with success.\n"
 | 
						|
		"testname:          Optional; name of the test to execute instead of all tests.\n"
 | 
						|
		"number:            Optional; for a multi-case test, run the given case only.\n"
 | 
						|
		"Both fixture and case numbering starts from 1.\n",
 | 
						|
		exe);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
parse_command_line(struct weston_test_harness *harness, int argc, char **argv)
 | 
						|
{
 | 
						|
	int c;
 | 
						|
	static const struct option opts[] = {
 | 
						|
		{ "fixture", required_argument, NULL,      'f' },
 | 
						|
		{ "help",    no_argument,       NULL,      'h' },
 | 
						|
		{ "list",    no_argument,       NULL,      'l' },
 | 
						|
		{ 0,         0,                 NULL,      0  }
 | 
						|
	};
 | 
						|
 | 
						|
	while ((c = getopt_long(argc, argv, "f:hl", opts, NULL)) != -1) {
 | 
						|
		switch (c) {
 | 
						|
		case 'f':
 | 
						|
			if (!safe_strtoint(optarg, &harness->fixt_ind)) {
 | 
						|
				fprintf(stderr,
 | 
						|
					"Error: '%s' does not look like a number (command line).\n",
 | 
						|
					optarg);
 | 
						|
				exit(RESULT_HARD_ERROR);
 | 
						|
			}
 | 
						|
			harness->fixt_ind--; /* convert base-1 to base 0 */
 | 
						|
			break;
 | 
						|
		case 'h':
 | 
						|
			help(argv[0]);
 | 
						|
			exit(RESULT_OK);
 | 
						|
		case 'l':
 | 
						|
			list_tests();
 | 
						|
			exit(RESULT_OK);
 | 
						|
		case 0:
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			exit(RESULT_HARD_ERROR);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (optind < argc)
 | 
						|
		harness->chosen_testname = argv[optind++];
 | 
						|
 | 
						|
	if (optind < argc) {
 | 
						|
		if (!safe_strtoint(argv[optind], &harness->case_ind)) {
 | 
						|
			fprintf(stderr,
 | 
						|
				"Error: '%s' does not look like a number (command line).\n",
 | 
						|
				argv[optind]);
 | 
						|
			exit(RESULT_HARD_ERROR);
 | 
						|
		}
 | 
						|
		harness->case_ind--; /* convert base-1 to base 0 */
 | 
						|
		optind++;
 | 
						|
	}
 | 
						|
 | 
						|
	if (optind < argc) {
 | 
						|
		fprintf(stderr, "Unexpected extra arguments given (command line).\n\n");
 | 
						|
		help(argv[0]);
 | 
						|
		exit(RESULT_HARD_ERROR);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static struct weston_test_harness *
 | 
						|
weston_test_harness_create(int argc, char **argv)
 | 
						|
{
 | 
						|
	const struct fixture_setup_array *fsa;
 | 
						|
	struct weston_test_harness *harness;
 | 
						|
 | 
						|
	harness = zalloc(sizeof(*harness));
 | 
						|
	assert(harness);
 | 
						|
 | 
						|
	harness->fixt_ind = -1;
 | 
						|
	harness->case_ind = -1;
 | 
						|
	parse_command_line(harness, argc, argv);
 | 
						|
 | 
						|
	fsa = fixture_setup_array_get_();
 | 
						|
	if (harness->fixt_ind < -1 || harness->fixt_ind >= fsa->n_elements) {
 | 
						|
		fprintf(stderr,
 | 
						|
			"Error: fixture index %d (command line) is invalid for this program.\n",
 | 
						|
			harness->fixt_ind + 1);
 | 
						|
		exit(RESULT_HARD_ERROR);
 | 
						|
	}
 | 
						|
 | 
						|
	if (harness->chosen_testname) {
 | 
						|
		const struct weston_test_entry *t;
 | 
						|
 | 
						|
		t = find_test(harness->chosen_testname);
 | 
						|
		if (!t) {
 | 
						|
			fprintf(stderr,
 | 
						|
				"Error: test '%s' not found (command line).\n",
 | 
						|
				harness->chosen_testname);
 | 
						|
			exit(RESULT_HARD_ERROR);
 | 
						|
		}
 | 
						|
 | 
						|
		if (harness->case_ind < -1 ||
 | 
						|
		    harness->case_ind >= t->n_elements) {
 | 
						|
			fprintf(stderr,
 | 
						|
				"Error: case index %d (command line) is invalid for this test.\n",
 | 
						|
				harness->case_ind + 1);
 | 
						|
			exit(RESULT_HARD_ERROR);
 | 
						|
		}
 | 
						|
 | 
						|
		harness->data.tests = t;
 | 
						|
		harness->data.tests_count = 1;
 | 
						|
		harness->data.case_index = harness->case_ind;
 | 
						|
	} else {
 | 
						|
		harness->data.tests = &__start_test_section;
 | 
						|
		harness->data.tests_count =
 | 
						|
			&__stop_test_section - &__start_test_section;
 | 
						|
		harness->data.case_index = -1;
 | 
						|
	}
 | 
						|
 | 
						|
	harness->data.run = testsuite_run;
 | 
						|
 | 
						|
	return harness;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
weston_test_harness_destroy(struct weston_test_harness *harness)
 | 
						|
{
 | 
						|
	free(harness);
 | 
						|
}
 | 
						|
 | 
						|
static enum test_result_code
 | 
						|
counts_to_result(const struct wet_testsuite_data *data)
 | 
						|
{
 | 
						|
#if WESTON_TEST_SKIP_IS_FAILURE
 | 
						|
	if (data->skipped > 0)
 | 
						|
		return RESULT_FAIL;
 | 
						|
#endif
 | 
						|
 | 
						|
	/* RESULT_SKIP is reserved for fixture setup itself skipping everything */
 | 
						|
	if (data->total == data->passed + data->skipped)
 | 
						|
		return RESULT_OK;
 | 
						|
	return RESULT_FAIL;
 | 
						|
}
 | 
						|
 | 
						|
/** Execute all tests as client tests
 | 
						|
 *
 | 
						|
 * \param harness The test harness context.
 | 
						|
 * \param setup The compositor configuration.
 | 
						|
 *
 | 
						|
 * Initializes the compositor with the given setup and executes the compositor.
 | 
						|
 * The compositor creates a new thread where all tests in the test program are
 | 
						|
 * serially executed. Once the thread finishes, the compositor returns from its
 | 
						|
 * event loop and cleans up.
 | 
						|
 *
 | 
						|
 * Returns RESULT_SKIP if the requested compositor features, e.g. GL-renderer,
 | 
						|
 * are not built.
 | 
						|
 *
 | 
						|
 * \sa DECLARE_FIXTURE_SETUP(), DECLARE_FIXTURE_SETUP_WITH_ARG()
 | 
						|
 * \ingroup testharness
 | 
						|
 */
 | 
						|
enum test_result_code
 | 
						|
weston_test_harness_execute_as_client(struct weston_test_harness *harness,
 | 
						|
				      const struct compositor_setup *setup)
 | 
						|
{
 | 
						|
	struct wet_testsuite_data *data = &harness->data;
 | 
						|
 | 
						|
	data->type = TEST_TYPE_CLIENT;
 | 
						|
	return execute_compositor(setup, data);
 | 
						|
}
 | 
						|
 | 
						|
/** Execute all tests as plugin tests
 | 
						|
 *
 | 
						|
 * \param harness The test harness context.
 | 
						|
 * \param setup The compositor configuration.
 | 
						|
 *
 | 
						|
 * Initializes the compositor with the given setup and executes the compositor.
 | 
						|
 * The compositor executes all tests in the test program serially from an idle
 | 
						|
 * handler, then returns from its event loop and cleans up.
 | 
						|
 *
 | 
						|
 * Returns RESULT_SKIP if the requested compositor features, e.g. GL-renderer,
 | 
						|
 * are not built.
 | 
						|
 *
 | 
						|
 * \sa DECLARE_FIXTURE_SETUP(), DECLARE_FIXTURE_SETUP_WITH_ARG()
 | 
						|
 * \ingroup testharness
 | 
						|
 */
 | 
						|
enum test_result_code
 | 
						|
weston_test_harness_execute_as_plugin(struct weston_test_harness *harness,
 | 
						|
				      const struct compositor_setup *setup)
 | 
						|
{
 | 
						|
	struct wet_testsuite_data *data = &harness->data;
 | 
						|
 | 
						|
	data->type = TEST_TYPE_PLUGIN;
 | 
						|
	return execute_compositor(setup, data);
 | 
						|
}
 | 
						|
 | 
						|
/** Execute all tests as standalone tests
 | 
						|
 *
 | 
						|
 * \param harness The test harness context.
 | 
						|
 *
 | 
						|
 * Executes all tests in the test program serially without any further setup,
 | 
						|
 * particularly without any compositor instance created.
 | 
						|
 *
 | 
						|
 * \sa DECLARE_FIXTURE_SETUP(), DECLARE_FIXTURE_SETUP_WITH_ARG()
 | 
						|
 * \ingroup testharness
 | 
						|
 */
 | 
						|
enum test_result_code
 | 
						|
weston_test_harness_execute_standalone(struct weston_test_harness *harness)
 | 
						|
{
 | 
						|
	struct wet_testsuite_data *data = &harness->data;
 | 
						|
 | 
						|
	data->type = TEST_TYPE_STANDALONE;
 | 
						|
	data->run(data);
 | 
						|
 | 
						|
	return RESULT_OK;
 | 
						|
}
 | 
						|
 | 
						|
/** Fixture data array getter method
 | 
						|
 *
 | 
						|
 * DECLARE_FIXTURE_SETUP_WITH_ARG() overrides this in test programs.
 | 
						|
 * The default implementation has no data and makes the tests run once.
 | 
						|
 *
 | 
						|
 * \ingroup testharness
 | 
						|
 */
 | 
						|
__attribute__((weak)) const struct fixture_setup_array *
 | 
						|
fixture_setup_array_get_(void)
 | 
						|
{
 | 
						|
	/* A dummy fixture without a data array. */
 | 
						|
	static const struct fixture_setup_array default_fsa = {
 | 
						|
		.array = NULL,
 | 
						|
		.element_size = 0,
 | 
						|
		.n_elements = 1,
 | 
						|
		.meta_offset = 0,
 | 
						|
	};
 | 
						|
 | 
						|
	return &default_fsa;
 | 
						|
}
 | 
						|
 | 
						|
/** Fixture setup function
 | 
						|
 *
 | 
						|
 * DECLARE_FIXTURE_SETUP() and DECLARE_FIXTURE_SETUP_WITH_ARG() override
 | 
						|
 * this in test programs.
 | 
						|
 * The default implementation just calls
 | 
						|
 * weston_test_harness_execute_standalone().
 | 
						|
 *
 | 
						|
 * \ingroup testharness
 | 
						|
 */
 | 
						|
__attribute__((weak)) enum test_result_code
 | 
						|
fixture_setup_run_(struct weston_test_harness *harness, const void *arg_)
 | 
						|
{
 | 
						|
	return weston_test_harness_execute_standalone(harness);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
fixture_report(const struct wet_testsuite_data *d, enum test_result_code ret)
 | 
						|
{
 | 
						|
	int fixture_nr = d->fixture_iteration + 1;
 | 
						|
 | 
						|
	testlog("--- Fixture %d (%s) %s: passed %d, skipped %d, failed %d, total %d\n",
 | 
						|
		fixture_nr, d->fixture_name, result_to_str(ret),
 | 
						|
		d->passed, d->skipped, d->failed, d->total);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
main(int argc, char *argv[])
 | 
						|
{
 | 
						|
	struct weston_test_harness *harness;
 | 
						|
	enum test_result_code ret;
 | 
						|
	enum test_result_code result = RESULT_OK;
 | 
						|
	const struct fixture_setup_array *fsa;
 | 
						|
	int fi;
 | 
						|
	int fi_end;
 | 
						|
 | 
						|
	harness = weston_test_harness_create(argc, argv);
 | 
						|
 | 
						|
	fsa = fixture_setup_array_get_();
 | 
						|
 | 
						|
	if (harness->fixt_ind == -1) {
 | 
						|
		fi = 0;
 | 
						|
		fi_end = fsa->n_elements;
 | 
						|
	} else {
 | 
						|
		fi = harness->fixt_ind;
 | 
						|
		fi_end = fi + 1;
 | 
						|
	}
 | 
						|
 | 
						|
	tap_plan(&harness->data, fi_end - fi);
 | 
						|
	testlog("Iterating through %d fixtures.\n", fi_end - fi);
 | 
						|
 | 
						|
	for (; fi < fi_end; fi++) {
 | 
						|
		const void *arg = fixture_setup_array_get_arg(fsa, fi);
 | 
						|
 | 
						|
		harness->data.fixture_iteration = fi;
 | 
						|
		harness->data.fixture_name = fixture_setup_array_get_name(fsa,
 | 
						|
									  fi);
 | 
						|
		harness->data.passed = 0;
 | 
						|
		harness->data.skipped = 0;
 | 
						|
		harness->data.failed = 0;
 | 
						|
 | 
						|
		testlog("--- Fixture %d (%s)...\n",
 | 
						|
			fi + 1, harness->data.fixture_name);
 | 
						|
 | 
						|
		ret = fixture_setup_run_(harness, arg);
 | 
						|
		fixture_report(&harness->data, ret);
 | 
						|
 | 
						|
		if (ret == RESULT_SKIP) {
 | 
						|
			tap_skip_fixture(&harness->data);
 | 
						|
#if WESTON_TEST_SKIP_IS_FAILURE
 | 
						|
			ret = RESULT_FAIL;
 | 
						|
#else
 | 
						|
			continue;
 | 
						|
#endif
 | 
						|
		}
 | 
						|
 | 
						|
		if (ret != RESULT_OK && result != RESULT_HARD_ERROR)
 | 
						|
			result = ret;
 | 
						|
		else if (counts_to_result(&harness->data) != RESULT_OK)
 | 
						|
			result = RESULT_FAIL;
 | 
						|
	}
 | 
						|
 | 
						|
	weston_test_harness_destroy(harness);
 | 
						|
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 |