diff --git a/Makefile.am b/Makefile.am index c764b4682..7a1eb7bb3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = deps cogl tests +SUBDIRS = deps test-fixtures cogl tests if BUILD_COGL_PANGO SUBDIRS += cogl-pango diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 9622c1c4f..4036ab26c 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -567,13 +567,16 @@ if !USE_GLIB libcogl_la_LIBADD += $(top_builddir)/deps/glib/libglib.la libcogl_la_LIBADD += $(top_builddir)/deps/gmodule/libgmodule.la endif +if UNIT_TESTS +libcogl_la_LIBADD += $(top_builddir)/test-fixtures/libtest-fixtures.la +endif # XXX: The aim is to eventually get rid of all private API exports # for cogl-pango. libcogl_la_LDFLAGS = \ -no-undefined \ -version-info @COGL_LT_CURRENT@:@COGL_LT_REVISION@:@COGL_LT_AGE@ \ -export-dynamic \ - -export-symbols-regex "^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_foreach_sub_texture_in_region|_cogl_atlas_texture_new_with_size|_cogl_profile_trace_message|_cogl_context_get_default).*" + -export-symbols-regex "^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_foreach_sub_texture_in_region|_cogl_atlas_texture_new_with_size|_cogl_profile_trace_message|_cogl_context_get_default|test_|unit_test_).*" libcogl_la_SOURCES = $(cogl_sources_c) nodist_libcogl_la_SOURCES = $(BUILT_SOURCES) @@ -690,6 +693,9 @@ Cogl-1.0.gir: libcogl.la Makefile Cogl_1_0_gir_NAMESPACE = Cogl Cogl_1_0_gir_VERSION = 1.0 Cogl_1_0_gir_LIBS = libcogl.la +if UNIT_TESTS +Cogl_1_0_gir_LIBS += $(top_builddir)/test-fixtures/libtest-fixtures.la +endif Cogl_1_0_gir_FILES = $(cogl_1_public_h) cogl-enum-types.h Cogl_1_0_gir_CFLAGS = $(AM_CPPFLAGS) $(COGL_DEP_CFLAGS) -UCOGL_ENABLE_EXPERIMENTAL_API -UCOGL_ENABLE_EXPERIMENTAL_2_0_API Cogl_1_0_gir_INCLUDES = GL-1.0 GObject-2.0 diff --git a/cogl/driver/gl/cogl-pipeline-opengl.c b/cogl/driver/gl/cogl-pipeline-opengl.c index 86d6124c6..735a45ccd 100644 --- a/cogl/driver/gl/cogl-pipeline-opengl.c +++ b/cogl/driver/gl/cogl-pipeline-opengl.c @@ -25,9 +25,7 @@ * Robert Bragg */ -#ifdef HAVE_CONFIG_H #include "config.h" -#endif #include "cogl-debug.h" #include "cogl-util-gl-private.h" @@ -41,6 +39,8 @@ #include "cogl-pipeline-progend-glsl-private.h" +#include + #include #include @@ -444,6 +444,38 @@ flush_depth_state (CoglContext *ctx, } } +UNIT_TEST (check_gl_blend_enable, + 0 /* no requirements */, + 0 /* no failure cases */) +{ + CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); + + /* By default blending should be disabled */ + g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0); + + cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1); + _cogl_framebuffer_flush_journal (test_fb); + + /* After drawing an opaque rectangle blending should still be + * disabled */ + g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0); + + cogl_pipeline_set_color4f (pipeline, 0, 0, 0, 0); + cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1); + _cogl_framebuffer_flush_journal (test_fb); + + /* After drawing a transparent rectangle blending should be enabled */ + g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 1); + + cogl_pipeline_set_blend (pipeline, "RGBA=ADD(SRC_COLOR, 0)", NULL); + cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1); + _cogl_framebuffer_flush_journal (test_fb); + + /* After setting a blend string that effectively disables blending + * then blending should be disabled */ + g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0); +} + static void _cogl_pipeline_flush_color_blend_alpha_depth_state ( CoglPipeline *pipeline, diff --git a/configure.ac b/configure.ac index daadfc74c..ea5bc174b 100644 --- a/configure.ac +++ b/configure.ac @@ -277,6 +277,18 @@ AS_CASE( AC_SUBST(COGL_DEBUG_CFLAGS) +AC_ARG_ENABLE( + [unit-tests], + [AC_HELP_STRING([--enable-unit-tests=@<:@no/yes@:>@], [Build Cogl unit tests @<:@default=yes@:>@])], + [], + enable_unit_tests=yes +) +AS_IF([test "x$enable_unit_tests" = "xyes"], + [ + AC_DEFINE([ENABLE_UNIT_TESTS], [1], [Whether to enable building unit tests]) + ] +) +AM_CONDITIONAL(UNIT_TESTS, test "x$enable_unit_tests" = "xyes") dnl ============================================================ dnl Enable cairo usage for debugging @@ -1361,6 +1373,7 @@ deps/Makefile deps/glib/Makefile deps/gmodule/Makefile deps/gmodule/gmoduleconf.h +test-fixtures/Makefile cogl/Makefile cogl/cogl-1.0.pc cogl/cogl-2.0-experimental.pc @@ -1384,9 +1397,9 @@ doc/reference/cogl-2.0-experimental/Makefile doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml examples/Makefile tests/Makefile +tests/config.env tests/conform/Makefile -tests/conform/config.env -tests/conform/test-launcher.sh +tests/unit/Makefile tests/micro-perf/Makefile tests/data/Makefile po/Makefile.in @@ -1443,6 +1456,7 @@ echo "" echo " • Extra:" echo " Build API reference: ${enable_gtk_doc}" echo " Build introspection data: ${enable_introspection}" +echo " Build unit tests: ${enable_unit_tests}" echo " Enable internationalization: ${USE_NLS}" echo "" diff --git a/test-fixtures/Makefile.am b/test-fixtures/Makefile.am new file mode 100644 index 000000000..62fd9d1f7 --- /dev/null +++ b/test-fixtures/Makefile.am @@ -0,0 +1,24 @@ + +noinst_LTLIBRARIES = libtest-fixtures.la + +libtest_fixtures_la_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_builddir)/cogl \ + -Wall \ + $(NULL) + +if !USE_GLIB +libtest_fixtures_la_CPPFLAGS += -I$(top_builddir)/deps/glib +endif + +libtest_fixtures_la_CPPFLAGS += \ + -DCOGL_DISABLE_DEPRECATED \ + -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\" \ + -DCOGL_COMPILATION + +libtest_fixtures_la_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) + +libtest_fixtures_la_SOURCES = \ + test-utils.h \ + test-utils.c + diff --git a/test-fixtures/test-unit.h b/test-fixtures/test-unit.h new file mode 100644 index 000000000..270a94134 --- /dev/null +++ b/test-fixtures/test-unit.h @@ -0,0 +1,31 @@ +#ifndef _TEST_UNIT_H_ +#define _TEST_UNIT_H_ + +#include + +#ifdef ENABLE_UNIT_TESTS + +typedef struct _CoglUnitTest +{ + const char *name; + TestFlags requirement_flags; + TestFlags known_failure_flags; + void (*run) (void); +} CoglUnitTest; + +#define UNIT_TEST(NAME, REQUIREMENT_FLAGS, KNOWN_FAILURE_FLAGS) \ + static void NAME (void); \ + \ + const CoglUnitTest unit_test_##NAME = \ + { #NAME, REQUIREMENT_FLAGS, KNOWN_FAILURE_FLAGS, NAME }; \ + \ + static void NAME (void) + +#else /* ENABLE_UNIT_TESTS */ + +#define UNIT_TEST(NAME, REQUIREMENT_FLAGS, KNOWN_FAILURE_FLAGS) \ + static inline void NAME (void) + +#endif /* ENABLE_UNIT_TESTS */ + +#endif /* _TEST_UNIT_H_ */ diff --git a/tests/conform/test-utils.c b/test-fixtures/test-utils.c similarity index 99% rename from tests/conform/test-utils.c rename to test-fixtures/test-utils.c index 827b9dc21..2c92007cf 100644 --- a/tests/conform/test-utils.c +++ b/test-fixtures/test-utils.c @@ -1,7 +1,9 @@ -#define COGL_ENABLE_EXPERIMENTAL_2_0_API +#include + #include #include +#include "test-unit.h" #include "test-utils.h" #define FB_WIDTH 512 diff --git a/tests/conform/test-utils.h b/test-fixtures/test-utils.h similarity index 99% rename from tests/conform/test-utils.h rename to test-fixtures/test-utils.h index 49dbe1b52..b5ecdd10e 100644 --- a/tests/conform/test-utils.h +++ b/test-fixtures/test-utils.h @@ -1,6 +1,7 @@ #ifndef _TEST_UTILS_H_ #define _TEST_UTILS_H_ +#include #include /* We don't really care about functions that are defined without a diff --git a/tests/Makefile.am b/tests/Makefile.am index f13c8a181..e23762ade 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,11 +1,23 @@ -SUBDIRS = conform micro-perf data +SUBDIRS = conform -DIST_SUBDIRS = conform micro-perf data +if UNIT_TESTS +SUBDIRS += unit +endif -EXTRA_DIST = README +SUBDIRS += micro-perf data +DIST_SUBDIRS = conform unit micro-perf data + +EXTRA_DIST = README test-launcher.sh run-tests.sh + +if UNIT_TESTS test conform: ( cd ./conform && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$? + ( cd ./unit && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$? +else +test conform: + ( cd ./conform && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$? +endif .PHONY: test conform diff --git a/tests/conform/config.env.in b/tests/config.env.in similarity index 100% rename from tests/conform/config.env.in rename to tests/config.env.in diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index eddb95884..ee10ac0e8 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -5,8 +5,6 @@ NULL = noinst_PROGRAMS = test-conformance common_sources = \ - test-utils.h \ - test-utils.c \ test-conform-main.c \ $(NULL) @@ -94,7 +92,7 @@ wrappers: stamp-test-conformance stamp-test-conformance: Makefile $(srcdir)/test-conform-main.c @mkdir -p wrappers @sed -n -e 's/^ \{1,\}ADD_TEST *( *\([a-zA-Z0-9_]\{1,\}\).*/\1/p' $(srcdir)/test-conform-main.c > unit-tests - @chmod +x test-launcher.sh + @chmod +x $(top_srcdir)/tests/test-launcher.sh @( echo "/stamp-test-conformance" ; \ echo "/test-conformance$(EXEEXT)" ; \ echo "*.o" ; \ @@ -104,7 +102,7 @@ stamp-test-conformance: Makefile $(srcdir)/test-conform-main.c do \ unit=`basename $$i | sed -e s/_/-/g`; \ echo " GEN $$unit"; \ - ( echo "#!/bin/sh" ; echo "$(abs_builddir)/test-launcher.sh '$$i' \"\$$@\"" ) > $$unit$(SHEXT) ; \ + ( echo "#!/bin/sh" ; echo "$(top_srcdir)/tests/test-launcher.sh $(abs_builddir)/test-conformance$(EXEEXT) '' '$$i' \"\$$@\"" ) > $$unit$(SHEXT) ; \ chmod +x $$unit$(SHEXT); \ echo "/$$unit$(SHEXT)" >> .gitignore; \ done \ @@ -129,6 +127,7 @@ BUILT_SOURCES = wrappers # testing (such as test-bitmask) will still compile AM_CPPFLAGS = \ -I$(top_srcdir) \ + -I$(top_srcdir)/test-fixtures \ -I$(top_builddir)/cogl if !USE_GLIB @@ -145,6 +144,7 @@ test_conformance_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) test_conformance_LDADD = \ $(COGL_DEP_LIBS) \ $(top_builddir)/cogl/libcogl.la \ + $(top_builddir)/test-fixtures/libtest-fixtures.la \ $(LIBM) if !USE_GLIB test_conformance_LDADD += $(top_builddir)/deps/glib/libglib.la @@ -152,7 +152,7 @@ endif test_conformance_LDFLAGS = -export-dynamic test: wrappers - @$(top_srcdir)/tests/conform/run-tests.sh $(abs_builddir)/config.env + @$(top_srcdir)/tests/run-tests.sh $(abs_builddir)/../config.env $(abs_builddir)/test-conformance$(EXEEXT) # XXX: we could prevent the conformance test suite from running # by simply defining this variable conditionally diff --git a/tests/conform/test-launcher.sh.in b/tests/conform/test-launcher.sh.in deleted file mode 100755 index 1c29003d0..000000000 --- a/tests/conform/test-launcher.sh.in +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -UNIT_TEST=$1 -shift - -test -z ${UNIT_TEST} && { - echo "Usage: $0 UNIT_TEST" - exit 1 -} - -UNIT_TEST=`echo $UNIT_TEST|sed 's/-/_/g'` - -echo "Running: ./test-conformance ${UNIT_TEST} $@" -echo "" -if test -f @abs_builddir@/test-conformance; then - TEST_CONFORMANCE=@abs_builddir@/test-conformance -elif test -f @abs_builddir@/test-conformance.exe; then - TEST_CONFORMANCE=@abs_builddir@/test-conformance.exe -fi -COGL_TEST_VERBOSE=1 $TEST_CONFORMANCE ${UNIT_TEST} "$@" -exit_val=$? - -echo "" -echo "NOTE: For debugging purposes, you can run this single test as follows:" -echo "$ libtool --mode=execute \\" -echo " gdb --eval-command=\"b ${UNIT_TEST}\" \\" -echo " --args ./test-conformance ${UNIT_TEST}" -echo "or:" -echo "$ env G_SLICE=always-malloc \\" -echo " libtool --mode=execute \\" -echo " valgrind ./test-conformance ${UNIT_TEST}" - -exit $exit_val diff --git a/tests/conform/run-tests.sh b/tests/run-tests.sh similarity index 93% rename from tests/conform/run-tests.sh rename to tests/run-tests.sh index 11e740a2a..a00494338 100755 --- a/tests/conform/run-tests.sh +++ b/tests/run-tests.sh @@ -1,6 +1,12 @@ #!/bin/bash -. $1 +ENVIRONMENT_CONFIG=$1 +shift + +TEST_BINARY=$1 +shift + +. $ENVIRONMENT_CONFIG set +m @@ -13,12 +19,6 @@ EXIT=0 MISSING_FEATURE="WARNING: Missing required feature"; KNOWN_FAILURE="WARNING: Test is known to fail"; -if test -f ./test-conformance; then - TEST_CONFORMANCE=./test-conformance -elif test -f ./test-conformance.exe; then - TEST_CONFORMANCE=./test-conformance.exe -fi - echo "Key:" echo "ok = Test passed" echo "n/a = Driver is missing a feature required for the test" @@ -54,7 +54,7 @@ get_status() run_test() { - $($TEST_CONFORMANCE $1 &>.log) + $($TEST_BINARY $1 &>.log) TMP=$? var_name=$2_result eval $var_name=$TMP diff --git a/tests/test-launcher.sh b/tests/test-launcher.sh new file mode 100755 index 000000000..e159e2e49 --- /dev/null +++ b/tests/test-launcher.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +TEST_BINARY=$1 +shift + +SYMBOL_PREFIX=$1 +shift + +UNIT_TEST=$1 +shift + +test -z ${UNIT_TEST} && { + echo "Usage: $0 UNIT_TEST" + exit 1 +} + +BINARY_NAME=`basename $TEST_BINARY` +UNIT_TEST=`echo $UNIT_TEST|sed 's/-/_/g'` + +echo "Running: ./$BINARY_NAME ${UNIT_TEST} $@" +echo "" +COGL_TEST_VERBOSE=1 $TEST_BINARY ${UNIT_TEST} "$@" +exit_val=$? + +if test $exit_val -eq 0; then + echo "OK" +fi + +echo "" +echo "NOTE: For debugging purposes, you can run this single test as follows:" +echo "$ libtool --mode=execute \\" +echo " gdb --eval-command=\"start\" --eval-command=\"b ${UNIT_TEST#${SYMBOL_PREFIX}}\" \\" +echo " --args ./$BINARY_NAME ${UNIT_TEST}" +echo "or:" +echo "$ env G_SLICE=always-malloc \\" +echo " libtool --mode=execute \\" +echo " valgrind ./$BINARY_NAME ${UNIT_TEST}" + +exit $exit_val diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am new file mode 100644 index 000000000..7ed2e0e6f --- /dev/null +++ b/tests/unit/Makefile.am @@ -0,0 +1,97 @@ +include $(top_srcdir)/build/autotools/Makefile.am.silent + +NULL = + +noinst_PROGRAMS = test-unit + +test_unit_SOURCES = test-unit-main.c + +if OS_WIN32 +SHEXT = +else +SHEXT = $(EXEEXT) +endif + +# For convenience, this provides a way to easily run individual unit tests: +.PHONY: wrappers clean-wrappers + +wrappers: stamp-test-unit + @true +stamp-test-unit: Makefile test-unit + @mkdir -p wrappers + source $(top_builddir)/cogl/libcogl.la ; \ + $(NM) $(top_builddir)/cogl/.libs/"$$dlname"| \ + grep 'D unit_test_'|sed 's/.\+ D //' > unit-tests + @chmod +x $(top_srcdir)/tests/test-launcher.sh + @( echo "/stamp-test-unit" ; \ + echo "/test-unit$(EXEEXT)" ; \ + echo "*.o" ; \ + echo ".gitignore" ; \ + echo "unit-tests" ; ) > .gitignore + @for i in `cat unit-tests`; \ + do \ + unit=`echo $$i | sed -e s/_/-/g | sed s/unit-test-//`; \ + echo " GEN $$unit"; \ + ( echo "#!/bin/sh" ; echo "$(top_srcdir)/tests/test-launcher.sh $(abs_builddir)/test-unit$(EXEEXT) 'unit_test_' '$$i' \"\$$@\"" ) > $$unit$(SHEXT) ; \ + chmod +x $$unit$(SHEXT); \ + echo "/$$unit$(SHEXT)" >> .gitignore; \ + done \ + && echo timestamp > $(@F) + +clean-wrappers: + @for i in `cat unit-tests`; \ + do \ + unit=`echo $$i | sed -e s/_/-/g | sed s/unit-test-//`; \ + echo " RM $$unit"; \ + rm -f $$unit$(SHEXT) ; \ + done \ + && rm -f unit-tests \ + && rm -f stamp-test-unit + +# NB: BUILT_SOURCES here a misnomer. We aren't building source, just inserting +# a phony rule that will generate symlink scripts for running individual tests +BUILT_SOURCES = wrappers + +# The include of the $(buildir)/cogl directory here is to make it so +# that tests that directly include Cogl source code for whitebox +# testing (such as test-bitmask) will still compile +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/test-fixtures \ + -I$(top_builddir)/cogl + +if !USE_GLIB +AM_CPPFLAGS += -I$(top_builddir)/deps/glib +endif + +AM_CPPFLAGS += \ + -DCOGL_DISABLE_DEPRECATED \ + -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\" \ + -DCOGL_COMPILATION + +test_unit_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) +test_unit_LDADD = \ + $(COGL_DEP_LIBS) \ + $(top_builddir)/cogl/libcogl.la \ + $(top_builddir)/test-fixtures/libtest-fixtures.la \ + $(LIBM) +if !USE_GLIB +test_unit_LDADD += $(top_builddir)/deps/glib/libglib.la +endif +test_unit_LDFLAGS = -export-dynamic + +test: wrappers + @$(top_srcdir)/tests/run-tests.sh $(abs_builddir)/../config.env $(abs_builddir)/test-unit$(EXEEXT) + +# XXX: we could prevent the unit test suite from running +# by simply defining this variable conditionally +TEST_PROGS = test-unit + +.PHONY: test + +DISTCLEANFILES = .gitignore + +# we override the clean-generic target to clean up the wrappers so +# we cannot use CLEANFILES +clean-generic: clean-wrappers + $(QUIET_RM)rm -f .log diff --git a/tests/unit/test-unit-main.c b/tests/unit/test-unit-main.c new file mode 100644 index 000000000..f78399ad0 --- /dev/null +++ b/tests/unit/test-unit-main.c @@ -0,0 +1,41 @@ +#include + +#include + +#include + +int +main (int argc, char **argv) +{ + const CoglUnitTest *unit_test; + int i; + + if (argc != 2) + { + g_printerr ("usage %s UNIT_TEST\n", argv[0]); + exit (1); + } + + /* Just for convenience in case people try passing the wrapper + * filenames for the UNIT_TEST argument we normalize '-' characters + * to '_' characters... */ + for (i = 0; argv[1][i]; i++) + { + if (argv[1][i] == '-') + argv[1][i] = '_'; + } + + unit_test = dlsym (RTLD_DEFAULT, argv[1]); + if (!unit_test) + { + g_printerr ("Unknown test name \"%s\"\n", argv[1]); + return 1; + } + + test_utils_init (unit_test->requirement_flags, + unit_test->known_failure_flags); + unit_test->run (); + test_utils_fini (); + + return 0; +}