diff --git a/Makefile.am b/Makefile.am
index e81c0bc44..95c5701f9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = src
+SUBDIRS = src test
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = harfbuzz.pc
diff --git a/test/Makefile.am b/test/Makefile.am
index e69de29bb..55d3976b0 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -0,0 +1,18 @@
+include Makefile.decl
+
+if HAVE_GLIB
+AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir)/src/
+LDADD = $(GLIB_LIBS) $(top_builddir)/src/libharfbuzz.la
+
+check_PROGRAMS = $(TEST_PROGS)
+
+TEST_PROGS += test-types
+
+
+else
+check-am:
+ @echo "You need to have glib support enabled to run the tests"
+ @exit 77
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/test/Makefile.decl b/test/Makefile.decl
new file mode 100644
index 000000000..c226169a8
--- /dev/null
+++ b/test/Makefile.decl
@@ -0,0 +1,90 @@
+GTESTER = gtester # for non-GLIB packages
+#GTESTER = $(top_builddir)/glib/gtester # for the GLIB package
+#GTESTER_REPORT = $(top_builddir)/glib/gtester-report # for the GLIB package
+
+# initialize variables for unconditional += appending
+EXTRA_DIST =
+TEST_PROGS =
+
+### testing rules
+
+# test: run all tests in cwd and subdirs
+test: test-nonrecursive
+ @ for subdir in $(SUBDIRS) . ; do \
+ test "$$subdir" = "." -o "$$subdir" = "po" || \
+ ( cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
+ done
+
+# test-nonrecursive: run tests only in cwd
+test-nonrecursive: ${TEST_PROGS}
+ @test -z "${TEST_PROGS}" || MALLOC_CHECK_=2 MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) ${GTESTER} --verbose ${TEST_PROGS}
+
+# test-report: run tests in subdirs and generate report
+# perf-report: run tests in subdirs with -m perf and generate report
+# full-report: like test-report: with -m perf and -m slow
+test-report perf-report full-report: ${TEST_PROGS}
+ @test -z "${TEST_PROGS}" || { \
+ case $@ in \
+ test-report) test_options="-k";; \
+ perf-report) test_options="-k -m=perf";; \
+ full-report) test_options="-k -m=perf -m=slow";; \
+ esac ; \
+ if test -z "$$GTESTER_LOGDIR" ; then \
+ ${GTESTER} --verbose $$test_options -o test-report.xml ${TEST_PROGS} ; \
+ elif test -n "${TEST_PROGS}" ; then \
+ ${GTESTER} --verbose $$test_options -o `mktemp "$$GTESTER_LOGDIR/log-XXXXXX"` ${TEST_PROGS} ; \
+ fi ; \
+ }
+ @ ignore_logdir=true ; \
+ if test -z "$$GTESTER_LOGDIR" ; then \
+ GTESTER_LOGDIR=`mktemp -d "\`pwd\`/.testlogs-XXXXXX"`; export GTESTER_LOGDIR ; \
+ ignore_logdir=false ; \
+ fi ; \
+ if test -d "$(top_srcdir)/.git" ; then \
+ REVISION=`git describe` ; \
+ else \
+ REVISION=$(VERSION) ; \
+ fi ; \
+ for subdir in $(SUBDIRS) . ; do \
+ test "$$subdir" = "." -o "$$subdir" = "po" || \
+ ( cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
+ done ; \
+ $$ignore_logdir || { \
+ echo '' > $@.xml ; \
+ echo '' >> $@.xml ; \
+ echo '' >> $@.xml ; \
+ echo ' $(PACKAGE)' >> $@.xml ; \
+ echo ' $(VERSION)' >> $@.xml ; \
+ echo " $$REVISION" >> $@.xml ; \
+ echo '' >> $@.xml ; \
+ for lf in `ls -L "$$GTESTER_LOGDIR"/.` ; do \
+ sed '1,1s/^?]*?>//' <"$$GTESTER_LOGDIR"/"$$lf" >> $@.xml ; \
+ done ; \
+ echo >> $@.xml ; \
+ echo '' >> $@.xml ; \
+ rm -rf "$$GTESTER_LOGDIR"/ ; \
+ ${GTESTER_REPORT} --version 2>/dev/null 1>&2 ; test "$$?" != 0 || ${GTESTER_REPORT} $@.xml >$@.html ; \
+ }
+.PHONY: test test-report perf-report full-report test-nonrecursive
+
+.PHONY: lcov genlcov lcov-clean
+# use recursive makes in order to ignore errors during check
+lcov:
+ -$(MAKE) $(AM_MAKEFLAGS) -k check
+ $(MAKE) $(AM_MAKEFLAGS) genlcov
+
+# we have to massage the lcov.info file slightly to hide the effect of libtool
+# placing the objects files in the .libs/ directory separate from the *.c
+# we also have to delete tests/.libs/libmoduletestplugin_*.gcda
+genlcov:
+ rm -f $(top_builddir)/tests/.libs/libmoduletestplugin_*.gcda
+ $(LTP) --directory $(top_builddir) --capture --output-file glib-lcov.info --test-name GLIB_PERF --no-checksum --compat-libtool
+ LANG=C $(LTP_GENHTML) --prefix $(top_builddir) --output-directory glib-lcov --title "GLib Code Coverage" --legend --show-details glib-lcov.info
+
+lcov-clean:
+ -$(LTP) --directory $(top_builddir) -z
+ -rm -rf glib-lcov.info glib-lcov
+ -find -name '*.gcda' -print | xargs rm
+
+# run tests in cwd as part of make check
+check-local: test-nonrecursive
diff --git a/test/hb-test.h b/test/hb-test.h
new file mode 100644
index 000000000..2ec02c26c
--- /dev/null
+++ b/test/hb-test.h
@@ -0,0 +1,67 @@
+/* * Copyright (C) 2010 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_TEST_H
+#define HB_TEST_H
+
+#include
+#include
+
+#include
+
+#include
+
+HB_BEGIN_DECLS
+
+/* Just in case */
+#undef G_DISABLE_ASSERT
+
+
+/* Bugzilla helpers */
+
+static inline void
+hb_test_bug (const char *uri_base, unsigned int number)
+{
+ char *s = g_strdup_printf ("%u", number);
+
+ g_test_bug_base (uri_base);
+ g_test_bug (s);
+
+ g_free (s);
+}
+
+static inline void
+hb_test_bug_freedesktop (unsigned int number)
+{
+ hb_test_bug ("http://bugs.freedesktop.org/", number);
+}
+
+static inline void
+hb_test_bug_gnome (unsigned int number)
+{
+ hb_test_bug ("http://bugzilla.gnome.org/", number);
+}
+
+static inline void
+hb_test_bug_mozilla (unsigned int number)
+{
+ hb_test_bug ("http://bugzilla.mozilla.org/", number);
+}
+
+static inline void
+hb_test_bug_redhat (unsigned int number)
+{
+ hb_test_bug ("http://bugzilla.redhat.com/", number);
+}
+
+HB_END_DECLS
+
+#endif /* HB_TEST_H */
diff --git a/test/test-types.c b/test/test-types.c
new file mode 100644
index 000000000..1c726737c
--- /dev/null
+++ b/test/test-types.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-test.h"
+
+/* This file tests types defined in hb-common.h */
+
+static void
+test_types_int (void)
+{
+ /* We already ASSERT_STATIC these in hb-common.h, but anyway */
+ g_assert_cmpint (sizeof (int8_t), ==, 1);
+ g_assert_cmpint (sizeof (uint8_t), ==, 1);
+ g_assert_cmpint (sizeof (int16_t), ==, 2);
+ g_assert_cmpint (sizeof (uint16_t), ==, 2);
+ g_assert_cmpint (sizeof (int32_t), ==, 4);
+ g_assert_cmpint (sizeof (uint32_t), ==, 4);
+ g_assert_cmpint (sizeof (int64_t), ==, 8);
+ g_assert_cmpint (sizeof (uint64_t), ==, 8);
+
+ g_assert_cmpint (sizeof (hb_codepoint_t), ==, 4);
+ g_assert_cmpint (sizeof (hb_position_t), ==, 4);
+ g_assert_cmpint (sizeof (hb_mask_t), ==, 4);
+ g_assert_cmpint (sizeof (hb_var_int_t), ==, 4);
+}
+
+static void
+test_types_direction (void)
+{
+ g_assert_cmpint ((signed) HB_DIRECTION_INVALID, <, 0);
+ g_assert_cmpint (HB_DIRECTION_LTR, ==, 0);
+
+ g_assert (HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_LTR));
+ g_assert (HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_RTL));
+ g_assert (!HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_TTB));
+ g_assert (!HB_DIRECTION_IS_HORIZONTAL (HB_DIRECTION_BTT));
+
+ g_assert (!HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_LTR));
+ g_assert (!HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_RTL));
+ g_assert (HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_TTB));
+ g_assert (HB_DIRECTION_IS_VERTICAL (HB_DIRECTION_BTT));
+
+ g_assert (HB_DIRECTION_IS_FORWARD (HB_DIRECTION_LTR));
+ g_assert (HB_DIRECTION_IS_FORWARD (HB_DIRECTION_TTB));
+ g_assert (!HB_DIRECTION_IS_FORWARD (HB_DIRECTION_RTL));
+ g_assert (!HB_DIRECTION_IS_FORWARD (HB_DIRECTION_BTT));
+
+ g_assert (!HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_LTR));
+ g_assert (!HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_TTB));
+ g_assert (HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_RTL));
+ g_assert (HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_BTT));
+
+ g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_LTR), ==, HB_DIRECTION_RTL);
+ g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_RTL), ==, HB_DIRECTION_LTR);
+ g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_TTB), ==, HB_DIRECTION_BTT);
+ g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_BTT), ==, HB_DIRECTION_TTB);
+}
+
+static void
+test_types_tag (void)
+{
+ g_assert_cmphex (HB_TAG_NONE, ==, 0);
+ g_assert_cmphex (HB_TAG ('a','B','c','D'), ==, 0x61426344);
+
+ g_assert_cmphex (HB_TAG_STR ("aBcD"), ==, 0x61426344);
+
+ g_assert_cmphex (hb_tag_from_string ("aBcDe"), ==, 0x61426344);
+ g_assert_cmphex (hb_tag_from_string ("aBcD"), ==, 0x61426344);
+ g_assert_cmphex (hb_tag_from_string ("aBc"), ==, 0x61426320);
+ g_assert_cmphex (hb_tag_from_string ("aB"), ==, 0x61422020);
+ g_assert_cmphex (hb_tag_from_string ("a"), ==, 0x61202020);
+ g_assert_cmphex (hb_tag_from_string (""), ==, 0x20202020);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/types/direction", test_types_direction);
+ g_test_add_func ("/types/int", test_types_int);
+ g_test_add_func ("/types/tag", test_types_tag);
+
+ return g_test_run();
+}