[PATCH weston v3 1/5] Expanded unit test framework to cover base requirements.

Jon A. Cruz jonc at osg.samsung.com
Thu Jun 4 00:50:47 PDT 2015


On 06/03/2015 10:15 PM, Peter Hutterer wrote:
> On Tue, May 26, 2015 at 04:06:37PM -0700, Jon A. Cruz wrote:
>> Added simple unit/integration test framework and corresponding
>> test program.
>>
>> Added a simple C-based test framework and an example program
>> that uses it to run through some simple wayland client checks.
> 
> what does the Z in zuc stand for? zimple? :)
> 

Oooh, that's good. Might go with it.

Originally it was 'letter that is more unlikely to already be in use and
collide'


>> Expanded code support in testing framework includes:
>>
>> * Running tests in forked child processes.
>> * Filtering of tests by both matches and exclusions.
>> * Per-suite and per-test setup and tear-down fixtures.
>> * Unconditional test stopping including skipping.
>> * Tracing of additional messages for failure logging.
>> * Works correctly with both debug and release builds (no assert, etc.)
>> * Randomization of tests.
>> * Repetition of tests.
>> * Parsing command-line parameters in test main()'s
>> * Return of proper exit codes including 77 for skip.
>> * Break on failure.
>>
>>     Signed-off-by: Jon A. Cruz <jonc at osg.samsung.com>
>>
>> Signed-off-by: Jon A. Cruz <jonc at osg.samsung.com>
>> ---
>>  .gitignore                                 |    3 +
>>  Makefile.am                                |   91 +-
>>  tools/Doxyfile                             |  318 ++++++
>>  tools/devdocs.doxyfile                     |  315 ++++++
>>  tools/devtools.dox                         |   52 +
>>  tools/tools.dox                            |   29 +
>>  tools/tools_arch_new.gv                    |   60 ++
>>  tools/tools_arch_old.gv                    |   28 +
>>  tools/waycheck/moretest.c                  |   83 ++
>>  tools/waycheck/rough_draw.c                |  265 +++++
>>  tools/waycheck/rough_draw.h                |   60 ++
>>  tools/waycheck/waycheck.c                  |  416 ++++++++
>>  tools/waycheck/waycheck.dox                |   29 +
>>  tools/wayland_fixtures/inc/wtst_fixtures.h |  230 +++++
>>  tools/wayland_fixtures/src/wtst_fixtures.c |  852 ++++++++++++++++
>>  tools/zunitc/doc/zunitc.dox                |  138 +++
>>  tools/zunitc/inc/zunitc/zunitc.h           |  537 ++++++++++
>>  tools/zunitc/inc/zunitc/zunitc_impl.h      |   87 ++
>>  tools/zunitc/src/main.c                    |   44 +
>>  tools/zunitc/src/zuc_base_logger.c         |  382 +++++++
>>  tools/zunitc/src/zuc_base_logger.h         |   34 +
>>  tools/zunitc/src/zuc_collector.c           |  321 ++++++
>>  tools/zunitc/src/zuc_collector.h           |   53 +
>>  tools/zunitc/src/zuc_context.h             |   55 +
>>  tools/zunitc/src/zuc_event.h               |   81 ++
>>  tools/zunitc/src/zuc_event_listener.h      |  167 +++
>>  tools/zunitc/src/zuc_types.h               |   76 ++
>>  tools/zunitc/src/zunitc_impl.c             | 1520 ++++++++++++++++++++++++++++
>>  tools/zunitc/test/fixtures_test.c          |  102 ++
>>  tools/zunitc/test/zunitc_test.c            |  314 ++++++
>>  30 files changed, 6741 insertions(+), 1 deletion(-)
>>  create mode 100644 tools/Doxyfile
>>  create mode 100644 tools/devdocs.doxyfile
>>  create mode 100644 tools/devtools.dox
>>  create mode 100644 tools/tools.dox
>>  create mode 100644 tools/tools_arch_new.gv
>>  create mode 100644 tools/tools_arch_old.gv
>>  create mode 100644 tools/waycheck/moretest.c
>>  create mode 100644 tools/waycheck/rough_draw.c
>>  create mode 100644 tools/waycheck/rough_draw.h
>>  create mode 100644 tools/waycheck/waycheck.c
>>  create mode 100644 tools/waycheck/waycheck.dox
>>  create mode 100644 tools/wayland_fixtures/inc/wtst_fixtures.h
>>  create mode 100644 tools/wayland_fixtures/src/wtst_fixtures.c
>>  create mode 100644 tools/zunitc/doc/zunitc.dox
>>  create mode 100644 tools/zunitc/inc/zunitc/zunitc.h
>>  create mode 100644 tools/zunitc/inc/zunitc/zunitc_impl.h
>>  create mode 100644 tools/zunitc/src/main.c
>>  create mode 100644 tools/zunitc/src/zuc_base_logger.c
>>  create mode 100644 tools/zunitc/src/zuc_base_logger.h
>>  create mode 100644 tools/zunitc/src/zuc_collector.c
>>  create mode 100644 tools/zunitc/src/zuc_collector.h
>>  create mode 100644 tools/zunitc/src/zuc_context.h
>>  create mode 100644 tools/zunitc/src/zuc_event.h
>>  create mode 100644 tools/zunitc/src/zuc_event_listener.h
>>  create mode 100644 tools/zunitc/src/zuc_types.h
>>  create mode 100644 tools/zunitc/src/zunitc_impl.c
>>  create mode 100644 tools/zunitc/test/fixtures_test.c
>>  create mode 100644 tools/zunitc/test/zunitc_test.c
>>
>> diff --git a/.gitignore b/.gitignore
>> index 047c386..e0cb805 100644
>> --- a/.gitignore
>> +++ b/.gitignore
>> @@ -98,3 +98,6 @@ weston-drm.7
>>  weston.ini.5
>>  
>>  /tests/weston-ivi.ini
>> +
>> +/waycheck
>> +/zuctest
>> diff --git a/Makefile.am b/Makefile.am
>> index e860e0e..d92498a 100644
>> --- a/Makefile.am
>> +++ b/Makefile.am
>> @@ -899,7 +899,8 @@ endif
>>  # Shared utilities
>>  #
>>  
>> -noinst_LTLIBRARIES += libshared.la libshared-cairo.la
>> +noinst_LTLIBRARIES += libshared.la libshared-cairo.la \
>> +	libzunitc.la libzunitcmain.la libwayland-fixtures.la
>>  
>>  libshared_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
>>  
>> @@ -936,6 +937,48 @@ libshared_cairo_la_SOURCES =			\
>>  	shared/frame.c				\
>>  	shared/cairo-util.h
>>  
>> +libwayland_fixtures_la_SOURCES = \
>> +	tools/wayland_fixtures/inc/wtst_fixtures.h	\
>> +	tools/wayland_fixtures/src/wtst_fixtures.c
>> +
>> +libwayland_fixtures_la_CFLAGS = \
>> +	-I${prefix}/include			\
>> +	-I$(top_srcdir)/tools/wayland_fixtures/inc	\
>> +	-I$(top_srcdir)/tools/zunitc/inc	\
>> +	$(GCC_CFLAGS)
>> +
>> +libwayland_fixtures_la_LIBADD = \
>> +	libshared.la
>> +
>> +libzunitc_la_SOURCES = \
>> +	tools/zunitc/inc/zunitc/zunitc.h	\
>> +	tools/zunitc/inc/zunitc/zunitc_impl.h	\
>> +	tools/zunitc/src/zuc_base_logger.c	\
>> +	tools/zunitc/src/zuc_base_logger.h	\
>> +	tools/zunitc/src/zuc_collector.c	\
>> +	tools/zunitc/src/zuc_collector.h	\
>> +	tools/zunitc/src/zuc_context.h		\
>> +	tools/zunitc/src/zuc_event.h		\
>> +	tools/zunitc/src/zuc_event_listener.h	\
>> +	tools/zunitc/src/zuc_types.h		\
>> +	tools/zunitc/src/zunitc_impl.c
>> +
>> +libzunitc_la_CFLAGS = \
>> +	-I$(top_srcdir)/tools/zunitc/inc	\
>> +	$(GCC_CFLAGS)
>> +
>> +libzunitc_la_LIBADD = \
>> +	libshared.la
>> +
>> +libzunitcmain_la_SOURCES = \
>> +	tools/zunitc/src/main.c
>> +
>> +libzunitcmain_la_CFLAGS = \
>> +	-I$(top_srcdir)/tools/zunitc/inc	\
>> +	$(GCC_CFLAGS)
>> +
>> +libzunitcmain_la_LIBADD = \
>> +	libshared.la
>>  
>>  #
>>  # tests subdirectory
>> @@ -1174,6 +1217,52 @@ setbacklight_CFLAGS = $(AM_CFLAGS) $(SETBACKLIGHT_CFLAGS)
>>  setbacklight_LDADD = $(SETBACKLIGHT_LIBS)
>>  endif
>>  
>> +# --------------------------------------------------------------------------
>> +
>> +all-local: waycheck$(EXEEXT) zuctest$(EXEEXT)
>> +
>> +noinst_PROGRAMS += zuctest$(EXEEXT)
>> +
>> +zuctest_LDADD =					\
>> +	libshared.la				\
>> +	libzunitc.la				\
>> +	libzunitcmain.la
>> +
>> +zuctest_CFLAGS =			\
>> +	-I$(top_srcdir)/tools/zunitc/inc
>> +
>> +zuctest_SOURCES =				\
>> +	tools/zunitc/test/fixtures_test.c	\
>> +	tools/zunitc/test/zunitc_test.c
>> +
>> +#
>> +
>> +noinst_PROGRAMS += waycheck$(EXEEXT)
>> +
>> +waycheck_LDADD =			\
>> +	$(WAYLAND_COMPOSITOR_LIBS)	\
>> +	$(COMPOSITOR_LIBS)		\
>> +	libshared.la			\
>> +	libwayland-fixtures.la		\
>> +	libzunitc.la			\
>> +	libzunitcmain.la
>> +
>> +waycheck_CFLAGS =				\
>> +	-I${prefix}/include			\
>> +	-I$(top_srcdir)/tools/zunitc/inc	\
>> +	-I$(top_srcdir)/tools/wayland_fixtures/inc	\
>> +	-I$(top_builddir)/clients		\
>> +	-I$(top_srcdir)/shared			\
>> +	$(AM_CFLAGS)
>> +
>> +waycheck_SOURCES =				\
>> +	tools/waycheck/waycheck.c		\
>> +	tools/waycheck/moretest.c		\
>> +	tools/waycheck/rough_draw.c		\
>> +	tools/waycheck/rough_draw.h
>> +
>> +# --------------------------------------------------------------------------
>> +
>>  EXTRA_DIST += tests/weston-tests-env
>>  
>>  BUILT_SOURCES +=				\
>> diff --git a/tools/Doxyfile b/tools/Doxyfile
>> new file mode 100644
>> index 0000000..e42cdbb
>> --- /dev/null
>> +++ b/tools/Doxyfile
>> @@ -0,0 +1,318 @@
>> +# Doxyfile 1.8.8
>> +
>> +#---------------------------------------------------------------------------
>> +# Project related configuration options
>> +#---------------------------------------------------------------------------
>> +DOXYFILE_ENCODING      = UTF-8
>> +PROJECT_NAME           = "Tools"
>> +PROJECT_NUMBER         =
> 
> that was already pointed out elsewhere, but if we can't do the cat approach
> from the Makefile maybe take the options that were customized and add them
> to the end of th edoxygen file. So you know that all but the last section is
> default gobbledegook.

I'll be switching to the cat approach. It also happens to work well on
Windows and DevStudio, but that doesn't really matter for us.


> also, what happens if we just drop all options but the customised ones? is
> the result usable?

Not sure... but might be worth investigating.


> [..]
>> diff --git a/tools/devtools.dox b/tools/devtools.dox
>> new file mode 100644
>> index 0000000..c1ec9fb
>> --- /dev/null
>> +++ b/tools/devtools.dox
>> @@ -0,0 +1,52 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +/**
>> + at mainpage
>> +
>> +- @ref zunitc - Simple test framework
>> +
>> +- @ref waycheck - Simple integration/acceptance test tool
>> +
>> + at section tools_overview Overview
> 
> weston standard seems to be using * at the beginning of each line, and
> using backslash for tags.

Good points to follow up on. I know that for .dox files it's very common
to omit the per-line *


>> +The tools area currently consists of two sub-projects (@ref zunitc and
>> + at ref waycheck) that are refined from the prior single weston/tests source
>> +folder.
>> +
>> + at subsection tools_overview_old Old Code Organization
>> +
>> +The original 'tests' folder contained basic weston testing with an
>> +integrated test runner framework. Over time things progressed to the
>> +stage where splitting apart into discrete layers was warranted.
>> +
>> + at dotfile tools_arch_old.gv "Original test code organization"
>> +
>> + at subsection tools_overview_new New Code Organization
>> +
>> +The test code that is not weston-specific gets split out to a separate
>> +folder and/or folders. Then an additional testing tool 'waycheck' that is
>> +compositor-agnostic is added.
>> +
>> + at dotfile tools_arch_new.gv "Refactored test code organization"
>> +
>> +*/
>> diff --git a/tools/tools.dox b/tools/tools.dox
>> new file mode 100644
>> index 0000000..e4f5524
>> --- /dev/null
>> +++ b/tools/tools.dox
>> @@ -0,0 +1,29 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +/**
>> + at mainpage
>> +
>> +- @ref zunitc - Simple test framework
>> +
>> +- @ref waycheck - Simple integration/acceptance test tool
>> +*/
>> diff --git a/tools/tools_arch_new.gv b/tools/tools_arch_new.gv
>> new file mode 100644
>> index 0000000..fe8b6c7
> 
> [...]
> 
>> diff --git a/tools/waycheck/moretest.c b/tools/waycheck/moretest.c
>> new file mode 100644
>> index 0000000..80ee5b4
>> --- /dev/null
>> +++ b/tools/waycheck/moretest.c
>> @@ -0,0 +1,83 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#include "config.h"
>> +
>> +#include "zunitc/zunitc.h"
>> +
>> +/* #define ENABLE_FAIL_TESTS */
>> +
>> +ZUC_TEST(more, good_Versions)
> 
> camel_Case??? my eyes, my eyes! :P

Fixed to snake_case locally. Should be covered in next push.


>> +{
>> +	ZUC_EXPECT_TRUE(1);
>> +	ZUC_EXPECT_TRUE(-1);
>> +	ZUC_EXPECT_TRUE(!0);
>> +
>> +	ZUC_EXPECT_FALSE(0);
>> +	ZUC_EXPECT_FALSE(!-1);
>> +	ZUC_EXPECT_FALSE(!1);
>> +
>> +	ZUC_EXPECT_EQ(4 + 0, 2 + 2);
>> +
>> +	ZUC_EXPECT_NE(5 - 1, 2 + 3);
>> +
>> +	ZUC_EXPECT_GE(4 - 0, 2 + 2);
>> +
>> +	ZUC_EXPECT_GT(4 - 9, 2 - 13);
>> +
>> +	ZUC_EXPECT_LE(4 + 3, 2 + 5);
>> +
>> +	ZUC_EXPECT_LT(4 + 9, 2 + 12);
>> +}
>> +
>> +#ifdef ENABLE_FAIL_TESTS
>> +ZUC_TEST(more, fail_Versions)
>> +{
>> +	ZUC_EXPECT_FALSE(zuc_has_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_fatal_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_nonfatal_failure());
>> +
>> +	ZUC_EXPECT_TRUE(0);
>> +	ZUC_EXPECT_TRUE(!-1);
>> +	ZUC_EXPECT_TRUE(!1);
>> +
>> +	ZUC_EXPECT_FALSE(1);
>> +	ZUC_EXPECT_FALSE(-1);
>> +	ZUC_EXPECT_FALSE(!0);
>> +
>> +	ZUC_EXPECT_EQ(4 + 0, 2 + 3);
>> +
>> +	ZUC_EXPECT_NE(5 - 1, 2 + 2);
>> +
>> +	ZUC_EXPECT_GE(4 - 0, 2 + 3);
>> +
>> +	ZUC_EXPECT_GT(4 - 9, 2 + 3);
>> +
>> +	ZUC_EXPECT_LE(4 + 3, 2 + 3);
>> +
>> +	ZUC_EXPECT_LT(4 + 9, 2 + 3);
>> +
>> +	ZUC_EXPECT_TRUE(zuc_has_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_fatal_failure());
>> +	ZUC_EXPECT_TRUE(zuc_has_nonfatal_failure());
>> +}
>> +#endif
>> diff --git a/tools/waycheck/rough_draw.c b/tools/waycheck/rough_draw.c
>> new file mode 100644
>> index 0000000..ed02a33
>> --- /dev/null
>> +++ b/tools/waycheck/rough_draw.c
>> @@ -0,0 +1,265 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#include <stddef.h>
>> +#include <string.h>
>> +
>> +#include "rough_draw.h"
>> +
>> +#define ARRAY_LENGTH(a) ((int) (sizeof (a) / sizeof (a)[0]))
> 
> how do we not have this in some util header file already...

Good question. I've noticed that a few things are not individually setup
for reuse. Probably good for later follow-up changesets.


>> +
>> +/**
>> + * Very simple way to track colors.
>> + */
>> +struct colorval {
>> +	float r;
>> +	float g;
>> +	float b;
>> +	float a;
>> +	enum pixel_form form;
>> +	int used;
>> +	uint8_t raw[4];
>> +};
>> +
>> +static void populate_color(struct colorval *color, enum pixel_form form)
>> +{
>> +	memset(color->raw, 0, sizeof(color->raw));
>> +	color->form = form;
>> +	switch (form) {
>> +	case PXL_ARGB32:
>> +		color->used = 4;
>> +		color->raw[3] = (0xff * color->a) + 0.5;
>> +		color->raw[2] = (0xff * color->r) + 0.5;
>> +		color->raw[1] = (0xff * color->g) + 0.5;
>> +		color->raw[0] = (0xff * color->b) + 0.5;
>> +		break;
>> +	case PXL_RGB565:
>> +		color->used = 2;
>> +		color->raw[1] = (uint8_t)((0x1f * color->r) + 0.5) << 3;
>> +		color->raw[0] = (0x3f * color->g) + 0.5;
>> +		color->raw[1] |= 0x07 & (color->raw[0] >> 3);
>> +		color->raw[0] <<= 5;
>> +		color->raw[0] |= (uint8_t)((0x1f * color->b) + 0.5);
>> +		break;
>> +	default:
>> +		color->form = PXL_NA;
>> +		/* fall-through */
>> +	case PXL_NA:
>> +		color->used = 0;
>> +	}
>> +}
>> +
>> +static void fill_rect(uint8_t *raw, struct colorval *color,
>> +		      int width, int height, int stride)
>> +{
>> +	int y = 0;
>> +	for (y = 0; y < height; ++y) {
>> +		int x = 0;
>> +		uint8_t *ptr = raw + (y * stride);
>> +		for (x = 0; x < width; ++x) {
>> +			memcpy(ptr, &color->raw[0], color->used);
>> +			ptr += color->used;
>> +		}
>> +	}
>> +}
>> +
>> +static void blend(struct colorval *dest,
>> +		  struct colorval const *val1, struct colorval const *val2,
>> +		  double factor)
>> +{
>> +	dest->r = (val1->r * (1.0 - factor)) + (val2->r * factor);
>> +	dest->g = (val1->g * (1.0 - factor)) + (val2->g * factor);
>> +	dest->b = (val1->b * (1.0 - factor)) + (val2->b * factor);
>> +	dest->a = (val1->a * (1.0 - factor)) + (val2->a * factor);
>> +	populate_color(dest, val1->form);
>> +}
>> +
>> +static void hgrad_rect(uint8_t *buf,
>> +		       struct colorval const *val1, struct colorval const *val2,
>> +		       int width, int height, int stride)
>> +{
>> +	int x = 0;
>> +	int y = 0;
>> +	int pw = val1->used;
>> +	struct colorval color = {.a=1.0};
>> +	double dwidth = (double)width;
>> +	for (x = 0; x < width; ++x) {
>> +		uint8_t *ptr = buf + x * pw;
>> +		blend(&color, val1, val2, x / dwidth);
>> +		for (y = 0; y < height; ++y) {
>> +			memcpy(ptr, &color.raw[0], color.used);
>> +			ptr += stride;
>> +		}
>> +	}
>> +}
>> +
>> +/*
>> + * Approximates common color bars with black at 16 and white at 235.
>> + */
>> +static const double lvblk = (16 + 0.00 * (235 - 16)) / 255.0;
>> +static const double lvwht = (16 + 1.00 * (235 - 16)) / 255.0;
>> +static const double lvupr = (16 + 0.75 * (235 - 16)) / 255.0;
>> +static const double lvmid = (16 + 0.40 * (235 - 16)) / 255.0;
>> +static const double lvb15 = (16 + 0.15 * (235 - 16)) / 255.0;
>> +static const double lvb_2 = (16 - 0.02 * (235 - 16)) / 255.0;
>> +static const double lvb02 = (16 + 0.02 * (235 - 16)) / 255.0;
>> +static const double lvb04 = (16 + 0.04 * (235 - 16)) / 255.0;
>> +
>> +void rd_draw_bars(uint8_t *buf, enum pixel_form form, int stride,
>> +		  int width, int height)
> 
> style: return type on separate line

Fixed for next push.

>> +{
>> +	int i;
>> +	int y0, y1, y2;
>> +	int h1, h2;
>> +	int w1, w2, w3, w4, hw;
>> +	int xr;
>> +	int pw;
>> +	int xoff;
>> +	double bar_span;
>> +	int bar_count;
>> +	struct colorval bars[] = {
>> +		{.r=lvmid, .g=lvmid, .b=lvmid, .a=1.0},
>> +		{.r=lvupr, .g=lvupr, .b=lvupr, .a=1.0},
>> +		{.r=lvupr, .g=lvupr, .b=lvblk, .a=1.0},
>> +		{.r=lvblk, .g=lvupr, .b=lvupr, .a=1.0},
>> +		{.r=lvblk, .g=lvupr, .b=lvblk, .a=1.0},
>> +		{.r=lvupr, .g=lvblk, .b=lvupr, .a=1.0},
>> +		{.r=lvupr, .g=lvblk, .b=lvblk, .a=1.0},
>> +		{.r=lvblk, .g=lvblk, .b=lvupr, .a=1.0},
>> +		{.r=lvmid, .g=lvmid, .b=lvmid, .a=1.0},
>> +		{.r=lvb15, .g=lvb15, .b=lvb15, .a=1.0},
>> +		{.r=lvwht, .g=lvwht, .b=lvwht, .a=1.0},
>> +		{.r=lvblk, .g=lvblk, .b=lvblk, .a=1.0},
>> +		{.r=lvb_2, .g=lvb_2, .b=lvb_2, .a=1.0},
>> +		{.r=lvb02, .g=lvb02, .b=lvb02, .a=1.0},
>> +		{.r=lvb04, .g=lvb04, .b=lvb04, .a=1.0},
>> +	};
>> +
>> +	if (!buf)
>> +		return;
>> +
>> +	for (i = 0; i < ARRAY_LENGTH(bars); ++i)
>> +		populate_color(&bars[i], form);
>> +
>> +	pw = bars[0].used;
>> +	y0 = ((height * 1.75) / 3);
>> +	y1 = ((height * 2) / 3);
>> +	y2 = ((height * 3) / 4);
>> +	h1 = y1 - y0;
>> +	h2 = height - y2;
>> +	w1 = width / 8;
>> +	w2 = (width * 0.75) / 7;
>> +	xr = pw * ((width * 7) / 8);
>> +
>> +	/* left gray: */
>> +	fill_rect(buf, &bars[0], w1, y0, stride);
>> +	fill_rect(buf + (y0 * stride), &bars[3], w1, h1, stride);
>> +	fill_rect(buf + (y1 * stride), &bars[2], w1, h1, stride);
>> +	fill_rect(buf + (y2 * stride), &bars[9], w1, h2, stride);
>> +
>> +	/* right gray */
>> +	fill_rect(buf + xr, &bars[0], w1, y0, stride);
>> +	fill_rect(buf + xr + (y0 * stride), &bars[7], w1, h1, stride);
>> +	fill_rect(buf + xr + (y1 * stride), &bars[6], w1, h1, stride);
>> +	fill_rect(buf + xr + (y2 * stride), &bars[9], w1, h2, stride);
>> +
>> +	xoff = w1 * pw;
>> +	fill_rect(buf + xoff + (y0 * stride), &bars[10], w2, h1, stride);
>> +	fill_rect(buf + xoff + (y1 * stride), &bars[11], w2, h1, stride);
>> +
>> +	bar_span = (width * 0.75);
>> +	bar_count = 7;
>> +	for (i = 0; i < bar_count; ++i)
>> +	{
> 
> move the { to the opening line

Fixed for next push.


>> +		int ww = (bar_span * (i + 1)) / bar_count;
>> +		xoff = (bar_span * i) / bar_count;
>> +		ww -= xoff;
>> +		xoff += w1;
>> +		fill_rect(buf + xoff * pw, &bars[i + 1], ww, y0, stride);
>> +	}
>> +
>> +
>> +	hw = width - (w1 + w1 + w2);
>> +	/* Gray horiz: */
>> +	xoff = w1 + w2;
>> +	fill_rect(buf + xoff * pw + (y0 * stride), &bars[1], hw, h1, stride);
>> +	hgrad_rect(buf + xoff * pw + (y1 * stride), &bars[11], &bars[10],
>> +		   hw, h1, stride);
>> +
>> +	/* note - horizontal positions of lower bars are not simple values */
>> +
>> +	xoff = (width * 0.85625) / 3;
>> +	w3 = (width * 0.64375) / 3;
>> +	fill_rect(buf + w1 * pw + (y2 * stride), &bars[11], width - (w1 * 2),
>> +		  h2, stride);
>> +	fill_rect(buf + xoff * pw + (y2 * stride), &bars[10], w3,
>> +		  h2, stride);
>> +
>> +	w4 = (width * 0.10625) / 3;
>> +	xoff = (width * 1.765625) / 3;
>> +	fill_rect(buf + xoff * pw + (y2 * stride), &bars[12], w4, h2, stride);
>> +
>> +	xoff = (width * 1.98125) / 3;
>> +	fill_rect(buf + xoff * pw + (y2 * stride), &bars[13], w4, h2, stride);
>> +
>> +	xoff = (width * 2.196875) / 3;
>> +	fill_rect(buf + xoff * pw + (y2 * stride), &bars[14], w4, h2, stride);
>> +}
>> +
>> +void rd_draw_crosshairs(uint8_t *buf, enum pixel_form form, int stride,
>> +			int width, int height)
>> +{
>> +	int pw;
>> +	int x = (width + 1) / 2;
>> +	int y = (height + 1) / 2;
>> +	struct colorval fg = {.r=0, .g=0, .b=0, .a=0.5};
>> +	struct colorval bg = {.r=0.5, .g=0.5, .b=0.5, .a=0.5};
>> +
>> +	if (!buf)
>> +		return;
>> +
>> +	populate_color(&fg, form);
>> +	populate_color(&bg, form);
>> +	pw = fg.used;
>> +
>> +	fill_rect(buf + ((y - 1) * stride), &bg, width, 3, stride);
>> +	fill_rect(buf + (y * stride), &fg, width, 1, stride);
>> +
>> +	fill_rect(buf + ((y - 2) * stride), &bg, width / 3, 5, stride);
>> +	fill_rect(buf + ((y - 1) * stride), &fg, width / 3, 3, stride);
>> +	fill_rect(buf + ((y - 2) * stride + (width * 2 / 3) * pw), &bg,
>> +		  width / 3, 5, stride);
>> +	fill_rect(buf + ((y - 1) * stride + (width * 2 / 3) * pw), &fg,
>> +		  width / 3, 3, stride);
>> +
>> +
>> +	fill_rect(buf + (x - 1) * pw, &bg, 3, height, stride);
>> +	fill_rect(buf + x * pw, &fg, 1, height, stride);
>> +
>> +	fill_rect(buf + (x - 2) * pw, &bg, 5, height / 3, stride);
>> +	fill_rect(buf + (x - 1) * pw, &fg, 3, height / 3, stride);
>> +
>> +	fill_rect(buf + (x - 2) * pw + ((height * 2 / 3) * stride), &bg,
>> +		  5, height / 3, stride);
>> +	fill_rect(buf + (x - 1) * pw + ((height * 2 / 3) * stride), &fg,
>> +		  3, height / 3, stride);
>> +}
>> diff --git a/tools/waycheck/rough_draw.h b/tools/waycheck/rough_draw.h
>> new file mode 100644
>> index 0000000..4bb2ce6
>> --- /dev/null
>> +++ b/tools/waycheck/rough_draw.h
>> @@ -0,0 +1,60 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef ROUGH_DRAW_H
>> +#define ROUGH_DRAW_H
>> +
>> +#ifdef __cplusplus
>> +extern "C" {
>> +#endif
>> +
>> +#include <stdint.h>
>> +
> 
> duplicate empty line
> 
>> +
>> +/**
>> + * Possible memory formats.
>> + * Very short list for now
>> + */
>> +enum pixel_form {
>> +	PXL_NA = 0,
>> +	PXL_ARGB32,
>> +	PXL_RGB565
>> +};
>> +
>> +/**
>> + * Draws a simple color-bars test pattern to the specified buffer.
>> + */
>> +void rd_draw_bars(uint8_t *buf, enum pixel_form form, int stride,
>> +		  int width, int height);
>> +
>> +/**
>> + * Draws a simple cross-hairs image suitable for a cursor to the specified
>> + * buffer.
>> + */
>> +void rd_draw_crosshairs(uint8_t *buf, enum pixel_form form, int stride,
>> +			int width, int height);
>> +
>> +#ifdef __cplusplus
>> +} /* extern "C" */
>> +#endif
>> +
>> +#endif /* ROUGH_DRAW_H */
>> diff --git a/tools/waycheck/waycheck.c b/tools/waycheck/waycheck.c
>> new file mode 100644
>> index 0000000..49d32ae
>> --- /dev/null
>> +++ b/tools/waycheck/waycheck.c
>> @@ -0,0 +1,416 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#include "config.h"
>> +
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <unistd.h>
>> +#include <stdbool.h>
>> +
>> +#include <sys/types.h>
>> +#include <sys/stat.h>
>> +#include <fcntl.h>
>> +
>> +#include <sys/mman.h>
>> +
>> +#include <linux/input.h>
>> +#include <wayland-client.h>
>> +
>> +
>> +#include "os-compatibility.h"
>> +#include "rough_draw.h"
>> +#include "shared/config-parser.h"
>> +#include "shared/zalloc.h"
>> +#include "wtst_fixtures.h"
>> +#include "zunitc/zunitc.h"
>> +
>> +#define ARRAY_LENGTH(a) ((int) (sizeof (a) / sizeof (a)[0]))
> 
> well, hello again, aren't you supposed to be in a header somewhere?

Yes... again.


>> +
>> +#define ARGB32_SIZE 4
>> +
>> +static const uint32_t PIXEL_FORMAT = WL_SHM_FORMAT_ARGB8888;
>> +
>> +static void *setup_test_config(void *data)
>> +{
>> +	struct wtst_ctx *ctx = wtst_ctx_create();
>> +	ZUC_EXPECT_TRUE(ctx != NULL);
>> +	if (zuc_has_failure())
>> +		ZUC_MARK_FATAL("Failure during fixture setup.");
>> +	return ctx;
>> +}
>> +
>> +static void cleanup_test_config(void *data)
>> +{
>> +	struct wtst_ctx *ctx = data;
>> +	ZUC_ASSERT_TRUE(ctx != NULL);
>> +	wtst_ctx_destroy(ctx);
>> +}
>> +
>> +static struct zuc_fixture base_test_f = {
>> +	.set_up = setup_test_config,
>> +	.tear_down = cleanup_test_config
>> +};
>> +
>> +/**
>> + * Baseline test to see if a connection can be made to the Wayland server.
>> + */
>> +ZUC_TEST(base_test, can_connect_display)
>> +{
>> +	struct wl_display *display = wl_display_connect(NULL);
>> +
>> +	ZUC_EXPECT_TRUE(display != NULL);
>> +
>> +	if (display) {
>> +		wl_display_disconnect(display);
>> +		display = NULL;
>> +	}
>> +}
>> +
>> +/* A very simple case that only exercises the test fixture. */
>> +ZUC_TEST(base_test, hello_wayland)
>> +{
>> +	struct wtst_ctx *ctx = wtst_ctx_create();
>> +	ZUC_ASSERT_TRUE(ctx != NULL);
>> +
>> +	wtst_ctx_destroy(ctx);
>> +}
>> +
>> +ZUC_TEST_F(base_test_f, advertises_required)
>> +{
>> +	int num_required = 0;
>> +	int i = 0;
>> +	char const *required[] = {
>> +		"wl_compositor",
>> +		"wl_data_device_manager",
>> +		"wl_output",
>> +		"wl_seat",
>> +		"wl_shell",
>> +		"wl_shm",
>> +		"wl_subcompositor",
>> +	};
>> +	struct wtst_ctx *ctx = data;
>> +
>> +	num_required = sizeof(required) / sizeof(required[0]);
>> +	for (i = 0; i < num_required; i++) {
>> +		ZUC_TRACEPOINT("Check %s\n", required[i]);
>> +		ZUC_EXPECT_TRUE(wtst_is_global_advertised(ctx, required[i]));
>> +	}
>> +}
>> +
>> +typedef void (*button_cb)(uint32_t serial, uint32_t time,
>> +			  uint32_t button, uint32_t state);
>> +
>> +struct surface_extras
>> +{
>> +	void (*button_cb)(uint32_t serial, uint32_t time,
>> +			  uint32_t button, uint32_t state);
>> +
>> +	uint8_t *membuf;
>> +	struct wl_buffer *buffer;
>> +	struct wl_surface *cursor;
>> +	int32_t hit_x;
>> +	int32_t hit_y;
>> +};
>> +
>> +static void setup_surface_extras(struct wtst_surface *wsurf)
>> +{
>> +	ZUC_ASSERT_TRUE(wsurf != NULL);
>> +	ZUC_EXPECT_TRUE(wsurf->data == NULL);
>> +	struct surface_extras *extras = zalloc(sizeof(*extras));
>> +	ZUC_ASSERT_TRUE(extras != NULL);
>> +	wsurf->data = extras;
>> +}
>> +
>> +/**
>> + * @todo refactor to be more genericly helpful then move this along with
> 
> typo, generically

Fixed.


>> + * the corresponding helper functions to fixtures lib
>> + */
>> +struct wtst_shm_pool {
>> +	struct wl_shm_pool *pool;
>> +
>> +	int fd;
>> +	uint8_t *membuf;
>> +	size_t flen;
>> +	size_t used;
>> +};
>> +
>> +/* Simple testing helpers: */
>> +static uint8_t *wtst_shm_pool_get_membuf(struct wtst_shm_pool *pool);
>> +static struct wl_shm_pool *wtst_shm_pool_get_pool(struct wtst_shm_pool *pool);
>> +static void wtst_shm_pool_consume(struct wtst_shm_pool *pool, size_t mem_used);
>> +
>> +static struct wtst_shm_pool *wtst_create_mempool(struct wl_shm *shm,
>> +					  int fd, size_t flen);
>> +
>> +
>> +static void setup_cursor(struct wtst_shm_pool *pool,
>> +			 unsigned int width,
>> +			 unsigned int height,
>> +			 int32_t hit_x, int32_t hit_y,
>> +			 struct wl_compositor *compositor,
>> +			 struct surface_extras *extras);
>> +
>> +static void set_button_cb(struct wtst_shell_surface *shell_surface,
>> +			  button_cb callback);
>> +
>> +static const struct wl_pointer_listener pointer_listener;
>> +
>> +static bool keep_alive = true;
>> +
>> +static void handle_button(uint32_t serial, uint32_t time,
>> +			  uint32_t button, uint32_t state)
>> +{
>> +	keep_alive = false;
>> +}
>> +
>> +ZUC_TEST(base_test, DISABLED_sleeper)
>> +{
>> +/* Simple disabled test */
>> +}
>> +
>> +ZUC_TEST_F(base_test_f, simple_setup)
>> +{
>> +	struct wtst_ctx *ctx = data;
>> +	size_t needed = 0;
>> +	int anon = 0;
>> +	const int surf_width = 355;
>> +	const int surf_height = 200;
>> +	const int cursor_size = 45;
>> +	const int mid_hit = cursor_size / 2;
>> +	struct wtst_shm_pool *pool = NULL;
>> +	struct wl_buffer *buffer = NULL;
>> +	struct wtst_shell_surface *sh_surface = NULL;
>> +
>> +	keep_alive = false; /* Don't run the main loop for normal testing */
>> +
>> +	wtst_set_dump_pointer_events(WTST_DBG_POINTER_ALL
>> +				     & ~WTST_DBG_POINTER_MOTION);
>> +
>> +	needed = ARGB32_SIZE * surf_width * surf_height;
>> +	needed += ARGB32_SIZE * cursor_size * cursor_size;
>> +
>> +	anon = os_create_anonymous_file(needed);
>> +	buffer = NULL;
>> +	pool = wtst_create_mempool(ctx->shm, anon, needed);
>> +	if (!pool) {
>> +		close(anon);
>> +		ZUC_ASSERT_TRUE(pool != NULL);
>> +	} else {
>> +		uint8_t *mem = wtst_shm_pool_get_membuf(pool);
>> +		rd_draw_bars(mem, PXL_ARGB32, surf_width * ARGB32_SIZE,
>> +			     surf_width, surf_height);
>> +
>> +		struct wl_shm_pool *shpool =
>> +			wtst_shm_pool_get_pool(pool);
>> +		buffer = wl_shm_pool_create_buffer(shpool,
>> +						 0,
>> +						 surf_width,
>> +						 surf_height,
>> +						 surf_width * ARGB32_SIZE,
>> +						 PIXEL_FORMAT);
>> +		wtst_shm_pool_consume(pool,
>> +				      surf_width * surf_height * ARGB32_SIZE);
>> +		ZUC_EXPECT_TRUE(buffer != NULL);
>> +	}
>> +
>> +	sh_surface = wtst_create_shell_surface(ctx->compositor, ctx->shell);
>> +	setup_surface_extras(sh_surface->surface);
>> +
>> +	if (buffer) {
>> +		wl_surface_attach(sh_surface->surface->wl_surface, buffer,
>> +				  0, 0);
>> +		wl_surface_commit(sh_surface->surface->wl_surface);
>> +	}
>> +
>> +	setup_cursor(pool, cursor_size, cursor_size, mid_hit, mid_hit,
>> +		     ctx->compositor, sh_surface->surface->data);
>> +
>> +	set_button_cb(sh_surface, handle_button);
>> +	wtst_pointer_add_listener(ctx->input->pointer,
>> +				  &pointer_listener, ctx->input->pointer);
>> +
>> +	while (keep_alive) {
>> +		if (wl_display_dispatch(ctx->display) < 0)
>> +			keep_alive = false;
>> +	}
>> +
>> +	wl_buffer_destroy(buffer);
>> +}
>> +
>> +uint8_t *wtst_shm_pool_get_membuf(struct wtst_shm_pool *pool)
>> +{
>> +	ZUC_EXPECT_TRUE(pool != NULL);
>> +	return (pool) ? pool->membuf : NULL;
>> +}
>> +
>> +struct wl_shm_pool *wtst_shm_pool_get_pool(struct wtst_shm_pool *pool)
>> +{
>> +	ZUC_EXPECT_TRUE(pool != NULL);
>> +	return (pool) ? pool->pool : NULL;
>> +}
>> +
>> +static void wtst_shm_pool_consume(struct wtst_shm_pool *pool, size_t mem_used)
>> +{
>> +	ZUC_ASSERT_TRUE(pool != NULL);
>> +	pool->used += mem_used;
>> +}
>> +
>> +struct wtst_shm_pool *wtst_create_mempool(struct wl_shm *shm,
>> +					  int fd, size_t flen)
>> +{
>> +	struct wtst_shm_pool *wtst_pool = zalloc(sizeof(struct wtst_shm_pool));
>> +	ZUC_EXPECT_TRUE(wtst_pool != NULL);
> 
> 
> I _think_ style is to have an empty line after declarations.

Mostly fixed. Will do another pass.


>> +	if (!wtst_pool)
>> +		return NULL;
>> +
>> +	wtst_pool->fd = fd;
>> +	wtst_pool->flen = flen;
>> +	wtst_pool->membuf = mmap(NULL, flen, PROT_READ | PROT_WRITE,
>> +				 MAP_SHARED, fd, 0);
>> +	ZUC_EXPECT_TRUE(wtst_pool->membuf != MAP_FAILED);
>> +	if (wtst_pool->membuf == MAP_FAILED) {
>> +		printf("%s:%d: error: unable to memmap.\n", __FILE__, __LINE__);
>> +	} else {
>> +		wtst_pool->pool = wl_shm_create_pool(shm, fd, flen);
>> +		ZUC_EXPECT_TRUE(wtst_pool->pool != NULL);
>> +		if (!wtst_pool->pool) {
>> +			printf("%s:%d: error: Unable to create pool.\n",
>> +			       __FILE__, __LINE__);
>> +			munmap(wtst_pool->membuf, flen);
>> +		}
>> +	}
>> +
>> +	if (!wtst_pool->pool) {
>> +		free(wtst_pool);
>> +		wtst_pool = NULL;
>> +	}
>> +
>> +	return wtst_pool;
>> +}
>> +
>> +void set_button_cb(struct wtst_shell_surface *shell_surface, button_cb callback)
>> +{
>> +	struct wtst_surface *wsurf = NULL;
>> +	ZUC_ASSERT_TRUE(shell_surface != NULL);
>> +	ZUC_ASSERT_TRUE(shell_surface->surface != NULL);
>> +	ZUC_ASSERT_TRUE(shell_surface->surface->wl_surface != NULL);
>> +
>> +	wsurf = shell_surface->surface;
>> +	ZUC_ASSERT_TRUE(wsurf != NULL);
>> +	ZUC_ASSERT_TRUE(wsurf->data != NULL);
>> +
>> +	((struct surface_extras *)wsurf->data)->button_cb = callback;
>> +}
>> +
>> +void setup_cursor(struct wtst_shm_pool *pool,
>> +		  unsigned int width, unsigned int height,
>> +		  int32_t hit_x, int32_t hit_y,
>> +		  struct wl_compositor *compositor,
>> +		  struct surface_extras *extras)
>> +{
>> +	int32_t stride = width * ARGB32_SIZE;
>> +	ZUC_ASSERT_TRUE(extras != NULL);
>> +	extras->hit_x = hit_x;
>> +	extras->hit_y = hit_y;
>> +
>> +	extras->cursor = wl_compositor_create_surface(compositor);
>> +	ZUC_EXPECT_TRUE(extras->cursor != NULL);
>> +	if (!extras->cursor)
>> +		return;
>> +
>> +	extras->membuf = pool->membuf;
>> +	extras->membuf += pool->used / sizeof(*extras->membuf);
>> +	rd_draw_crosshairs(extras->membuf, PXL_ARGB32, width * ARGB32_SIZE,
>> +			   width, height);
>> +
>> +	extras->buffer = wl_shm_pool_create_buffer(pool->pool,
>> +						   pool->used,
>> +						   width,
>> +						   height,
>> +						   stride,
>> +						   PIXEL_FORMAT);
>> +	pool->used += width * height * ARGB32_SIZE;
>> +	ZUC_EXPECT_TRUE(extras->buffer != NULL);
>> +
>> +	if (extras->buffer) {
>> +		rd_draw_crosshairs(extras->membuf, PXL_ARGB32,
>> +				   width * ARGB32_SIZE,
>> +				   width, height);
>> +	}
>> +}
>> +
>> +
>> +static void foo_enter(void *data,
>> +		      struct wl_pointer *wl_pointer,
>> +		      uint32_t serial, struct wl_surface *surface,
>> +		      wl_fixed_t surface_x, wl_fixed_t surface_y)
>> +{
>> +	struct wtst_pointer *pointer = data;
>> +	if (pointer && pointer->focus && pointer->focus->data) {
>> +		struct surface_extras *extras = pointer->focus->data;
>> +		wl_surface_attach(extras->cursor, extras->buffer, 0, 0);
>> +		wl_surface_commit(extras->cursor);
>> +		wl_pointer_set_cursor(pointer->wl_pointer, serial,
>> +				      extras->cursor,
>> +				      extras->hit_x, extras->hit_y);
>> +	}
>> +}
>> +
>> +static void foo_leave(void *data,
>> +		      struct wl_pointer *wl_pointer, uint32_t serial,
>> +		      struct wl_surface *wl_surface)
>> +{
>> +}
>> +
>> +static void foo_motion(void *data,
>> +		       struct wl_pointer *wl_pointer, uint32_t time,
>> +		       wl_fixed_t surface_x, wl_fixed_t surface_y)
>> +{
>> +}
>> +
>> +static void foo_button(void *data,
>> +		       struct wl_pointer *wl_pointer, uint32_t serial,
>> +		       uint32_t time, uint32_t button, uint32_t state)
>> +{
>> +	struct wtst_pointer *pointer = data;
>> +	if (pointer && pointer->focus && pointer->focus->data) {
>> +		struct surface_extras *extras = pointer->focus->data;
>> +		if (extras->button_cb)
>> +			extras->button_cb(serial, time, button, state);
>> +	}
>> +}
>> +
>> +static void foo_axis(void *data,
>> +			 struct wl_pointer *wl_pointer, uint32_t time,
>> +			 uint32_t axis, wl_fixed_t value)
>> +{
>> +}
>> +
>> +static const struct wl_pointer_listener pointer_listener = {
>> +	.enter = foo_enter,
>> +	.leave = foo_leave,
>> +	.motion = foo_motion,
>> +	.button = foo_button,
>> +	.axis = foo_axis
>> +};
>> diff --git a/tools/waycheck/waycheck.dox b/tools/waycheck/waycheck.dox
>> new file mode 100644
>> index 0000000..66ae65b
>> --- /dev/null
>> +++ b/tools/waycheck/waycheck.dox
>> @@ -0,0 +1,29 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +/**
>> + at page waycheck
>> +
>> +A simple integration/acceptance tool to exercise Wayland compositors.
>> +
>> +Tests use @ref zunitc for their infrastructure, and most include use of a common wtst_ctx test fixture.
>> +*/
>> \ No newline at end of file
>> diff --git a/tools/wayland_fixtures/inc/wtst_fixtures.h b/tools/wayland_fixtures/inc/wtst_fixtures.h
>> new file mode 100644
>> index 0000000..bf95603
>> --- /dev/null
>> +++ b/tools/wayland_fixtures/inc/wtst_fixtures.h
>> @@ -0,0 +1,230 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef WTST_FIXTURES_H
>> +#define WTST_FIXTURES_H
>> +
>> +/**
>> + * @file
>> + * Common helpers for Wayland tests.
>> + */
>> +
>> +#include <stdint.h>
>> +#include <stdbool.h>
>> +
>> +#include <wayland-client.h>
>> +
>> +#ifdef __cplusplus
>> +extern "C" {
>> +#endif
>> +
>> +/**
>> + * Test fixture that holds the basics for simple Wayland client testing.
>> + *
>> + * @see wtst_ctx_create()
>> + * @see wtst_ctx_destroy()
>> + */
>> +struct wtst_ctx
>> +{
>> +	/** The display the client is connected to. */
>> +	struct wl_display *display;
>> +
>> +	/** The registry the client is connected to. */
>> +	struct wl_registry *registry;
>> +
>> +	/** Main compositor as advertised and updated by the registry. */
>> +	struct wl_compositor *compositor;
>> +
>> +	/**
>> +	 * Main shared memory object as advertised and updated by the
>> +	 * registry.
>> +	 */
>> +	struct wl_shm *shm;
>> +
>> +// -------------------------------------
> 
> /* */ style please

Removed.

>> +
>> +	/** The seat that is actually used for input events. */
>> +	struct wtst_input *input;
>> +
>> +	/**
>> +	 * Server can have more wl_seats. We need keep them all until we
>> +	 * find the one that we need. After that, the others
>> +	 * will be destroyed, so this list will have the length of 1.
>> +	 * If some day in the future we will need the other seats,
>> +	 * we can just keep them here.
>> +	 */
>> +	struct wl_list inputs;
>> +
>> +	struct wtst_output *output;
>> +
>> +	struct wtst_surface *surface;
>> +
>> +	bool has_argb;
>> +
>> +	bool has_wl_drm;
>> +
>> +// -------------------------------------
>> +
>> +	/** Main shell as advertised and updated by the registry. */
>> +	struct wl_shell *shell;
>> +
>> +	/** Listener registered with the registry. */
>> +	struct wl_registry_listener *reg_listener;
>> +
>> +	/** Context for internal implementation details. */
>> +	struct wtst_ctx_private *private;
>> +};
>> +
>> +struct wtst_global {
>> +	uint32_t name;
>> +	char *interface;
>> +	uint32_t version;
>> +	struct wl_list link;
>> +};
>> +
>> +struct wtst_input {
>> +	struct wl_seat *wl_seat;
>> +	struct wtst_pointer *pointer;
>> +	struct wtst_keyboard *keyboard;
>> +	struct wtst_touch *touch;
>> +	char *seat_name;
>> +	enum wl_seat_capability caps;
>> +	struct wl_list link;
>> +};
>> +
>> +struct wtst_pointer {
>> +	struct wl_pointer *wl_pointer;
>> +	struct wtst_surface *focus;
>> +	int x;
>> +	int y;
>> +	uint32_t button;
>> +	uint32_t state;
>> +	struct wtst_pointer_private *private;
>> +};
>> +
>> +struct wtst_keyboard {
>> +	struct wl_keyboard *wl_keyboard;
>> +	struct wtst_surface *focus;
>> +	uint32_t key;
>> +	uint32_t state;
>> +	uint32_t mods_depressed;
>> +	uint32_t mods_latched;
>> +	uint32_t mods_locked;
>> +	uint32_t group;
>> +	struct {
>> +		int rate;
>> +		int delay;
>> +	} repeat_info;
>> +};
>> +
>> +struct wtst_touch {
>> +	struct wl_touch *wl_touch;
>> +	int down_x;
>> +	int down_y;
>> +	int x;
>> +	int y;
>> +	int id;
>> +	int up_id; /* id of last wl_touch.up event */
>> +	int frame_no;
>> +	int cancel_no;
>> +};
>> +
>> +struct wtst_output {
>> +	struct wl_output *wl_output;
>> +	int x;
>> +	int y;
>> +	int width;
>> +	int height;
>> +	int scale;
>> +	bool initialized;
>> +};
>> +
>> +struct wtst_surface {
>> +	struct wl_surface *wl_surface;
>> +	struct wl_buffer *wl_buffer;
>> +	struct wtst_output *output;
>> +	int x;
>> +	int y;
>> +	int width;
>> +	int height;
>> +	void *data;
>> +};
>> +
>> +struct wtst_shell_surface {
>> +	struct wl_shell_surface *wl_shell_surface;
>> +	struct wtst_surface *surface; /**< surface that this is wrapping. */
>> +};
>> +
>> +enum wtst_dbgevents_pointer {
>> +	WTST_DBG_POINTER_NONE = 0x00,
>> +	WTST_DBG_POINTER_ENTER = 0x01,
>> +	WTST_DBG_POINTER_LEAVE = 0x02,
>> +	WTST_DBG_POINTER_MOTION = 0x04,
>> +	WTST_DBG_POINTER_BUTTON = 0x08,
>> +	WTST_DBG_POINTER_AXIS = 0x10,
>> +	WTST_DBG_POINTER_ALL = 0x1f
>> +};
>> +
>> +/**
>> + * Creates an instance of the test fixture.
>> + *
>> + * @return a pointer to a test fixture upon success, NULL otherwise.
>> + * @see wtst_ctx_destroy()
>> + */
>> +struct wtst_ctx *wtst_ctx_create(void);
>> +
>> +/**
>> + * Destroys a test fixture.
>> + *
>> + * @param ctx pointer to a test fixture to destroy.
>> + * It should have previously been created via wtst_ctx_create().
>> + * @see wtst_ctx_create()
>> + */
>> +void wtst_ctx_destroy(struct wtst_ctx *ctx);
>> +
>> +/**
>> + * Determines of an interface has been advertized by the Wayland registry
>> + * as being present.
>> + *
>> + * @param ctx the test fixture in use.
>> + * @param interface the name of the interface to query.
>> + * @return true if the interface is supported, false otherwise.
>> + */
>> +int wtst_is_global_advertised(struct wtst_ctx *ctx, char const *interface);
>> +
>> +int wtst_pointer_add_listener(struct wtst_pointer *pointer,
>> +			      const struct wl_pointer_listener *listener,
>> +			      void *data);
>> +
>> +void wtst_set_dump_pointer_events(enum wtst_dbgevents_pointer mask);
>> +
>> +/**
>> + * Creates a wl_shell_surface and packages it in a wtst_shell_surface wrapper.
>> + */
>> +struct wtst_shell_surface *wtst_create_shell_surface(
>> +	struct wl_compositor *compositor, struct wl_shell *shell);
>> +
>> +#ifdef __cplusplus
>> +} /* extern "C" */
>> +#endif
>> +
>> +#endif /* WTST_FIXTURES_H */
>> diff --git a/tools/wayland_fixtures/src/wtst_fixtures.c b/tools/wayland_fixtures/src/wtst_fixtures.c
>> new file mode 100644
>> index 0000000..a1dbade
>> --- /dev/null
>> +++ b/tools/wayland_fixtures/src/wtst_fixtures.c
>> @@ -0,0 +1,852 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#include "wtst_fixtures.h"
>> +
>> +#include <stdint.h>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <unistd.h>
>> +
>> +#include "shared/zalloc.h"
>> +#include "zunitc/zunitc.h"
>> +
>> +struct wtst_ctx_private {
>> +
>> +	/** List of all known global advertised by the registry. */
>> +	struct wl_list global_list;
>> +
>> +	/** Current main compositor name advertised by the registry. */
>> +	uint32_t compositor_name;
>> +
>> +	/** Current shared memory object name advertised by the registry. */
>> +	uint32_t shm_name;
>> +
>> +	/** Current shell name advertised by the registry. */
>> +	uint32_t shell_name;
>> +};
>> +
>> +/**
>> + * Find the test-seat and set it in client while destroying other inputs.
>> + * @todo probably need to defer input selection to higher layers and not
>> + * hardcode to "test-seat" here.
>> + */
>> +static void wtst_ctx_set_input(struct wtst_ctx *ctx);
>> +
>> +static void input_update_devices(struct wtst_input *input);
>> +
>> +static int logle = 0;
> 
> I match your "logle" and raise you an extra "vel". let's not have arbitrary
> abbreviations please.

Removed for next push.


>> +
>> +static enum wtst_dbgevents_pointer g_pointer_dbg_mask = WTST_DBG_POINTER_ALL;
>> +
>> +void wtst_set_dump_pointer_events(enum wtst_dbgevents_pointer mask)
>> +{
>> +	g_pointer_dbg_mask = mask;
>> +}
>> +
>> +static void input_destroy(struct wtst_input *inp)
>> +{
>> +	wl_list_remove(&inp->link);
>> +	wl_seat_destroy(inp->wl_seat);
>> +	free(inp);
>> +}
>> +
>> +struct wtst_pointer_private
>> +{
>> +	void *data;
>> +	const struct wl_pointer_listener *listener;
>> +	struct wl_list link;
>> +};
>> +
>> +static void output_handle_geometry(void *data,
>> +				   struct wl_output *wl_output,
>> +				   int x, int y,
>> +				   int physical_width, int physical_height,
>> +				   int subpixel,
>> +				   const char *make, const char *model,
>> +				   int32_t transform)
>> +{
>> +	struct wtst_output *output = data;
>> +
>> +	output->x = x;
>> +	output->y = y;
>> +}
>> +
>> +static void output_handle_mode(void *data,
>> +			       struct wl_output *wl_output,
>> +			       uint32_t flags,
>> +			       int width, int height,
>> +			       int refresh)
>> +{
>> +	struct wtst_output *output = data;
>> +
>> +	if (flags & WL_OUTPUT_MODE_CURRENT) {
>> +		output->width = width;
>> +		output->height = height;
>> +	}
>> +}
>> +
>> +static void output_handle_scale(void *data,
>> +				struct wl_output *wl_output,
>> +				int scale)
>> +{
>> +	struct wtst_output *output = data;
>> +
>> +	output->scale = scale;
>> +}
>> +
>> +static void output_handle_done(void *data,
>> +			       struct wl_output *wl_output)
>> +{
>> +	struct wtst_output *output = data;
>> +
>> +	output->initialized = true;
>> +}
>> +
>> +static void seat_handle_capabilities(void *data, struct wl_seat *seat,
>> +				     enum wl_seat_capability caps)
>> +{
>> +	struct wtst_input *input = data;
>> +
>> +	input->caps = caps;
>> +
>> +	/* we will create/update the devices only with the right (test) seat.
>> +	 * If we haven't discovered which seat is the test seat, just
>> +	 * store capabilities and bail out */
>> +	if(input->seat_name && strcmp(input->seat_name, "test-seat") == 0)
>> +		input_update_devices(input);
>> +
>> +	fprintf(stderr, "test-client: got seat %p capabilities: %x\n",
>> +		input, caps);
>> +}
>> +
>> +static void seat_handle_name(void *data, struct wl_seat *seat, const char *name)
>> +{
>> +	struct wtst_input *input = data;
>> +
>> +	input->seat_name = strdup(name);
>> +	ZUC_ASSERT_TRUE(input->seat_name != NULL);
>> +
>> +	fprintf(stderr, "test-client: got seat %p name: \'%s\'\n",
>> +		input, name);
>> +}
>> +
>> +static void shell_surface_ping(void *data,
>> +			       struct wl_shell_surface *shell_surface,
>> +			       uint32_t serial)
>> +{
>> +    wl_shell_surface_pong(shell_surface, serial);
>> +}
>> +
>> +static void shell_surface_configure(void *data,
>> +				    struct wl_shell_surface *shell_surface,
>> +				    uint32_t edges,
>> +				    int32_t width, int32_t height)
>> +{
>> +}
>> +
>> +static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
>> +				 uint32_t serial, struct wl_surface *wl_surface,
>> +				 wl_fixed_t x, wl_fixed_t y)
>> +{
>> +	struct wtst_pointer *pointer = data;
>> +	struct wtst_pointer_private *entry = NULL;
>> +	struct wtst_pointer_private *tmp = NULL;
>> +
>> +	pointer->focus = wl_surface_get_user_data(wl_surface);
>> +	pointer->x = wl_fixed_to_int(x);
>> +	pointer->y = wl_fixed_to_int(y);
>> +
>> +	if (g_pointer_dbg_mask & WTST_DBG_POINTER_ENTER)
>> +		fprintf(stderr, "test-client: "
>> +			"got pointer enter %d %d, surface %p\n",
>> +			pointer->x, pointer->y, pointer->focus);
>> +
>> +	wl_list_for_each_safe(entry, tmp, &pointer->private->link, link)
>> +		if (entry->listener && entry->listener->enter)
>> +			entry->listener->enter(entry->data, wl_pointer,
>> +					       serial, wl_surface, x, y);
>> +}
>> +
>> +static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
>> +				 uint32_t serial, struct wl_surface *wl_surface)
>> +{
>> +	struct wtst_pointer *pointer = data;
>> +	struct wtst_pointer_private *entry = NULL;
>> +	struct wtst_pointer_private *tmp = NULL;
>> +
>> +	pointer->focus = NULL;
>> +
>> +	if (g_pointer_dbg_mask & WTST_DBG_POINTER_LEAVE)
>> +		fprintf(stderr, "test-client: "
>> +			"got pointer leave, surface %p\n",
>> +			wl_surface_get_user_data(wl_surface));
>> +
>> +	wl_list_for_each_safe(entry, tmp, &pointer->private->link, link)
>> +		if (entry->listener && entry->listener->leave)
>> +			entry->listener->leave(entry->data, wl_pointer,
>> +					       serial, wl_surface);
>> +}
>> +
>> +static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
>> +				  uint32_t time, wl_fixed_t x, wl_fixed_t y)
>> +{
>> +	struct wtst_pointer *pointer = data;
>> +	struct wtst_pointer_private *entry = NULL;
>> +	struct wtst_pointer_private *tmp = NULL;
>> +
>> +	pointer->x = wl_fixed_to_int(x);
>> +	pointer->y = wl_fixed_to_int(y);
>> +
>> +	if (g_pointer_dbg_mask & WTST_DBG_POINTER_MOTION)
>> +		fprintf(stderr, "test-client: "
>> +			"got pointer motion %d %d\n",
>> +			pointer->x, pointer->y);
>> +
>> +	wl_list_for_each_safe(entry, tmp, &pointer->private->link, link)
>> +		if (entry->listener && entry->listener->motion)
>> +			entry->listener->motion(entry->data, wl_pointer,
>> +			   time, x, y);
>> +}
>> +
>> +static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
>> +				  uint32_t serial, uint32_t time,
>> +				  uint32_t button, uint32_t state)
>> +{
>> +	struct wtst_pointer *pointer = data;
>> +	struct wtst_pointer_private *entry = NULL;
>> +	struct wtst_pointer_private *tmp = NULL;
>> +
>> +	pointer->button = button;
>> +	pointer->state = state;
>> +
>> +	if (g_pointer_dbg_mask & WTST_DBG_POINTER_BUTTON)
>> +		fprintf(stderr, "test-client: "
>> +			"got pointer button %u %u\n",
>> +			button, state);
>> +
>> +	wl_list_for_each_safe(entry, tmp, &pointer->private->link, link)
>> +		if (entry->listener && entry->listener->button)
>> +			entry->listener->button(entry->data, wl_pointer,
>> +						serial, time, button, state);
>> +}
>> +
>> +static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
>> +				uint32_t time, uint32_t axis, wl_fixed_t value)
>> +{
>> +	struct wtst_pointer *pointer = data;
>> +	struct wtst_pointer_private *entry = NULL;
>> +	struct wtst_pointer_private *tmp = NULL;
>> +
>> +	fprintf(stderr, "test-client: got pointer axis %u %f\n",
>> +		axis, wl_fixed_to_double(value));
>> +
>> +	wl_list_for_each_safe(entry, tmp, &pointer->private->link, link)
>> +		if (entry->listener && entry->listener->axis)
>> +			entry->listener->axis(entry->data, wl_pointer,
>> +					      time, axis, value);
>> +}
>> +
>> +static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
>> +				   uint32_t format, int fd, uint32_t size)
>> +{
>> +	close(fd);
>> +
>> +	fprintf(stderr, "test-client: got keyboard keymap\n");
>> +}
>> +
>> +static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
>> +				  uint32_t serial,
>> +				  struct wl_surface *wl_surface,
>> +				  struct wl_array *keys)
>> +{
>> +	struct wtst_keyboard *keyboard = data;
>> +
>> +	keyboard->focus = wl_surface_get_user_data(wl_surface);
>> +
>> +	fprintf(stderr, "test-client: got keyboard enter, surface %p\n",
>> +		keyboard->focus);
>> +}
>> +
>> +static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
>> +				  uint32_t serial,
>> +				  struct wl_surface *wl_surface)
>> +{
>> +	struct wtst_keyboard *keyboard = data;
>> +
>> +	keyboard->focus = NULL;
>> +
>> +	fprintf(stderr, "test-client: got keyboard leave, surface %p\n",
>> +		wl_surface_get_user_data(wl_surface));
>> +}
>> +
>> +static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
>> +				uint32_t serial, uint32_t time, uint32_t key,
>> +				uint32_t state)
>> +{
>> +	struct wtst_keyboard *keyboard = data;
>> +
>> +	keyboard->key = key;
>> +	keyboard->state = state;
>> +
>> +	fprintf(stderr, "test-client: got keyboard key %u %u\n", key, state);
>> +}
>> +
>> +static void keyboard_handle_modifiers(void *data,
>> +				      struct wl_keyboard *wl_keyboard,
>> +				      uint32_t serial, uint32_t mods_depressed,
>> +				      uint32_t mods_latched,
>> +				      uint32_t mods_locked,
>> +				      uint32_t group)
>> +{
>> +	struct wtst_keyboard *keyboard = data;
>> +
>> +	keyboard->mods_depressed = mods_depressed;
>> +	keyboard->mods_latched = mods_latched;
>> +	keyboard->mods_locked = mods_locked;
>> +	keyboard->group = group;
>> +
>> +	fprintf(stderr, "test-client: got keyboard modifiers %u %u %u %u\n",
>> +		mods_depressed, mods_latched, mods_locked, group);
>> +}
>> +
>> +static void keyboard_handle_repeat_info(void *data,
>> +					struct wl_keyboard *wl_keyboard,
>> +					int32_t rate, int32_t delay)
>> +{
>> +	struct wtst_keyboard *keyboard = data;
>> +
>> +	keyboard->repeat_info.rate = rate;
>> +	keyboard->repeat_info.delay = delay;
>> +
>> +	fprintf(stderr, "test-client: got keyboard repeat_info %d %d\n",
>> +		rate, delay);
>> +}
>> +
>> +static void touch_handle_down(void *data, struct wl_touch *wl_touch,
>> +			      uint32_t serial, uint32_t time,
>> +			      struct wl_surface *surface,
>> +			      int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
>> +{
>> +	struct wtst_touch *touch = data;
>> +
>> +	touch->down_x = wl_fixed_to_int(x_w);
>> +	touch->down_y = wl_fixed_to_int(y_w);
>> +	touch->id = id;
>> +
>> +	fprintf(stderr, "test-client: got touch down %d %d, surf: %p, id: %d\n",
>> +		touch->down_x, touch->down_y, surface, id);
>> +}
>> +
>> +static void touch_handle_up(void *data, struct wl_touch *wl_touch,
>> +			    uint32_t serial, uint32_t time, int32_t id)
>> +{
>> +	struct wtst_touch *touch = data;
>> +	touch->up_id = id;
>> +
>> +	fprintf(stderr, "test-client: got touch up, id: %d\n", id);
>> +}
>> +
>> +static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
>> +				uint32_t time, int32_t id,
>> +				wl_fixed_t x_w, wl_fixed_t y_w)
>> +{
>> +	struct wtst_touch *touch = data;
>> +	touch->x = wl_fixed_to_int(x_w);
>> +	touch->y = wl_fixed_to_int(y_w);
>> +
>> +	fprintf(stderr, "test-client: got touch motion, %d %d, id: %d\n",
>> +		touch->x, touch->y, id);
>> +}
>> +
>> +static void touch_handle_frame(void *data, struct wl_touch *wl_touch)
>> +{
>> +	struct wtst_touch *touch = data;
>> +
>> +	++touch->frame_no;
>> +
>> +	fprintf(stderr, "test-client: got touch frame (%d)\n", touch->frame_no);
>> +}
>> +
>> +static void touch_handle_cancel(void *data, struct wl_touch *wl_touch)
>> +{
>> +	struct wtst_touch *touch = data;
>> +
>> +	++touch->cancel_no;
>> +
>> +	fprintf(stderr, "test-client: got touch cancel (%d)\n",
>> +		touch->cancel_no);
>> +}
>> +
>> +static void surface_handle_enter(void *data, struct wl_surface *wl_surface,
>> +				 struct wl_output *output)
>> +{
>> +	struct wtst_surface *surface = data;
>> +
>> +	surface->output = wl_output_get_user_data(output);
>> +
>> +	fprintf(stderr, "test-client: got surface enter output %p\n",
>> +		surface->output);
>> +}
>> +
>> +static void surface_handle_leave(void *data, struct wl_surface *wl_surface,
>> +				 struct wl_output *output)
>> +{
>> +	struct wtst_surface *surface = data;
>> +
>> +	surface->output = NULL;
>> +
>> +	fprintf(stderr, "test-client: got surface leave output %p\n",
>> +		wl_output_get_user_data(output));
>> +}
>> +
>> +static const struct wl_shell_surface_listener
>> +shell_surface_listener = {
>> +	.ping = shell_surface_ping,
>> +	.configure = shell_surface_configure,
>> +};
>> +
>> +static const struct wl_output_listener output_listener = {
>> +	output_handle_geometry,
>> +	output_handle_mode,
>> +	output_handle_done,
>> +	output_handle_scale,
>> +};
>> +
>> +static const struct wl_seat_listener seat_listener = {
>> +	seat_handle_capabilities,
>> +	seat_handle_name,
>> +};
>> +
>> +static const struct wl_pointer_listener pointer_listener = {
>> +	pointer_handle_enter,
>> +	pointer_handle_leave,
>> +	pointer_handle_motion,
>> +	pointer_handle_button,
>> +	pointer_handle_axis,
>> +};
>> +
>> +static const struct wl_keyboard_listener keyboard_listener = {
>> +	keyboard_handle_keymap,
>> +	keyboard_handle_enter,
>> +	keyboard_handle_leave,
>> +	keyboard_handle_key,
>> +	keyboard_handle_modifiers,
>> +	keyboard_handle_repeat_info
>> +};
>> +
>> +static const struct wl_touch_listener touch_listener = {
>> +	touch_handle_down,
>> +	touch_handle_up,
>> +	touch_handle_motion,
>> +	touch_handle_frame,
>> +	touch_handle_cancel,
>> +};
>> +
>> +static const struct wl_surface_listener surface_listener = {
>> +	surface_handle_enter,
>> +	surface_handle_leave
>> +};
>> +
>> +static void add_global_advert(struct wtst_ctx *ctx,
>> +			      uint32_t name,
>> +			      const char *interface,
>> +			      uint32_t version)
>> +{
>> +	if (!ctx || !ctx->private)
>> +		return;
>> +
>> +	/* See if we've got this interface already */
>> +	struct wtst_global *curr = NULL;
>> +	struct wtst_global *tmp = NULL;
>> +	wl_list_for_each(tmp, &ctx->private->global_list, link)
>> +		if (strcmp(tmp->interface, interface) == 0) {
>> +			curr = tmp;
>> +			break;
>> +		}
>> +
>> +	if (curr) {
>> +		/* These are not supposed to change. */
>> +		ZUC_EXPECT_EQ(curr->name, name);
>> +		ZUC_EXPECT_EQ(curr->version, version);
>> +	} else {
>> +		struct wtst_global *glbl = zalloc(sizeof(*glbl));
>> +		ZUC_ASSERT_TRUE(glbl != NULL);
>> +		glbl->name = name;
>> +		glbl->interface = strdup(interface);
>> +		glbl->version = version;
>> +		wl_list_insert(&ctx->private->global_list, &glbl->link);
>> +	}
>> +}
>> +
>> +static void reg_global(void *data,
>> +		       struct wl_registry *registry,
>> +		       uint32_t name,
>> +		       const char *interface,
>> +		       uint32_t version)
>> +{
>> +	struct wtst_ctx *ctx = (struct wtst_ctx *)data;
>> +	struct wtst_input *input = NULL;
>> +
>> +	if (logle > 1) {
>> +		printf("reg_global ++: %2d   %s  v%d\n",
>> +		       name, interface, version);
>> +	}
>> +
>> +	ZUC_EXPECT_EQ(0, strcmp(wl_compositor_interface.name,
>> +				"wl_compositor"));
>> +
>> +	add_global_advert(ctx, name, interface, version);
>> +
>> +	if (strcmp(interface, wl_compositor_interface.name) == 0) {
>> +		ctx->compositor = wl_registry_bind(registry, name,
>> +						   &wl_compositor_interface,
>> +						   version);
>> +		ctx->private->compositor_name = name;
>> +	} else if (strcmp(interface, wl_seat_interface.name) == 0) {
>> +		input = zalloc(sizeof(*input));
>> +		ZUC_ASSERT_TRUE(input != NULL);
>> +		input->wl_seat = wl_registry_bind(registry, name,
>> +						  &wl_seat_interface, version);
>> +		wl_seat_add_listener(input->wl_seat, &seat_listener, input);
>> +		wl_list_insert(&ctx->inputs, &input->link);
>> +	} else if (strcmp(interface, wl_shm_interface.name) == 0) {
>> +		ZUC_EXPECT_TRUE(ctx->shm == NULL);
>> +		if (ctx->shm)
>> +			wl_shm_destroy(ctx->shm);
>> +		ctx->shm = wl_registry_bind(registry, name,
>> +					    &wl_shm_interface, version);
>> +		ctx->private->shm_name = name;
>> +	} else if (strcmp(interface, wl_output_interface.name) == 0) {
>> +		struct wtst_output *output = zalloc(sizeof(*output));
>> +		ZUC_ASSERT_TRUE(output != NULL);
>> +		output->wl_output = wl_registry_bind(registry, name,
>> +						     &wl_output_interface,
>> +						     version);
>> +		wl_output_add_listener(output->wl_output,
>> +				       &output_listener, output);
>> +		ctx->output = output;
>> +	} else if (strcmp(interface, wl_shell_interface.name) == 0) {
>> +		ZUC_EXPECT_TRUE(ctx->shell == NULL);
>> +		if (ctx->shell)
>> +			wl_shell_destroy(ctx->shell);
>> +		ctx->shell = wl_registry_bind(registry, name,
>> +					      &wl_shell_interface, version);
>> +		ctx->private->shell_name = name;
>> +	} else if (strcmp(interface, "wl_drm") == 0) {
>> +		ctx->has_wl_drm = true;
>> +	}
>> +}
>> +
>> +static void reg_global_remove(void *data,
>> +			      struct wl_registry *registry,
>> +			      uint32_t name)
>> +{
>> +	struct wtst_ctx *ctx = (struct wtst_ctx *)data;
>> +	if (logle > 1)
>> +		printf("reg_global --: %2d\n", name);
> 
> wrap this in trace(), debug(), whatever() macros please.

Removed for next push.


>> +	if (name == ctx->private->compositor_name) {
>> +		if (ctx->compositor)
>> +			wl_compositor_destroy(ctx->compositor);
>> +		ctx->compositor = NULL;
>> +		ctx->private->compositor_name = 0;
>> +	} else if (name == ctx->private->shm_name) {
>> +		if (ctx->shm)
>> +			wl_shm_destroy(ctx->shm);
>> +		ctx->shm = NULL;
>> +		ctx->private->shm_name = 0;
>> +	} else if (name == ctx->private->shell_name) {
>> +		if (ctx->shell)
>> +			wl_shell_destroy(ctx->shell);
>> +		ctx->shell = NULL;
>> +		ctx->private->shell_name = 0;
>> +	}
>> +}
>> +
>> +static struct wtst_ctx_private *wtst_ctx_private_create(void)
>> +{
>> +	struct wtst_ctx_private *private =
>> +		zalloc(sizeof(struct wtst_ctx_private));
>> +	ZUC_EXPECT_TRUE(private != NULL);
>> +	if (private) {
>> +		wl_list_init(&private->global_list);
>> +	}
>> +
>> +	return private;
>> +}
>> +
>> +static void wtst_ctx_private_destroy(struct wtst_ctx_private *private)
>> +{
>> +	if (!private)
>> +		return;
>> +
>> +	if (!wl_list_empty(&private->global_list)) {
>> +		struct wtst_global *entry = NULL;
>> +		struct wtst_global *tmp = NULL;
>> +		wl_list_for_each_reverse_safe(entry, tmp,
>> +					      &private->global_list, link) {
>> +			wl_list_remove(&entry->link);
>> +			free(entry);
>> +		}
>> +	}
>> +
>> +	free(private);
>> +}
>> +
>> +struct wtst_ctx *wtst_ctx_create(void)
>> +{
>> +	struct wtst_ctx *ctx = zalloc(sizeof(*ctx));
>> +	if (!ctx) {
>> +		ZUC_FAIL("Unable to allocate context.");
>> +	} else {
>> +		wl_list_init(&ctx->inputs);
>> +		ctx->reg_listener = zalloc(sizeof(*(ctx->reg_listener)));
>> +		ZUC_EXPECT_TRUE(ctx->reg_listener != NULL);
>> +
>> +		/* connect to display. */
>> +		ctx->display = wl_display_connect(NULL);
>> +		if (!ctx->display) {
>> +			ZUC_FAIL("Unable to connect to display");
>> +			free(ctx->reg_listener);
>> +			free(ctx);
>> +			ctx = NULL;
>> +		} else {
>> +			ctx->private = wtst_ctx_private_create();
>> +
>> +			/* setup registry so we can bind to interfaces. */
>> +			ctx->registry = wl_display_get_registry(ctx->display);
>> +			ctx->reg_listener->global = reg_global;
>> +			ctx->reg_listener->global_remove = reg_global_remove;
>> +			wl_registry_add_listener(ctx->registry,
>> +						 ctx->reg_listener,
>> +						 ctx);
>> +
>> +			/* this roundtrip makes sure we have all globals
>> +			 * and we have bound to them: */
>> +			wl_display_roundtrip(ctx->display);
>> +
>> +			/* this roundtrip makes sure we got all wl_shm
>> +			 * format and wl_seat.* events: */
>> +			wl_display_roundtrip(ctx->display);
>> +
>> +			/* find the right input for us */
>> +			wtst_ctx_set_input(ctx);
>> +
>> +			/* must have an output */
>> +			ZUC_EXPECT_TRUE(ctx->output != NULL);
>> +
>> +			/* the output must be initialized */
>> +			if (ctx->output)
>> +				ZUC_EXPECT_TRUE(ctx->output->initialized);
>> +
>> +			/* must have seat set */
>> +			ZUC_EXPECT_TRUE(ctx->input != NULL);
>> +		}
>> +	}
>> +
>> +	return ctx;
>> +}
>> +
>> +void wtst_ctx_destroy(struct wtst_ctx *ctx)
>> +{
>> +	if (ctx) {
>> +		if (ctx->registry)
>> +			wl_registry_destroy(ctx->registry);
>> +		if (ctx->reg_listener)
>> +			free(ctx->reg_listener);
>> +		if (ctx->shell)
>> +			wl_shell_destroy(ctx->shell);
>> +		if (ctx->shm)
>> +			wl_shm_destroy(ctx->shm);
>> +		if (ctx->compositor)
>> +			wl_compositor_destroy(ctx->compositor);
>> +		if (ctx->display)
>> +			wl_display_disconnect(ctx->display);
>> +		wtst_ctx_private_destroy(ctx->private);
>> +		free(ctx);
>> +	}
>> +}
>> +
>> +static struct wtst_pointer *wtst_pointer_create(void)
>> +{
>> +	struct wtst_pointer *pointer = zalloc(sizeof(*pointer));
>> +	ZUC_EXPECT_TRUE(pointer != NULL);
>> +	if (pointer) {
>> +		pointer->private = zalloc(sizeof(struct wtst_pointer_private));
>> +		ZUC_EXPECT_TRUE(pointer->private != NULL);
>> +		wl_list_init(&pointer->private->link);
>> +	}
>> +	return pointer;
>> +}
>> +
>> +int wtst_pointer_add_listener(struct wtst_pointer *pointer,
>> +			      const struct wl_pointer_listener *listener,
>> +			      void *data)
>> +{
>> +	struct wtst_pointer_private *priv =
>> +		zalloc(sizeof(struct wtst_pointer_private));
>> +	ZUC_EXPECT_TRUE(priv != NULL);
>> +	priv->data = data;
>> +	priv->listener = listener;
>> +	wl_list_insert(&pointer->private->link, &priv->link);
>> +	return 0;
>> +}
>> +
>> +void input_update_devices(struct wtst_input *input)
>> +{
>> +	struct wl_seat *seat = input->wl_seat;
>> +	enum wl_seat_capability caps = input->caps;
>> +
>> +	if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
>> +		struct wtst_pointer *pointer = wtst_pointer_create();
>> +		pointer->wl_pointer = wl_seat_get_pointer(seat);
>> +		wl_pointer_set_user_data(pointer->wl_pointer, pointer);
>> +		wl_pointer_add_listener(pointer->wl_pointer, &pointer_listener,
>> +					pointer);
>> +		input->pointer = pointer;
>> +	} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
>> +		wl_pointer_destroy(input->pointer->wl_pointer);
>> +		free(input->pointer);
>> +		input->pointer = NULL;
>> +	}
>> +
>> +	if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
>> +		struct wtst_keyboard *keyboard = zalloc(sizeof(*keyboard));
>> +		ZUC_ASSERT_TRUE(keyboard != NULL);
>> +		keyboard->wl_keyboard = wl_seat_get_keyboard(seat);
>> +		wl_keyboard_set_user_data(keyboard->wl_keyboard, keyboard);
>> +		wl_keyboard_add_listener(keyboard->wl_keyboard,
>> +					 &keyboard_listener, keyboard);
>> +		input->keyboard = keyboard;
>> +	} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
>> +		wl_keyboard_destroy(input->keyboard->wl_keyboard);
>> +		free(input->keyboard);
>> +		input->keyboard = NULL;
>> +	}
>> +
>> +	if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
>> +		struct wtst_touch *touch = zalloc(sizeof(*touch));
>> +		ZUC_ASSERT_TRUE(touch != NULL);
>> +		touch->wl_touch = wl_seat_get_touch(seat);
>> +		wl_touch_set_user_data(touch->wl_touch, touch);
>> +		wl_touch_add_listener(touch->wl_touch, &touch_listener,
>> +					 touch);
>> +		input->touch = touch;
>> +	} else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
>> +		wl_touch_destroy(input->touch->wl_touch);
>> +		free(input->touch);
>> +		input->touch = NULL;
>> +	}
>> +}
>> +
>> +void wtst_ctx_set_input(struct wtst_ctx *ctx)
>> +{
>> +	/* For now prune all but first. Later support looking for named seats */
>> +	struct wtst_input *inp, *inptmp;
>> +	wl_list_for_each_safe(inp, inptmp, &ctx->inputs, link) {
>> +		ZUC_ASSERT_TRUE(inp->seat_name && "BUG: input with no name");
>> +		if (!ctx->input) {
>> +			ctx->input = inp;
>> +			input_update_devices(inp);
>> +		} else {
>> +			input_destroy(inp);
>> +		}
>> +	}
>> +
>> +	/* we keep only one input */
>> +	ZUC_ASSERT_EQ(1, wl_list_length(&ctx->inputs));
>> +}
>> +
>> +int wtst_is_global_advertised(struct wtst_ctx *ctx, char const *interface)
>> +{
>> +	int found = 0;
>> +	if (ctx && ctx->private && interface) {
>> +		struct wtst_global *tmp = NULL;
>> +		wl_list_for_each(tmp, &ctx->private->global_list, link)
>> +			if (strcmp(interface, tmp->interface) == 0) {
>> +				found = true;
>> +				break;
>> +			}
>> +	}
>> +	return found;
>> +}
>> +
>> +static struct wtst_surface *wrap_wl_surface(struct wl_surface *wl_surface)
>> +{
>> +	struct wtst_surface *wsurf = NULL;
>> +	ZUC_EXPECT_TRUE(wl_surface != NULL);
>> +	if (wl_surface) {
>> +		wsurf = zalloc(sizeof(*wsurf));
>> +		ZUC_EXPECT_TRUE(wsurf != NULL);
>> +		wl_surface_set_user_data(wl_surface, wsurf);
>> +		if (wsurf) {
>> +			wsurf->wl_surface = wl_surface;
>> +			wl_surface_add_listener(wl_surface, &surface_listener,
>> +						wsurf);
>> +		}
>> +	}
>> +	return wsurf;
>> +}
>> +
>> +struct wtst_shell_surface *wtst_create_shell_surface(
>> +	struct wl_compositor *compositor,
>> +	struct wl_shell *shell)
>> +{
>> +	struct wtst_shell_surface *wss =
>> +		zalloc(sizeof(struct wtst_shell_surface));
>> +	ZUC_EXPECT_TRUE(wss != NULL);
>> +	if (wss) {
>> +		struct wl_surface *wl_surface =
>> +			wl_compositor_create_surface(compositor);
>> +		ZUC_EXPECT_TRUE(wl_surface != NULL);
>> +		wss->surface = wrap_wl_surface(wl_surface);
>> +	}
>> +
>> +	if (wss && wss->surface) {
>> +		wss->wl_shell_surface =
>> +			wl_shell_get_shell_surface(shell,
>> +						   wss->surface->wl_surface);
>> +		ZUC_EXPECT_TRUE(wss->wl_shell_surface != NULL);
>> +		if (wss->wl_shell_surface) {
>> +			wl_shell_surface_add_listener(wss->wl_shell_surface,
>> +						      &shell_surface_listener,
>> +						      wss);
>> +			wl_shell_surface_set_toplevel(wss->wl_shell_surface);
>> +			wl_shell_surface_set_user_data(wss->wl_shell_surface,
>> +						       wss);
>> +		}
>> +	}
>> +
>> +	if (wss && (!wss->surface || !wss->wl_shell_surface)) {
>> +		if (wss->surface) {
>> +			struct wl_surface *wl_surface =
>> +				wss->surface->wl_surface;
>> +			free(wss->surface);
>> +			wl_surface_destroy(wl_surface);
>> +		}
>> +		free(wss);
>> +		wss = NULL;
>> +	}
>> +
>> +	return wss;
>> +}
>> diff --git a/tools/zunitc/doc/zunitc.dox b/tools/zunitc/doc/zunitc.dox
>> new file mode 100644
>> index 0000000..4595d7d
>> --- /dev/null
>> +++ b/tools/zunitc/doc/zunitc.dox
>> @@ -0,0 +1,138 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +/**
>> + at page zunitc zunitc
>> +
>> +- @ref zunitc_overview
>> +- @ref zunitc_execution
>> +  - @ref zunitc_execution_commandline
>> +  - @ref zunitc_execution_matching
>> +  - @ref zunitc_execution_wildcards
>> +  - @ref zunitc_execution_repeat
>> +  - @ref zunitc_execution_randomize
>> +- @ref zunitc_fixtures
>> +- @ref zunitc_functions
> 
> yikes, is there no way to get a page-level TOC?

Not until version 1.8.1 or later. Wayland is currently only requiring 1.6+


>> +
>> + at section zunitc_overview Overview
>> +
>> +A simple test framework in plain C suitable for basic unit and integration testing.
>> +
>> +The main rationale for creating this framework was to have a simple to use testing
>> +framework with tests implemented in C using common patterns and under a
>> +compatible license. The structure of the test code and macro use is intended to
>> +follow common patterns established by frameworks such as Boost Test and Google Test.
>> +
>> +
>> +To get started, one or more tests should be defined via ZUC_TEST() and/or
>> +ZUC_TEST_F(), which set up automatic test registration via gcc extensions.
>> +To actually execute tests, ZUC_RUN_TESTS() should be called.
> 
> @example here would be nice

Yes. Good suggestion.


>> +
>> +
>> +Tests can use several ZUC_EXPECT_* or ZUC_ASSERT_* checks to validate
>> +conditions. The ZUC_EXPECT_* ones upon failure will mark the current test
>> +as failing, but allow execution to continue. On the other hand, the
>> +ZUC_ASSERT_* tests will mark the current test as failed and then immediately
>> +terminate the test.
>> +
>> +The set of non-fatal test checks are
>> +
>> +- ZUC_EXPECT_TRUE()
>> +- ZUC_EXPECT_FALSE()
>> +- ZUC_EXPECT_EQ()
>> +- ZUC_EXPECT_NE()
>> +- ZUC_EXPECT_LT()
>> +- ZUC_EXPECT_LE()
>> +- ZUC_EXPECT_GT()
>> +- ZUC_EXPECT_GE()
>> +
> 
> this is personal opinion, but one of the things I really like about check is
> the nice and soothing ck_assert() over the deafening FOO_ASSERT FOO_PANIC
> FOO_WAAAAH from other test suites :)

I've found that it makes the test code a bit more legible. And this
comes from helping both senior architects through fresh interns get up
to speed on testing in many projects.


>> +The set of fatal test checks are
>> +
>> +- ZUC_ASSERT_TRUE()
>> +- ZUC_ASSERT_FALSE()
>> +- ZUC_ASSERT_EQ()
>> +- ZUC_ASSERT_NE()
>> +- ZUC_ASSERT_LT()
>> +- ZUC_ASSERT_LE()
>> +- ZUC_ASSERT_GT()
>> +- ZUC_ASSERT_GE()
>> +
>> +Unconditional test values for logging and termination are
>> +- ZUC_SKIP()
>> +- ZUC_FAIL()
>> +- ZUC_FATAL()
>> +
>> +Unconditional message logging for failure cases only is
>> +- ZUC_TRACEPOINT()
>> +
>> + at section zunitc_execution Controlling Execution
>> +
>> +To control execution, the various zuc_set_* functions can be called before invoking ZUC_RUN_TESTS(). 
>> +
>> + at subsection zunitc_execution_commandline Commandline Parameters
>> +
>> +The current implementation defers processing of command-line parameters to the main application hosting the testing. It is possible that a helper to process certain parameters may be added.
>> +
>> + at subsection zunitc_execution_matching Matching Patterns for Tests
>> +
>> +The function zuc_set_filter() can be used to specify a pattern for matching or excluding tests from a run. The general form is
>> + match1[:match2[:match3..n]][:-exclude1[:exclude2[:exclude3..n]]]
>> +
>> + at subsection zunitc_execution_wildcards Matching Wildcards
>> +
>> +Wildcards can be used in the match/exclude patterns and recognize the following two special characters:
>> +- '*' matches any number of characters including zero.
>> +- '?' matches any single character.
>> +
>> +Calling zuc_list_tests() after zuc_set_filter() can be done to show the effects of the matching without needing to actually run tests.
>> +
>> + at subsection zunitc_execution_repeat Repeating Tests
>> +
>> +Setting the repeat count higher than 1 ( via zuc_set_repeat() ) will cause the tests to be executed several times in a row. This can be useful for stress testing, checking for leaks, etc.
>> +
>> + at subsection zunitc_execution_randomize Randomizing Tests
>> +
>> +Test ordering can be randomized by setting a non-zero positive value to zuc_set_random(). Setting it to 1 will cause the framework to pick a random seed based on the time. A value greater than 1 will be taken as a random seed itself. And setting it to 0 will disable randomization and allow the test to be executed in their natural ordering.
>> +
>> + at section zunitc_fixtures Fixtures
>> +
>> +Per-suite and per-test setup and teardown fixtures can be implemented by defining an instance of struct zuc_fixture and using it as the first parameter to ZUC_TEST_F().
>> +
>> + at section zunitc_functions Functions
>> +
>> +- zuc_get_fixture_data()
>> +- ZUC_TEST()
>> +- ZUC_TEST_F()
>> +- ZUC_RUN_TESTS()
>> +- zuc_cleanup()
>> +- zuc_list_tests()
>> +- zuc_set_filter()
>> +- zuc_set_random()
>> +- zuc_set_spawn()
>> +- zuc_set_output_tap()
>> +- zuc_set_output_junit()
>> +- zuc_has_skip()
>> +- zuc_has_failure()
>> +- zuc_has_fatal_failure()
>> +- zuc_has_nonfatal_failure()
>> +
>> +*/
>> diff --git a/tools/zunitc/inc/zunitc/zunitc.h b/tools/zunitc/inc/zunitc/zunitc.h
>> new file mode 100644
>> index 0000000..869b46a
>> --- /dev/null
>> +++ b/tools/zunitc/inc/zunitc/zunitc.h
>> @@ -0,0 +1,537 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef Z_UNIT_C_H
>> +#define Z_UNIT_C_H
>> +
>> +#include <stdarg.h>
>> +#include <stdbool.h>
>> +
>> +#include "zunitc/zunitc_impl.h"
>> +
>> +/**
>> + * @file
>> + * Simple unit test framework declarations.
>> + */
>> +
>> +#ifdef __cplusplus
>> +extern "C" {
>> +#endif
>> +
>> +/**
>> + * @page zunitc
>> + */
>> +
>> +/**
>> + * Structure to use when defining a test fixture.
>> + * @note likely pending refactoring as use cases are refined.
>> + */
>> +struct zuc_fixture {
>> +	/**
>> +	 * Initial optional seed data to pass to setup functions and/or tests.
>> +	 */
>> +	const void *data;
>> +
>> +	/**
>> +	 * Per-suite setup called before invoking any of the tests
>> +	 * contained in the suite.
>> +	 *
>> +	 * @return a pointer to test data, or NULL.
>> +	 */
>> +	void *(*set_up_test_case)(const void *data);
>> +
>> +	/**
>> +	 * Per-suite tear-down called after invoking all of the tests
>> +	 * contained in the suite.
>> +	 *
>> +	 * @param data pointer returned from the setup function.
>> +	 */
>> +	void (*tear_down_test_case)(void *data);
>> +
>> +	/**
>> +	 * Setup called before running each of the tests in the suite.
>> +	 *
>> +	 * @param data optional data from suite setup, or NULL.
>> +	 * @return a pointer to test data, or NULL.
>> +	 */
>> +	void *(*set_up)(void *data);
>> +
>> +	/**
>> +	 * Tear-down called after running each of the tests in the suite.
>> +	 *
>> +	 * @param data pointer returned from the setup function.
>> +	 */
>> +	void (*tear_down)(void *data);
>> +};
>> +
>> +/**
>> + * Process exit code to mark skipped tests, consistent with
>> + * automake tests.
>> + */
>> +#define ZUC_EXIT_SKIP 77
>> +
>> +/**
>> + * Initializes the test framework and consumes any known command-line
>> + * parameters from the list.
>> + * The exception is 'h/help' which will be left in place for follow-up
>> + * processing by the hosting app if so desired.
>> + *
>> + * @param argc poitner to argc value to read and possibly change.
> 
> typo: pointer

Fixed.


>> + * @param argv array of parameter pointers to read and possibly change.
>> + * @param help_flagged if non-NULL will be set to true if the user
>> + * specifies the help flag (and framework help has been output).
>> + * @return EXIT_SUCCESS upon success setting or help, EXIT_FAILURE otherwise.
>> + */
>> +int zuc_initialize(int *argc, char *argv[], bool *help_flagged);
>> +
>> +/**
>> + * Runs all tests that have been registered.
>> + * Expected return values include EXIT_FAILURE if any errors or failures
>> + * have occurred, ZUC_EXIT_SKIP if no failures have occurred but at least
> 
> @ref missing

@ref is usually not needed. Appending () for functions or prepending the
global scope :: for defined constants is automatcially recognized by
Doxygen.

However, in thise case we can't flag EXIT_FAILURE nor EXIT_SUCCESS since
our code did not define and document them. ZUC_EXIT_SKIP is fixed for
next push, though.


>> + * one test reported skipped, otherwise EXIT_SUCCESS if nothing of note
>> + * was recorded.
>> + *
>> + * @return expected exit status - normally EXIT_SUCCESS, ZUC_EXIT_SKIP,
>> + * or EXIT_FAILURE.
>> + */
>> +#define ZUC_RUN_TESTS() \
>> +	zucimpl_run_tests()
>> +
>> +/**
>> + * Clears the test system in preparation for application shutdown.
>> + */
>> +void zuc_cleanup(void);
>> +
>> +/**
>> + * Displays all known tests.
>> + * The list returned is affected to any filtering in place.
>> + *
>> + * @see zuc_set_filter()
>> + */
>> +void zuc_list_tests(void);
>> +
>> +#if !__GNUC__
>> +#error Framework currently requires gcc or compatible compiler.
>> +#endif
> 
> why is this hidden down here, shouldn't this be the first line (maybe after the
> includes)?

It was originally placed next to the GNU specific using code. That has
moved out, so I fixed the placement of this check.


>> +
>> +
>> +/**
>> + * Sets the filter string to use for tests.
>> + * The format is a series of patterns separated by a colon, with wildcards
>> + * and an optional flag for negative matching. For wildcards, the '*'
>> + * character will match any sequence and the '?' character will match any
>> + * single character.
>> + * The '-' character at the start of a pattern marks the end of the
>> + * patterns required to match and the begining of patterns that names
>> + * must not match.
>> + *
>> + * @param filter the filter string to apply to tests.
>> + */
>> +void zuc_set_filter(const char *filter);
>> +
>> +/**
>> + * Trigger specific failure/signal upon test failures; useful when
>> + * running under a debugger.
>> + *
>> + * @param break_on_failure true to cause a break when tests fail, false to
>> + * allow normal operation upon failures.
>> + */
>> +void zuc_set_break_on_failure(bool break_on_failure);
>> +
>> +/**
>> + * Sets the number of times to repeat the tests.
>> + * Any number higher than 1 will cause the tests to be repeated the
>> + * specified number of times.
>> + *
>> + * @param repeat number of times to repeat the tests.
>> + */
>> +void zuc_set_repeat(int repeat);
>> +
>> +/**
>> + * Randomizes the order in which tests are executed.
>> + * A value of 0 (the default) means tests are executed in their natural
>> + * ordering. A value of 1 will pick a random seed based on the time to
>> + * use for running tests in a pseudo-random order. A value greater than 1
>> + * will be used directly for the initial seed.
>> + *
>> + * If the tests are also repeated, the seed will be incremented for each
>> + * subsequent run.
>> + *
>> + * @param random 0|1|seed value.
>> + * @see zuc_set_repeat()
>> + */
>> +void zuc_set_random(int random);
>> +
>> +/**
>> + * Controls whether or not to run the tests as forked child processes.
>> + *
>> + * @param spawn true to spawn each test in a forked child process,
>> + * false to run tests directly.
>> + */
>> +void zuc_set_spawn(bool spawn);
>> +
>> +/**
>> + * Defines a test case that can be registered to run.
>> + */
>> +#define ZUC_TEST(tcase, test) \
>> +	static void zuctest_##tcase##_##test(void); \
>> +	\
>> +	const struct zuc_registration zzz_##tcase##_##test \
>> +	__attribute__ ((section ("zuc_tsect"))) = \
>> +	{ \
>> +		#tcase, #test, 0,		\
>> +		zuctest_##tcase##_##test,	\
>> +		0				\
>> +	}; \
>> +	\
>> +	static void zuctest_##tcase##_##test(void)
>> +
>> +/**
>> + * Defines a test case that can be registered to run along with setup/teardown
>> + * support per-test and/or per test case.
>> + *
>> + * @note likely pending refactoring as use cases are refined.
>> + */
>> +#define ZUC_TEST_F(tcase, test) \
>> +	static void zuctest_##tcase##_##test(void *data); \
>> +	\
>> +	const struct zuc_registration zzz_##tcase##_##test \
>> +	__attribute__ ((section ("zuc_tsect"))) = \
>> +	{ \
>> +		#tcase, #test, &tcase,		\
>> +		0,				\
>> +		zuctest_##tcase##_##test	\
>> +	}; \
>> +	\
>> +	static void zuctest_##tcase##_##test(void *data)
>> +
>> +
>> +/**
>> + * Returns true if the currently executing test has encounted any skips.
>> + *
>> + * @return true if there is currently a test executing and it has
>> + * encounted any skips.
> 
> typo: encountered, same below
> 
>> + * @see zuc_has_failure
>> + * @see zuc_has_fatal_failure
>> + * @see zuc_has_nonfatal_failure
>> + */
>> +bool zuc_has_skip(void);
>> +
>> +/**
>> + * Returns true if the currently executing test has encounted any failures.
>> + *
>> + * @return true if there is currently a test executing and it has
>> + * encounted any failures.
>> + * @see zuc_has_skip
>> + * @see zuc_has_fatal_failure
>> + * @see zuc_has_nonfatal_failure
>> + */
>> +bool zuc_has_failure(void);
>> +
>> +/**
>> + * Returns true if the currently executing test has encounted fatal failures.
>> + *
>> + * @return true if there is currently a test executing and it has
>> + * encounted fatal failures.
>> + * @see zuc_has_skip
>> + * @see zuc_has_failure
>> + * @see zuc_has_nonfatal_failure
>> + */
>> +bool zuc_has_fatal_failure(void);
>> +
>> +/**
>> + * Returns true if the currently executing test has encounted any
>> + * non-fatal failures.
>> + *
>> + * @return true if there is currently a test executing and it has
>> + * encounted non-fatal failures.
>> + * @see zuc_has_skip
>> + * @see zuc_has_failure
>> + * @see zuc_has_fatal_failure
>> + */
>> +bool zuc_has_nonfatal_failure(void);
>> +
>> +/**
>> + * Terminates the current test without marking it as failed.
>> + *
>> + * @param message the message to log as to why the test has been skipped.
>> + */
>> +#define ZUC_SKIP(message) \
>> +	do { \
>> +		zucimpl_terminate(__FILE__, __LINE__, false, false, #message); \
>> +		return; \
>> +	} \
>> +	while (0)
> 
> I'll be frank: the return and the following requirement that anything using
> the macros needs to be a void function is the most annoying thing about
> gtest. I much prefer the approach of forking each test and abort() on
> failure.

I agree that it is an annoying aspect. Boost is handier in that it uses
exceptions. However, the non-exception approach of gtest does lend
itself to being helpful for certain things, including C code and tools
such as valgrind.

If it does present itself to be a problem in practice there are a few
approaches that can be used to mitigate complications. One is to add
something similar to glibs g_return_val_if_fail. Another could be to add
an option to actually abort() on failure.

Then again, things such as complex mocking can benefit from the gtest
style approach.

BTW, applying the flag to break on failure might work for some use cases.


>> +
>> +/**
>> + * Marks the current test as failed, but continues execution.
>> + *
>> + * @param message the message to log as to why the test has failed.
>> + */
>> +#define ZUC_FAIL(message) \
>> +	zucimpl_terminate(__FILE__, __LINE__, true, false, #message)
>> +
>> +/**
>> + * Terminates the current test and marks it as failed.
>> + *
>> + * @param message the message to log as to why the test has failed.
>> + */
>> +#define ZUC_FATAL(message) \
>> +	do { \
>> +		zucimpl_terminate(__FILE__, __LINE__, true, true, #message); \
>> +		return; \
>> +	} \
>> +	while (0)
>> +
>> +/**
>> + * Marks the current test as failed with a fatal issue, but does not
>> + * immediately return from the current function. ZUC_FATAL() is normally
>> + * preferred, but when further cleanup is needed, or the current function
>> + * needs to return a value, this macro may be required.
>> + *
>> + * @param message the message to log as to why the test has failed.
>> + * @see ZUC_FATAL()
>> + */
>> +#define ZUC_MARK_FATAL(message) \
>> +	do { \
>> +		zucimpl_terminate(__FILE__, __LINE__, true, true, #message); \
>> +	} \
>> +	while (0)
>> +
>> +/**
>> + * Creates a message that will be processed in the case of failure.
>> + * If the test encounters any failures (fatal or non-fatal) then these
>> + * messages are included in output. Otherwise they are discarded at the
>> + * end of the test run.
>> + *
>> + * @param message the format string style message.
>> + */
>> +#define ZUC_TRACEPOINT(message, ...) \
>> +	zucimpl_tracepoint(__FILE__, __LINE__, message, ##__VA_ARGS__);
>> +
>> +/**
>> + * Verfies that the specified expression is true and marks the test as failed
>> + * if it is not.
>> + *
>> + * @param condition the expression that is expected to be true.
>> + * @note it is far better to use a more specific check when possible
>> + * (e.g. ZUC_EXPECT_EQ(), ZUC_EXPECT_NE(), etc.)
>> + */
>> +#define ZUC_EXPECT_TRUE(condition) \
>> +	zucimpl_expect_pred2(__FILE__, __LINE__, ZUC_OP_TRUE, false, \
>> +			     (condition), 0, #condition, "")
>> +
>> +/**
>> + * Verfies that the specified expression is false and marks the test as failed
>> + * if it is not.
>> + *
>> + * @param condition the expression that is expected to be false.
>> + * @note it is far better to use a more specific check when possible
>> + * (e.g. ZUC_EXPECT_EQ(), ZUC_EXPECT_NE(), etc.)
>> + */
>> +#define ZUC_EXPECT_FALSE(condition) \
>> +	zucimpl_expect_pred2(__FILE__, __LINE__, ZUC_OP_FALSE, false, \
>> +			     (condition), 0, #condition, "")
>> +
>> +/**
>> + * Verfies that the values of the specified expressions match and marks
>> + * the test as failed if they do not.
>> + *
>> + * @param expected the value the result should hold.
>> + * @param actual the actual value seen in testing.
>> + */
>> +#define ZUC_EXPECT_EQ(expected, actual) \
>> +	zucimpl_expect_pred2(__FILE__, __LINE__, ZUC_OP_EQ, false, \
>> +			     (expected), (actual), #expected, #actual);
>> +
>> +/**
>> + * Verfies that the values of the specified expressions differ and marks
>> + * the test as failed if they do not.
>> + *
>> + * @param expected the value the result should not hold.
>> + * @param actual the actual value seen in testing.
>> + */
>> +#define ZUC_EXPECT_NE(expected, actual) \
>> +	zucimpl_expect_pred2(__FILE__, __LINE__, ZUC_OP_NE, false, \
>> +			     (expected), (actual), #expected, #actual);
>> +
>> +/**
>> + * Verifies that the value of the first expression is less than the value
>> + * of the second expression and marks the test as failed if it is not.
>> + *
>> + * @param lhs the expression whose value should be lesser than the other.
>> + * @param rhs the expression whose value should be greater than the other.
>> + */
>> +#define ZUC_EXPECT_LT(lhs, rhs) \
>> +	zucimpl_expect_pred2(__FILE__, __LINE__, ZUC_OP_LT, false, \
>> +			     (lhs), (rhs), #lhs, #rhs);
>> +
>> +/**
>> + * Verifies that the value of the first expression is less than or equal
>> + * to the value of the second expression and marks the test as failed if
>> + * it is not.
>> + *
>> + * @param lhs the expression whose value should be lesser than or equal to
>> + * the other.
>> + * @param rhs the expression whose value should be greater than or equal to
>> + * the other.
>> + */
>> +#define ZUC_EXPECT_LE(lhs, rhs) \
>> +	zucimpl_expect_pred2(__FILE__, __LINE__, ZUC_OP_LE, false, \
>> +			     (lhs), (rhs), #lhs, #rhs);
>> +
>> +/**
>> + * Verifies that the value of the first expression is greater than the
>> + * value of the second expression and marks the test as failed if it is not.
>> + *
>> + * @param lhs the expression whose value should be greater than the other.
>> + * @param rhs the expression whose value should be lesser than the other.
>> + */
>> +#define ZUC_EXPECT_GT(lhs, rhs) \
>> +	zucimpl_expect_pred2(__FILE__, __LINE__, ZUC_OP_GT, false, \
>> +			     (lhs), (rhs), #lhs, #rhs);
>> +
>> +/**
>> + * Verifies that the value of the first expression is greater than or equal
>> + * to the value of the second expression and marks the test as failed if
>> + * it is not.
>> + *
>> + * @param lhs the expression whose value should be greater than or equal to
>> + * the other.
>> + * @param rhs the expression whose value should be lesser than or equal to
>> + * the other.
>> + */
>> +#define ZUC_EXPECT_GE(lhs, rhs) \
>> +	zucimpl_expect_pred2(__FILE__, __LINE__, ZUC_OP_GE, false, \
>> +			     (lhs), (rhs), #lhs, #rhs);
>> +
>> +
>> +/**
>> + * Internal use macro for ASSERT implementation.
>> + * Should not be used directly in code.
>> + */
>> +#define ZUCIMPL_ASSERT(opcode, lhs, rhs) \
>> +	do { \
>> +		if (zucimpl_expect_pred2(__FILE__, __LINE__, \
>> +					 (opcode), true, \
>> +					 (lhs), (rhs), #lhs, #rhs)) { \
>> +			return; \
>> +		} \
>> +	} \
>> +	while (0)
>> +
>> +
>> +/**
>> + * Verfies that the specified expression is true, marks the test as failed
> 
> typo: verifies, affects below too
> 
>> + * and terminates the test if it is not.
>> + *
>> + * @param condition the expression that is expected to be true.
>> + * @note it is far better to use a more specific check when possible
>> + * (e.g. ZUC_EXPECT_EQ(), ZUC_EXPECT_NE(), etc.)
>> + */
>> +#define ZUC_ASSERT_TRUE(condition) \
>> +	ZUCIMPL_ASSERT(ZUC_OP_TRUE, condition, 0)
>> +
>> +/**
>> + * Verfies that the specified expression is false, marks the test as
>> + * failed and terminates the test if it is not.
>> + *
>> + * @param condition the expression that is expected to be false.
>> + * @note it is far better to use a more specific check when possible
>> + * (e.g. ZUC_EXPECT_EQ(), ZUC_EXPECT_NE(), etc.)
>> + */
>> +#define ZUC_ASSERT_FALSE(condition) \
>> +	ZUCIMPL_ASSERT(ZUC_OP_FALSE, condition, 0)
>> +
>> +/**
>> + * Verfies that the values of the specified expressions match, marks the
>> + * test as failed and terminates the test if they do not.
>> + *
>> + * @param expected the value the result should hold.
>> + * @param actual the actual value seen in testing.
>> + */
>> +#define ZUC_ASSERT_EQ(expected, actual) \
>> +	ZUCIMPL_ASSERT(ZUC_OP_EQ, expected, actual)
>> +
>> +/**
>> + * Verfies that the values of the specified expressions differ, marks the
>> + * test as failed and terminates the test if they do not.
>> + *
>> + * @param expected the value the result should not hold.
>> + * @param actual the actual value seen in testing.
>> + */
>> +#define ZUC_ASSERT_NE(expected, actual) \
>> +	ZUCIMPL_ASSERT(ZUC_OP_NE, expected, actual)
>> +
>> +/**
>> + * Verifies that the value of the first expression is less than the value
>> + * of the second expression, marks the test as failed and terminates the
>> + * test if it is not.
>> + *
>> + * @param lhs the expression whose value should be lesser than the other.
>> + * @param rhs the expression whose value should be greater than the other.
>> + */
>> +#define ZUC_ASSERT_LT(lhs, rhs) \
>> +	ZUCIMPL_ASSERT(ZUC_OP_LT, lhs, rhs)
> 
> less nice for copy/paste but you could name it as
> 
>> +#define ZUC_ASSERT_LT(lesser, greater) \
> 
> and the same for the others

done.


>> +
>> +/**
>> + * Verifies that the value of the first expression is less than or equal
>> + * to the value of the second expression, marks the test as failed and
>> + * terminates the test if it is not.
>> + *
>> + * @param lhs the expression whose value should be lesser than or equal to
>> + * the other.
>> + * @param rhs the expression whose value should be greater than or equal to
>> + * the other.
>> + */
>> +#define ZUC_ASSERT_LE(lhs, rhs) \
>> +	ZUCIMPL_ASSERT(ZUC_OP_LE, lhs, rhs)
>> +
>> +/**
>> + * Verifies that the value of the first expression is greater than the
>> + * value of the second expression, marks the test as failed and terminates
>> + * the test if it is not.
>> + *
>> + * @param lhs the expression whose value should be greater than the other.
>> + * @param rhs the expression whose value should be lesser than the other.
>> + */
>> +#define ZUC_ASSERT_GT(lhs, rhs) \
>> +	ZUCIMPL_ASSERT(ZUC_OP_GT, lhs, rhs)
>> +
>> +/**
>> + * Verifies that the value of the first expression is greater than or equal
>> + * to the value of the second expression, marks the test as failed and
>> + * terminates the test if it is not.
>> + *
>> + * @param lhs the expression whose value should be greater than or equal to
>> + * the other.
>> + * @param rhs the expression whose value should be lesser than or equal to
>> + * the other.
>> + */
>> +#define ZUC_ASSERT_GE(lhs, rhs) \
>> +	ZUCIMPL_ASSERT(ZUC_OP_GE, lhs, rhs)
>> +
>> +#ifdef __cplusplus
>> +} /* extern "C" */
>> +#endif
>> +
>> +#endif /* Z_UNIT_C_H */
>> diff --git a/tools/zunitc/inc/zunitc/zunitc_impl.h b/tools/zunitc/inc/zunitc/zunitc_impl.h
>> new file mode 100644
>> index 0000000..46253d0
>> --- /dev/null
>> +++ b/tools/zunitc/inc/zunitc/zunitc_impl.h
>> @@ -0,0 +1,87 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef Z_UNIT_C_IMPL_H
>> +#define Z_UNIT_C_IMPL_H
>> +
>> +/**
>> + * @file
>> + * Internal details to bridge the public API - should not be used
>> + * directly in user code.
>> + */
>> +
>> +#include <stdbool.h>
>> +
>> +#ifdef __cplusplus
>> +extern "C" {
>> +#endif
>> +
>> +enum zuc_check_op
>> +{
>> +	ZUC_OP_TRUE,
>> +	ZUC_OP_FALSE,
>> +	ZUC_OP_EQ,
>> +	ZUC_OP_NE,
>> +	ZUC_OP_GE,
>> +	ZUC_OP_GT,
>> +	ZUC_OP_LE,
>> +	ZUC_OP_LT,
>> +	ZUC_OP_TERMINATE,
>> +	ZUC_OP_TRACEPOINT
>> +};
>> +
>> +typedef void (*zucimpl_test_fn)(void);
>> +
>> +typedef void (*zucimpl_test_fn_f)(void *);
>> +
>> +/**
>> + * Internal use structure for automatic test case registration.
>> + * Should not be used directly in code.
>> + */
>> +struct zuc_registration {
>> +	const char *tcase;		/**< Name of the test case. */
>> +	const char *test;		/**< Name of the specific test. */
>> +	const struct zuc_fixture* fxt;	/**< Optional fixture for test/case. */
>> +	zucimpl_test_fn fn;		/**< function implementing base test. */
>> +	zucimpl_test_fn_f fn_f;	/**< function implementing test with
>> +					   fixture. */
>> +} __attribute__ ((aligned (32)));
>> +
>> +
>> +int zucimpl_run_tests(void);
>> +
>> +void zucimpl_terminate(char const *file, int line,
>> +		       bool fail, bool fatal, const char *msg);
>> +
>> +int zucimpl_tracepoint(char const *file, int line, const char *fmt, ...)
>> +	__attribute__ ((format (printf, 3, 4)));
>> +
>> +int zucimpl_expect_pred2(char const *file, int line,
>> +			 enum zuc_check_op, bool fatal,
>> +			 int lhs, int rhs,
>> +			 const char *lhs_str, const char* rhs_str);
>> +
>> +#ifdef __cplusplus
>> +}
>> +#endif
>> +
>> +#endif /* Z_UNIT_C_IMPL_H */
>> diff --git a/tools/zunitc/src/main.c b/tools/zunitc/src/main.c
>> new file mode 100644
>> index 0000000..7049db0
>> --- /dev/null
>> +++ b/tools/zunitc/src/main.c
>> @@ -0,0 +1,44 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +/*
>> + * Common main() for test programs.
>> + */
>> +
>> +#include "config.h"
>> +
>> +#include <stdlib.h>
>> +
>> +#include "zunitc/zunitc.h"
>> +
>> +int main( int argc, char* argv[] )
> 
> drop spaces around ( )

Done.

> ok, now my brain is starting to get mushy, so I'll leave it at that for now.
> 


Thanks. I really think this will help development, so the effort is
appreciated.



> Cheers,
>    Peter
> 
> 
>> +{
>> +	bool helped = false;
>> +	int rc = zuc_initialize(&argc, argv, &helped);
>> +
>> +	if ((rc == EXIT_SUCCESS) && !helped) {
>> +		rc = ZUC_RUN_TESTS();
>> +	}
>> +
>> +	zuc_cleanup();
>> +	return rc;
>> +}
>> diff --git a/tools/zunitc/src/zuc_base_logger.c b/tools/zunitc/src/zuc_base_logger.c
>> new file mode 100644
>> index 0000000..2ac2e01
>> --- /dev/null
>> +++ b/tools/zunitc/src/zuc_base_logger.c
>> @@ -0,0 +1,382 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#include "zuc_base_logger.h"
>> +
>> +#include <memory.h>
>> +#include <stdarg.h>
>> +#include <stdbool.h>
>> +#include <stdio.h>
>> +#include <unistd.h>
>> +
>> +#include "zuc_event_listener.h"
>> +#include "zuc_types.h"
>> +
>> +#include "shared/zalloc.h"
>> +
>> +/* a few sequences for rudimentary ANSI graphics. */
>> +#define CSI_GRN "\x1b[0;32m"
>> +#define CSI_RED "\x1b[0;31m"
>> +#define CSI_YLW "\x1b[0;33m"
>> +#define CSI_RST "\x1b[m"
>> +
>> +/**
>> + * Logical mappings of style levels.
>> + */
>> +enum style_level {
>> +	STYLE_GOOD,
>> +	STYLE_WARN,
>> +	STYLE_BAD
>> +};
>> +
>> +/**
>> + * Structure for internal context.
>> + */
>> +struct base_data {
>> +	bool use_color;
>> +};
>> +
>> +/**
>> + * Prints a formatted string with optional ANSI coloring.
>> + *
>> + * @param use_color true to colorize the output, false to output normally.
>> + * @param slevel the logical type to color for.
>> + * @param fmt the format string to print with.
>> + */
>> +static void styled_printf(bool use_color, enum style_level slevel,
>> +			  const char *fmt, ...);
>> +
>> +static void destroy(void *data);
>> +static void pre_run(void *data,
>> +		    int pass_count,
>> +		    int pass_num,
>> +		    int seed,
>> +		    const char *filter);
>> +static void run_started(void *data,
>> +			int live_case_count,
>> +			int live_test_count,
>> +			int disabled_count);
>> +static void run_ended(void *data,
>> +		      int case_count,
>> +		      struct zuc_case **cases,
>> +		      int live_case_count,
>> +		      int live_test_count,
>> +		      int total_passed,
>> +		      int total_failed,
>> +		      int total_disabled,
>> +		      long total_elapsed);
>> +static void case_started(void *data,
>> +			 struct zuc_case *test_case,
>> +			 int live_test_count,
>> +			 int disabled_count);
>> +static void case_ended(void *data,
>> +		       struct zuc_case *test_case);
>> +static void test_started(void *data,
>> +			 struct zuc_test *test);
>> +static void test_ended(void *data,
>> +		       struct zuc_test *test);
>> +static void check_triggered(void *data,
>> +			    char const *file,
>> +			    int line,
>> +			    enum zuc_fail_state state,
>> +			    enum zuc_check_op op,
>> +			    int val1,
>> +			    int val2,
>> +			    const char *expr1,
>> +			    const char *expr2);
>> +
>> +struct zuc_event_listener * zuc_base_logger_create(void)
>> +{
>> +	struct zuc_event_listener *listener =
>> +		zalloc(sizeof(struct zuc_event_listener));
>> +
>> +	listener->data = zalloc(sizeof(struct base_data));
>> +	listener->destroy = destroy;
>> +	listener->pre_run = pre_run;
>> +	listener->run_started = run_started;
>> +	listener->run_ended = run_ended;
>> +	listener->case_started = case_started;
>> +	listener->case_ended = case_ended;
>> +	listener->test_started = test_started;
>> +	listener->test_ended = test_ended;
>> +	listener->check_triggered = check_triggered;
>> +
>> +	return listener;
>> +}
>> +
>> +void styled_printf(bool use_color, enum style_level slevel,
>> +		   const char *fmt, ...)
>> +{
>> +	va_list argp;
>> +
>> +	if (use_color)
>> +		switch (slevel) {
>> +		case STYLE_GOOD:
>> +			printf(CSI_GRN);
>> +			break;
>> +		case STYLE_WARN:
>> +			printf(CSI_YLW);
>> +			break;
>> +		case STYLE_BAD:
>> +			printf(CSI_RED);
>> +			break;
>> +		default:
>> +			break;
>> +		}
>> +
>> +	va_start(argp, fmt);
>> +	vprintf(fmt, argp);
>> +	va_end(argp);
>> +
>> +	if (use_color)
>> +		printf(CSI_RST);
>> +}
>> +
>> +void destroy(void *data)
>> +{
>> +	free(data);
>> +}
>> +
>> +void pre_run(void *data,
>> +	     int pass_count,
>> +	     int pass_num,
>> +	     int seed,
>> +	     const char *filter)
>> +{
>> +	struct base_data *bdata = data;
>> +
>> +	bdata->use_color = isatty(fileno(stdout))
>> +		&& getenv("TERM") && strcmp(getenv("TERM"), "dumb");
>> +
>> +	if (pass_count > 1)
>> +		printf("\nRepeating all tests (iteration %d) . . .\n\n",
>> +		       pass_num);
>> +
>> +	if (filter && filter[0])
>> +		styled_printf(bdata->use_color, STYLE_WARN,
>> +			      "Note: test filter = %s\n",
>> +			      filter);
>> +
>> +	if (seed > 0)
>> +		styled_printf(bdata->use_color, STYLE_WARN,
>> +			      "Note: Randomizing tests' orders"
>> +			      " with a seed of %u .\n",
>> +			      seed);
>> +}
>> +
>> +void run_started(void *data,
>> +		 int live_case_count,
>> +		 int live_test_count,
>> +		 int disabled_count)
>> +{
>> +	struct base_data *bdata = data;
>> +
>> +	styled_printf(bdata->use_color, STYLE_GOOD, "[==========]");
>> +	printf(" Running %d %s from %d test %s.\n",
>> +	       live_test_count,
>> +	       (live_test_count == 1) ? "test" : "tests",
>> +	       live_case_count,
>> +	       (live_case_count == 1) ? "case" : "cases");
>> +}
>> +
>> +void run_ended(void *data,
>> +	       int case_count,
>> +	       struct zuc_case **cases,
>> +	       int live_case_count,
>> +	       int live_test_count,
>> +	       int total_passed,
>> +	       int total_failed,
>> +	       int total_disabled,
>> +	       long total_elapsed)
>> +{
>> +	struct base_data *bdata = data;
>> +	styled_printf(bdata->use_color, STYLE_GOOD, "[==========]");
>> +	printf(" %d %s from %d test %s ran. (%ld ms)\n",
>> +	       live_test_count,
>> +	       (live_test_count == 1) ? "test" : "tests",
>> +	       live_case_count,
>> +	       (live_case_count == 1) ? "case" : "cases",
>> +	       total_elapsed);
>> +
>> +	if (total_passed) {
>> +		styled_printf(bdata->use_color, STYLE_GOOD, "[  PASSED  ]");
>> +		printf(" %d %s.\n", total_passed,
>> +		       (total_passed == 1) ? "test" : "tests");
>> +	}
>> +
>> +	if (total_failed) {
>> +		int case_num;
>> +		styled_printf(bdata->use_color, STYLE_BAD, "[  FAILED  ]");
>> +		printf(" %d %s, listed below:\n",
>> +		       total_failed, (total_failed == 1) ? "test" : "tests");
>> +
>> +		for (case_num = 0; case_num < case_count; ++case_num) {
>> +			int i;
>> +			for (i = 0; i < cases[case_num]->test_count; ++i) {
>> +				struct zuc_test *curr =
>> +					cases[case_num]->tests[i];
>> +				if (curr->failed || curr->fatal) {
>> +					styled_printf(bdata->use_color,
>> +						      STYLE_BAD,
>> +						      "[  FAILED  ]");
>> +					printf(" %s.%s\n",
>> +					       cases[case_num]->name,
>> +					       curr->name);
>> +				}
>> +			}
>> +		}
>> +	}
>> +
>> +	if (total_failed || total_disabled)
>> +		printf("\n");
>> +
>> +	if (total_failed)
>> +		printf(" %d FAILED %s\n",
>> +		       total_failed,
>> +		       (total_failed == 1) ? "TEST" : "TESTS");
>> +
>> +	if (total_disabled)
>> +		styled_printf(bdata->use_color, STYLE_WARN,
>> +			      "  YOU HAVE %d DISABLED %s\n",
>> +			      total_disabled,
>> +			      (total_disabled == 1) ? "TEST" : "TESTS");
>> +}
>> +
>> +void case_started(void *data,
>> +		  struct zuc_case *test_case,
>> +		  int live_test_count,
>> +		  int disabled_count)
>> +{
>> +	struct base_data *bdata = data;
>> +	styled_printf(bdata->use_color, STYLE_GOOD, "[----------]");
>> +	printf(" %d %s from %s.\n",
>> +	       live_test_count,
>> +	       (live_test_count == 1) ? "test" : "tests",
>> +	       test_case->name);
>> +
>> +}
>> +
>> +void case_ended(void *data,
>> +		struct zuc_case *test_case)
>> +{
>> +	struct base_data *bdata = data;
>> +	styled_printf(bdata->use_color, STYLE_GOOD, "[----------]");
>> +	printf(" %d %s from %s (%ld ms)\n",
>> +	       test_case->test_count,
>> +	       (test_case->test_count == 1) ? "test" : "tests",
>> +	       test_case->name,
>> +	       test_case->elapsed);
>> +	printf("\n");
>> +}
>> +
>> +void test_started(void *data,
>> +		  struct zuc_test *test)
>> +{
>> +	struct base_data *bdata = data;
>> +	styled_printf(bdata->use_color, STYLE_GOOD, "[ RUN      ]");
>> +	printf(" %s.%s\n", test->test_case->name, test->name);
>> +}
>> +
>> +void test_ended(void *data,
>> +		struct zuc_test *test)
>> +{
>> +	struct base_data *bdata = data;
>> +	if (test->failed || test->fatal) {
>> +		styled_printf(bdata->use_color, STYLE_BAD, "[  FAILED  ]");
>> +		printf(" %s.%s (%ld ms)\n",
>> +		       test->test_case->name, test->name, test->elapsed);
>> +	} else {
>> +		styled_printf(bdata->use_color, STYLE_GOOD, "[       OK ]");
>> +		printf(" %s.%s (%ld ms)\n",
>> +		       test->test_case->name, test->name, test->elapsed);
>> +	}
>> +}
>> +
>> +const char *zuc_get_opstr(enum zuc_check_op op)
>> +{
>> +	switch (op) {
>> +	case ZUC_OP_EQ:
>> +		return "=";
>> +		break;
>> +	case ZUC_OP_NE:
>> +		return "!=";
>> +		break;
>> +	case ZUC_OP_GE:
>> +		return ">=";
>> +		break;
>> +	case ZUC_OP_GT:
>> +		return ">";
>> +		break;
>> +	case ZUC_OP_LE:
>> +		return "<=";
>> +		break;
>> +	case ZUC_OP_LT:
>> +		return "<";
>> +		break;
>> +	default:
>> +		return "???";
>> +	}
>> +}
>> +
>> +void check_triggered(void *data,
>> +		     char const *file,
>> +		     int line,
>> +		     enum zuc_fail_state state,
>> +		     enum zuc_check_op op,
>> +		     int val1,
>> +		     int val2,
>> +		     const char *expr1,
>> +		     const char *expr2)
>> +{
>> +	switch (op) {
>> +	case ZUC_OP_TRUE:
>> +		printf("%s:%d: error: Value of: %s\n", file, line, expr1);
>> +		printf("  Actual: false\n");
>> +		printf("Expected: true\n");
>> +		break;
>> +	case ZUC_OP_FALSE:
>> +		printf("%s:%d: error: Value of: %s\n", file, line, expr1);
>> +		printf("  Actual: true\n");
>> +		printf("Expected: false\n");
>> +		break;
>> +	case ZUC_OP_EQ:
>> +		printf("%s:%d: error: Value of: %s\n", file, line, expr2);
>> +		printf("  Actual: %d\n", val2);
>> +		printf("Expected: %s\n", expr1);
>> +		printf("Which is: %d\n", val1);
>> +		break;
>> +	case ZUC_OP_TERMINATE: {
>> +		char const *level = (val1 == 0) ? "error"
>> +			: (val1 == 1) ? "warning"
>> +			: "note";
>> +		printf("%s:%d: %s: %s\n", file, line, level, expr1);
>> +		break;
>> +	}
>> +	case ZUC_OP_TRACEPOINT:
>> +		printf("%s:%d: note: %s\n", file, line, expr1);
>> +		break;
>> +	default:
>> +		printf("%s:%d: error: ", file, line);
>> +		printf("Expected: (%s) %s (%s), actual: %d vs %d\n",
>> +		       expr1, zuc_get_opstr(op), expr2, val1, val2);
>> +	}
>> +}
>> diff --git a/tools/zunitc/src/zuc_base_logger.h b/tools/zunitc/src/zuc_base_logger.h
>> new file mode 100644
>> index 0000000..809d616
>> --- /dev/null
>> +++ b/tools/zunitc/src/zuc_base_logger.h
>> @@ -0,0 +1,34 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef ZUC_BASE_LOGGER_H
>> +#define ZUC_BASE_LOGGER_H
>> +
>> +struct zuc_event_listener;
>> +
>> +/**
>> + * Creates a new logger that outputs data to console in the default
>> + * format.
>> + */
>> +struct zuc_event_listener * zuc_base_logger_create(void);
>> +
>> +#endif /* ZUC_BASE_LOGGER_H */
>> diff --git a/tools/zunitc/src/zuc_collector.c b/tools/zunitc/src/zuc_collector.c
>> new file mode 100644
>> index 0000000..3a95390
>> --- /dev/null
>> +++ b/tools/zunitc/src/zuc_collector.c
>> @@ -0,0 +1,321 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#include "zuc_collector.h"
>> +
>> +#include <stdint.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <unistd.h>
>> +
>> +#include "shared/zalloc.h"
>> +#include "zuc_event_listener.h"
>> +#include "zunitc/zunitc_impl.h"
>> +
>> +#include <sys/types.h>
>> +#include <sys/stat.h>
>> +#include <fcntl.h>
>> +
>> +/**
>> + * @file
>> + * General handling of collecting events during testing to pass back to
>> + * main tracking of fork()'d tests.
>> + *
>> + * @note implementation of zuc_process_message() is included here so that
>> + * all child->parent IPC is in a single source file for easier maintenance
>> + * and updating.
>> + */
>> +
>> +/**
>> + * Internal data struct for processing.
>> + */
>> +struct collector_data
>> +{
>> +	int *fd;		/**< file descriptor to output to. */
>> +	struct zuc_test *test;	/**< current test, or NULL. */
>> +};
>> +
>> +/**
>> + * Stores an int32_t into the given buffer.
>> + *
>> + * @param ptr the buffer to store to.
>> + * @param val the value to store.
>> + * @return a pointer to the position in the buffer after the stored value.
>> + */
>> +static char *pack_int32(char *ptr, int32_t val);
>> +
>> +/**
>> + * Extracts a int32_t from the given buffer.
>> + *
>> + * @param ptr the buffer to extract from.
>> + * @param val the value to set.
>> + * @return a pointer to the position in the buffer after the extracted
>> + * value.
>> + */
>> +static char const *unpack_int32(char const *ptr, int32_t *val);
>> +
>> +/**
>> + * Extracts a length-prefixed string from the given buffer.
>> + *
>> + * @param ptr the buffer to extract from.
>> + * @param str the value to set.
>> + * @return a pointer to the position in the buffer after the extracted
>> + * value.
>> + */
>> +static char const *unpack_string(char const *ptr, char **str);
>> +
>> +/**
>> + * Extracts an event from the given buffer.
>> + *
>> + * @param ptr the buffer to extract from.
>> + * @param len the length of the given buffer.
>> + * @return an event that was packed in the buffer
>> + */
>> +static struct zuc_event *unpack_event(char const *ptr, int32_t len);
>> +
>> +/**
>> + * Handles an event by either attaching it directly or sending it over IPC
>> + * as needed.
>> + */
>> +static void store_event(struct collector_data *cdata,
>> +			enum zuc_event_type event_type,
>> +			char const *file,
>> +			int line,
>> +			enum zuc_fail_state state,
>> +			enum zuc_check_op op,
>> +			int val1,
>> +			int val2,
>> +			const char *expr1,
>> +			const char *expr2);
>> +
>> +static void destroy(void *data);
>> +static void test_started(void *data, struct zuc_test *test);
>> +static void test_ended(void *data, struct zuc_test *test);
>> +static void check_triggered(void *data,
>> +			    char const *file,
>> +			    int line,
>> +			    enum zuc_fail_state state,
>> +			    enum zuc_check_op op,
>> +			    int val1,
>> +			    int val2,
>> +			    const char *expr1,
>> +			    const char *expr2);
>> +static void collect_event(void *data,
>> +			  char const *file,
>> +			  int line,
>> +			  const char *expr1);
>> +
>> +struct zuc_event_listener * zuc_collector_create(int *pipe_fd)
>> +{
>> +	struct zuc_event_listener *listener =
>> +		zalloc(sizeof(struct zuc_event_listener));
>> +
>> +	listener->data = zalloc(sizeof(struct collector_data));
>> +	((struct collector_data *)listener->data)->fd = pipe_fd;
>> +	listener->destroy = destroy;
>> +	listener->test_started = test_started;
>> +	listener->test_ended = test_ended;
>> +	listener->check_triggered = check_triggered;
>> +	listener->collect_event = collect_event;
>> +
>> +	return listener;
>> +}
>> +
>> +char *pack_int32(char *ptr, int32_t val)
>> +{
>> +	memcpy(ptr, &val, sizeof(val));
>> +	return ptr + sizeof(val);
>> +}
>> +
>> +void destroy(void *data)
>> +{
>> +	free(data);
>> +}
>> +
>> +void test_started(void *data, struct zuc_test *test)
>> +{
>> +	struct collector_data *cdata = data;
>> +	cdata->test = test;
>> +}
>> +
>> +void test_ended(void *data, struct zuc_test *test)
>> +{
>> +	struct collector_data *cdata = data;
>> +	cdata->test = NULL;
>> +}
>> +
>> +void check_triggered(void *data,
>> +		     char const *file,
>> +		     int line,
>> +		     enum zuc_fail_state state,
>> +		     enum zuc_check_op op,
>> +		     int val1,
>> +		     int val2,
>> +		     const char *expr1,
>> +		     const char *expr2)
>> +{
>> +	struct collector_data *cdata = data;
>> +	if (op != ZUC_OP_TRACEPOINT)
>> +		store_event(cdata, ZUC_EVENT_IMMEDIATE, file, line, state, op,
>> +			      val1, val2, expr1, expr2);
>> +}
>> +
>> +void collect_event(void *data,
>> +		   char const *file,
>> +		   int line,
>> +		   const char *expr1)
>> +{
>> +	struct collector_data *cdata = data;
>> +	store_event(cdata, ZUC_EVENT_DEFERRED, file, line, ZUC_CHECK_OK,
>> +		    ZUC_OP_TRACEPOINT,
>> +		    0, 0, expr1, "");
>> +}
>> +
>> +void store_event(struct collector_data *cdata,
>> +		 enum zuc_event_type event_type,
>> +		 char const *file,
>> +		 int line,
>> +		 enum zuc_fail_state state,
>> +		 enum zuc_check_op op,
>> +		 int val1,
>> +		 int val2,
>> +		 const char *expr1,
>> +		 const char *expr2)
>> +{
>> +	struct zuc_event *event = zalloc(sizeof(*event));
>> +	event->file = strdup(file);
>> +	event->line = line;
>> +	event->state = state;
>> +	event->op = op;
>> +	event->val1 = val1;
>> +	event->val2 = val2;
>> +	event->expr1 = strdup(expr1);
>> +	event->expr2 = strdup(expr2);
>> +
>> +	zuc_attach_event(cdata->test, event, event_type, false);
>> +
>> +	if (*cdata->fd == -1) {
>> +	} else {
>> +		/* Need to pass it back */
>> +		int sent;
>> +		int count;
>> +		int expr1_len = strlen(expr1);
>> +		int expr2_len = strlen(expr2);
>> +		int file_len = strlen(file);
>> +		int len = (4 * 10) + file_len + expr1_len + expr2_len;
>> +		char *buf = zalloc(len);
>> +
>> +		char *ptr = pack_int32(buf, len - 4);
>> +		ptr = pack_int32(ptr, event_type);
>> +		ptr = pack_int32(ptr, file_len);
>> +		memcpy(ptr, file, file_len);
>> +		ptr += file_len;
>> +		ptr = pack_int32(ptr, line);
>> +		ptr = pack_int32(ptr, state);
>> +		ptr = pack_int32(ptr, op);
>> +		ptr = pack_int32(ptr, val1);
>> +		ptr = pack_int32(ptr, val2);
>> +		ptr = pack_int32(ptr, expr1_len);
>> +		if (expr1_len) {
>> +			memcpy(ptr, expr1, expr1_len);
>> +			ptr += expr1_len;
>> +		}
>> +		ptr = pack_int32(ptr, expr2_len);
>> +		if (expr2_len) {
>> +			memcpy(ptr, expr2, expr2_len);
>> +			ptr += expr2_len;
>> +		}
>> +
>> +
>> +		sent = 0;
>> +		while (sent < len) {
>> +			count = write(*cdata->fd, buf, len);
>> +			if (count == -1)
>> +				break;
>> +			sent += count;
>> +		}
>> +
>> +		free(buf);
>> +	}
>> +}
>> +
>> +char const *unpack_int32(char const *ptr, int32_t *val)
>> +{
>> +	memcpy(val, ptr, sizeof(*val));
>> +	return ptr + sizeof(*val);
>> +}
>> +
>> +char const *unpack_string(char const *ptr, char **str)
>> +{
>> +	int32_t len = 0;
>> +	ptr = unpack_int32(ptr, &len);
>> +	*str = zalloc(len + 1);
>> +	if (len)
>> +		memcpy(*str, ptr, len);
>> +	ptr += len;
>> +	return ptr;
>> +}
>> +
>> +struct zuc_event *unpack_event(char const *ptr, int32_t len)
>> +{
>> +	int32_t val = 0;
>> +	struct zuc_event *evt = zalloc(sizeof(*evt));
>> +	char const *tmp = unpack_string(ptr, &evt->file);
>> +	tmp = unpack_int32(tmp, &evt->line);
>> +
>> +	tmp = unpack_int32(tmp, &val);
>> +	evt->state = val;
>> +	tmp = unpack_int32(tmp, &val);
>> +	evt->op = val;
>> +
>> +	tmp = unpack_int32(tmp, &evt->val1);
>> +	tmp = unpack_int32(tmp, &evt->val2);
>> +
>> +	tmp = unpack_string(tmp, &evt->expr1);
>> +	tmp = unpack_string(tmp, &evt->expr2);
>> +
>> +	return evt;
>> +}
>> +
>> +int zuc_process_message(struct zuc_test *test, int fd)
>> +{
>> +	char buf[4] = {};
>> +	int got = read(fd, buf, 4);
>> +	if (got == 4) {
>> +		enum zuc_event_type event_type = ZUC_EVENT_IMMEDIATE;
>> +		int32_t val = 0;
>> +		int32_t len = 0;
>> +		const char *tmp = NULL;
>> +		char *raw = NULL;
>> +		unpack_int32(buf, &len);
>> +		raw = zalloc(len);
>> +		got = read(fd, raw, len);
>> +
>> +		tmp = unpack_int32(raw, &val);
>> +		event_type = val;
>> +
>> +		struct zuc_event *evt = unpack_event(tmp, len - (tmp - raw));
>> +		zuc_attach_event(test, evt, event_type, true);
>> +		free(raw);
>> +	}
>> +	return got;
>> +}
>> diff --git a/tools/zunitc/src/zuc_collector.h b/tools/zunitc/src/zuc_collector.h
>> new file mode 100644
>> index 0000000..bbd8b73
>> --- /dev/null
>> +++ b/tools/zunitc/src/zuc_collector.h
>> @@ -0,0 +1,53 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef ZUC_COLLECTOR_H
>> +#define ZUC_COLLECTOR_H
>> +
>> +struct zuc_event_listener;
>> +struct zuc_test;
>> +
>> +/**
>> + * Creates a new instance of an even collector that will attatch events
>> + * to the current test directly or via connection from child to parent.
>> + *
>> + * @param pipe_fd pointer to the file descriptor to use for communication if
>> + * needed. If the value is -1 the events will be attached directly to the
>> + * current test. Otherwise events will be passed back via IPC over this
>> + * pipe with the expectation that the payload will be handled in the parent
>> + * process via zuc_process_message().
>> + * @return a new collector intance.
>> + * @see zuc_process_message()
>> + */
>> +struct zuc_event_listener * zuc_collector_create(int *pipe_fd);
>> +
>> +/**
>> + * Reads events from the given pipe and processes them.
>> + *
>> + * @param test the currently active test to attache events for.
>> + * @param pipe_fd the file descriptor of the pipe to read from.
>> + * @return a positive value if a message was received, 0 if the end has
>> + * been reached and -1 if an error has occurred.
>> + */
>> +int zuc_process_message(struct zuc_test *test, int pipe_fd);
>> +
>> +#endif /* ZUC_COLLECTOR_H */
>> diff --git a/tools/zunitc/src/zuc_context.h b/tools/zunitc/src/zuc_context.h
>> new file mode 100644
>> index 0000000..6a4fb41
>> --- /dev/null
>> +++ b/tools/zunitc/src/zuc_context.h
>> @@ -0,0 +1,55 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef ZUC_CONTEXT_H
>> +#define ZUC_CONTEXT_H
>> +
>> +#include "zuc_types.h"
>> +
>> +struct zuc_slinked;
>> +
>> +/**
>> + * Internal context for processing.
>> + * Collecting data members here minimizes use of globals.
>> + */
>> +struct zuc_context {
>> +	int case_count;
>> +	struct zuc_case **cases;
>> +
>> +	bool fatal;
>> +	int repeat;
>> +	int random;
>> +	unsigned int seed;
>> +	bool spawn;
>> +	bool break_on_failure;
>> +	bool output_tap;
>> +	bool output_junit;
>> +	int fds[2];
>> +	char *filter;
>> +
>> +	struct zuc_slinked *listeners;
>> +
>> +	struct zuc_case *curr_case;
>> +	struct zuc_test *curr_test;
>> +};
>> +
>> +#endif /* ZUC_CONTEXT_H */
>> diff --git a/tools/zunitc/src/zuc_event.h b/tools/zunitc/src/zuc_event.h
>> new file mode 100644
>> index 0000000..d2b9fb2
>> --- /dev/null
>> +++ b/tools/zunitc/src/zuc_event.h
>> @@ -0,0 +1,81 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef ZUC_EVENT_H
>> +#define ZUC_EVENT_H
>> +
>> +#include <stdint.h>
>> +
>> +#include "zunitc/zunitc_impl.h"
>> +
>> +/**
>> + *
>> + */
>> +enum zuc_event_type
>> +{
>> +	ZUC_EVENT_IMMEDIATE,
>> +	ZUC_EVENT_DEFERRED
>> +};
>> +
>> +/**
>> + * Status enum for posted events.
>> + */
>> +enum zuc_fail_state
>> +{
>> +	ZUC_CHECK_OK, /**< no problem. */
>> +	ZUC_CHECK_SKIP, /**< runtime skip directive encountered. */
>> +	ZUC_CHECK_FAIL, /**< non-fatal check fails. */
>> +	ZUC_CHECK_FATAL, /**< fatal assertion/check fails. */
>> +	ZUC_CHECK_ERROR /**< internal level problem. */
>> +};
>> +
>> +/**
>> + * Record of an event that occurs during testing such as assert macro
>> + * failures.
>> + */
>> +struct zuc_event
>> +{
>> +	char *file;
>> +	int32_t line;
>> +	enum zuc_fail_state state;
>> +	enum zuc_check_op op;
>> +	int32_t val1;
>> +	int32_t val2;
>> +	char *expr1;
>> +	char *expr2;
>> +
>> +	struct zuc_event *next;
>> +};
>> +
>> +/**
>> + * Attaches an event to the specified test.
>> + *
>> + * @param test the test to attach to.
>> + * @param event the event to attach.
>> + * @param event_type of event (immediate or deferred) to attach.
>> + * @param transferred true if the event has been processed elsewhere and
>> + * is being transferred for storage, false otherwise.
>> + */
>> +void zuc_attach_event(struct zuc_test *test, struct zuc_event *event,
>> +		      enum zuc_event_type event_type, bool transferred);
>> +
>> +#endif /* ZUC_EVENT_H */
>> diff --git a/tools/zunitc/src/zuc_event_listener.h b/tools/zunitc/src/zuc_event_listener.h
>> new file mode 100644
>> index 0000000..6b16376
>> --- /dev/null
>> +++ b/tools/zunitc/src/zuc_event_listener.h
>> @@ -0,0 +1,167 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef ZUC_EVENT_HANDLER_H
>> +#define ZUC_EVENT_HANDLER_H
>> +
>> +#include "zuc_context.h"
>> +#include "zuc_event.h"
>> +
>> +struct zuc_test;
>> +struct zuc_case;
>> +
>> +/**
>> + * Interface to allow components to process testing events as they occur.
>> + *
>> + * Event listeners that will stream output as testing progresses are often
>> + * named "*_logger" whereas those that produce their output upon test run
>> + * completion are named "*_reporter".
>> + */
>> +struct zuc_event_listener {
>> +	/**
>> +	 * User data pointer.
>> +	 */
>> +	void *data;
>> +
>> +	/**
>> +	 * Destructor.
>> +	 * @param data the user data associated with this instance.
>> +	 */
>> +	void (*destroy)(void *data);
>> +
>> +	/**
>> +	 * Handler for simple pre-run state.
>> +	 *
>> +	 * @param pass_count total number of expected test passes.
>> +	 * @param pass_num current pass iteration number.
>> +	 * @param seed random seed being used, or 0 for no randomization.
>> +	 * @param filter filter string used for tests, or NULL/blank for none.
>> +	 */
>> +	void (*pre_run)(void *data,
>> +			int pass_count,
>> +			int pass_num,
>> +			int seed,
>> +			const char *filter);
>> +
>> +	/**
>> +	 * Handler for test runs starting.
>> +	 *
>> +	 * @param data the user data associated with this instance.
>> +	 * @param live_case_count number of active test cases in this run.
>> +	 * @param live_test_count number of active tests in this run.
>> +	 * @param disabled_count number of disabled tests in this run.
>> +	 */
>> +	void (*run_started)(void *data,
>> +			    int live_case_count,
>> +			    int live_test_count,
>> +			    int disabled_count);
>> +
>> +	/**
>> +	 * Handler for test runs ending.
>> +	 *
>> +	 * @param data the user data associated with this instance.
>> +	 */
>> +	void (*run_ended)(void *data,
>> +			  int case_count,
>> +			  struct zuc_case** cases,
>> +			  int live_case_count,
>> +			  int live_test_count,
>> +			  int total_passed,
>> +			  int total_failed,
>> +			  int total_disabled,
>> +			  long total_elapsed);
>> +
>> +	/**
>> +	 * Handler for test case starting.
>> +	 *
>> +	 * @param data the user data associated with this instance.
>> +	 */
>> +	void (*case_started)(void *data,
>> +			     struct zuc_case *test_case,
>> +			     int live_test_count,
>> +			     int disabled_count);
>> +
>> +	/**
>> +	 * Handler for test case ending.
>> +	 *
>> +	 * @param data the user data associated with this instance.
>> +	 */
>> +	void (*case_ended)(void *data,
>> +			   struct zuc_case *test_case);
>> +
>> +	/**
>> +	 * Handler for test starting.
>> +	 *
>> +	 * @param data the user data associated with this instance.
>> +	 */
>> +	void (*test_started)(void *data,
>> +			     struct zuc_test *test);
>> +
>> +	/**
>> +	 * Handler for test ending.
>> +	 *
>> +	 * @param data the user data associated with this instance.
>> +	 */
>> +	void (*test_ended)(void *data,
>> +			   struct zuc_test *test);
>> +
>> +	/**
>> +	 * Handler for disabled test notification.
>> +	 *
>> +	 * @param data the user data associated with this instance.
>> +	 */
>> +	void (*test_disabled)(void *data,
>> +			      struct zuc_test *test);
>> +
>> +	/**
>> +	 * Handler for check/assertion fired due to failure, warning, etc.
>> +	 *
>> +	 * @param data the user data associated with this instance.
>> +	 */
>> +	void (*check_triggered)(void *data,
>> +				char const *file,
>> +				int line,
>> +				enum zuc_fail_state state,
>> +				enum zuc_check_op op,
>> +				int val1,
>> +				int val2,
>> +				const char *expr1,
>> +				const char *expr2);
>> +
>> +	/**
>> +	 * Handler for tracepoints and such that may be displayed later.
>> +	 *
>> +	 * @param data the user data associated with this instance.
>> +	 */
>> +	void (*collect_event)(void *data,
>> +			      char const *file,
>> +			      int line,
>> +			      const char *expr1);
>> +};
>> +
>> +/**
>> + * Registers an event listener instance to be called.
>> + */
>> +void zuc_add_event_listener(struct zuc_event_listener *event_listener);
>> +
>> +
>> +#endif /* ZUC_EVENT_HANDLER_H */
>> diff --git a/tools/zunitc/src/zuc_types.h b/tools/zunitc/src/zuc_types.h
>> new file mode 100644
>> index 0000000..2b66852
>> --- /dev/null
>> +++ b/tools/zunitc/src/zuc_types.h
>> @@ -0,0 +1,76 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef ZUC_TYPES_H
>> +#define ZUC_TYPES_H
>> +
>> +#include "zunitc/zunitc_impl.h"
>> +
>> +struct zuc_case;
>> +
>> +/**
>> + * Represents a specific test.
>> + */
>> +struct zuc_test
>> +{
>> +	int order;
>> +	struct zuc_case *test_case;
>> +	zucimpl_test_fn fn;
>> +	zucimpl_test_fn_f fn_f;
>> +	char *name;
>> +	int disabled;
>> +	int skipped;
>> +	int failed;
>> +	int fatal;
>> +	long elapsed;
>> +	struct zuc_event *events;
>> +	struct zuc_event *deferred;
>> +};
>> +
>> +/**
>> + * Represents a test case that can hold a collection of tests.
>> + */
>> +struct zuc_case
>> +{
>> +	int order;
>> +	char *name;
>> +	const struct zuc_fixture* fxt;
>> +	int disabled;
>> +	int skipped;
>> +	int failed;
>> +	int fatal;
>> +	int passed;
>> +	long elapsed;
>> +	int test_count;
>> +	struct zuc_test **tests;
>> +};
>> +
>> +/**
>> + * Returns a human-readable version of the comparison opcode.
>> + *
>> + * @param op the opcode to get a string version of.
>> + * @return a human-readable string of the opcode.
>> + * (This value should not be freed)
>> + */
>> +const char *zuc_get_opstr(enum zuc_check_op op);
>> +
>> +#endif /* ZUC_TYPES_H */
>> diff --git a/tools/zunitc/src/zunitc_impl.c b/tools/zunitc/src/zunitc_impl.c
>> new file mode 100644
>> index 0000000..fecd7a6
>> --- /dev/null
>> +++ b/tools/zunitc/src/zunitc_impl.c
>> @@ -0,0 +1,1520 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#include "config.h"
>> +
>> +#include <fnmatch.h>
>> +
>> +#include <errno.h>
>> +#include <fcntl.h>
>> +#include <stdarg.h>
>> +#include <stdbool.h>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <sys/types.h>
>> +#include <sys/wait.h>
>> +#include <time.h>
>> +#include <unistd.h>
>> +
>> +#include "zunitc/zunitc_impl.h"
>> +#include "zunitc/zunitc.h"
>> +
>> +#include "zuc_base_logger.h"
>> +#include "zuc_collector.h"
>> +#include "zuc_context.h"
>> +#include "zuc_event_listener.h"
>> +
>> +#include "shared/config-parser.h"
>> +#include "shared/zalloc.h"
>> +
>> +#define ARRAY_LENGTH(a) ((int) (sizeof (a) / sizeof (a)[0]))
>> +
>> +/*
>> + * If CLOCK_MONOTONIC is present on the system it will give us reliable
>> + * results under certain edge conditions that normally require manual
>> + * admin actions to trigger. If not, CLOCK_REALTIME is a reasonable
>> + * fallback.
>> + */
>> +#if _POSIX_MONOTONIC_CLOCK
>> +static const clockid_t TARGET_TIMER = CLOCK_MONOTONIC;
>> +#else
>> +static const clockid_t TARGET_TIMER = CLOCK_REALTIME;
>> +#endif
>> +
>> +static char const DISABLED_PREFIX[] = "DISABLED_";
>> +
>> +#define MS_PER_SEC 1000L
>> +#define NANO_PER_MS 1000000L
>> +
>> +/**
>> + * Simple single-linked list structure.
>> + */
>> +struct zuc_slinked {
>> +	void *data;
>> +	struct zuc_slinked *next;
>> +};
>> +
>> +static struct zuc_context g_ctx = {
>> +	.case_count = 0,
>> +	.cases = NULL,
>> +
>> +	.fatal = false,
>> +	.repeat = 0,
>> +	.random = 0,
>> +	.spawn = true,
>> +	.break_on_failure = false,
>> +	.fds = {-1, -1},
>> +
>> +	.listeners = NULL,
>> +
>> +	.curr_case = NULL,
>> +	.curr_test = NULL,
>> +};
>> +
>> +
>> +static void initialize(void);
>> +static void register_tests(void);
>> +static void free_test_case(struct zuc_case *test_case);
>> +static struct zuc_test *create_test(int order,
>> +				    zucimpl_test_fn fn, zucimpl_test_fn_f fn_f,
>> +				    char const *case_name,
>> +				    char const *test_name,
>> +				    struct zuc_case *parent);
>> +static void free_test(struct zuc_test *test);
>> +static void free_events(struct zuc_event **events);
>> +static void migrate_deferred_events(struct zuc_test *test, bool transferred);
>> +
>> +static int compare_regs(const void *lhs, const void *rhs);
>> +static int compare_case_order(const void *lhs, const void *rhs);
>> +static int compare_test_order(const void *lhs, const void *rhs);
>> +static void order_cases(int count, struct zuc_case **cases);
>> +static void shuffle_cases(int count, struct zuc_case **cases,
>> +			  unsigned int seed);
>> +static void filter_cases(int *count, struct zuc_case **cases,
>> +			 char const *filter);
>> +static unsigned int get_seed_from_time(void);
>> +
>> +/**
>> + * A very simple matching that is compatible with the algorithm used in
>> + * Google Test.
>> + *
>> + * @param wildcard sequence of '?', '*' or normal characters to match.
>> + * @param str string to check for matching.
>> + * @return true if the wildcard matches the entire string, false otherwise.
>> + */
>> +static bool wildcard_matches(char const *wildcard, char const *str);
>> +
>> +static bool test_has_skip(struct zuc_test *test);
>> +static bool test_has_failure(struct zuc_test *test);
>> +static bool test_has_fatal_failure(struct zuc_test *test);
>> +static bool test_has_nonfatal_failure(struct zuc_test *test);
>> +static void reset_test_values(struct zuc_case **cases, int case_count);
>> +static void mark_failed(struct zuc_test *test, enum zuc_fail_state state);
>> +static void mark_single_failed(struct zuc_test *test,
>> +			       enum zuc_fail_state state);
>> +static int run_single_pass(void);
>> +static void run_single_case(struct zuc_case *test_case);
>> +static void run_single_test(struct zuc_test *test,
>> +			    const struct zuc_fixture *fxt,
>> +			    void *case_data,
>> +			    bool spawn);
>> +static void spawn_test(struct zuc_test *test, void *test_data,
>> +		       void (*cleanup_fn)(void *data), void *cleanup_data);
>> +
>> +typedef int (*comp_pred2)(int lhs, int rhs);
>> +
>> +static comp_pred2 get_pred2(enum zuc_check_op op);
>> +
>> +/* for outputting results */
>> +static void dispatch_pre_run(struct zuc_context *ctx,
>> +			     int pass_count,
>> +			     int pass_num,
>> +			     int seed,
>> +			     const char *filter);
>> +static void dispatch_run_started(struct zuc_context *ctx,
>> +				 int live_case_count,
>> +				 int live_test_count,
>> +				 int disabled_count);
>> +static void dispatch_run_ended(struct zuc_context *ctx,
>> +			       int live_case_count,
>> +			       int live_test_count,
>> +			       int total_passed,
>> +			       int total_failed,
>> +			       int total_disabled,
>> +			       long total_elapsed);
>> +static void dispatch_case_started(struct zuc_context *ctx,
>> +				  struct zuc_case *test_case,
>> +				  int live_test_count,
>> +				  int disabled_count);
>> +static void dispatch_case_ended(struct zuc_context *ctx,
>> +				struct zuc_case *test_case);
>> +static void dispatch_test_started(struct zuc_context *ctx,
>> +				  struct zuc_test *test);
>> +static void dispatch_test_ended(struct zuc_context *ctx,
>> +				  struct zuc_test *test);
>> +static void dispatch_test_disabled(struct zuc_context *ctx,
>> +				   struct zuc_test *test);
>> +static void dispatch_check_triggered(struct zuc_context *ctx,
>> +				     char const *file,
>> +				     int line,
>> +				     enum zuc_fail_state state,
>> +				     enum zuc_check_op op,
>> +				     int val1,
>> +				     int val2,
>> +				     const char *expr1,
>> +				     const char *expr2);
>> +static void dispatch_collect_event(struct zuc_context *ctx,
>> +				   char const *file,
>> +				   int line,
>> +				   const char *expr1);
>> +
>> +
>> +bool zuc_has_skip(void)
>> +{
>> +	bool skip = g_ctx.curr_test ?
>> +		test_has_skip(g_ctx.curr_test) : false;
>> +	return skip;
>> +}
>> +
>> +bool zuc_has_failure(void)
>> +{
>> +	bool failure = g_ctx.curr_test ?
>> +		test_has_failure(g_ctx.curr_test) : false;
>> +	return failure;
>> +}
>> +
>> +bool zuc_has_fatal_failure(void)
>> +{
>> +	bool failure = g_ctx.curr_test ?
>> +		test_has_fatal_failure(g_ctx.curr_test) : false;
>> +	return failure;
>> +}
>> +
>> +bool zuc_has_nonfatal_failure(void)
>> +{
>> +	bool failure = g_ctx.curr_test ?
>> +		test_has_nonfatal_failure(g_ctx.curr_test) : false;
>> +	return failure;
>> +}
>> +
>> +void zuc_set_filter(const char *filter)
>> +{
>> +	g_ctx.filter = strdup(filter);
>> +}
>> +
>> +void zuc_set_repeat(int repeat)
>> +{
>> +	g_ctx.repeat = repeat;
>> +}
>> +
>> +void zuc_set_random(int random)
>> +{
>> +	g_ctx.random = random;
>> +}
>> +
>> +void zuc_set_spawn(bool spawn)
>> +{
>> +	g_ctx.spawn = spawn;
>> +}
>> +
>> +void zuc_set_break_on_failure(bool break_on_failure)
>> +{
>> +	g_ctx.break_on_failure = break_on_failure;
>> +}
>> +
>> +int zuc_initialize(int *argc, char *argv[], bool *help_flagged)
>> +{
>> +	int rc = EXIT_FAILURE;
>> +	int opt_help = 0;
>> +	int opt_nofork = 0;
>> +	int opt_list = 0;
>> +	int opt_repeat = 0;
>> +	int opt_random = 0;
>> +	int opt_break_on_failure = 0;
>> +	char *opt_filter = NULL;
>> +
>> +	char *help_param = NULL;
>> +	int argc_in = *argc;
>> +
>> +	const struct weston_option options[] = {
>> +		{ WESTON_OPTION_BOOLEAN, "zuc-nofork", 0, &opt_nofork },
>> +		{ WESTON_OPTION_BOOLEAN, "zuc-list-tests", 0, &opt_list },
>> +		{ WESTON_OPTION_INTEGER, "zuc-repeat", 0, &opt_repeat },
>> +		{ WESTON_OPTION_INTEGER, "zuc-random", 0, &opt_random },
>> +		{ WESTON_OPTION_BOOLEAN, "zuc-break-on-failure", 0,
>> +		  &opt_break_on_failure },
>> +		{ WESTON_OPTION_STRING, "zuc-filter", 0, &opt_filter },
>> +	};
>> +
>> +	initialize();
>> +	if (g_ctx.fatal)
>> +		return EXIT_FAILURE;
>> +
>> +	if (help_flagged)
>> +		*help_flagged = false;
>> +
>> +	{
>> +		/* Help param will be a special case and need restoring. */
>> +		int i = 0;
>> +		char **argv_in = NULL;
>> +		const struct weston_option help_options[] = {
>> +			{ WESTON_OPTION_BOOLEAN, "help", 'h', &opt_help },
>> +		};
>> +		argv_in = zalloc(sizeof(char *) * argc_in);
>> +		if (!argv_in) {
>> +			printf("%s:%d: error: alloc failed.\n",
>> +			       __FILE__, __LINE__);
>> +			return EXIT_FAILURE;
>> +		}
>> +		for (i = 0; i < argc_in; ++i)
>> +			argv_in[i] = argv[i];
>> +
>> +		parse_options(help_options, ARRAY_LENGTH(help_options),
>> +			      argc, argv);
>> +		if (*argc < argc_in) {
>> +			for (i = 1; (i < argc_in) && !help_param; ++i) {
>> +				bool found = false;
>> +				int j = 0;
>> +				for (j = 0; (j < *argc) && !found; ++j)
>> +					found = (argv[j] == argv_in[i]);
>> +
>> +				if (!found)
>> +					help_param = argv_in[i];
>> +			}
>> +		}
>> +		free(argv_in);
>> +	}
>> +
>> +	parse_options(options, ARRAY_LENGTH(options), argc, argv);
>> +
>> +	if (help_param && (*argc < argc_in))
>> +		argv[(*argc)++] = help_param;
>> +
>> +	if (opt_filter) {
>> +		zuc_set_filter(opt_filter);
>> +		free(opt_filter);
>> +	}
>> +
>> +	if (opt_help) {
>> +		printf("Usage: %s [OPTIONS]\n"
>> +		       "  --zuc-break-on-failure\n"
>> +		       "  --zuc-filter=FILTER\n"
>> +		       "  --zuc-list-tests\n"
>> +		       "  --zuc-nofork\n"
>> +		       "  --zuc-random=N            [0|1|<seed number>]\n"
>> +		       "  --zuc-repeat=N\n"
>> +		       "  --help\n",
>> +		       argv[0]);
>> +		if (help_flagged)
>> +			*help_flagged = true;
>> +		rc = EXIT_SUCCESS;
>> +	} else if (opt_list) {
>> +		zuc_list_tests();
>> +		rc = EXIT_FAILURE;
>> +	} else {
>> +		zuc_set_repeat(opt_repeat);
>> +		zuc_set_random(opt_random);
>> +		zuc_set_spawn(!opt_nofork);
>> +		zuc_set_break_on_failure(opt_break_on_failure);
>> +		rc = EXIT_SUCCESS;
>> +	}
>> +
>> +	return rc;
>> +}
>> +
>> +void free_test_case(struct zuc_case *test_case)
>> +{
>> +	int i;
>> +	free(test_case->name);
>> +	for (i = test_case->test_count - 1; i >= 0; --i) {
>> +		free_test(test_case->tests[i]);
>> +		test_case->tests[i] = NULL;
>> +	}
>> +	free(test_case->tests);
>> +	free(test_case);
>> +}
>> +
>> +struct zuc_test *create_test(int order,
>> +			     zucimpl_test_fn fn, zucimpl_test_fn_f fn_f,
>> +			     char const *case_name,
>> +			     char const *test_name,
>> +			     struct zuc_case *parent)
>> +{
>> +	struct zuc_test *test = zalloc(sizeof(struct zuc_test));
>> +	ZUC_EXPECT_TRUE(test != NULL);
>> +	if (!test)
>> +		return NULL;
>> +	test->order = order;
>> +	test->fn = fn;
>> +	test->fn_f = fn_f;
>> +	test->name = strdup(test_name);
>> +	if ((!fn && !fn_f) ||
>> +	    (strncmp(DISABLED_PREFIX,
>> +		     test_name, sizeof(DISABLED_PREFIX) - 1) == 0))
>> +		test->disabled = 1;
>> +
>> +	test->test_case = parent;
>> +
>> +	return test;
>> +}
>> +
>> +void free_test(struct zuc_test *test)
>> +{
>> +	free(test->name);
>> +	free_events(&test->events);
>> +	free_events(&test->deferred);
>> +	free(test);
>> +}
>> +
>> +void free_events(struct zuc_event **events)
>> +{
>> +	struct zuc_event *evt = *events;
>> +	*events = NULL;
>> +	while (evt) {
>> +		struct zuc_event *old = evt;
>> +		evt = evt->next;
>> +		free(old->file);
>> +		free(old->expr1);
>> +		free(old->expr2);
>> +		free(old);
>> +	}
>> +}
>> +
>> +void zuc_attach_event(struct zuc_test *test, struct zuc_event *event,
>> +		      enum zuc_event_type event_type, bool transferred)
>> +{
>> +	if (!test) {
>> +		/*
>> +		 * consider adding events directly to the case.
>> +		 * would be for use during per-suite setup and teardown.
>> +		 */
>> +		printf("%s:%d: error: No current test.\n", __FILE__, __LINE__);
>> +	} else if (event_type == ZUC_EVENT_DEFERRED) {
>> +		if (test->deferred) {
>> +			struct zuc_event *curr = test->deferred;
>> +			while (curr->next)
>> +				curr = curr->next;
>> +			curr->next = event;
>> +		} else {
>> +			test->deferred = event;
>> +		}
>> +	} else {
>> +		if (test)
>> +			migrate_deferred_events(test, transferred);
>> +
>> +		if (test->events) {
>> +			struct zuc_event *curr = test->events;
>> +			while (curr->next)
>> +				curr = curr->next;
>> +			curr->next = event;
>> +		} else {
>> +			test->events = event;
>> +		}
>> +		mark_failed(test, event->state);
>> +	}
>> +}
>> +
>> +void migrate_deferred_events(struct zuc_test *test, bool transferred)
>> +{
>> +	struct zuc_event *evt = test->deferred;
>> +	if (!evt)
>> +		return;
>> +
>> +	test->deferred = NULL;
>> +	if (test->events) {
>> +		struct zuc_event *old = test->events;
>> +		while (old->next)
>> +			old = old->next;
>> +		old->next = evt;
>> +	} else {
>> +		test->events = evt;
>> +	}
>> +	while (evt && !transferred) {
>> +		dispatch_check_triggered(&g_ctx,
>> +					 evt->file, evt->line,
>> +					 evt->state, evt->op,
>> +					 evt->val1, evt->val2,
>> +					 evt->expr1, evt->expr2);
>> +		evt = evt->next;
>> +	}
>> +}
>> +
>> +void zuc_add_event_listener(struct zuc_event_listener *event_listener)
>> +{
>> +	if (!event_listener) /* ensure null entries are not added */
>> +		return;
>> +
>> +	if (!g_ctx.listeners) {
>> +		g_ctx.listeners = zalloc(sizeof(struct zuc_slinked));
>> +		ZUC_ASSERT_TRUE(g_ctx.listeners != NULL);
>> +		g_ctx.listeners->data = event_listener;
>> +	} else {
>> +		struct zuc_slinked *curr = g_ctx.listeners;
>> +		while (curr->next)
>> +			curr = curr->next;
>> +		curr->next = zalloc(sizeof(struct zuc_slinked));
>> +		ZUC_ASSERT_TRUE(curr->next != NULL);
>> +		curr->next->data = event_listener;
>> +	}
>> +}
>> +
>> +
>> +void initialize(void)
>> +{
>> +	static bool init = false;
>> +	if (init)
>> +		return;
>> +
>> +	init = true;
>> +	register_tests();
>> +	if (g_ctx.fatal)
>> +		return;
>> +
>> +	if (g_ctx.random > 1) {
>> +		g_ctx.seed = g_ctx.random;
>> +	} else if (g_ctx.random == 1) {
>> +		g_ctx.seed = get_seed_from_time();
>> +	}
>> +
>> +	if (g_ctx.listeners == NULL) {
>> +		zuc_add_event_listener(zuc_collector_create(&(g_ctx.fds[1])));
>> +		zuc_add_event_listener(zuc_base_logger_create());
>> +	}
>> +
>> +	if (g_ctx.case_count) {
>> +		order_cases(g_ctx.case_count, g_ctx.cases);
>> +		if (g_ctx.filter && g_ctx.filter[0])
>> +			filter_cases(&g_ctx.case_count, g_ctx.cases,
>> +				     g_ctx.filter);
>> +	}
>> +}
>> +
>> +void zuc_cleanup(void)
>> +{
>> +	int i;
>> +	free(g_ctx.filter);
>> +	g_ctx.filter = 0;
>> +	for (i = 0; i < 2; ++i)
>> +		if (g_ctx.fds[i] != -1) {
>> +			close(g_ctx.fds[i]);
>> +			g_ctx.fds[i] = -1;
>> +		}
>> +
>> +	if (g_ctx.listeners) {
>> +		struct zuc_slinked *curr = g_ctx.listeners;
>> +		while (curr) {
>> +			struct zuc_slinked *old = curr;
>> +			struct zuc_event_listener *listener = curr->data;
>> +			if (listener->destroy)
>> +				listener->destroy(listener->data);
>> +			free(listener);
>> +			curr = curr->next;
>> +			free(old);
>> +		}
>> +		g_ctx.listeners = NULL;
>> +	}
>> +
>> +	for (i = g_ctx.case_count - 1; i >= 0; --i) {
>> +		free_test_case(g_ctx.cases[i]);
>> +		g_ctx.cases[i] = NULL;
>> +	}
>> +	free(g_ctx.cases);
>> +	g_ctx.cases = NULL;
>> +}
>> +
>> +/* gcc-specific markers for auto test case registration: */
>> +extern const struct zuc_registration __start_zuc_tsect;
>> +extern const struct zuc_registration __stop_zuc_tsect;
>> +
>> +void register_tests(void)
>> +{
>> +	size_t case_count = 0;
>> +	size_t count = &__stop_zuc_tsect - &__start_zuc_tsect;
>> +	size_t i;
>> +	int idx = 0;
>> +	const char *last_name = NULL;
>> +	void **array = zalloc(sizeof(void *) * count);
>> +	ZUC_ASSERT_TRUE(array != NULL);
>> +	for (i = 0; i < count; ++i)
>> +		array[i] = (void *)(&__start_zuc_tsect + i);
>> +
>> +	qsort(array, count, sizeof(array[0]), compare_regs);
>> +
>> +	/* Count transitions to get number of test cases. */
>> +	last_name = NULL;
>> +	for (i = 0; i < count; ++i) {
>> +		const struct zuc_registration *reg =
>> +			(const struct zuc_registration *)array[i];
>> +		if (!last_name || (strcmp(last_name, reg->tcase))) {
>> +			last_name = reg->tcase;
>> +			case_count++;
>> +		}
>> +	}
>> +
>> +	/* Create test case data items. */
>> +	struct zuc_case **case_array =
>> +		zalloc(sizeof(struct zuc_case *) * case_count);
>> +	ZUC_ASSERT_TRUE(case_array != NULL);
>> +	struct zuc_case *last_case = NULL;
>> +	size_t case_num = 0;
>> +	for (i = 0; i < count; ++i) {
>> +		const struct zuc_registration *reg =
>> +			(const struct zuc_registration *)array[i];
>> +		if (!last_case || (strcmp(last_case->name, reg->tcase))) {
>> +			last_case = zalloc(sizeof(struct zuc_case));
>> +			ZUC_ASSERT_TRUE(last_case != NULL);
>> +			last_case->order = count;
>> +			last_case->name = strdup(reg->tcase);
>> +			last_case->fxt = reg->fxt;
>> +			last_case->test_count = i;
>> +			if (case_num > 0) {
>> +				int tcount = i
>> +					- case_array[case_num - 1]->test_count;
>> +				case_array[case_num - 1]->test_count = tcount;
>> +			}
>> +			case_array[case_num++] = last_case;
>> +		}
>> +	}
>> +	case_array[case_count - 1]->test_count = count
>> +		- case_array[case_count - 1]->test_count;
>> +
>> +	/* Reserve space for tests per test case. */
>> +	for (case_num = 0; case_num < case_count; ++case_num) {
>> +		case_array[case_num]->tests =
>> +			zalloc(case_array[case_num]->test_count
>> +			       * sizeof(struct zuc_test *));
>> +		ZUC_ASSERT_TRUE(case_array[case_num]->tests != NULL);
>> +	}
>> +
>> +	last_name = NULL;
>> +	case_num = -1;
>> +	for (i = 0; i < count; ++i) {
>> +		const struct zuc_registration *reg =
>> +			(const struct zuc_registration *)array[i];
>> +		int order = count - (1 + (reg - &__start_zuc_tsect));
>> +
>> +		if (!last_name || (strcmp(last_name, reg->tcase))) {
>> +			last_name = reg->tcase;
>> +			case_num++;
>> +			idx = 0;
>> +		}
>> +		if (order < case_array[case_num]->order)
>> +			case_array[case_num]->order = order;
>> +		case_array[case_num]->tests[idx] =
>> +			create_test(order, reg->fn, reg->fn_f,
>> +				    reg->tcase, reg->test,
>> +				    case_array[case_num]);
>> +
>> +		if (case_array[case_num]->fxt != reg->fxt)
>> +			printf("%s:%d: error: Mismatched fixtures for '%s'\n",
>> +			       __FILE__, __LINE__, case_array[case_num]->name);
>> +
>> +		idx++;
>> +	}
>> +	free(array);
>> +
>> +	g_ctx.case_count = case_count;
>> +	g_ctx.cases = case_array;
>> +}
>> +
>> +int compare_regs(const void *lhs, const void *rhs)
>> +{
>> +	int rc = strcmp((*(struct zuc_registration **)lhs)->tcase,
>> +		      (*(struct zuc_registration **)rhs)->tcase);
>> +	if (rc == 0)
>> +		rc = strcmp((*(struct zuc_registration **)lhs)->test,
>> +		      (*(struct zuc_registration **)rhs)->test);
>> +
>> +	return rc;
>> +}
>> +
>> +int compare_case_order(const void *lhs, const void *rhs)
>> +{
>> +	return (*(struct zuc_case **)lhs)->order
>> +		- (*(struct zuc_case **)rhs)->order;
>> +}
>> +
>> +int compare_test_order(const void *lhs, const void *rhs)
>> +{
>> +	return (*(struct zuc_test **)lhs)->order
>> +		- (*(struct zuc_test **)rhs)->order;
>> +}
>> +
>> +void order_cases(int count, struct zuc_case **cases)
>> +{
>> +	int i;
>> +	qsort(cases, count, sizeof(*cases), compare_case_order);
>> +	for (i = 0; i < count; ++i) {
>> +		qsort(cases[i]->tests, cases[i]->test_count,
>> +		      sizeof(*cases[i]->tests), compare_test_order);
>> +	}
>> +}
>> +
>> +void shuffle_cases(int count, struct zuc_case **cases,
>> +		   unsigned int seed)
>> +{
>> +	int i;
>> +	unsigned int rseed = seed;
>> +	for (i = 0; i < count; ++i) {
>> +		int j;
>> +		for (j = cases[i]->test_count - 1; j > 0 ; --j) {
>> +			int val = rand_r(&rseed);
>> +			int b = ((val / (double)RAND_MAX) * j + 0.5);
>> +			if (j != b) {
>> +				struct zuc_test *tmp = cases[i]->tests[j];
>> +				cases[i]->tests[j] = cases[i]->tests[b];
>> +				cases[i]->tests[b] = tmp;
>> +			}
>> +		}
>> +	}
>> +
>> +	for (i = count - 1; i > 0; --i) {
>> +		int val = rand_r(&rseed);
>> +		int j = ((val / (double)RAND_MAX) * i + 0.5);
>> +
>> +		if (i != j) {
>> +			struct zuc_case *tmp = cases[i];
>> +			cases[i] = cases[j];
>> +			cases[j] = tmp;
>> +		}
>> +	}
>> +}
>> +
>> +static char** segment_str(char *str)
>> +{
>> +	int count = 1;
>> +	char **parts = NULL;
>> +	int i = 0;
>> +	for (i = 0; str[i]; ++i)
>> +		if (str[i] == ':')
>> +			count++;
>> +	parts = zalloc(sizeof(char*) * (count + 1));
>> +	ZUC_EXPECT_TRUE(parts != NULL);
>> +	if (parts) {
>> +		char *saved = NULL;
>> +		char *tok = strtok_r(str, ":", &saved);
>> +		i = 0;
>> +		parts[i++] = tok;
>> +		while (tok) {
>> +			tok = strtok_r(NULL, ":", &saved);
>> +			parts[i++] = tok;
>> +		}
>> +	}
>> +	return parts;
>> +}
>> +
>> +bool wildcard_matches(char const *wildcard, char const *str)
>> +{
>> +	switch (*wildcard) {
>> +	case '\0':
>> +		return !*str;
>> +	case '?':
>> +		return *str && wildcard_matches(wildcard + 1, str + 1);
>> +	case '*':
>> +		return (*str && wildcard_matches(wildcard, str + 1))
>> +			|| wildcard_matches(wildcard + 1, str);
>> +	default:
>> +		return (*wildcard == *str)
>> +			&& wildcard_matches(wildcard + 1, str + 1);
>> +	};
>> +}
>> +
>> +void filter_cases(int *count, struct zuc_case **cases, char const *filter)
>> +{
>> +	int i = 0;
>> +	int j = 0;
>> +	int num_pos = 0;
>> +	int negative = -1;
>> +	char *buf = strdup(filter);
>> +	char **parts = segment_str(buf);
>> +
>> +	for (i = 0; parts[i]; ++i) {
>> +		if (parts[i][0] == '-') {
>> +			parts[i]++;
>> +			negative = i;
>> +			break;
>> +		}
>> +		num_pos++;
>> +	}
>> +
>> +	for (i = 0; i < *count; ++i) {
>> +		/* Walk backwards for easier pruning. */
>> +		for (j = cases[i]->test_count - 1; j >= 0; --j) {
>> +			int x;
>> +			bool keep = num_pos == 0;
>> +			char *name = NULL;
>> +			struct zuc_test *test = cases[i]->tests[j];
>> +			if (asprintf(&name, "%s.%s", cases[i]->name,
>> +				     test->name) < 0) {
>> +				printf("%s:%d: error: %d\n", __FILE__, __LINE__,
>> +				       errno);
>> +				exit(EXIT_FAILURE);
>> +			}
>> +			for (x = 0; (x < num_pos) && !keep; ++x)
>> +				keep = wildcard_matches(parts[x], name);
>> +			if (keep && (negative >= 0))
>> +				for (x = negative; parts[x] && keep; ++x)
>> +					keep &= !wildcard_matches(parts[x],
>> +								  name);
>> +			if (!keep) {
>> +				int w;
>> +				free_test(test);
>> +				for (w = j + 1; w < cases[i]->test_count; w++)
>> +					cases[i]->tests[w - 1] =
>> +						cases[i]->tests[w];
>> +				cases[i]->test_count--;
>> +			}
>> +
>> +			free(name);
>> +		}
>> +	}
>> +	free(parts);
>> +	parts = NULL;
>> +	free(buf);
>> +	buf = NULL;
>> +
>> +	/* Prune any cases with no more tests. */
>> +	for (i = *count - 1; i >= 0; --i) {
>> +		if (cases[i]->test_count < 1) {
>> +			free_test_case(cases[i]);
>> +			for (j = i + 1; j < *count; ++j)
>> +				cases[j - 1] = cases[j];
>> +			cases[*count - 1] = NULL;
>> +			(*count)--;
>> +		}
>> +	}
>> +}
>> +
>> +unsigned int get_seed_from_time(void)
>> +{
>> +	time_t sec = time(NULL);
>> +	unsigned int seed = (unsigned int) sec % 100000;
>> +	if (seed < 2)
>> +		seed = 2;
>> +
>> +	return seed;
>> +}
>> +
>> +void zuc_list_tests(void)
>> +{
>> +	int i;
>> +	int j;
>> +	initialize();
>> +	if (g_ctx.fatal)
>> +		return;
>> +	for (i = 0; i < g_ctx.case_count; ++i) {
>> +		printf("%s.\n", g_ctx.cases[i]->name);
>> +		for (j = 0; j < g_ctx.cases[i]->test_count; ++j) {
>> +			printf("  %s\n", g_ctx.cases[i]->tests[j]->name);
>> +		}
>> +	}
>> +}
>> +
>> +int zucimpl_run_tests(void)
>> +{
>> +	int rc = EXIT_SUCCESS;
>> +	int i;
>> +	int limit = g_ctx.repeat > 0 ? g_ctx.repeat : 1;
>> +
>> +	initialize();
>> +	if (g_ctx.fatal)
>> +		return EXIT_FAILURE;
>> +
>> +	if (g_ctx.case_count < 1) {
>> +		printf("%s:%d: error: Setup error: test tree is empty\n",
>> +		       __FILE__, __LINE__);
>> +		rc = EXIT_FAILURE;
>> +	}
>> +
>> +	for (i = 0; (i < limit) && (g_ctx.case_count > 0); ++i) {
>> +		int pass_code = EXIT_SUCCESS;
>> +		dispatch_pre_run(&g_ctx, limit, i + 1,
>> +				 (g_ctx.random > 0) ? g_ctx.seed : 0,
>> +				 g_ctx.filter);
>> +
>> +		order_cases(g_ctx.case_count, g_ctx.cases);
>> +		if (g_ctx.random > 0)
>> +			shuffle_cases(g_ctx.case_count, g_ctx.cases,
>> +				      g_ctx.seed);
>> +
>> +		pass_code = run_single_pass();
>> +		if (pass_code == EXIT_FAILURE)
>> +			rc = EXIT_FAILURE;
>> +		else if ((pass_code == ZUC_EXIT_SKIP) && (rc == EXIT_SUCCESS))
>> +			rc = ZUC_EXIT_SKIP;
>> +
>> +		g_ctx.seed++;
>> +	}
>> +
>> +	return rc;
>> +}
>> +
>> +void reset_test_values(struct zuc_case **cases, int case_count)
>> +{
>> +	int i;
>> +	for (i = 0; i < case_count; ++i) {
>> +		int j;
>> +		cases[i]->disabled = 0;
>> +		cases[i]->skipped = 0;
>> +		cases[i]->failed = 0;
>> +		cases[i]->fatal = 0;
>> +		cases[i]->passed = 0;
>> +		cases[i]->elapsed = 0;
>> +		for (j = 0; j < cases[i]->test_count; ++j) {
>> +			struct zuc_test *test = cases[i]->tests[j];
>> +			if (test->disabled)
>> +				cases[i]->disabled++;
>> +			test->skipped = 0;
>> +			test->failed = 0;
>> +			test->fatal = 0;
>> +			test->elapsed = 0;
>> +
>> +			free_events(&test->events);
>> +			free_events(&test->deferred);
>> +		}
>> +	}
>> +}
>> +
>> +int run_single_pass(void)
>> +{
>> +	long total_elapsed = 0;
>> +	int total_passed = 0;
>> +	int total_failed = 0;
>> +	int total_skipped = 0;
>> +	int live_case_count = 0;
>> +	int live_test_count = 0;
>> +	int disabled_test_count = 0;
>> +	int i;
>> +
>> +	reset_test_values(g_ctx.cases, g_ctx.case_count);
>> +	for (i = 0; i <  g_ctx.case_count; ++i) {
>> +		int live = g_ctx.cases[i]->test_count
>> +			- g_ctx.cases[i]->disabled;
>> +		if (live) {
>> +			live_test_count += live;
>> +			live_case_count++;
>> +		}
>> +		if (g_ctx.cases[i]->disabled)
>> +			disabled_test_count++;
>> +	}
>> +
>> +	dispatch_run_started(&g_ctx, live_case_count, live_test_count,
>> +			     disabled_test_count);
>> +
>> +	for (i = 0; i <  g_ctx.case_count; ++i) {
>> +		run_single_case(g_ctx.cases[i]);
>> +		total_failed += g_ctx.cases[i]->test_count
>> +			- (g_ctx.cases[i]->passed + g_ctx.cases[i]->disabled);
>> +		total_passed += g_ctx.cases[i]->passed;
>> +		total_elapsed += g_ctx.cases[i]->elapsed;
>> +		total_skipped += g_ctx.cases[i]->skipped;
>> +	}
>> +
>> +	dispatch_run_ended(&g_ctx, live_case_count, live_test_count,
>> +			   total_passed, total_failed, disabled_test_count,
>> +			   total_elapsed);
>> +
>> +	if (total_failed)
>> +		return EXIT_FAILURE;
>> +	else if (total_skipped)
>> +		return ZUC_EXIT_SKIP;
>> +	else
>> +		return EXIT_SUCCESS;
>> +}
>> +
>> +void run_single_case(struct zuc_case *test_case)
>> +{
>> +	int count_live = test_case->test_count - test_case->disabled;
>> +	g_ctx.curr_case = test_case;
>> +	if (count_live) {
>> +		int i = 0;
>> +		const struct zuc_fixture *fxt = test_case->fxt;
>> +		void *case_data = fxt ? (void *)fxt->data : NULL;
>> +
>> +		dispatch_case_started(&g_ctx, test_case,
>> +				      count_live, test_case->disabled);
>> +
>> +		if (fxt && fxt->set_up_test_case)
>> +			case_data = fxt->set_up_test_case(fxt->data);
>> +
>> +		for (i = 0; i < test_case->test_count; ++i) {
>> +			struct zuc_test *curr = test_case->tests[i];
>> +			if (curr->disabled) {
>> +				dispatch_test_disabled(&g_ctx, curr);
>> +			} else {
>> +				run_single_test(curr, fxt, case_data,
>> +						g_ctx.spawn);
>> +				if (curr->skipped)
>> +					test_case->skipped++;
>> +				if (curr->failed)
>> +					test_case->failed++;
>> +				if (curr->fatal)
>> +					test_case->fatal++;
>> +				if (!curr->failed && !curr->fatal)
>> +					test_case->passed++;
>> +				test_case->elapsed += curr->elapsed;
>> +			}
>> +		}
>> +
>> +		if (fxt && fxt->tear_down_test_case)
>> +			fxt->tear_down_test_case(case_data);
>> +
>> +		dispatch_case_ended(&g_ctx, test_case);
>> +	}
>> +	g_ctx.curr_case = NULL;
>> +}
>> +
>> +void run_single_test(struct zuc_test *test,
>> +		     const struct zuc_fixture *fxt,
>> +		     void *case_data,
>> +		     bool spawn)
>> +{
>> +	long elapsed = 0;
>> +	struct timespec begin;
>> +	struct timespec end;
>> +	void *test_data = NULL;
>> +	void *cleanup_data = NULL;
>> +	void (*cleanup_fn)(void *data) = NULL;
>> +	memset(&begin, 0, sizeof(begin));
>> +	memset(&end, 0, sizeof(end));
>> +
>> +	g_ctx.curr_test = test;
>> +	dispatch_test_started(&g_ctx, test);
>> +
>> +	cleanup_fn = fxt ? fxt->tear_down : NULL;
>> +	cleanup_data = NULL;
>> +
>> +	if (fxt && fxt->set_up) {
>> +		test_data = fxt->set_up(case_data);
>> +		cleanup_data = test_data;
>> +	} else {
>> +		test_data = case_data;
>> +	}
>> +
>> +	clock_gettime(TARGET_TIMER, &begin);
>> +
>> +	/* Need to re-check these, as fixtures might have changed test state. */
>> +	if (!test->fatal && !test->skipped) {
>> +		if (spawn) {
>> +			spawn_test(test, test_data,
>> +				   cleanup_fn, cleanup_data);
>> +		} else {
>> +			if (test->fn_f)
>> +				test->fn_f(test_data);
>> +			else
>> +				test->fn();
>> +		}
>> +	}
>> +
>> +	clock_gettime(TARGET_TIMER, &end);
>> +
>> +	elapsed = (end.tv_sec - begin.tv_sec) * MS_PER_SEC;
>> +	if (end.tv_sec != begin.tv_sec) {
>> +		elapsed -= (begin.tv_nsec) / NANO_PER_MS;
>> +		elapsed += (end.tv_nsec) / NANO_PER_MS;
>> +	} else {
>> +		elapsed += (end.tv_nsec - begin.tv_nsec) / NANO_PER_MS;
>> +	}
>> +	test->elapsed = elapsed;
>> +
>> +	if (cleanup_fn)
>> +		cleanup_fn(cleanup_data);
>> +
>> +	if (test->deferred) {
>> +		if (test_has_failure(test))
>> +			migrate_deferred_events(test, false);
>> +		else
>> +			free_events(&test->deferred);
>> +	}
>> +
>> +	dispatch_test_ended(&g_ctx, test);
>> +
>> +	g_ctx.curr_test = NULL;
>> +}
>> +
>> +void spawn_test(struct zuc_test *test, void *test_data,
>> +		void (*cleanup_fn)(void *data), void *cleanup_data)
>> +{
>> +	pid_t pid = -1;
>> +
>> +	if (!test || (!test->fn && !test->fn_f))
>> +		return;
>> +
>> +	if (pipe2(g_ctx.fds, O_CLOEXEC)) {
>> +		printf("%s:%d: error: Unable to create pipe: %d\n",
>> +		       __FILE__, __LINE__, errno);
>> +		mark_failed(test, ZUC_CHECK_ERROR);
>> +		return;
>> +	}
>> +
>> +	fflush(NULL); /* important. avoid duplication of output */
>> +	pid = fork();
>> +	switch (pid) {
>> +	case -1: /* Error forking */
>> +		printf("%s:%d: error: Problem with fork: %d\n",
>> +		       __FILE__, __LINE__, errno);
>> +		mark_failed(test, ZUC_CHECK_ERROR);
>> +		close(g_ctx.fds[0]);
>> +		g_ctx.fds[0] = -1;
>> +		close(g_ctx.fds[1]);
>> +		g_ctx.fds[1] = -1;
>> +		break;
>> +	case 0: { /* child */
>> +		int rc = EXIT_SUCCESS;
>> +		close(g_ctx.fds[0]);
>> +		g_ctx.fds[0] = -1;
>> +
>> +		if (test->fn_f)
>> +			test->fn_f(test_data);
>> +		else
>> +			test->fn();
>> +
>> +		if (test_has_failure(test))
>> +			rc = EXIT_FAILURE;
>> +		else if (test_has_skip(test))
>> +			rc = ZUC_EXIT_SKIP;
>> +
>> +		/* Avoid confusing memory tools like valgrind */
>> +		if (cleanup_fn)
>> +			cleanup_fn(cleanup_data);
>> +
>> +		zuc_cleanup();
>> +		exit(rc);
>> +		break;
>> +	}
>> +	default: { /* parent */
>> +		ssize_t rc = 0;
>> +		siginfo_t info = {};
>> +
>> +		close(g_ctx.fds[1]);
>> +		g_ctx.fds[1] = -1;
>> +
>> +		do {
>> +			rc = zuc_process_message(g_ctx.curr_test,
>> +						 g_ctx.fds[0]);
>> +		} while (rc > 0);
>> +		close(g_ctx.fds[0]);
>> +		g_ctx.fds[0] = -1;
>> +
>> +		if (waitid(P_ALL, 0, &info, WEXITED)) {
>> +			printf("%s:%d: error: waitid failed. (%d)\n",
>> +			       __FILE__, __LINE__, errno);
>> +			mark_failed(test, ZUC_CHECK_ERROR);
>> +		} else {
>> +			switch (info.si_code) {
>> +			case CLD_EXITED: {
>> +				int exit_code = info.si_status;
>> +				switch(exit_code) {
>> +				case EXIT_SUCCESS:
>> +					break;
>> +				case ZUC_EXIT_SKIP:
>> +					if (!test_has_skip(g_ctx.curr_test) &&
>> +					    !test_has_failure(g_ctx.curr_test))
>> +						ZUC_SKIP("Child exited SKIP");
>> +					break;
>> +				default:
>> +					/* unexpected failure */
>> +					if (!test_has_failure(g_ctx.curr_test))
>> +						ZUC_EXPECT_EQ(0, exit_code);
>> +				}
>> +				break;
>> +			}
>> +			case CLD_KILLED:
>> +			case CLD_DUMPED:
>> +				printf("%s:%d: error: signaled: %d\n",
>> +				       __FILE__, __LINE__, info.si_status);
>> +				mark_failed(test, ZUC_CHECK_ERROR);
>> +				break;
>> +			}
>> +		}
>> +	}
>> +	}
>> +}
>> +
>> +bool test_has_skip(struct zuc_test *test)
>> +{
>> +	return test->skipped;
>> +}
>> +
>> +bool test_has_failure(struct zuc_test *test)
>> +{
>> +	return test->fatal || test->failed;
>> +}
>> +
>> +bool test_has_fatal_failure(struct zuc_test *test)
>> +{
>> +	return test->fatal;
>> +}
>> +
>> +bool test_has_nonfatal_failure(struct zuc_test *test)
>> +{
>> +	return test->failed;
>> +}
>> +
>> +void mark_failed(struct zuc_test *test, enum zuc_fail_state state)
>> +{
>> +	if (!test && g_ctx.curr_test)
>> +		test = g_ctx.curr_test;
>> +
>> +	if (test) {
>> +		mark_single_failed(test, state);
>> +	} else if (g_ctx.curr_case) {
>> +		/* In setup or tear-down of test suite */
>> +		int i;
>> +		for (i = 0; i < g_ctx.curr_case->test_count; ++i)
>> +			mark_single_failed(g_ctx.curr_case->tests[i], state);
>> +	}
>> +	if ((state == ZUC_CHECK_FATAL) || (state == ZUC_CHECK_ERROR))
>> +		g_ctx.fatal = true;
>> +}
>> +
>> +void mark_single_failed(struct zuc_test *test, enum zuc_fail_state state)
>> +{
>> +	switch (state) {
>> +	case ZUC_CHECK_OK:
>> +		/* no internal state to change */
>> +		break;
>> +	case ZUC_CHECK_SKIP:
>> +		if (test)
>> +			test->skipped = 1;
>> +		break;
>> +	case ZUC_CHECK_FAIL:
>> +		if (test)
>> +			test->failed = 1;
>> +		break;
>> +	case ZUC_CHECK_ERROR:
>> +	case ZUC_CHECK_FATAL:
>> +		if (test)
>> +			test->fatal = 1;
>> +		break;
>> +	}
>> +
>> +	if (g_ctx.break_on_failure)
>> +		raise(SIGABRT);
>> +
>> +}
>> +
>> +int zucimpl_tracepoint(char const *file, int line, char const *fmt, ...)
>> +{
>> +	int rc = -1;
>> +	va_list argp;
>> +	char *msg = NULL;
>> +
>> +
>> +	va_start(argp, fmt);
>> +	rc = vasprintf(&msg, fmt, argp);
>> +	if (rc == -1) {
>> +		msg = NULL;
>> +	}
>> +	va_end(argp);
>> +
>> +	dispatch_collect_event(&g_ctx,
>> +			       file, line,
>> +			       msg);
>> +
>> +	free(msg);
>> +
>> +	return rc;
>> +}
>> +
>> +void zucimpl_terminate(char const *file, int line,
>> +		       bool fail, bool fatal, const char *msg)
>> +{
>> +	enum zuc_fail_state state = ZUC_CHECK_SKIP;
>> +	int level = 2;
>> +	if (fail && fatal) {
>> +		state =  ZUC_CHECK_FATAL;
>> +		level = 0;
>> +	} else if (fail && !fatal) {
>> +		state = ZUC_CHECK_FAIL;
>> +		level = 0;
>> +	}
>> +
>> +	mark_failed(g_ctx.curr_test, state);
>> +
>> +	if ((state != ZUC_CHECK_OK) && g_ctx.curr_test)
>> +		migrate_deferred_events(g_ctx.curr_test, false);
>> +
>> +	dispatch_check_triggered(&g_ctx,
>> +				 file, line,
>> +				 state,
>> +				 ZUC_OP_TERMINATE,
>> +				 level, 0,
>> +				 msg, "");
>> +}
>> +
>> +int zucimpl_expect_pred2(char const *file, int line,
>> +			 enum zuc_check_op op, bool fatal,
>> +			 int lhs, int rhs,
>> +			 const char *lhs_str, const char* rhs_str)
>> +{
>> +	enum zuc_fail_state state = fatal ?  ZUC_CHECK_FATAL : ZUC_CHECK_FAIL;
>> +	comp_pred2 pred = get_pred2(op);
>> +	int failed = !pred(lhs, rhs);
>> +	if (failed) {
>> +		mark_failed(g_ctx.curr_test, state);
>> +
>> +		if (g_ctx.curr_test)
>> +			migrate_deferred_events(g_ctx.curr_test, false);
>> +
>> +		dispatch_check_triggered(&g_ctx,
>> +					 file, line,
>> +					 fatal ? ZUC_CHECK_FATAL
>> +					 : ZUC_CHECK_FAIL,
>> +					 op,
>> +					 lhs, rhs,
>> +					 lhs_str, rhs_str);
>> +	}
>> +	return failed;
>> +}
>> +
>> +void dispatch_pre_run(struct zuc_context *ctx,
>> +		      int pass_count,
>> +		      int pass_num,
>> +		      int seed,
>> +		      const char *filter)
>> +{
>> +	struct zuc_slinked *curr;
>> +	for (curr = ctx->listeners; curr; curr = curr->next) {
>> +		struct zuc_event_listener *listener = curr->data;
>> +		if (listener->pre_run)
>> +			listener->pre_run(listener->data,
>> +					  pass_count,
>> +					  pass_num,
>> +					  seed,
>> +					  filter);
>> +	}
>> +}
>> +
>> +void dispatch_run_started(struct zuc_context *ctx,
>> +			  int live_case_count,
>> +			  int live_test_count,
>> +			  int disabled_count)
>> +{
>> +	struct zuc_slinked *curr;
>> +	for (curr = ctx->listeners; curr; curr = curr->next) {
>> +		struct zuc_event_listener *listener = curr->data;
>> +		if (listener->run_started)
>> +			listener->run_started(listener->data,
>> +					      live_case_count,
>> +					      live_test_count,
>> +					      disabled_count);
>> +	}
>> +}
>> +
>> +void dispatch_run_ended(struct zuc_context *ctx,
>> +			int live_case_count,
>> +			int live_test_count,
>> +			int total_passed,
>> +			int total_failed,
>> +			int total_disabled,
>> +			long total_elapsed)
>> +{
>> +	struct zuc_slinked *curr;
>> +	for (curr = ctx->listeners; curr; curr = curr->next) {
>> +		struct zuc_event_listener *listener = curr->data;
>> +		if (listener->run_ended)
>> +			listener->run_ended(listener->data,
>> +					    ctx->case_count,
>> +					    ctx->cases,
>> +					    live_case_count,
>> +					    live_test_count,
>> +					    total_passed,
>> +					    total_failed,
>> +					    total_disabled,
>> +					    total_elapsed);
>> +	}
>> +}
>> +
>> +void dispatch_case_started(struct zuc_context *ctx,
>> +			   struct zuc_case *test_case,
>> +			   int live_test_count,
>> +			   int disabled_count)
>> +{
>> +	struct zuc_slinked *curr;
>> +	for (curr = ctx->listeners; curr; curr = curr->next) {
>> +		struct zuc_event_listener *listener = curr->data;
>> +		if (listener->case_started)
>> +			listener->case_started(listener->data,
>> +					       test_case,
>> +					       live_test_count,
>> +					       disabled_count);
>> +	}
>> +}
>> +
>> +void dispatch_case_ended(struct zuc_context *ctx,
>> +			 struct zuc_case *test_case)
>> +{
>> +	struct zuc_slinked *curr;
>> +	for (curr = ctx->listeners; curr; curr = curr->next) {
>> +		struct zuc_event_listener *listener = curr->data;
>> +		if (listener->case_ended)
>> +			listener->case_ended(listener->data, test_case);
>> +	}
>> +}
>> +
>> +void dispatch_test_started(struct zuc_context *ctx,
>> +			   struct zuc_test *test)
>> +{
>> +	struct zuc_slinked *curr;
>> +	for (curr = ctx->listeners; curr; curr = curr->next) {
>> +		struct zuc_event_listener *listener = curr->data;
>> +		if (listener->test_started)
>> +			listener->test_started(listener->data, test);
>> +	}
>> +}
>> +
>> +void dispatch_test_ended(struct zuc_context *ctx,
>> +			 struct zuc_test *test)
>> +{
>> +	struct zuc_slinked *curr;
>> +	for (curr = ctx->listeners; curr; curr = curr->next) {
>> +		struct zuc_event_listener *listener = curr->data;
>> +		if (listener->test_ended)
>> +			listener->test_ended(listener->data, test);
>> +	}
>> +}
>> +
>> +void dispatch_test_disabled(struct zuc_context *ctx,
>> +			    struct zuc_test *test)
>> +{
>> +	struct zuc_slinked *curr;
>> +	for (curr = ctx->listeners; curr; curr = curr->next) {
>> +		struct zuc_event_listener *listener = curr->data;
>> +		if (listener->test_disabled)
>> +			listener->test_disabled(listener->data, test);
>> +	}
>> +}
>> +
>> +void dispatch_check_triggered(struct zuc_context *ctx,
>> +			      char const *file,
>> +			      int line,
>> +			      enum zuc_fail_state state,
>> +			      enum zuc_check_op op,
>> +			      int val1,
>> +			      int val2,
>> +			      const char *expr1,
>> +			      const char *expr2)
>> +{
>> +	struct zuc_slinked *curr;
>> +	for (curr = ctx->listeners; curr; curr = curr->next) {
>> +		struct zuc_event_listener *listener = curr->data;
>> +		if (listener->check_triggered)
>> +			listener->check_triggered(listener->data,
>> +						  file, line,
>> +						  state, op,
>> +						  val1, val2,
>> +						  expr1, expr2);
>> +	}
>> +}
>> +
>> +void dispatch_collect_event(struct zuc_context *ctx,
>> +			    char const *file,
>> +			    int line,
>> +			    const char *expr1)
>> +{
>> +	struct zuc_slinked *curr;
>> +	for (curr = ctx->listeners; curr; curr = curr->next) {
>> +		struct zuc_event_listener *listener = curr->data;
>> +		if (listener->collect_event)
>> +			listener->collect_event(listener->data,
>> +						file, line, expr1);
>> +	}
>> +}
>> +
>> +static int pred2_unknown(int lhs, int rhs)
>> +{
>> +	return 0;
>> +}
>> +
>> +static int pred2_true(int lhs, int rhs)
>> +{
>> +	return lhs;
>> +}
>> +
>> +static int pred2_false(int lhs, int rhs)
>> +{
>> +	return !lhs;
>> +}
>> +
>> +static int pred2_eq(int lhs, int rhs)
>> +{
>> +	return lhs == rhs;
>> +}
>> +
>> +static int pred2_ne(int lhs, int rhs)
>> +{
>> +	return lhs != rhs;
>> +}
>> +
>> +static int pred2_ge(int lhs, int rhs)
>> +{
>> +	return lhs >= rhs;
>> +}
>> +
>> +static int pred2_gt(int lhs, int rhs)
>> +{
>> +	return lhs > rhs;
>> +}
>> +
>> +static int pred2_le(int lhs, int rhs)
>> +{
>> +	return lhs <= rhs;
>> +}
>> +
>> +static int pred2_lt(int lhs, int rhs)
>> +{
>> +	return lhs < rhs;
>> +}
>> +
>> +comp_pred2 get_pred2(enum zuc_check_op op)
>> +{
>> +	switch (op) {
>> +	case ZUC_OP_TRUE:
>> +		return pred2_true;
>> +		break;
>> +	case ZUC_OP_FALSE:
>> +		return pred2_false;
>> +		break;
>> +	case ZUC_OP_EQ:
>> +		return pred2_eq;
>> +		break;
>> +	case ZUC_OP_NE:
>> +		return pred2_ne;
>> +		break;
>> +	case ZUC_OP_GE:
>> +		return pred2_ge;
>> +		break;
>> +	case ZUC_OP_GT:
>> +		return pred2_gt;
>> +		break;
>> +	case ZUC_OP_LE:
>> +		return pred2_le;
>> +		break;
>> +	case ZUC_OP_LT:
>> +		return pred2_lt;
>> +		break;
>> +	default:
>> +		return pred2_unknown;
>> +	}
>> +}
>> diff --git a/tools/zunitc/test/fixtures_test.c b/tools/zunitc/test/fixtures_test.c
>> new file mode 100644
>> index 0000000..7a79d49
>> --- /dev/null
>> +++ b/tools/zunitc/test/fixtures_test.c
>> @@ -0,0 +1,102 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +/**
>> + * Tests of fixtures.
>> + */
>> +
>> +#include "config.h"
>> +
>> +#include <ctype.h>
>> +#include <stdlib.h>
>> +#include <stddef.h>
>> +#include <string.h>
>> +
>> +#include "zunitc/zunitc.h"
>> +
>> +
>> +
>> +/* Use a simple string for a simplistic fixture */
>> +static struct zuc_fixture fixture_minimal = {
>> +	.data = "for all good men to",
>> +};
>> +
>> +ZUC_TEST_F(fixture_minimal, just_as_is)
>> +{
>> +	const char *str = data;
>> +	ZUC_ASSERT_TRUE(str != NULL);
>> +
>> +	ZUC_ASSERT_EQ(0, strcmp("for all good men to", str));
>> +}
>> +
>> +/*
>> + * Not important what or how data is manipulated, just that this function
>> + * does something non-transparent to it.
>> + */
>> +static void *setup_test_config(void *data)
>> +{
>> +	int i;
>> +	const char *str = data;
>> +	char *upper = NULL;
>> +	ZUC_EXPECT_TRUE(data != NULL);
>> +	if (str) {
>> +		upper = strdup(str);
>> +		ZUC_EXPECT_TRUE(upper != NULL);
>> +		if (upper) {
>> +			for (i = 0; upper[i]; ++i)
>> +				upper[i] = (char)toupper(upper[i]);
>> +		}
>> +	}
>> +
>> +	return upper;
>> +}
>> +
>> +static void teardown_test_config(void *data)
>> +{
>> +	ZUC_ASSERT_TRUE(data != NULL);
>> +	free(data);
>> +}
>> +
>> +static struct zuc_fixture fixture_data0 = {
>> +	.data = "Now is the time",
>> +	.set_up = setup_test_config,
>> +	.tear_down = teardown_test_config
>> +};
>> +
>> +ZUC_TEST_F(fixture_data0, base)
>> +{
>> +	const char *str = data;
>> +	ZUC_ASSERT_TRUE(str != NULL);
>> +
>> +	ZUC_ASSERT_EQ(0, strcmp("NOW IS THE TIME", str));
>> +}
>> +
>> +/* Use the same fixture for a second test. */
>> +ZUC_TEST_F(fixture_data0, no_lower)
>> +{
>> +	int i;
>> +	const char *str = data;
>> +	ZUC_ASSERT_TRUE(str != NULL);
>> +
>> +	for (i = 0; str[i]; ++i)
>> +		ZUC_ASSERT_EQ(0, islower(str[i]));
>> +}
>> diff --git a/tools/zunitc/test/zunitc_test.c b/tools/zunitc/test/zunitc_test.c
>> new file mode 100644
>> index 0000000..434026b
>> --- /dev/null
>> +++ b/tools/zunitc/test/zunitc_test.c
>> @@ -0,0 +1,314 @@
>> +/*
>> + * Copyright © 2015 Samsung Electronics Co., Ltd
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and
>> + * its documentation for any purpose is hereby granted without fee, provided
>> + * that the above copyright notice appear in all copies and that both that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be used in
>> + * advertising or publicity pertaining to distribution of the software
>> + * without specific, written prior permission.  The copyright holders make
>> + * no representations about the suitability of this software for any
>> + * purpose.  It is provided "as is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +/*
>> + * A simple file to show tests being setup and run.
>> + */
>> +
>> +#include "config.h"
>> +
>> +#include <stddef.h>
>> +
>> +#include "zunitc/zunitc.h"
>> +
>> +/* #define ENABLE_FAIL_TESTS */
>> +/* #define ENABLE_SKIP_TESTS */
>> +
>> +ZUC_TEST(base_test, math_is_sane)
>> +{
>> +	ZUC_EXPECT_EQ(4, 2 + 2);
>> +}
>> +
>> +ZUC_TEST(base_test, math_is_hard)
>> +{
>> +	ZUC_TRACEPOINT("Tracepoint here.");
>> +
>> +	ZUC_TRACEPOINT("Checking %d", 4);
>> +
>> +#ifdef ENABLE_FAIL_TESTS
>> +
>> +	ZUC_EXPECT_EQ(5, 2 + 2);
>> +	ZUC_TRACEPOINT("flip %1.3f", 3.1415927);
>> +
>> +	ZUC_EXPECT_EQ(7, 9);
>> +#endif
>> +}
>> +
>> +#ifdef ENABLE_FAIL_TESTS
>> +ZUC_TEST(base_test, tracepoint_after_assert)
>> +{
>> +	ZUC_TRACEPOINT("Should be seen in output");
>> +
>> +	ZUC_ASSERT_EQ(5, 2 + 2);
>> +
>> +	ZUC_TRACEPOINT("Should NOT be seen in output");
>> +}
>> +#endif
>> +
>> +ZUC_TEST(base_test, math_is_more_hard)
>> +{
>> +#ifdef ENABLE_FAIL_TESTS
>> +	ZUC_ASSERT_EQ(5, 2 + 2);
>> +	ZUC_ASSERT_EQ(7, 9);
>> +#endif
>> +}
>> +
>> +ZUC_TEST(base_test, time_counted)
>> +{
>> +	ZUC_TRACEPOINT("Never seen");
>> +
>> +	ZUC_TRACEPOINT("Sleepy Time %d", 10000 * 5);
>> +	ZUC_EXPECT_EQ(0, usleep(10000 * 5)); /* 50ms to show up in reporting */
>> +}
>> +
>> +ZUC_TEST(other_test, math_monkey)
>> +{
>> +	ZUC_EXPECT_TRUE(1);
>> +	ZUC_EXPECT_TRUE(3);
>> +	ZUC_EXPECT_FALSE(0);
>> +
>> +	ZUC_ASSERT_TRUE(1);
>> +	ZUC_ASSERT_TRUE(3);
>> +	ZUC_ASSERT_FALSE(0);
>> +
>> +	ZUC_EXPECT_EQ(5, 2 + 3);
>> +	ZUC_ASSERT_EQ(5, 2 + 3);
>> +
>> +	int b = 9;
>> +	ZUC_EXPECT_NE(1, 2);
>> +	ZUC_EXPECT_NE(b, b + 2);
>> +
>> +	ZUC_ASSERT_NE(1, 2);
>> +	ZUC_ASSERT_NE(b, b + 1);
>> +
>> +	ZUC_EXPECT_LT(1, 2);
>> +	ZUC_ASSERT_LT(1, 3);
>> +
>> +	ZUC_EXPECT_LE(1, 2);
>> +	ZUC_ASSERT_LE(1, 3);
>> +
>> +	ZUC_EXPECT_LE(1, 1);
>> +	ZUC_ASSERT_LE(1, 1);
>> +
>> +	ZUC_EXPECT_GT(2, 1);
>> +	ZUC_ASSERT_GT(3, 1);
>> +
>> +	ZUC_EXPECT_GE(1, 1);
>> +	ZUC_ASSERT_GE(1, 1);
>> +
>> +	ZUC_EXPECT_GE(2, 1);
>> +	ZUC_ASSERT_GE(3, 1);
>> +}
>> +
>> +
>> +static void force_non_fatal_failure(void)
>> +{
>> +#ifdef ENABLE_FAIL_TESTS
>> +	bool expected_to_fail_here = true;
>> +	ZUC_EXPECT_FALSE(expected_to_fail_here);
>> +#endif
>> +}
>> +
>> +static void force_fatal_failure(void)
>> +{
>> +#ifdef ENABLE_FAIL_TESTS
>> +	bool expected_to_fail_here = true;
>> +	ZUC_ASSERT_FALSE(expected_to_fail_here);
>> +
>> +	ZUC_FATAL("Should never reach here");
>> +	ZUC_ASSERT_NE(1, 1);
>> +#endif
>> +}
>> +
>> +#ifdef ENABLE_FAIL_TESTS
>> +ZUC_TEST(infrastructure, fail_keeps_testing)
>> +{
>> +	ZUC_FAIL("Time to fail testing");
>> +
>> +	ZUC_FATAL("Should always reach here");
>> +	ZUC_ASSERT_NE(1, 1); /* in case ZUC_FATAL doesn't work. */
>> +}
>> +#endif
>> +
>> +#ifdef ENABLE_FAIL_TESTS
>> +ZUC_TEST(infrastructure, fatal_stops_test)
>> +{
>> +	ZUC_FATAL("Time to kill testing");
>> +
>> +	ZUC_FATAL("Should never reach here");
>> +	ZUC_ASSERT_NE(1, 1); /* in case ZUC_FATAL doesn't work. */
>> +}
>> +#endif
>> +
>> +#ifdef ENABLE_SKIP_TESTS
>> +ZUC_TEST(infrastructure, skip_stops_test)
>> +{
>> +	ZUC_SKIP("Time to skip testing");
>> +
>> +	ZUC_FATAL("Should never reach here");
>> +	ZUC_ASSERT_NE(1, 1); /* in case ZUC_FATAL doesn't work. */
>> +}
>> +#endif
>> +
>> +struct fixture_data {
>> +	int case_counter;
>> +	int test_counter;
>> +};
>> +
>> +static struct fixture_data fixture_info = {0, 0};
>> +
>> +static void *complex_test_set_up_case(const void *data)
>> +{
>> +	fixture_info.case_counter++;
>> +	return &fixture_info;
>> +}
>> +
>> +static void complex_test_tear_down_case(void *data)
>> +{
>> +	ZUC_EXPECT_TRUE(&fixture_info == data);
>> +	fixture_info.case_counter--;
>> +}
>> +
>> +static void *complex_test_set_up(void *data)
>> +{
>> +	fixture_info.test_counter = fixture_info.case_counter;
>> +	return &fixture_info;
>> +}
>> +
>> +static void complex_test_tear_down(void *data)
>> +{
>> +	ZUC_ASSERT_EQ(1, fixture_info.case_counter);
>> +}
>> +
>> +struct zuc_fixture complex_test = {
>> +	.set_up = complex_test_set_up,
>> +	.tear_down = complex_test_tear_down,
>> +	.set_up_test_case = complex_test_set_up_case,
>> +	.tear_down_test_case = complex_test_tear_down_case
>> +};
>> +
>> +/*
>> + * Note that these next cases all try to modify the test_counter member,
>> + * but the fixture should reset that.
>> +*/
>> +
>> +ZUC_TEST_F(complex_test, bases_cenario)
>> +{
>> +	struct fixture_data *fdata = data;
>> +	ZUC_ASSERT_TRUE(fdata != NULL);
>> +
>> +	ZUC_EXPECT_EQ(4, 3 + 1);
>> +	ZUC_EXPECT_EQ(1, fdata->case_counter);
>> +	ZUC_EXPECT_EQ(1, fdata->test_counter);
>> +	fdata->test_counter++;
>> +	ZUC_EXPECT_EQ(2, fdata->test_counter);
>> +}
>> +
>> +ZUC_TEST_F(complex_test, something)
>> +{
>> +	struct fixture_data *fdata = data;
>> +	ZUC_ASSERT_TRUE(fdata != NULL);
>> +
>> +	ZUC_EXPECT_EQ(4, 3 + 1);
>> +	ZUC_EXPECT_EQ(1, fdata->case_counter);
>> +	ZUC_EXPECT_EQ(1, fdata->test_counter);
>> +	fdata->test_counter++;
>> +	ZUC_EXPECT_EQ(2, fdata->test_counter);
>> +}
>> +
>> +ZUC_TEST_F(complex_test, else_here)
>> +{
>> +	struct fixture_data *fdata = data;
>> +	ZUC_ASSERT_TRUE(fdata != NULL);
>> +
>> +	ZUC_EXPECT_EQ(4, 3 + 1);
>> +	ZUC_EXPECT_EQ(1, fdata->case_counter);
>> +	ZUC_EXPECT_EQ(1, fdata->test_counter);
>> +	fdata->test_counter++;
>> +	ZUC_EXPECT_EQ(2, fdata->test_counter);
>> +}
>> +
>> +ZUC_TEST(more, DISABLED_not_run)
>> +{
>> +	ZUC_ASSERT_EQ(1, 2);
>> +}
>> +
>> +ZUC_TEST(more, failure_states)
>> +{
>> +#ifdef ENABLE_FAIL_TESTS
>> +	bool expected_to_fail_here = true;
>> +#endif
>> +
>> +	ZUC_EXPECT_FALSE(zuc_has_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_nonfatal_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_fatal_failure());
>> +
>> +#ifdef ENABLE_FAIL_TESTS
>> +	ZUC_EXPECT_FALSE(expected_to_fail_here); /* should fail */
>> +
>> +	ZUC_EXPECT_TRUE(zuc_has_failure());
>> +	ZUC_EXPECT_TRUE(zuc_has_nonfatal_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_fatal_failure());
>> +#endif
>> +}
>> +
>> +ZUC_TEST(more, failure_sub_nonfatal)
>> +{
>> +	ZUC_EXPECT_FALSE(zuc_has_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_nonfatal_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_fatal_failure());
>> +
>> +	force_non_fatal_failure();
>> +
>> +#ifdef ENABLE_FAIL_TESTS
>> +	ZUC_EXPECT_TRUE(zuc_has_failure());
>> +	ZUC_EXPECT_TRUE(zuc_has_nonfatal_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_fatal_failure());
>> +#endif
>> +}
>> +
>> +ZUC_TEST(more, failure_sub_fatal)
>> +{
>> +	ZUC_EXPECT_FALSE(zuc_has_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_nonfatal_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_fatal_failure());
>> +
>> +	force_fatal_failure();
>> +
>> +#ifdef ENABLE_FAIL_TESTS
>> +	ZUC_EXPECT_TRUE(zuc_has_failure());
>> +	ZUC_EXPECT_FALSE(zuc_has_nonfatal_failure());
>> +	ZUC_EXPECT_TRUE(zuc_has_fatal_failure());
>> +#endif
>> +}
>> +
>> +ZUC_TEST(base_test, later)
>> +{
>> +	/* an additional test for the same case but later in source */
>> +	ZUC_EXPECT_EQ(3, 5 - 2);
>> +}
>> +
>> +ZUC_TEST(base_test, zed)
>> +{
>> +	/* an additional test for the same case but later in source */
>> +	ZUC_EXPECT_EQ(3, 5 - 2);
>> +}
>> -- 
>> 2.1.0
>>
>> _______________________________________________
>> wayland-devel mailing list
>> wayland-devel at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>>

-- 
Jon A. Cruz - Senior Open Source Developer
Samsung Open Source Group
jonc at osg.samsung.com


More information about the wayland-devel mailing list