summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/Makefile.am5
-rw-r--r--test/Makefile.in593
-rw-r--r--test/api/Makefile.am125
-rw-r--r--test/api/Makefile.in914
-rw-r--r--test/api/hb-test.h268
-rw-r--r--test/api/test-blob.c301
-rw-r--r--test/api/test-buffer.c783
-rw-r--r--test/api/test-c.c58
-rw-r--r--test/api/test-common.c225
-rw-r--r--test/api/test-cplusplus.cc30
-rw-r--r--test/api/test-font.c502
-rw-r--r--test/api/test-object.c367
-rw-r--r--test/api/test-ot-tag.c241
-rw-r--r--test/api/test-shape.c165
-rw-r--r--test/api/test-unicode.c937
-rw-r--r--test/api/test-version.c80
-rw-r--r--test/shaping/Makefile.am35
-rw-r--r--test/shaping/Makefile.in408
-rwxr-xr-xtest/shaping/hb-diff10
-rwxr-xr-xtest/shaping/hb-diff-colorize7
-rwxr-xr-xtest/shaping/hb-diff-filter-failures5
-rwxr-xr-xtest/shaping/hb-diff-ngrams5
-rwxr-xr-xtest/shaping/hb-diff-stat5
-rwxr-xr-xtest/shaping/hb-manifest-read5
-rwxr-xr-xtest/shaping/hb-manifest-update5
-rwxr-xr-xtest/shaping/hb-unicode-decode5
-rwxr-xr-xtest/shaping/hb-unicode-encode5
-rwxr-xr-xtest/shaping/hb-unicode-prettyname6
-rw-r--r--test/shaping/hb_test_tools.py516
29 files changed, 6611 insertions, 0 deletions
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..16a3cd2
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,5 @@
+# Process this file with automake to produce Makefile.in
+
+SUBDIRS = api shaping
+
+-include $(top_srcdir)/git.mk
diff --git a/test/Makefile.in b/test/Makefile.in
new file mode 100644
index 0000000..dee13f6
--- /dev/null
+++ b/test/Makefile.in
@@ -0,0 +1,593 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Process this file with automake to produce Makefile.in
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_FT_CFLAGS = @CAIRO_FT_CFLAGS@
+CAIRO_FT_LIBS = @CAIRO_FT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CORETEXT_CFLAGS = @CORETEXT_CFLAGS@
+CORETEXT_LIBS = @CORETEXT_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GRAPHITE2_CFLAGS = @GRAPHITE2_CFLAGS@
+GRAPHITE2_LIBS = @GRAPHITE2_LIBS@
+GREP = @GREP@
+GTHREAD_CFLAGS = @GTHREAD_CFLAGS@
+GTHREAD_LIBS = @GTHREAD_LIBS@
+HB_LIBTOOL_VERSION_INFO = @HB_LIBTOOL_VERSION_INFO@
+HB_VERSION = @HB_VERSION@
+HB_VERSION_MAJOR = @HB_VERSION_MAJOR@
+HB_VERSION_MICRO = @HB_VERSION_MICRO@
+HB_VERSION_MINOR = @HB_VERSION_MINOR@
+ICU_CFLAGS = @ICU_CFLAGS@
+ICU_LIBS = @ICU_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
+UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = api shaping
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits test/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnits test/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+ install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-generic clean-libtool \
+ ctags ctags-recursive distclean distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am
+
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
new file mode 100644
index 0000000..e6c0c01
--- /dev/null
+++ b/test/api/Makefile.am
@@ -0,0 +1,125 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+EXTRA_DIST =
+CLEANFILES =
+DISTCLEANFILES =
+MAINTAINERCLEANFILES =
+
+if HAVE_GLIB
+AM_CPPFLAGS = -DSRCDIR="\"$(srcdir)\"" -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS) $(GTHREAD_CFLAGS)
+LDADD = $(top_builddir)/src/libharfbuzz.la $(GLIB_LIBS) $(GTHREAD_LIBS)
+
+EXTRA_DIST += hb-test.h
+
+check_PROGRAMS = $(TEST_PROGS)
+noinst_PROGRAMS = $(TEST_PROGS)
+
+TEST_PROGS = \
+ test-blob \
+ test-buffer \
+ test-common \
+ test-font \
+ test-object \
+ test-shape \
+ test-unicode \
+ test-version \
+ $(NULL)
+
+if HAVE_OT
+TEST_PROGS += \
+ test-ot-tag \
+ $(NULL)
+endif
+
+# Tests for header compilation
+TEST_PROGS += \
+ test-c \
+ test-cplusplus \
+ $(NULL)
+test_cplusplus_SOURCES = test-cplusplus.cc
+test_c_CPPFLAGS = $(AM_CPPFLAGS)
+test_cplusplus_CPPFLAGS = $(AM_CPPFLAGS)
+if HAVE_ICU
+test_c_CPPFLAGS += $(ICU_CFLAGS)
+test_cplusplus_CPPFLAGS += $(ICU_CFLAGS)
+endif
+if HAVE_FREETYPE
+test_c_CPPFLAGS += $(FREETYPE_CFLAGS)
+test_cplusplus_CPPFLAGS += $(FREETYPE_CFLAGS)
+endif
+
+
+# Default test running environment
+TESTS = $(TEST_PROGS)
+TESTS_ENVIRONMENT = \
+ MALLOC_CHECK_=2 \
+ MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) \
+ G_DEBUG=gc-friendly \
+ G_SLICE=always-malloc \
+ srcdir=$(srcdir) \
+ $(ENV)
+
+
+# check-tool: Run tests under $(TOOL)
+check-tool:
+ $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) check \
+ TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) $(top_builddir)/libtool --mode=execute \
+ env $(TOOL)'
+# check-tool-raw: Run tests under $(TOOL), but don't run under libtool
+check-tool-raw:
+ $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) check \
+ TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) \
+ env $(TOOL)'
+
+# check-gtester: Run tests under gtester
+GTESTER = gtester
+check-gtester:
+ $(AM_V_at)$(MAKE) $(AM_MAKEFLGS) check-tool-raw TOOL="$(GTESTER) --verbose --keep-going"
+
+
+# Check tests under valgrind. Saves log to log-valgrind.txt
+VALGRIND_FLAGS = \
+ --tool=memcheck --suppressions=$(srcdir)/.valgrind-suppressions \
+ --track-origins=yes \
+ --leak-check=yes
+ $(EXTRA_VALGRIND_FLAGS)
+# Can't do for now: --show-reachable=yes
+CLEANFILES += log-valgrind.txt
+valgrind_verbose = $(valgrind_verbose_$(V))
+valgrind_verbose_ = $(valgrind_verbose_$(AM_DEFAULT_VERBOSITY))
+valgrind_verbose_0 = | \
+ grep '\(^[^=]\|ERROR SUMMARY\|definitely lost\|indirectly lost\)' | grep -v ': 0'
+# TODO: The following check does not fail if valgrind finds error. It should.
+check-valgrind:
+ $(AM_V_at)$(MAKE) $(AM_MAKEFLGS) check-tool TOOL="valgrind $(VALGRIND_FLAGS)" \
+ 2>&1 | tee log-valgrind.txt $(valgrind_verbose)
+
+
+# check-symbols: Finds untested API symbols
+symbols-tested.txt: $(TEST_PROGS)
+ $(AM_V_GEN)$(top_builddir)/libtool --mode=execute nm $^ \
+ | grep ' U hb_' | sed 's/.* U hb_/hb_/' \
+ | sort | uniq > $@.tmp && mv $@.tmp $@
+symbols-exported.txt: $(top_builddir)/src/.libs/libharfbuzz.so
+ $(AM_V_GEN)$(top_builddir)/libtool --mode=execute nm $^ \
+ | grep ' T ' | sed 's/.* T //' | grep -v '^\(_init\|_fini\)$$' \
+ | sort | uniq > $@.tmp && mv $@.tmp $@
+symbols-untested.txt: symbols-tested.txt symbols-exported.txt
+ $(AM_V_GEN)diff $^ > $@.tmp; mv $@.tmp $@
+CLEANFILES += symbols-tested.txt symbols-exported.txt symbols-untested.txt
+check-symbols: symbols-untested.txt
+ @! cat $^ | grep .
+
+
+
+else
+check-am: err-glib
+err-glib:
+ @echo "You need to have glib support enabled to run the tests"
+ @exit 77
+endif
+
+.PHONY: check-symbols check-tool check-valgrind
+
+-include $(top_srcdir)/git.mk
diff --git a/test/api/Makefile.in b/test/api/Makefile.in
new file mode 100644
index 0000000..d6c087a
--- /dev/null
+++ b/test/api/Makefile.in
@@ -0,0 +1,914 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Process this file with automake to produce Makefile.in
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_GLIB_TRUE@am__append_1 = hb-test.h
+@HAVE_GLIB_TRUE@check_PROGRAMS = $(am__EXEEXT_3)
+@HAVE_GLIB_TRUE@noinst_PROGRAMS = $(am__EXEEXT_3)
+@HAVE_GLIB_TRUE@@HAVE_OT_TRUE@am__append_2 = \
+@HAVE_GLIB_TRUE@@HAVE_OT_TRUE@ test-ot-tag \
+@HAVE_GLIB_TRUE@@HAVE_OT_TRUE@ $(NULL)
+
+@HAVE_GLIB_TRUE@@HAVE_ICU_TRUE@am__append_3 = $(ICU_CFLAGS)
+@HAVE_GLIB_TRUE@@HAVE_ICU_TRUE@am__append_4 = $(ICU_CFLAGS)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_5 = $(FREETYPE_CFLAGS)
+@HAVE_FREETYPE_TRUE@@HAVE_GLIB_TRUE@am__append_6 = $(FREETYPE_CFLAGS)
+@HAVE_GLIB_TRUE@TESTS = $(am__EXEEXT_3)
+# Can't do for now: --show-reachable=yes
+@HAVE_GLIB_TRUE@am__append_7 = log-valgrind.txt symbols-tested.txt \
+@HAVE_GLIB_TRUE@ symbols-exported.txt symbols-untested.txt
+subdir = test/api
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__EXEEXT_1 =
+@HAVE_GLIB_TRUE@@HAVE_OT_TRUE@am__EXEEXT_2 = test-ot-tag$(EXEEXT) \
+@HAVE_GLIB_TRUE@@HAVE_OT_TRUE@ $(am__EXEEXT_1)
+@HAVE_GLIB_TRUE@am__EXEEXT_3 = test-blob$(EXEEXT) test-buffer$(EXEEXT) \
+@HAVE_GLIB_TRUE@ test-common$(EXEEXT) test-font$(EXEEXT) \
+@HAVE_GLIB_TRUE@ test-object$(EXEEXT) test-shape$(EXEEXT) \
+@HAVE_GLIB_TRUE@ test-unicode$(EXEEXT) test-version$(EXEEXT) \
+@HAVE_GLIB_TRUE@ $(am__EXEEXT_1) $(am__EXEEXT_2) \
+@HAVE_GLIB_TRUE@ test-c$(EXEEXT) test-cplusplus$(EXEEXT) \
+@HAVE_GLIB_TRUE@ $(am__EXEEXT_1)
+PROGRAMS = $(noinst_PROGRAMS)
+test_blob_SOURCES = test-blob.c
+test_blob_OBJECTS = test-blob.$(OBJEXT)
+test_blob_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+@HAVE_GLIB_TRUE@test_blob_DEPENDENCIES = \
+@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+test_buffer_SOURCES = test-buffer.c
+test_buffer_OBJECTS = test-buffer.$(OBJEXT)
+test_buffer_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_buffer_DEPENDENCIES = \
+@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+test_c_SOURCES = test-c.c
+test_c_OBJECTS = test_c-test-c.$(OBJEXT)
+test_c_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_c_DEPENDENCIES = \
+@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+test_common_SOURCES = test-common.c
+test_common_OBJECTS = test-common.$(OBJEXT)
+test_common_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_common_DEPENDENCIES = \
+@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am__test_cplusplus_SOURCES_DIST = test-cplusplus.cc
+@HAVE_GLIB_TRUE@am_test_cplusplus_OBJECTS = \
+@HAVE_GLIB_TRUE@ test_cplusplus-test-cplusplus.$(OBJEXT)
+test_cplusplus_OBJECTS = $(am_test_cplusplus_OBJECTS)
+test_cplusplus_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_cplusplus_DEPENDENCIES = \
+@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+test_font_SOURCES = test-font.c
+test_font_OBJECTS = test-font.$(OBJEXT)
+test_font_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_font_DEPENDENCIES = \
+@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+test_object_SOURCES = test-object.c
+test_object_OBJECTS = test-object.$(OBJEXT)
+test_object_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_object_DEPENDENCIES = \
+@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+test_ot_tag_SOURCES = test-ot-tag.c
+test_ot_tag_OBJECTS = test-ot-tag.$(OBJEXT)
+test_ot_tag_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_ot_tag_DEPENDENCIES = \
+@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+test_shape_SOURCES = test-shape.c
+test_shape_OBJECTS = test-shape.$(OBJEXT)
+test_shape_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_shape_DEPENDENCIES = \
+@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+test_unicode_SOURCES = test-unicode.c
+test_unicode_OBJECTS = test-unicode.$(OBJEXT)
+test_unicode_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_unicode_DEPENDENCIES = \
+@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+test_version_SOURCES = test-version.c
+test_version_OBJECTS = test-version.$(OBJEXT)
+test_version_LDADD = $(LDADD)
+@HAVE_GLIB_TRUE@test_version_DEPENDENCIES = \
+@HAVE_GLIB_TRUE@ $(top_builddir)/src/libharfbuzz.la \
+@HAVE_GLIB_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_$(V))
+am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY))
+am__v_CXX_0 = @echo " CXX " $@;
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_$(V))
+am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = test-blob.c test-buffer.c test-c.c test-common.c \
+ $(test_cplusplus_SOURCES) test-font.c test-object.c \
+ test-ot-tag.c test-shape.c test-unicode.c test-version.c
+DIST_SOURCES = test-blob.c test-buffer.c test-c.c test-common.c \
+ $(am__test_cplusplus_SOURCES_DIST) test-font.c test-object.c \
+ test-ot-tag.c test-shape.c test-unicode.c test-version.c
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_FT_CFLAGS = @CAIRO_FT_CFLAGS@
+CAIRO_FT_LIBS = @CAIRO_FT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CORETEXT_CFLAGS = @CORETEXT_CFLAGS@
+CORETEXT_LIBS = @CORETEXT_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GRAPHITE2_CFLAGS = @GRAPHITE2_CFLAGS@
+GRAPHITE2_LIBS = @GRAPHITE2_LIBS@
+GREP = @GREP@
+GTHREAD_CFLAGS = @GTHREAD_CFLAGS@
+GTHREAD_LIBS = @GTHREAD_LIBS@
+HB_LIBTOOL_VERSION_INFO = @HB_LIBTOOL_VERSION_INFO@
+HB_VERSION = @HB_VERSION@
+HB_VERSION_MAJOR = @HB_VERSION_MAJOR@
+HB_VERSION_MICRO = @HB_VERSION_MICRO@
+HB_VERSION_MINOR = @HB_VERSION_MINOR@
+ICU_CFLAGS = @ICU_CFLAGS@
+ICU_LIBS = @ICU_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
+UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+NULL =
+EXTRA_DIST = $(am__append_1)
+CLEANFILES = $(am__append_7)
+DISTCLEANFILES =
+MAINTAINERCLEANFILES =
+@HAVE_GLIB_TRUE@AM_CPPFLAGS = -DSRCDIR="\"$(srcdir)\"" -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS) $(GTHREAD_CFLAGS)
+@HAVE_GLIB_TRUE@LDADD = $(top_builddir)/src/libharfbuzz.la $(GLIB_LIBS) $(GTHREAD_LIBS)
+
+# Tests for header compilation
+@HAVE_GLIB_TRUE@TEST_PROGS = test-blob test-buffer test-common \
+@HAVE_GLIB_TRUE@ test-font test-object test-shape test-unicode \
+@HAVE_GLIB_TRUE@ test-version $(NULL) $(am__append_2) test-c \
+@HAVE_GLIB_TRUE@ test-cplusplus $(NULL)
+@HAVE_GLIB_TRUE@test_cplusplus_SOURCES = test-cplusplus.cc
+@HAVE_GLIB_TRUE@test_c_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_3) \
+@HAVE_GLIB_TRUE@ $(am__append_5)
+@HAVE_GLIB_TRUE@test_cplusplus_CPPFLAGS = $(AM_CPPFLAGS) \
+@HAVE_GLIB_TRUE@ $(am__append_4) $(am__append_6)
+@HAVE_GLIB_TRUE@TESTS_ENVIRONMENT = \
+@HAVE_GLIB_TRUE@ MALLOC_CHECK_=2 \
+@HAVE_GLIB_TRUE@ MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) \
+@HAVE_GLIB_TRUE@ G_DEBUG=gc-friendly \
+@HAVE_GLIB_TRUE@ G_SLICE=always-malloc \
+@HAVE_GLIB_TRUE@ srcdir=$(srcdir) \
+@HAVE_GLIB_TRUE@ $(ENV)
+
+
+# check-gtester: Run tests under gtester
+@HAVE_GLIB_TRUE@GTESTER = gtester
+
+# Check tests under valgrind. Saves log to log-valgrind.txt
+@HAVE_GLIB_TRUE@VALGRIND_FLAGS = \
+@HAVE_GLIB_TRUE@ --tool=memcheck --suppressions=$(srcdir)/.valgrind-suppressions \
+@HAVE_GLIB_TRUE@ --track-origins=yes \
+@HAVE_GLIB_TRUE@ --leak-check=yes
+
+@HAVE_GLIB_TRUE@valgrind_verbose = $(valgrind_verbose_$(V))
+@HAVE_GLIB_TRUE@valgrind_verbose_ = $(valgrind_verbose_$(AM_DEFAULT_VERBOSITY))
+@HAVE_GLIB_TRUE@valgrind_verbose_0 = | \
+@HAVE_GLIB_TRUE@ grep '\(^[^=]\|ERROR SUMMARY\|definitely lost\|indirectly lost\)' | grep -v ': 0'
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits test/api/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnits test/api/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+test-blob$(EXEEXT): $(test_blob_OBJECTS) $(test_blob_DEPENDENCIES)
+ @rm -f test-blob$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_blob_OBJECTS) $(test_blob_LDADD) $(LIBS)
+test-buffer$(EXEEXT): $(test_buffer_OBJECTS) $(test_buffer_DEPENDENCIES)
+ @rm -f test-buffer$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_buffer_OBJECTS) $(test_buffer_LDADD) $(LIBS)
+test-c$(EXEEXT): $(test_c_OBJECTS) $(test_c_DEPENDENCIES)
+ @rm -f test-c$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_c_OBJECTS) $(test_c_LDADD) $(LIBS)
+test-common$(EXEEXT): $(test_common_OBJECTS) $(test_common_DEPENDENCIES)
+ @rm -f test-common$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_common_OBJECTS) $(test_common_LDADD) $(LIBS)
+test-cplusplus$(EXEEXT): $(test_cplusplus_OBJECTS) $(test_cplusplus_DEPENDENCIES)
+ @rm -f test-cplusplus$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(test_cplusplus_OBJECTS) $(test_cplusplus_LDADD) $(LIBS)
+test-font$(EXEEXT): $(test_font_OBJECTS) $(test_font_DEPENDENCIES)
+ @rm -f test-font$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_font_OBJECTS) $(test_font_LDADD) $(LIBS)
+test-object$(EXEEXT): $(test_object_OBJECTS) $(test_object_DEPENDENCIES)
+ @rm -f test-object$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_object_OBJECTS) $(test_object_LDADD) $(LIBS)
+test-ot-tag$(EXEEXT): $(test_ot_tag_OBJECTS) $(test_ot_tag_DEPENDENCIES)
+ @rm -f test-ot-tag$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_ot_tag_OBJECTS) $(test_ot_tag_LDADD) $(LIBS)
+test-shape$(EXEEXT): $(test_shape_OBJECTS) $(test_shape_DEPENDENCIES)
+ @rm -f test-shape$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_shape_OBJECTS) $(test_shape_LDADD) $(LIBS)
+test-unicode$(EXEEXT): $(test_unicode_OBJECTS) $(test_unicode_DEPENDENCIES)
+ @rm -f test-unicode$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_unicode_OBJECTS) $(test_unicode_LDADD) $(LIBS)
+test-version$(EXEEXT): $(test_version_OBJECTS) $(test_version_DEPENDENCIES)
+ @rm -f test-version$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_version_OBJECTS) $(test_version_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-blob.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-buffer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-font.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-object.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-ot-tag.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-shape.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-unicode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_c-test-c.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cplusplus-test-cplusplus.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+test_c-test-c.o: test-c.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_c_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_c-test-c.o -MD -MP -MF $(DEPDIR)/test_c-test-c.Tpo -c -o test_c-test-c.o `test -f 'test-c.c' || echo '$(srcdir)/'`test-c.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_c-test-c.Tpo $(DEPDIR)/test_c-test-c.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-c.c' object='test_c-test-c.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_c_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_c-test-c.o `test -f 'test-c.c' || echo '$(srcdir)/'`test-c.c
+
+test_c-test-c.obj: test-c.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_c_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_c-test-c.obj -MD -MP -MF $(DEPDIR)/test_c-test-c.Tpo -c -o test_c-test-c.obj `if test -f 'test-c.c'; then $(CYGPATH_W) 'test-c.c'; else $(CYGPATH_W) '$(srcdir)/test-c.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_c-test-c.Tpo $(DEPDIR)/test_c-test-c.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-c.c' object='test_c-test-c.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_c_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_c-test-c.obj `if test -f 'test-c.c'; then $(CYGPATH_W) 'test-c.c'; else $(CYGPATH_W) '$(srcdir)/test-c.c'; fi`
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
+
+test_cplusplus-test-cplusplus.o: test-cplusplus.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cplusplus_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_cplusplus-test-cplusplus.o -MD -MP -MF $(DEPDIR)/test_cplusplus-test-cplusplus.Tpo -c -o test_cplusplus-test-cplusplus.o `test -f 'test-cplusplus.cc' || echo '$(srcdir)/'`test-cplusplus.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cplusplus-test-cplusplus.Tpo $(DEPDIR)/test_cplusplus-test-cplusplus.Po
+@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='test-cplusplus.cc' object='test_cplusplus-test-cplusplus.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cplusplus_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_cplusplus-test-cplusplus.o `test -f 'test-cplusplus.cc' || echo '$(srcdir)/'`test-cplusplus.cc
+
+test_cplusplus-test-cplusplus.obj: test-cplusplus.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cplusplus_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT test_cplusplus-test-cplusplus.obj -MD -MP -MF $(DEPDIR)/test_cplusplus-test-cplusplus.Tpo -c -o test_cplusplus-test-cplusplus.obj `if test -f 'test-cplusplus.cc'; then $(CYGPATH_W) 'test-cplusplus.cc'; else $(CYGPATH_W) '$(srcdir)/test-cplusplus.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cplusplus-test-cplusplus.Tpo $(DEPDIR)/test_cplusplus-test-cplusplus.Po
+@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='test-cplusplus.cc' object='test_cplusplus-test-cplusplus.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cplusplus_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_cplusplus-test-cplusplus.obj `if test -f 'test-cplusplus.cc'; then $(CYGPATH_W) 'test-cplusplus.cc'; else $(CYGPATH_W) '$(srcdir)/test-cplusplus.cc'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ echo "$$grn$$dashes"; \
+ else \
+ echo "$$red$$dashes"; \
+ fi; \
+ echo "$$banner"; \
+ test -z "$$skipped" || echo "$$skipped"; \
+ test -z "$$report" || echo "$$report"; \
+ echo "$$dashes$$std"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool \
+ clean-noinstPROGRAMS ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am
+
+
+# check-tool: Run tests under $(TOOL)
+@HAVE_GLIB_TRUE@check-tool:
+@HAVE_GLIB_TRUE@ $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) check \
+@HAVE_GLIB_TRUE@ TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) $(top_builddir)/libtool --mode=execute \
+@HAVE_GLIB_TRUE@ env $(TOOL)'
+# check-tool-raw: Run tests under $(TOOL), but don't run under libtool
+@HAVE_GLIB_TRUE@check-tool-raw:
+@HAVE_GLIB_TRUE@ $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) check \
+@HAVE_GLIB_TRUE@ TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) \
+@HAVE_GLIB_TRUE@ env $(TOOL)'
+@HAVE_GLIB_TRUE@check-gtester:
+@HAVE_GLIB_TRUE@ $(AM_V_at)$(MAKE) $(AM_MAKEFLGS) check-tool-raw TOOL="$(GTESTER) --verbose --keep-going"
+@HAVE_GLIB_TRUE@ $(EXTRA_VALGRIND_FLAGS)
+# TODO: The following check does not fail if valgrind finds error. It should.
+@HAVE_GLIB_TRUE@check-valgrind:
+@HAVE_GLIB_TRUE@ $(AM_V_at)$(MAKE) $(AM_MAKEFLGS) check-tool TOOL="valgrind $(VALGRIND_FLAGS)" \
+@HAVE_GLIB_TRUE@ 2>&1 | tee log-valgrind.txt $(valgrind_verbose)
+
+# check-symbols: Finds untested API symbols
+@HAVE_GLIB_TRUE@symbols-tested.txt: $(TEST_PROGS)
+@HAVE_GLIB_TRUE@ $(AM_V_GEN)$(top_builddir)/libtool --mode=execute nm $^ \
+@HAVE_GLIB_TRUE@ | grep ' U hb_' | sed 's/.* U hb_/hb_/' \
+@HAVE_GLIB_TRUE@ | sort | uniq > $@.tmp && mv $@.tmp $@
+@HAVE_GLIB_TRUE@symbols-exported.txt: $(top_builddir)/src/.libs/libharfbuzz.so
+@HAVE_GLIB_TRUE@ $(AM_V_GEN)$(top_builddir)/libtool --mode=execute nm $^ \
+@HAVE_GLIB_TRUE@ | grep ' T ' | sed 's/.* T //' | grep -v '^\(_init\|_fini\)$$' \
+@HAVE_GLIB_TRUE@ | sort | uniq > $@.tmp && mv $@.tmp $@
+@HAVE_GLIB_TRUE@symbols-untested.txt: symbols-tested.txt symbols-exported.txt
+@HAVE_GLIB_TRUE@ $(AM_V_GEN)diff $^ > $@.tmp; mv $@.tmp $@
+@HAVE_GLIB_TRUE@check-symbols: symbols-untested.txt
+@HAVE_GLIB_TRUE@ @! cat $^ | grep .
+
+@HAVE_GLIB_FALSE@check-am: err-glib
+@HAVE_GLIB_FALSE@err-glib:
+@HAVE_GLIB_FALSE@ @echo "You need to have glib support enabled to run the tests"
+@HAVE_GLIB_FALSE@ @exit 77
+
+.PHONY: check-symbols check-tool check-valgrind
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/api/hb-test.h b/test/api/hb-test.h
new file mode 100644
index 0000000..8655f41
--- /dev/null
+++ b/test/api/hb-test.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright © 2011 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 <config.h>
+
+#include <hb-glib.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+HB_BEGIN_DECLS
+
+/* Just in case */
+#undef G_DISABLE_ASSERT
+
+
+/* Misc */
+
+/* This is too ugly to be public API, but quite handy. */
+#define HB_TAG_CHAR4(s) (HB_TAG(((const char *) s)[0], \
+ ((const char *) s)[1], \
+ ((const char *) s)[2], \
+ ((const char *) s)[3]))
+
+
+static inline const char *
+srcdir (void)
+{
+ static const char *s;
+
+ if (!s) {
+ s = getenv ("srcdir");
+
+#ifdef SRCDIR
+ if (!s || !s[0])
+ s = SRCDIR;
+#endif
+
+ if (!s || !s[0])
+ s = ".";
+ }
+
+ return s;
+}
+
+
+/* Helpers */
+
+static inline void
+hb_test_init (int *argc, char ***argv)
+{
+#if !GLIB_CHECK_VERSION(2,32,0)
+ g_thread_init (NULL);
+#endif
+ g_test_init (argc, argv, NULL);
+}
+
+static inline int
+hb_test_run (void)
+{
+ return g_test_run ();
+}
+
+
+/* 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);
+}
+
+
+/* Wrap glib test functions to simplify. Should have been in glib already. */
+
+/* Drops the "test_" prefix and converts '_' to '/'.
+ * Essentially builds test path from function name. */
+static inline char *
+hb_test_normalize_path (const char *path)
+{
+ char *s, *p;
+
+ g_assert (0 == strncmp (path, "test_", 5));
+ path += 4;
+
+ s = g_strdup (path);
+ for (p = s; *p; p++)
+ if (*p == '_')
+ *p = '/';
+
+ return s;
+}
+
+
+#if GLIB_CHECK_VERSION(2,25,12)
+typedef GTestFunc hb_test_func_t;
+typedef GTestDataFunc hb_test_data_func_t;
+typedef GTestFixtureFunc hb_test_fixture_func_t;
+#else
+typedef void (*hb_test_func_t) (void);
+typedef void (*hb_test_data_func_t) (gconstpointer user_data);
+typedef void (*hb_test_fixture_func_t) (void);
+#endif
+
+#if !GLIB_CHECK_VERSION(2,30,0)
+#define g_test_fail() g_error("Test failed")
+#endif
+
+static inline void
+hb_test_add_func (const char *test_path,
+ hb_test_func_t test_func)
+{
+ char *normal_path = hb_test_normalize_path (test_path);
+ g_test_add_func (normal_path, test_func);
+ g_free (normal_path);
+}
+#define hb_test_add(Func) hb_test_add_func (#Func, Func)
+
+static inline void
+hb_test_add_func_flavor (const char *test_path,
+ const char *flavor,
+ hb_test_func_t test_func)
+{
+ char *path = g_strdup_printf ("%s/%s", test_path, flavor);
+ hb_test_add_func (path, test_func);
+ g_free (path);
+}
+#define hb_test_add_flavor(Flavor, Func) hb_test_add_func (#Func, Flavor, Func)
+
+static inline void
+hb_test_add_data_func (const char *test_path,
+ gconstpointer test_data,
+ hb_test_data_func_t test_func)
+{
+ char *normal_path = hb_test_normalize_path (test_path);
+ g_test_add_data_func (normal_path, test_data, test_func);
+ g_free (normal_path);
+}
+#define hb_test_add_data(UserData, Func) hb_test_add_data_func (#Func, UserData, Func)
+
+static inline void
+hb_test_add_data_func_flavor (const char *test_path,
+ const char *flavor,
+ gconstpointer test_data,
+ hb_test_data_func_t test_func)
+{
+ char *path = g_strdup_printf ("%s/%s", test_path, flavor);
+ hb_test_add_data_func (path, test_data, test_func);
+ g_free (path);
+}
+#define hb_test_add_data_flavor(UserData, Flavor, Func) hb_test_add_data_func_flavor (#Func, Flavor, UserData, Func)
+
+
+static inline void
+hb_test_add_vtable (const char *test_path,
+ gsize data_size,
+ gconstpointer test_data,
+ hb_test_fixture_func_t data_setup,
+ hb_test_fixture_func_t data_test,
+ hb_test_fixture_func_t data_teardown)
+{
+ char *normal_path = hb_test_normalize_path (test_path);
+ g_test_add_vtable (normal_path, data_size, test_data, data_setup, data_test, data_teardown);
+ g_free (normal_path);
+}
+#define hb_test_add_fixture(FixturePrefix, UserData, Func) \
+G_STMT_START { \
+ typedef G_PASTE (FixturePrefix, _t) Fixture; \
+ void (*add_vtable) (const char*, gsize, gconstpointer, \
+ void (*) (Fixture*, gconstpointer), \
+ void (*) (Fixture*, gconstpointer), \
+ void (*) (Fixture*, gconstpointer)) \
+ = (void (*) (const gchar *, gsize, gconstpointer, \
+ void (*) (Fixture*, gconstpointer), \
+ void (*) (Fixture*, gconstpointer), \
+ void (*) (Fixture*, gconstpointer))) hb_test_add_vtable; \
+ add_vtable (#Func, sizeof (G_PASTE (FixturePrefix, _t)), UserData, \
+ G_PASTE (FixturePrefix, _init), Func, G_PASTE (FixturePrefix, _finish)); \
+} G_STMT_END
+
+static inline void
+hb_test_add_vtable_flavor (const char *test_path,
+ const char *flavor,
+ gsize data_size,
+ gconstpointer test_data,
+ hb_test_fixture_func_t data_setup,
+ hb_test_fixture_func_t data_test,
+ hb_test_fixture_func_t data_teardown)
+{
+ char *path = g_strdup_printf ("%s/%s", test_path, flavor);
+ hb_test_add_vtable (path, data_size, test_data, data_setup, data_test, data_teardown);
+ g_free (path);
+}
+#define hb_test_add_fixture_flavor(FixturePrefix, UserData, Flavor, Func) \
+G_STMT_START { \
+ typedef G_PASTE (FixturePrefix, _t) Fixture; \
+ void (*add_vtable) (const char*, const char *, gsize, gconstpointer, \
+ void (*) (Fixture*, gconstpointer), \
+ void (*) (Fixture*, gconstpointer), \
+ void (*) (Fixture*, gconstpointer)) \
+ = (void (*) (const gchar *, const char *, gsize, gconstpointer, \
+ void (*) (Fixture*, gconstpointer), \
+ void (*) (Fixture*, gconstpointer), \
+ void (*) (Fixture*, gconstpointer))) hb_test_add_vtable_flavor; \
+ add_vtable (#Func, Flavor, sizeof (G_PASTE (FixturePrefix, _t)), UserData, \
+ G_PASTE (FixturePrefix, _init), Func, G_PASTE (FixturePrefix, _finish)); \
+} G_STMT_END
+
+
+HB_END_DECLS
+
+#endif /* HB_TEST_H */
diff --git a/test/api/test-blob.c b/test/api/test-blob.c
new file mode 100644
index 0000000..0e65e2f
--- /dev/null
+++ b/test/api/test-blob.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright © 2011 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"
+
+/* Unit tests for hb-blob.h */
+
+#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT) && defined(HAVE_MMAP)
+
+# define TEST_MMAP 1
+
+#ifdef HAVE_SYS_MMAN_H
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <sys/mman.h>
+#endif /* HAVE_SYS_MMAN_H */
+
+#endif
+
+
+static void
+test_blob_empty (void)
+{
+ hb_blob_t *blob;
+ unsigned int len;
+ const char *data;
+ char *data_writable;
+
+ g_assert (hb_blob_is_immutable (hb_blob_get_empty ()));
+ g_assert (hb_blob_get_empty () != NULL);
+ g_assert (hb_blob_get_empty () == hb_blob_create (NULL, 0, HB_MEMORY_MODE_READONLY, NULL, NULL));
+
+ blob = hb_blob_get_empty ();
+ g_assert (blob == hb_blob_get_empty ());
+
+ len = hb_blob_get_length (blob);
+ g_assert_cmpint (len, ==, 0);
+
+ data = hb_blob_get_data (blob, NULL);
+ g_assert (data == NULL);
+
+ data = hb_blob_get_data (blob, &len);
+ g_assert (data == NULL);
+ g_assert_cmpint (len, ==, 0);
+
+ data_writable = hb_blob_get_data_writable (blob, NULL);
+ g_assert (data_writable == NULL);
+
+ data_writable = hb_blob_get_data_writable (blob, &len);
+ g_assert (data_writable == NULL);
+ g_assert_cmpint (len, ==, 0);
+}
+
+static const char test_data[] = "test\0data";
+
+static const char *blob_names[] = {
+ "duplicate",
+ "readonly",
+ "writable"
+#ifdef TEST_MMAP
+ , "readonly-may-make-writable"
+#endif
+};
+
+typedef struct
+{
+ hb_blob_t *blob;
+ int freed;
+ char *data;
+ unsigned int len;
+} fixture_t;
+
+static void
+free_up (fixture_t *fixture)
+{
+ g_assert_cmpint (fixture->freed, ==, 0);
+ fixture->freed++;
+}
+
+static void
+free_up_free (fixture_t *fixture)
+{
+ free_up (fixture);
+ free (fixture->data);
+}
+
+
+#ifdef TEST_MMAP
+static uintptr_t
+get_pagesize (void)
+{
+ uintptr_t pagesize = -1;
+
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
+ pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
+#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
+ pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
+#elif defined(HAVE_GETPAGESIZE)
+ pagesize = (uintptr_t) getpagesize ();
+#endif
+
+ g_assert (pagesize != (uintptr_t) -1);
+
+ return pagesize;
+}
+
+static void
+free_up_munmap (fixture_t *fixture)
+{
+ free_up (fixture);
+ munmap (fixture->data, get_pagesize ());
+}
+#endif
+
+#include <errno.h>
+static void
+fixture_init (fixture_t *fixture, gconstpointer user_data)
+{
+ hb_memory_mode_t mm = (hb_memory_mode_t) GPOINTER_TO_INT (user_data);
+ unsigned int len;
+ const char *data;
+ hb_destroy_func_t free_func;
+
+ switch (GPOINTER_TO_INT (user_data))
+ {
+ case HB_MEMORY_MODE_DUPLICATE:
+ data = test_data;
+ len = sizeof (test_data);
+ free_func = (hb_destroy_func_t) free_up;
+ break;
+
+ case HB_MEMORY_MODE_READONLY:
+ data = test_data;
+ len = sizeof (test_data);
+ free_func = (hb_destroy_func_t) free_up;
+ break;
+
+ case HB_MEMORY_MODE_WRITABLE:
+ data = malloc (sizeof (test_data));
+ memcpy ((char *) data, test_data, sizeof (test_data));
+ len = sizeof (test_data);
+ free_func = (hb_destroy_func_t) free_up_free;
+ break;
+
+#ifdef TEST_MMAP
+ case HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE:
+ {
+ uintptr_t pagesize = get_pagesize ();
+
+ data = mmap (NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ g_assert (data != (char *) -1);
+ memcpy ((char *) data, test_data, sizeof (test_data));
+ mprotect ((char *) data, pagesize, PROT_READ);
+ len = sizeof (test_data);
+ free_func = (hb_destroy_func_t) free_up_munmap;
+ break;
+ }
+#endif
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ fixture->freed = 0;
+ fixture->data = (char *) data;
+ fixture->len = len;
+ fixture->blob = hb_blob_create (data, len, mm, fixture, free_func);
+}
+
+static void
+fixture_finish (fixture_t *fixture, gconstpointer user_data)
+{
+ hb_blob_destroy (fixture->blob);
+ g_assert_cmpint (fixture->freed, ==, 1);
+}
+
+
+static void
+test_blob (fixture_t *fixture, gconstpointer user_data)
+{
+ hb_blob_t *b = fixture->blob;
+ hb_memory_mode_t mm = GPOINTER_TO_INT (user_data);
+ unsigned int len;
+ const char *data;
+ char *data_writable;
+ unsigned int i;
+
+ g_assert (b);
+
+ len = hb_blob_get_length (b);
+ g_assert_cmpint (len, ==, fixture->len);
+
+ data = hb_blob_get_data (b, &len);
+ g_assert_cmpint (len, ==, fixture->len);
+ if (mm == HB_MEMORY_MODE_DUPLICATE) {
+ g_assert (data != fixture->data);
+ g_assert_cmpint (fixture->freed, ==, 1);
+ mm = HB_MEMORY_MODE_WRITABLE;
+ } else {
+ g_assert (data == fixture->data);
+ g_assert_cmpint (fixture->freed, ==, 0);
+ }
+
+ data_writable = hb_blob_get_data_writable (b, &len);
+ g_assert_cmpint (len, ==, fixture->len);
+ g_assert (data_writable);
+ g_assert (0 == memcmp (data_writable, fixture->data, fixture->len));
+ if (mm == HB_MEMORY_MODE_READONLY) {
+ g_assert (data_writable != data);
+ g_assert_cmpint (fixture->freed, ==, 1);
+ } else {
+ g_assert (data_writable == data);
+ }
+
+ data = hb_blob_get_data (b, &len);
+ g_assert_cmpint (len, ==, fixture->len);
+ g_assert (data == data_writable);
+
+ memset (data_writable, 0, fixture->len);
+
+ /* Now, make it immutable and watch get_data_writable() fail */
+
+ g_assert (!hb_blob_is_immutable (b));
+ hb_blob_make_immutable (b);
+ g_assert (hb_blob_is_immutable (b));
+
+ data_writable = hb_blob_get_data_writable (b, &len);
+ g_assert (!data_writable);
+ g_assert_cmpint (len, ==, 0);
+
+ data = hb_blob_get_data (b, &len);
+ g_assert_cmpint (len, ==, fixture->len);
+ for (i = 0; i < len; i++)
+ g_assert ('\0' == data[i]);
+}
+
+static void
+test_blob_subblob (fixture_t *fixture, gconstpointer user_data)
+{
+ hb_blob_t *b = fixture->blob;
+
+ fixture->len -= 2;
+ fixture->data++;
+ fixture->blob = hb_blob_create_sub_blob (b, 1, fixture->len);
+ hb_blob_destroy (b);
+
+ test_blob (fixture, user_data);
+
+ fixture->data--;
+ fixture->len += 2;
+}
+
+
+int
+main (int argc, char **argv)
+{
+ unsigned int i;
+
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_blob_empty);
+
+ for (i = 0; i < G_N_ELEMENTS (blob_names); i++)
+ {
+ const void *blob_type = GINT_TO_POINTER (i);
+ const char *blob_name = blob_names[i];
+
+ hb_test_add_fixture_flavor (fixture, blob_type, blob_name, test_blob);
+ hb_test_add_fixture_flavor (fixture, blob_type, blob_name, test_blob_subblob);
+ }
+
+ /*
+ * create_sub_blob
+ */
+
+ return hb_test_run ();
+}
diff --git a/test/api/test-buffer.c b/test/api/test-buffer.c
new file mode 100644
index 0000000..1ddc3d8
--- /dev/null
+++ b/test/api/test-buffer.c
@@ -0,0 +1,783 @@
+/*
+ * Copyright © 2011 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"
+
+/* Unit tests for hb-buffer.h */
+
+
+static const char utf8[10] = "ab\360\240\200\200defg";
+static const uint16_t utf16[8] = {'a', 'b', 0xD840, 0xDC00, 'd', 'e', 'f', 'g'};
+static const uint32_t utf32[7] = {'a', 'b', 0x20000, 'd', 'e', 'f', 'g'};
+
+
+typedef enum {
+ BUFFER_EMPTY,
+ BUFFER_ONE_BY_ONE,
+ BUFFER_UTF32,
+ BUFFER_UTF16,
+ BUFFER_UTF8,
+ BUFFER_NUM_TYPES,
+} buffer_type_t;
+
+static const char *buffer_names[] = {
+ "empty",
+ "one-by-one",
+ "utf32",
+ "utf16",
+ "utf8"
+};
+
+typedef struct
+{
+ hb_buffer_t *buffer;
+} fixture_t;
+
+static void
+fixture_init (fixture_t *fixture, gconstpointer user_data)
+{
+ hb_buffer_t *b;
+ unsigned int i;
+
+ b = fixture->buffer = hb_buffer_create ();
+
+ switch (GPOINTER_TO_INT (user_data))
+ {
+ case BUFFER_EMPTY:
+ break;
+
+ case BUFFER_ONE_BY_ONE:
+ for (i = 1; i < G_N_ELEMENTS (utf32) - 1; i++)
+ hb_buffer_add (b, utf32[i], 1, i);
+ break;
+
+ case BUFFER_UTF32:
+ hb_buffer_add_utf32 (b, utf32, G_N_ELEMENTS (utf32), 1, G_N_ELEMENTS (utf32) - 2);
+ break;
+
+ case BUFFER_UTF16:
+ hb_buffer_add_utf16 (b, utf16, G_N_ELEMENTS (utf16), 1, G_N_ELEMENTS (utf16) - 2);
+ break;
+
+ case BUFFER_UTF8:
+ hb_buffer_add_utf8 (b, utf8, G_N_ELEMENTS (utf8), 1, G_N_ELEMENTS (utf8) - 2);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+fixture_finish (fixture_t *fixture, gconstpointer user_data)
+{
+ hb_buffer_destroy (fixture->buffer);
+}
+
+
+static void
+test_buffer_properties (fixture_t *fixture, gconstpointer user_data)
+{
+ hb_buffer_t *b = fixture->buffer;
+ hb_unicode_funcs_t *ufuncs;
+
+ /* test default properties */
+
+ g_assert (hb_buffer_get_unicode_funcs (b) == hb_unicode_funcs_get_default ());
+ g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_INVALID);
+ g_assert (hb_buffer_get_script (b) == HB_SCRIPT_INVALID);
+ g_assert (hb_buffer_get_language (b) == NULL);
+
+
+ /* test property changes are retained */
+ ufuncs = hb_unicode_funcs_create (NULL);
+ hb_buffer_set_unicode_funcs (b, ufuncs);
+ hb_unicode_funcs_destroy (ufuncs);
+ g_assert (hb_buffer_get_unicode_funcs (b) == ufuncs);
+
+ hb_buffer_set_direction (b, HB_DIRECTION_RTL);
+ g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_RTL);
+
+ hb_buffer_set_script (b, HB_SCRIPT_ARABIC);
+ g_assert (hb_buffer_get_script (b) == HB_SCRIPT_ARABIC);
+
+ hb_buffer_set_language (b, hb_language_from_string ("fa", -1));
+ g_assert (hb_buffer_get_language (b) == hb_language_from_string ("Fa", -1));
+
+
+ /* test reset clears properties */
+
+ hb_buffer_reset (b);
+
+ g_assert (hb_buffer_get_unicode_funcs (b) == hb_unicode_funcs_get_default ());
+ g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_INVALID);
+ g_assert (hb_buffer_get_script (b) == HB_SCRIPT_INVALID);
+ g_assert (hb_buffer_get_language (b) == NULL);
+}
+
+static void
+test_buffer_contents (fixture_t *fixture, gconstpointer user_data)
+{
+ hb_buffer_t *b = fixture->buffer;
+ unsigned int i, len, len2;
+ buffer_type_t buffer_type = GPOINTER_TO_INT (user_data);
+ hb_glyph_info_t *glyphs;
+
+ if (buffer_type == BUFFER_EMPTY) {
+ g_assert_cmpint (hb_buffer_get_length (b), ==, 0);
+ return;
+ }
+
+ len = hb_buffer_get_length (b);
+ hb_buffer_get_glyph_infos (b, NULL); /* test NULL */
+ glyphs = hb_buffer_get_glyph_infos (b, &len2);
+ g_assert_cmpint (len, ==, len2);
+ g_assert_cmpint (len, ==, 5);
+
+ for (i = 0; i < len; i++) {
+ g_assert_cmphex (glyphs[i].mask, ==, 1);
+ g_assert_cmphex (glyphs[i].var1.u32, ==, 0);
+ g_assert_cmphex (glyphs[i].var2.u32, ==, 0);
+ }
+
+ for (i = 0; i < len; i++) {
+ unsigned int cluster;
+ cluster = 1+i;
+ if (i >= 2) {
+ if (buffer_type == BUFFER_UTF16)
+ cluster++;
+ else if (buffer_type == BUFFER_UTF8)
+ cluster += 3;
+ }
+ g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
+ g_assert_cmphex (glyphs[i].cluster, ==, cluster);
+ }
+
+ /* reverse, test, and reverse back */
+
+ hb_buffer_reverse (b);
+ for (i = 0; i < len; i++)
+ g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]);
+
+ hb_buffer_reverse (b);
+ for (i = 0; i < len; i++)
+ g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
+
+ /* reverse_clusters works same as reverse for now since each codepoint is
+ * in its own cluster */
+
+ hb_buffer_reverse_clusters (b);
+ for (i = 0; i < len; i++)
+ g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]);
+
+ hb_buffer_reverse_clusters (b);
+ for (i = 0; i < len; i++)
+ g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
+
+ /* now form a cluster and test again */
+ glyphs[2].cluster = glyphs[1].cluster;
+
+ /* reverse, test, and reverse back */
+
+ hb_buffer_reverse (b);
+ for (i = 0; i < len; i++)
+ g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]);
+
+ hb_buffer_reverse (b);
+ for (i = 0; i < len; i++)
+ g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
+
+ /* reverse_clusters twice still should return the original string,
+ * but when applied once, the 1-2 cluster should be retained. */
+
+ hb_buffer_reverse_clusters (b);
+ for (i = 0; i < len; i++) {
+ unsigned int j = len-1-i;
+ if (j == 1)
+ j = 2;
+ else if (j == 2)
+ j = 1;
+ g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+j]);
+ }
+
+ hb_buffer_reverse_clusters (b);
+ for (i = 0; i < len; i++)
+ g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
+
+
+ /* test setting length */
+
+ /* enlarge */
+ g_assert (hb_buffer_set_length (b, 10));
+ glyphs = hb_buffer_get_glyph_infos (b, NULL);
+ g_assert_cmpint (hb_buffer_get_length (b), ==, 10);
+ for (i = 0; i < 5; i++)
+ g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
+ for (i = 5; i < 10; i++)
+ g_assert_cmphex (glyphs[i].codepoint, ==, 0);
+ /* shrink */
+ g_assert (hb_buffer_set_length (b, 3));
+ glyphs = hb_buffer_get_glyph_infos (b, NULL);
+ g_assert_cmpint (hb_buffer_get_length (b), ==, 3);
+ for (i = 0; i < 3; i++)
+ g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
+
+
+ g_assert (hb_buffer_allocation_successful (b));
+
+
+ /* test reset clears content */
+
+ hb_buffer_reset (b);
+ g_assert_cmpint (hb_buffer_get_length (b), ==, 0);
+}
+
+static void
+test_buffer_positions (fixture_t *fixture, gconstpointer user_data)
+{
+ hb_buffer_t *b = fixture->buffer;
+ unsigned int i, len, len2;
+ hb_glyph_position_t *positions;
+
+ /* Without shaping, positions should all be zero */
+ len = hb_buffer_get_length (b);
+ hb_buffer_get_glyph_positions (b, NULL); /* test NULL */
+ positions = hb_buffer_get_glyph_positions (b, &len2);
+ g_assert_cmpint (len, ==, len2);
+ for (i = 0; i < len; i++) {
+ g_assert_cmpint (0, ==, positions[i].x_advance);
+ g_assert_cmpint (0, ==, positions[i].y_advance);
+ g_assert_cmpint (0, ==, positions[i].x_offset);
+ g_assert_cmpint (0, ==, positions[i].y_offset);
+ g_assert_cmpint (0, ==, positions[i].var.i32);
+ }
+
+ /* test reset clears content */
+ hb_buffer_reset (b);
+ g_assert_cmpint (hb_buffer_get_length (b), ==, 0);
+}
+
+static void
+test_buffer_allocation (fixture_t *fixture, gconstpointer user_data)
+{
+ hb_buffer_t *b = fixture->buffer;
+
+ g_assert_cmpint (hb_buffer_get_length (b), ==, 0);
+
+ g_assert (hb_buffer_pre_allocate (b, 100));
+ g_assert_cmpint (hb_buffer_get_length (b), ==, 0);
+ g_assert (hb_buffer_allocation_successful (b));
+
+ /* lets try a huge allocation, make sure it fails */
+ g_assert (!hb_buffer_pre_allocate (b, (unsigned int) -1));
+ g_assert_cmpint (hb_buffer_get_length (b), ==, 0);
+ g_assert (!hb_buffer_allocation_successful (b));
+
+ /* small one again */
+ g_assert (hb_buffer_pre_allocate (b, 50));
+ g_assert_cmpint (hb_buffer_get_length (b), ==, 0);
+ g_assert (!hb_buffer_allocation_successful (b));
+
+ hb_buffer_reset (b);
+ g_assert (hb_buffer_allocation_successful (b));
+
+ /* all allocation and size */
+ g_assert (!hb_buffer_pre_allocate (b, ((unsigned int) -1) / 20 + 1));
+ g_assert (!hb_buffer_allocation_successful (b));
+
+ hb_buffer_reset (b);
+ g_assert (hb_buffer_allocation_successful (b));
+
+ /* technically, this one can actually pass on 64bit machines, but
+ * I'm doubtful that any malloc allows 4GB allocations at a time.
+ * But let's only enable it on a 32-bit machine. */
+ if (sizeof (long) == 4) {
+ g_assert (!hb_buffer_pre_allocate (b, ((unsigned int) -1) / 20 - 1));
+ g_assert (!hb_buffer_allocation_successful (b));
+ }
+
+ hb_buffer_reset (b);
+ g_assert (hb_buffer_allocation_successful (b));
+}
+
+
+typedef struct {
+ const char utf8[8];
+ const uint32_t codepoints[8];
+} utf8_conversion_test_t;
+
+/* note: we skip the first and last byte when adding to buffer */
+static const utf8_conversion_test_t utf8_conversion_tests[] = {
+ {"a\303\207", {-1}},
+ {"a\303\207b", {0xC7}},
+ {"ab\303cd", {'b', -1, 'c'}},
+ {"ab\303\302\301cd", {'b', -1, -1, -1, 'c'}}
+};
+
+static void
+test_buffer_utf8_conversion (void)
+{
+ hb_buffer_t *b;
+ hb_glyph_info_t *glyphs;
+ unsigned int bytes, chars, i, j, len;
+
+ b = hb_buffer_create ();
+
+ for (i = 0; i < G_N_ELEMENTS (utf8_conversion_tests); i++)
+ {
+ const utf8_conversion_test_t *test = &utf8_conversion_tests[i];
+ char *escaped;
+
+ escaped = g_strescape (test->utf8, NULL);
+ g_test_message ("UTF-8 test #%d: %s", i, escaped);
+ g_free (escaped);
+
+ bytes = strlen (test->utf8);
+ for (chars = 0; test->codepoints[chars]; chars++)
+ ;
+
+ hb_buffer_reset (b);
+ hb_buffer_add_utf8 (b, test->utf8, bytes, 1, bytes - 2);
+
+ glyphs = hb_buffer_get_glyph_infos (b, &len);
+ g_assert_cmpint (len, ==, chars);
+ for (j = 0; j < chars; j++)
+ g_assert_cmphex (glyphs[j].codepoint, ==, test->codepoints[j]);
+ }
+
+ hb_buffer_destroy (b);
+}
+
+
+
+/* Following test table is adapted from glib/glib/tests/utf8-validate.c
+ * with relicensing permission from Matthias Clasen. */
+
+typedef struct {
+ const char *utf8;
+ int max_len;
+ unsigned int offset;
+ gboolean valid;
+} utf8_validity_test_t;
+
+static const utf8_validity_test_t utf8_validity_tests[] = {
+ /* some tests to check max_len handling */
+ /* length 1 */
+ { "abcde", -1, 5, TRUE },
+ { "abcde", 3, 3, TRUE },
+ { "abcde", 5, 5, TRUE },
+ /* length 2 */
+ { "\xc2\xa9\xc2\xa9\xc2\xa9", -1, 6, TRUE },
+ { "\xc2\xa9\xc2\xa9\xc2\xa9", 1, 0, FALSE },
+ { "\xc2\xa9\xc2\xa9\xc2\xa9", 2, 2, TRUE },
+ { "\xc2\xa9\xc2\xa9\xc2\xa9", 3, 2, FALSE },
+ { "\xc2\xa9\xc2\xa9\xc2\xa9", 4, 4, TRUE },
+ { "\xc2\xa9\xc2\xa9\xc2\xa9", 5, 4, FALSE },
+ { "\xc2\xa9\xc2\xa9\xc2\xa9", 6, 6, TRUE },
+ /* length 3 */
+ { "\xe2\x89\xa0\xe2\x89\xa0", -1, 6, TRUE },
+ { "\xe2\x89\xa0\xe2\x89\xa0", 1, 0, FALSE },
+ { "\xe2\x89\xa0\xe2\x89\xa0", 2, 0, FALSE },
+ { "\xe2\x89\xa0\xe2\x89\xa0", 3, 3, TRUE },
+ { "\xe2\x89\xa0\xe2\x89\xa0", 4, 3, FALSE },
+ { "\xe2\x89\xa0\xe2\x89\xa0", 5, 3, FALSE },
+ { "\xe2\x89\xa0\xe2\x89\xa0", 6, 6, TRUE },
+
+ /* examples from http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt */
+ /* greek 'kosme' */
+ { "\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5", -1, 11, TRUE },
+ /* first sequence of each length */
+ { "\x00", -1, 0, TRUE },
+ { "\xc2\x80", -1, 2, TRUE },
+ { "\xe0\xa0\x80", -1, 3, TRUE },
+ { "\xf0\x90\x80\x80", -1, 4, TRUE },
+ { "\xf8\x88\x80\x80\x80", -1, 0, FALSE },
+ { "\xfc\x84\x80\x80\x80\x80", -1, 0, FALSE },
+ /* last sequence of each length */
+ { "\x7f", -1, 1, TRUE },
+ { "\xdf\xbf", -1, 2, TRUE },
+ { "\xef\xbf\xbf", -1, 0, TRUE },
+ { "\xf7\xbf\xbf\xbf", -1, 0, TRUE },
+ { "\xfb\xbf\xbf\xbf\xbf", -1, 0, FALSE },
+ { "\xfd\xbf\xbf\xbf\xbf\xbf", -1, 0, FALSE },
+ /* other boundary conditions */
+ { "\xed\x9f\xbf", -1, 3, TRUE },
+ { "\xee\x80\x80", -1, 3, TRUE },
+ { "\xef\xbf\xbd", -1, 3, TRUE },
+ { "\xf4\x8f\xbf\xbf", -1, 0, TRUE },
+ /* malformed sequences */
+ /* continuation bytes */
+ { "\x80", -1, 0, FALSE },
+ { "\xbf", -1, 0, FALSE },
+ { "\x80\xbf", -1, 0, FALSE },
+ { "\x80\xbf\x80", -1, 0, FALSE },
+ { "\x80\xbf\x80\xbf", -1, 0, FALSE },
+ { "\x80\xbf\x80\xbf\x80", -1, 0, FALSE },
+ { "\x80\xbf\x80\xbf\x80\xbf", -1, 0, FALSE },
+ { "\x80\xbf\x80\xbf\x80\xbf\x80", -1, 0, FALSE },
+
+ /* all possible continuation byte */
+ { "\x80", -1, 0, FALSE },
+ { "\x81", -1, 0, FALSE },
+ { "\x82", -1, 0, FALSE },
+ { "\x83", -1, 0, FALSE },
+ { "\x84", -1, 0, FALSE },
+ { "\x85", -1, 0, FALSE },
+ { "\x86", -1, 0, FALSE },
+ { "\x87", -1, 0, FALSE },
+ { "\x88", -1, 0, FALSE },
+ { "\x89", -1, 0, FALSE },
+ { "\x8a", -1, 0, FALSE },
+ { "\x8b", -1, 0, FALSE },
+ { "\x8c", -1, 0, FALSE },
+ { "\x8d", -1, 0, FALSE },
+ { "\x8e", -1, 0, FALSE },
+ { "\x8f", -1, 0, FALSE },
+ { "\x90", -1, 0, FALSE },
+ { "\x91", -1, 0, FALSE },
+ { "\x92", -1, 0, FALSE },
+ { "\x93", -1, 0, FALSE },
+ { "\x94", -1, 0, FALSE },
+ { "\x95", -1, 0, FALSE },
+ { "\x96", -1, 0, FALSE },
+ { "\x97", -1, 0, FALSE },
+ { "\x98", -1, 0, FALSE },
+ { "\x99", -1, 0, FALSE },
+ { "\x9a", -1, 0, FALSE },
+ { "\x9b", -1, 0, FALSE },
+ { "\x9c", -1, 0, FALSE },
+ { "\x9d", -1, 0, FALSE },
+ { "\x9e", -1, 0, FALSE },
+ { "\x9f", -1, 0, FALSE },
+ { "\xa0", -1, 0, FALSE },
+ { "\xa1", -1, 0, FALSE },
+ { "\xa2", -1, 0, FALSE },
+ { "\xa3", -1, 0, FALSE },
+ { "\xa4", -1, 0, FALSE },
+ { "\xa5", -1, 0, FALSE },
+ { "\xa6", -1, 0, FALSE },
+ { "\xa7", -1, 0, FALSE },
+ { "\xa8", -1, 0, FALSE },
+ { "\xa9", -1, 0, FALSE },
+ { "\xaa", -1, 0, FALSE },
+ { "\xab", -1, 0, FALSE },
+ { "\xac", -1, 0, FALSE },
+ { "\xad", -1, 0, FALSE },
+ { "\xae", -1, 0, FALSE },
+ { "\xaf", -1, 0, FALSE },
+ { "\xb0", -1, 0, FALSE },
+ { "\xb1", -1, 0, FALSE },
+ { "\xb2", -1, 0, FALSE },
+ { "\xb3", -1, 0, FALSE },
+ { "\xb4", -1, 0, FALSE },
+ { "\xb5", -1, 0, FALSE },
+ { "\xb6", -1, 0, FALSE },
+ { "\xb7", -1, 0, FALSE },
+ { "\xb8", -1, 0, FALSE },
+ { "\xb9", -1, 0, FALSE },
+ { "\xba", -1, 0, FALSE },
+ { "\xbb", -1, 0, FALSE },
+ { "\xbc", -1, 0, FALSE },
+ { "\xbd", -1, 0, FALSE },
+ { "\xbe", -1, 0, FALSE },
+ { "\xbf", -1, 0, FALSE },
+ /* lone start characters */
+ { "\xc0\x20", -1, 0, FALSE },
+ { "\xc1\x20", -1, 0, FALSE },
+ { "\xc2\x20", -1, 0, FALSE },
+ { "\xc3\x20", -1, 0, FALSE },
+ { "\xc4\x20", -1, 0, FALSE },
+ { "\xc5\x20", -1, 0, FALSE },
+ { "\xc6\x20", -1, 0, FALSE },
+ { "\xc7\x20", -1, 0, FALSE },
+ { "\xc8\x20", -1, 0, FALSE },
+ { "\xc9\x20", -1, 0, FALSE },
+ { "\xca\x20", -1, 0, FALSE },
+ { "\xcb\x20", -1, 0, FALSE },
+ { "\xcc\x20", -1, 0, FALSE },
+ { "\xcd\x20", -1, 0, FALSE },
+ { "\xce\x20", -1, 0, FALSE },
+ { "\xcf\x20", -1, 0, FALSE },
+ { "\xd0\x20", -1, 0, FALSE },
+ { "\xd1\x20", -1, 0, FALSE },
+ { "\xd2\x20", -1, 0, FALSE },
+ { "\xd3\x20", -1, 0, FALSE },
+ { "\xd4\x20", -1, 0, FALSE },
+ { "\xd5\x20", -1, 0, FALSE },
+ { "\xd6\x20", -1, 0, FALSE },
+ { "\xd7\x20", -1, 0, FALSE },
+ { "\xd8\x20", -1, 0, FALSE },
+ { "\xd9\x20", -1, 0, FALSE },
+ { "\xda\x20", -1, 0, FALSE },
+ { "\xdb\x20", -1, 0, FALSE },
+ { "\xdc\x20", -1, 0, FALSE },
+ { "\xdd\x20", -1, 0, FALSE },
+ { "\xde\x20", -1, 0, FALSE },
+ { "\xdf\x20", -1, 0, FALSE },
+ { "\xe0\x20", -1, 0, FALSE },
+ { "\xe1\x20", -1, 0, FALSE },
+ { "\xe2\x20", -1, 0, FALSE },
+ { "\xe3\x20", -1, 0, FALSE },
+ { "\xe4\x20", -1, 0, FALSE },
+ { "\xe5\x20", -1, 0, FALSE },
+ { "\xe6\x20", -1, 0, FALSE },
+ { "\xe7\x20", -1, 0, FALSE },
+ { "\xe8\x20", -1, 0, FALSE },
+ { "\xe9\x20", -1, 0, FALSE },
+ { "\xea\x20", -1, 0, FALSE },
+ { "\xeb\x20", -1, 0, FALSE },
+ { "\xec\x20", -1, 0, FALSE },
+ { "\xed\x20", -1, 0, FALSE },
+ { "\xee\x20", -1, 0, FALSE },
+ { "\xef\x20", -1, 0, FALSE },
+ { "\xf0\x20", -1, 0, FALSE },
+ { "\xf1\x20", -1, 0, FALSE },
+ { "\xf2\x20", -1, 0, FALSE },
+ { "\xf3\x20", -1, 0, FALSE },
+ { "\xf4\x20", -1, 0, FALSE },
+ { "\xf5\x20", -1, 0, FALSE },
+ { "\xf6\x20", -1, 0, FALSE },
+ { "\xf7\x20", -1, 0, FALSE },
+ { "\xf8\x20", -1, 0, FALSE },
+ { "\xf9\x20", -1, 0, FALSE },
+ { "\xfa\x20", -1, 0, FALSE },
+ { "\xfb\x20", -1, 0, FALSE },
+ { "\xfc\x20", -1, 0, FALSE },
+ { "\xfd\x20", -1, 0, FALSE },
+ /* missing continuation bytes */
+ { "\x20\xc0", -1, 1, FALSE },
+ { "\x20\xe0\x80", -1, 1, FALSE },
+ { "\x20\xf0\x80\x80", -1, 1, FALSE },
+ { "\x20\xf8\x80\x80\x80", -1, 1, FALSE },
+ { "\x20\xfc\x80\x80\x80\x80", -1, 1, FALSE },
+ { "\x20\xdf", -1, 1, FALSE },
+ { "\x20\xef\xbf", -1, 1, FALSE },
+ { "\x20\xf7\xbf\xbf", -1, 1, FALSE },
+ { "\x20\xfb\xbf\xbf\xbf", -1, 1, FALSE },
+ { "\x20\xfd\xbf\xbf\xbf\xbf", -1, 1, FALSE },
+ /* impossible bytes */
+ { "\x20\xfe\x20", -1, 1, FALSE },
+ { "\x20\xff\x20", -1, 1, FALSE },
+#if 0
+ /* XXX fix these, or document that we don't detect them? */
+ /* overlong sequences */
+ { "\x20\xc0\xaf\x20", -1, 1, FALSE },
+ { "\x20\xe0\x80\xaf\x20", -1, 1, FALSE },
+ { "\x20\xf0\x80\x80\xaf\x20", -1, 1, FALSE },
+ { "\x20\xf8\x80\x80\x80\xaf\x20", -1, 1, FALSE },
+ { "\x20\xfc\x80\x80\x80\x80\xaf\x20", -1, 1, FALSE },
+ { "\x20\xc1\xbf\x20", -1, 1, FALSE },
+ { "\x20\xe0\x9f\xbf\x20", -1, 1, FALSE },
+ { "\x20\xf0\x8f\xbf\xbf\x20", -1, 1, FALSE },
+ { "\x20\xf8\x87\xbf\xbf\xbf\x20", -1, 1, FALSE },
+ { "\x20\xfc\x83\xbf\xbf\xbf\xbf\x20", -1, 1, FALSE },
+ { "\x20\xc0\x80\x20", -1, 1, FALSE },
+ { "\x20\xe0\x80\x80\x20", -1, 1, FALSE },
+ { "\x20\xf0\x80\x80\x80\x20", -1, 1, FALSE },
+ { "\x20\xf8\x80\x80\x80\x80\x20", -1, 1, FALSE },
+ { "\x20\xfc\x80\x80\x80\x80\x80\x20", -1, 1, FALSE },
+ /* illegal code positions */
+ { "\x20\xed\xa0\x80\x20", -1, 1, FALSE },
+ { "\x20\xed\xad\xbf\x20", -1, 1, FALSE },
+ { "\x20\xed\xae\x80\x20", -1, 1, FALSE },
+ { "\x20\xed\xaf\xbf\x20", -1, 1, FALSE },
+ { "\x20\xed\xb0\x80\x20", -1, 1, FALSE },
+ { "\x20\xed\xbe\x80\x20", -1, 1, FALSE },
+ { "\x20\xed\xbf\xbf\x20", -1, 1, FALSE },
+ { "\x20\xed\xa0\x80\xed\xb0\x80\x20", -1, 1, FALSE },
+ { "\x20\xed\xa0\x80\xed\xbf\xbf\x20", -1, 1, FALSE },
+ { "\x20\xed\xad\xbf\xed\xb0\x80\x20", -1, 1, FALSE },
+ { "\x20\xed\xad\xbf\xed\xbf\xbf\x20", -1, 1, FALSE },
+ { "\x20\xed\xae\x80\xed\xb0\x80\x20", -1, 1, FALSE },
+ { "\x20\xed\xae\x80\xed\xbf\xbf\x20", -1, 1, FALSE },
+ { "\x20\xed\xaf\xbf\xed\xb0\x80\x20", -1, 1, FALSE },
+ { "\x20\xed\xaf\xbf\xed\xbf\xbf\x20", -1, 1, FALSE },
+ { "\x20\xef\xbf\xbe\x20", -1, 1, FALSE },
+ { "\x20\xef\xbf\xbf\x20", -1, 1, FALSE },
+#endif
+ { "", -1, 0, TRUE }
+};
+
+static void
+test_buffer_utf8_validity (void)
+{
+ hb_buffer_t *b;
+ unsigned int i;
+
+ b = hb_buffer_create ();
+
+ for (i = 0; i < G_N_ELEMENTS (utf8_validity_tests); i++)
+ {
+ const utf8_validity_test_t *test = &utf8_validity_tests[i];
+ unsigned int text_bytes, segment_bytes, j, len;
+ hb_glyph_info_t *glyphs;
+ char *escaped;
+
+ escaped = g_strescape (test->utf8, NULL);
+ g_test_message ("UTF-8 test #%d: %s", i, escaped);
+ g_free (escaped);
+
+ text_bytes = strlen (test->utf8);
+ if (test->max_len == -1)
+ segment_bytes = text_bytes;
+ else
+ segment_bytes = test->max_len;
+
+ hb_buffer_reset (b);
+ hb_buffer_add_utf8 (b, test->utf8, text_bytes, 0, segment_bytes);
+
+ glyphs = hb_buffer_get_glyph_infos (b, &len);
+ for (j = 0; j < len; j++)
+ if (glyphs[j].codepoint == (hb_codepoint_t) -1)
+ break;
+
+ g_assert (test->valid ? j == len : j < len);
+ if (!test->valid)
+ g_assert (glyphs[j].cluster == test->offset);
+ }
+
+ hb_buffer_destroy (b);
+}
+
+
+typedef struct {
+ const uint16_t utf16[8];
+ const uint32_t codepoints[8];
+} utf16_conversion_test_t;
+
+/* note: we skip the first and last item from utf16 when adding to buffer */
+static const utf16_conversion_test_t utf16_conversion_tests[] = {
+ {{0x41, 0x004D, 0x0430, 0x4E8C, 0xD800, 0xDF02, 0x61} , {0x004D, 0x0430, 0x4E8C, 0x10302}},
+ {{0x41, 0xD800, 0xDF02, 0x61}, {0x10302}},
+ {{0x41, 0xD800, 0xDF02}, {-1}},
+ {{0x41, 0x61, 0xD800, 0xDF02}, {0x61, -1}},
+ {{0x41, 0xD800, 0x61, 0xDF02}, {-1, 0x61}},
+ {{0x41, 0x61}, {}}
+};
+
+static void
+test_buffer_utf16_conversion (void)
+{
+ hb_buffer_t *b;
+ unsigned int i;
+
+ b = hb_buffer_create ();
+
+ for (i = 0; i < G_N_ELEMENTS (utf16_conversion_tests); i++)
+ {
+ const utf16_conversion_test_t *test = &utf16_conversion_tests[i];
+ unsigned int u_len, chars, j, len;
+ hb_glyph_info_t *glyphs;
+
+ g_test_message ("UTF-16 test #%d", i);
+
+ for (u_len = 0; test->utf16[u_len]; u_len++)
+ ;
+ for (chars = 0; test->codepoints[chars]; chars++)
+ ;
+
+ hb_buffer_reset (b);
+ hb_buffer_add_utf16 (b, test->utf16, u_len, 1, u_len - 2);
+
+ glyphs = hb_buffer_get_glyph_infos (b, &len);
+ g_assert_cmpint (len, ==, chars);
+ for (j = 0; j < chars; j++)
+ g_assert_cmphex (glyphs[j].codepoint, ==, test->codepoints[j]);
+ }
+
+ hb_buffer_destroy (b);
+}
+
+static void
+test_empty (hb_buffer_t *b)
+{
+ g_assert_cmpint (hb_buffer_get_length (b), ==, 0);
+ g_assert (!hb_buffer_get_glyph_infos (b, NULL));
+ g_assert (!hb_buffer_get_glyph_positions (b, NULL));
+}
+
+static void
+test_buffer_empty (void)
+{
+ hb_buffer_t *b = hb_buffer_get_empty ();
+
+ g_assert (hb_buffer_get_empty ());
+ g_assert (hb_buffer_get_empty () == b);
+
+ g_assert (!hb_buffer_allocation_successful (b));
+
+ test_empty (b);
+
+ hb_buffer_add_utf32 (b, utf32, G_N_ELEMENTS (utf32), 1, G_N_ELEMENTS (utf32) - 2);
+
+ test_empty (b);
+
+ hb_buffer_reverse (b);
+ hb_buffer_reverse_clusters (b);
+
+ g_assert (!hb_buffer_set_length (b, 10));
+
+ test_empty (b);
+
+ g_assert (hb_buffer_set_length (b, 0));
+
+ test_empty (b);
+
+ g_assert (!hb_buffer_allocation_successful (b));
+
+ hb_buffer_reset (b);
+
+ test_empty (b);
+
+ g_assert (!hb_buffer_allocation_successful (b));
+}
+
+int
+main (int argc, char **argv)
+{
+ unsigned int i;
+
+ hb_test_init (&argc, &argv);
+
+ for (i = 0; i < BUFFER_NUM_TYPES; i++)
+ {
+ const void *buffer_type = GINT_TO_POINTER (i);
+ const char *buffer_name = buffer_names[i];
+
+ hb_test_add_fixture_flavor (fixture, buffer_type, buffer_name, test_buffer_properties);
+ hb_test_add_fixture_flavor (fixture, buffer_type, buffer_name, test_buffer_contents);
+ hb_test_add_fixture_flavor (fixture, buffer_type, buffer_name, test_buffer_positions);
+ }
+
+ hb_test_add_fixture (fixture, GINT_TO_POINTER (BUFFER_EMPTY), test_buffer_allocation);
+
+ hb_test_add (test_buffer_utf8_conversion);
+ hb_test_add (test_buffer_utf8_validity);
+ hb_test_add (test_buffer_utf16_conversion);
+ hb_test_add (test_buffer_empty);
+
+ return hb_test_run();
+}
diff --git a/test/api/test-c.c b/test/api/test-c.c
new file mode 100644
index 0000000..25a38e5
--- /dev/null
+++ b/test/api/test-c.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2011 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
+ */
+
+/* This file tests that all headers can be included from .c files */
+
+
+#include <config.h>
+
+#include <hb.h>
+
+#ifdef HAVE_GLIB
+#include <hb-glib.h>
+#endif
+
+#ifdef HAVE_ICU
+#include <hb-icu.h>
+#endif
+
+#ifdef HAVE_FREETYPE
+#include <hb-ft.h>
+#endif
+
+#ifdef HAVE_OT
+#include <hb-ot.h>
+#endif
+
+#ifdef HAVE_UNISCRIBE
+#include <hb-uniscribe.h>
+#endif
+
+int
+main (int argc, char **argv)
+{
+ return !*hb_shape_list_shapers ();
+}
diff --git a/test/api/test-common.c b/test/api/test-common.c
new file mode 100644
index 0000000..74b50be
--- /dev/null
+++ b/test/api/test-common.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright © 2011 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"
+
+/* Unit tests for hb-common.h */
+
+
+static void
+test_types_int (void)
+{
+ /* We already ASSERT_STATIC these in hb-private.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_HORIZONTAL (HB_DIRECTION_INVALID));
+
+ 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_VERTICAL (HB_DIRECTION_INVALID));
+
+ 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_FORWARD (HB_DIRECTION_INVALID));
+
+ 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 (!HB_DIRECTION_IS_BACKWARD (HB_DIRECTION_INVALID));
+
+ g_assert (HB_DIRECTION_IS_VALID (HB_DIRECTION_LTR));
+ g_assert (HB_DIRECTION_IS_VALID (HB_DIRECTION_TTB));
+ g_assert (HB_DIRECTION_IS_VALID (HB_DIRECTION_RTL));
+ g_assert (HB_DIRECTION_IS_VALID (HB_DIRECTION_BTT));
+ g_assert (!HB_DIRECTION_IS_VALID (HB_DIRECTION_INVALID));
+ g_assert (!HB_DIRECTION_IS_VALID ((hb_direction_t) 0x12345678));
+
+ 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);
+ //g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_INVALID), ==, HB_DIRECTION_INVALID);
+
+ g_assert_cmpint (HB_DIRECTION_INVALID, ==, hb_direction_from_string (NULL, -1));
+ g_assert_cmpint (HB_DIRECTION_INVALID, ==, hb_direction_from_string ("", -1));
+ g_assert_cmpint (HB_DIRECTION_INVALID, ==, hb_direction_from_string ("t", 0));
+ g_assert_cmpint (HB_DIRECTION_INVALID, ==, hb_direction_from_string ("x", -1));
+ g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("r", -1));
+ g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("rtl", -1));
+ g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("RtL", -1));
+ g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("right-to-left", -1));
+ g_assert_cmpint (HB_DIRECTION_TTB, ==, hb_direction_from_string ("ttb", -1));
+
+ g_assert (0 == strcmp ("ltr", hb_direction_to_string (HB_DIRECTION_LTR)));
+ g_assert (0 == strcmp ("rtl", hb_direction_to_string (HB_DIRECTION_RTL)));
+ g_assert (0 == strcmp ("ttb", hb_direction_to_string (HB_DIRECTION_TTB)));
+ g_assert (0 == strcmp ("btt", hb_direction_to_string (HB_DIRECTION_BTT)));
+ g_assert (0 == strcmp ("invalid", hb_direction_to_string (HB_DIRECTION_INVALID)));
+}
+
+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_from_string ("aBcDe", -1), ==, 0x61426344);
+ g_assert_cmphex (hb_tag_from_string ("aBcD", -1), ==, 0x61426344);
+ g_assert_cmphex (hb_tag_from_string ("aBc", -1), ==, 0x61426320);
+ g_assert_cmphex (hb_tag_from_string ("aB", -1), ==, 0x61422020);
+ g_assert_cmphex (hb_tag_from_string ("a", -1), ==, 0x61202020);
+ g_assert_cmphex (hb_tag_from_string ("aBcDe", 1), ==, 0x61202020);
+ g_assert_cmphex (hb_tag_from_string ("aBcDe", 2), ==, 0x61422020);
+ g_assert_cmphex (hb_tag_from_string ("aBcDe", 3), ==, 0x61426320);
+ g_assert_cmphex (hb_tag_from_string ("aBcDe", 4), ==, 0x61426344);
+ g_assert_cmphex (hb_tag_from_string ("aBcDe", 4), ==, 0x61426344);
+
+ g_assert_cmphex (hb_tag_from_string ("", -1), ==, HB_TAG_NONE);
+ g_assert_cmphex (hb_tag_from_string ("x", 0), ==, HB_TAG_NONE);
+ g_assert_cmphex (hb_tag_from_string (NULL, -1), ==, HB_TAG_NONE);
+}
+
+static void
+test_types_script (void)
+{
+ hb_tag_t arab = HB_TAG_CHAR4 ("arab");
+ hb_tag_t Arab = HB_TAG_CHAR4 ("Arab");
+ hb_tag_t ARAB = HB_TAG_CHAR4 ("ARAB");
+
+ hb_tag_t wWyZ = HB_TAG_CHAR4 ("wWyZ");
+ hb_tag_t Wwyz = HB_TAG_CHAR4 ("Wwyz");
+
+ hb_tag_t x123 = HB_TAG_CHAR4 ("x123");
+
+ g_assert_cmpint (HB_SCRIPT_INVALID, ==, (hb_script_t) HB_TAG_NONE);
+ g_assert_cmphex (HB_SCRIPT_ARABIC, !=, HB_SCRIPT_LATIN);
+
+ g_assert_cmphex (HB_SCRIPT_INVALID, ==, hb_script_from_string (NULL, -1));
+ g_assert_cmphex (HB_SCRIPT_INVALID, ==, hb_script_from_string ("", -1));
+ g_assert_cmphex (HB_SCRIPT_INVALID, ==, hb_script_from_string ("x", 0));
+ g_assert_cmphex (HB_SCRIPT_UNKNOWN, ==, hb_script_from_string ("x", -1));
+
+ g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_string ("arab", -1));
+ g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_string ("Arab", -1));
+ g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_string ("ARAB", -1));
+ g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_string ("Arabic", 6));
+ g_assert_cmphex (HB_SCRIPT_ARABIC, !=, hb_script_from_string ("Arabic", 3));
+
+ g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (arab));
+ g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (Arab));
+ g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (ARAB));
+
+ /* Arbitrary tags that look like may be valid ISO 15924 should be preserved. */
+ g_assert_cmphex (HB_SCRIPT_UNKNOWN, !=, hb_script_from_string ("wWyZ", -1));
+ g_assert_cmphex (HB_SCRIPT_UNKNOWN, !=, hb_script_from_iso15924_tag (wWyZ));
+ /* Otherwise, UNKNOWN should be returned. */
+ g_assert_cmphex (HB_SCRIPT_UNKNOWN, ==, hb_script_from_string ("x123", -1));
+ g_assert_cmphex (HB_SCRIPT_UNKNOWN, ==, hb_script_from_iso15924_tag (x123));
+
+ g_assert_cmphex (hb_script_to_iso15924_tag (HB_SCRIPT_ARABIC), ==, Arab);
+ g_assert_cmphex (hb_script_to_iso15924_tag (hb_script_from_iso15924_tag (wWyZ)), ==, Wwyz);
+
+ g_assert_cmpint (hb_script_get_horizontal_direction (HB_SCRIPT_LATIN), ==, HB_DIRECTION_LTR);
+ g_assert_cmpint (hb_script_get_horizontal_direction (HB_SCRIPT_ARABIC), ==, HB_DIRECTION_RTL);
+ g_assert_cmpint (hb_script_get_horizontal_direction (hb_script_from_iso15924_tag (wWyZ)), ==, HB_DIRECTION_LTR);
+}
+
+static void
+test_types_language (void)
+{
+ hb_language_t fa = hb_language_from_string ("fa", -1);
+ hb_language_t fa_IR = hb_language_from_string ("fa_IR", -1);
+ hb_language_t fa_ir = hb_language_from_string ("fa-ir", -1);
+ hb_language_t en = hb_language_from_string ("en", -1);
+
+ g_assert (HB_LANGUAGE_INVALID == NULL);
+
+ g_assert (fa != NULL);
+ g_assert (fa_IR != NULL);
+ g_assert (fa_IR == fa_ir);
+
+ g_assert (en != NULL);
+ g_assert (en != fa);
+
+ /* Test recall */
+ g_assert (en == hb_language_from_string ("en", -1));
+ g_assert (en == hb_language_from_string ("eN", -1));
+ g_assert (en == hb_language_from_string ("Enx", 2));
+
+ g_assert (HB_LANGUAGE_INVALID == hb_language_from_string (NULL, -1));
+ g_assert (HB_LANGUAGE_INVALID == hb_language_from_string ("", -1));
+ g_assert (HB_LANGUAGE_INVALID == hb_language_from_string ("en", 0));
+ g_assert (HB_LANGUAGE_INVALID != hb_language_from_string ("en", 1));
+ g_assert (NULL == hb_language_to_string (HB_LANGUAGE_INVALID));
+
+ /* Not sure how to test this better. Setting env vars
+ * here doesn't sound like the right approach, and I'm
+ * not sure that it even works. */
+ g_assert (HB_LANGUAGE_INVALID != hb_language_get_default ());
+}
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_types_int);
+ hb_test_add (test_types_direction);
+ hb_test_add (test_types_tag);
+ hb_test_add (test_types_script);
+ hb_test_add (test_types_language);
+
+ return hb_test_run();
+}
diff --git a/test/api/test-cplusplus.cc b/test/api/test-cplusplus.cc
new file mode 100644
index 0000000..3313d74
--- /dev/null
+++ b/test/api/test-cplusplus.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright © 2011 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
+ */
+
+/* This file tests that all headers can be included from .cc files */
+
+
+#include "test-c.c"
diff --git a/test/api/test-font.c b/test/api/test-font.c
new file mode 100644
index 0000000..40540c4
--- /dev/null
+++ b/test/api/test-font.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright © 2011 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"
+
+/* Unit tests for hb-font.h */
+
+
+static const char test_data[] = "test\0data";
+
+
+static void
+test_face_empty (void)
+{
+ g_assert (hb_face_get_empty ());
+ g_assert (hb_face_get_empty () == hb_face_create (hb_blob_get_empty (), 0));
+ g_assert (hb_face_get_empty () == hb_face_create (NULL, 0));
+
+ g_assert (hb_face_reference_table (hb_face_get_empty (), HB_TAG ('h','e','a','d')) == hb_blob_get_empty ());
+
+ g_assert_cmpint (hb_face_get_upem (hb_face_get_empty ()), ==, 1000);
+}
+
+static void
+test_face_create (void)
+{
+ hb_face_t *face;
+ hb_blob_t *blob;
+
+ blob = hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL);
+ face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+
+ g_assert (hb_face_reference_table (face, HB_TAG ('h','e','a','d')) == hb_blob_get_empty ());
+
+ g_assert_cmpint (hb_face_get_upem (face), ==, 1000);
+
+ hb_face_destroy (face);
+}
+
+
+static void
+free_up (void *user_data)
+{
+ int *freed = (int *) user_data;
+
+ g_assert (!*freed);
+
+ (*freed)++;
+}
+
+static hb_blob_t *
+get_table (hb_face_t *face, hb_tag_t tag, void *user_data)
+{
+ if (tag == HB_TAG ('a','b','c','d'))
+ return hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL);
+
+ return hb_blob_get_empty ();
+}
+
+static void
+test_face_createfortables (void)
+{
+ hb_face_t *face;
+ hb_blob_t *blob;
+ const char *data;
+ unsigned int len;
+ int freed = 0;
+
+ face = hb_face_create_for_tables (get_table, &freed, free_up);
+ g_assert (!freed);
+
+ g_assert (hb_face_reference_table (face, HB_TAG ('h','e','a','d')) == hb_blob_get_empty ());
+
+ blob = hb_face_reference_table (face, HB_TAG ('a','b','c','d'));
+ g_assert (blob != hb_blob_get_empty ());
+
+ data = hb_blob_get_data (blob, &len);
+ g_assert_cmpint (len, ==, sizeof (test_data));
+ g_assert (0 == memcmp (data, test_data, sizeof (test_data)));
+ hb_blob_destroy (blob);
+
+ g_assert_cmpint (hb_face_get_upem (face), ==, 1000);
+
+ hb_face_destroy (face);
+ g_assert (freed);
+}
+
+static void
+_test_font_nil_funcs (hb_font_t *font)
+{
+ hb_codepoint_t glyph;
+ hb_position_t x, y;
+ hb_glyph_extents_t extents;
+
+ x = y = 13;
+ g_assert (!hb_font_get_glyph_contour_point (font, 17, 2, &x, &y));
+ g_assert_cmpint (x, ==, 0);
+ g_assert_cmpint (y, ==, 0);
+
+ x = hb_font_get_glyph_h_advance (font, 17);
+ g_assert_cmpint (x, ==, 0);
+
+ extents.x_bearing = extents.y_bearing = 13;
+ extents.width = extents.height = 15;
+ hb_font_get_glyph_extents (font, 17, &extents);
+ g_assert_cmpint (extents.x_bearing, ==, 0);
+ g_assert_cmpint (extents.y_bearing, ==, 0);
+ g_assert_cmpint (extents.width, ==, 0);
+ g_assert_cmpint (extents.height, ==, 0);
+
+ glyph = 3;
+ g_assert (!hb_font_get_glyph (font, 17, 2, &glyph));
+ g_assert_cmpint (glyph, ==, 0);
+
+ x = 13;
+ x = hb_font_get_glyph_h_kerning (font, 17, 19);
+ g_assert_cmpint (x, ==, 0);
+}
+
+static void
+_test_fontfuncs_nil (hb_font_funcs_t *ffuncs)
+{
+ hb_blob_t *blob;
+ hb_face_t *face;
+ hb_font_t *font;
+ hb_font_t *subfont;
+ int freed = 0;
+
+ blob = hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL);
+ face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+ g_assert (!hb_face_is_immutable (face));
+ font = hb_font_create (face);
+ g_assert (font);
+ g_assert (hb_face_is_immutable (face));
+ hb_face_destroy (face);
+
+
+ hb_font_set_funcs (font, ffuncs, &freed, free_up);
+ g_assert_cmpint (freed, ==, 0);
+
+ _test_font_nil_funcs (font);
+
+ subfont = hb_font_create_sub_font (font);
+ g_assert (subfont);
+
+ g_assert_cmpint (freed, ==, 0);
+ hb_font_destroy (font);
+ g_assert_cmpint (freed, ==, 0);
+
+ _test_font_nil_funcs (subfont);
+
+ hb_font_destroy (subfont);
+ g_assert_cmpint (freed, ==, 1);
+}
+
+static void
+test_fontfuncs_empty (void)
+{
+ g_assert (hb_font_funcs_get_empty ());
+ g_assert (hb_font_funcs_is_immutable (hb_font_funcs_get_empty ()));
+ _test_fontfuncs_nil (hb_font_funcs_get_empty ());
+}
+
+static void
+test_fontfuncs_nil (void)
+{
+ hb_font_funcs_t *ffuncs;
+
+ ffuncs = hb_font_funcs_create ();
+
+ g_assert (!hb_font_funcs_is_immutable (ffuncs));
+ _test_fontfuncs_nil (hb_font_funcs_get_empty ());
+
+ hb_font_funcs_destroy (ffuncs);
+}
+
+static hb_bool_t
+contour_point_func1 (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph, unsigned int point_index,
+ hb_position_t *x, hb_position_t *y,
+ void *user_data)
+{
+ if (glyph == 1) {
+ *x = 2;
+ *y = 3;
+ return TRUE;
+ }
+ if (glyph == 2) {
+ *x = 4;
+ *y = 5;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static hb_bool_t
+contour_point_func2 (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph, unsigned int point_index,
+ hb_position_t *x, hb_position_t *y,
+ void *user_data)
+{
+ if (glyph == 1) {
+ *x = 6;
+ *y = 7;
+ return TRUE;
+ }
+
+ return hb_font_get_glyph_contour_point (hb_font_get_parent (font),
+ glyph, point_index, x, y);
+}
+
+static hb_position_t
+glyph_h_advance_func1 (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ void *user_data)
+{
+ if (glyph == 1)
+ return 8;
+
+ return 0;
+}
+
+static void
+test_fontfuncs_subclassing (void)
+{
+ hb_blob_t *blob;
+ hb_face_t *face;
+
+ hb_font_funcs_t *ffuncs1;
+ hb_font_funcs_t *ffuncs2;
+
+ hb_font_t *font1;
+ hb_font_t *font2;
+ hb_font_t *font3;
+
+ hb_position_t x;
+ hb_position_t y;
+
+ blob = hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL);
+ face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+ font1 = hb_font_create (face);
+ hb_face_destroy (face);
+ hb_font_set_scale (font1, 10, 10);
+
+ /* setup font1 */
+ ffuncs1 = hb_font_funcs_create ();
+ hb_font_funcs_set_glyph_contour_point_func (ffuncs1, contour_point_func1, NULL, NULL);
+ hb_font_funcs_set_glyph_h_advance_func (ffuncs1, glyph_h_advance_func1, NULL, NULL);
+ hb_font_set_funcs (font1, ffuncs1, NULL, NULL);
+ hb_font_funcs_destroy (ffuncs1);
+
+ x = y = 1;
+ g_assert (hb_font_get_glyph_contour_point_for_origin (font1, 1, 2, HB_DIRECTION_LTR, &x, &y));
+ g_assert_cmpint (x, ==, 2);
+ g_assert_cmpint (y, ==, 3);
+ g_assert (hb_font_get_glyph_contour_point_for_origin (font1, 2, 5, HB_DIRECTION_LTR, &x, &y));
+ g_assert_cmpint (x, ==, 4);
+ g_assert_cmpint (y, ==, 5);
+ g_assert (!hb_font_get_glyph_contour_point_for_origin (font1, 3, 7, HB_DIRECTION_RTL, &x, &y));
+ g_assert_cmpint (x, ==, 0);
+ g_assert_cmpint (y, ==, 0);
+ x = hb_font_get_glyph_h_advance (font1, 1);
+ g_assert_cmpint (x, ==, 8);
+ x = hb_font_get_glyph_h_advance (font1, 2);
+ g_assert_cmpint (x, ==, 0);
+
+
+ font2 = hb_font_create_sub_font (font1);
+ g_assert (hb_font_is_immutable (font1));
+ hb_font_destroy (font1);
+
+ /* setup font2 to override some funcs */
+ ffuncs2 = hb_font_funcs_create ();
+ hb_font_funcs_set_glyph_contour_point_func (ffuncs2, contour_point_func2, NULL, NULL);
+ hb_font_set_funcs (font2, ffuncs2, NULL, NULL);
+ hb_font_funcs_destroy (ffuncs2);
+
+ x = y = 1;
+ g_assert (hb_font_get_glyph_contour_point_for_origin (font2, 1, 2, HB_DIRECTION_LTR, &x, &y));
+ g_assert_cmpint (x, ==, 6);
+ g_assert_cmpint (y, ==, 7);
+ g_assert (hb_font_get_glyph_contour_point_for_origin (font2, 2, 5, HB_DIRECTION_RTL, &x, &y));
+ g_assert_cmpint (x, ==, 4);
+ g_assert_cmpint (y, ==, 5);
+ g_assert (!hb_font_get_glyph_contour_point_for_origin (font2, 3, 7, HB_DIRECTION_LTR, &x, &y));
+ g_assert_cmpint (x, ==, 0);
+ g_assert_cmpint (y, ==, 0);
+ x = hb_font_get_glyph_h_advance (font2, 1);
+ g_assert_cmpint (x, ==, 8);
+ x = hb_font_get_glyph_h_advance (font2, 2);
+ g_assert_cmpint (x, ==, 0);
+
+
+ font3 = hb_font_create_sub_font (font2);
+ g_assert (hb_font_is_immutable (font2));
+ hb_font_destroy (font2);
+
+ /* setup font3 to override scale */
+ hb_font_set_scale (font3, 20, 30);
+
+ x = y = 1;
+ g_assert (hb_font_get_glyph_contour_point_for_origin (font3, 1, 2, HB_DIRECTION_RTL, &x, &y));
+ g_assert_cmpint (x, ==, 6*2);
+ g_assert_cmpint (y, ==, 7*3);
+ g_assert (hb_font_get_glyph_contour_point_for_origin (font3, 2, 5, HB_DIRECTION_LTR, &x, &y));
+ g_assert_cmpint (x, ==, 4*2);
+ g_assert_cmpint (y, ==, 5*3);
+ g_assert (!hb_font_get_glyph_contour_point_for_origin (font3, 3, 7, HB_DIRECTION_LTR, &x, &y));
+ g_assert_cmpint (x, ==, 0*2);
+ g_assert_cmpint (y, ==, 0*3);
+ x = hb_font_get_glyph_h_advance (font3, 1);
+ g_assert_cmpint (x, ==, 8*2);
+ x = hb_font_get_glyph_h_advance (font3, 2);
+ g_assert_cmpint (x, ==, 0*2);
+
+
+ hb_font_destroy (font3);
+}
+
+
+static void
+test_font_empty (void)
+{
+ g_assert (hb_font_get_empty ());
+ g_assert (hb_font_get_empty () == hb_font_create (hb_face_get_empty ()));
+ g_assert (hb_font_get_empty () == hb_font_create (NULL));
+ g_assert (hb_font_get_empty () == hb_font_create_sub_font (NULL));
+ g_assert (hb_font_is_immutable (hb_font_get_empty ()));
+
+ g_assert (hb_font_get_face (hb_font_get_empty ()) == hb_face_get_empty ());
+ g_assert (hb_font_get_parent (hb_font_get_empty ()) == NULL);
+}
+
+static void
+test_font_properties (void)
+{
+ hb_blob_t *blob;
+ hb_face_t *face;
+ hb_font_t *font;
+ hb_font_t *subfont;
+ int x_scale, y_scale;
+ unsigned int x_ppem, y_ppem;
+
+ blob = hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL);
+ face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+ font = hb_font_create (face);
+ hb_face_destroy (face);
+
+
+ g_assert (hb_font_get_face (font) == face);
+ g_assert (hb_font_get_parent (font) == NULL);
+
+
+ /* Check scale */
+
+ hb_font_get_scale (font, NULL, NULL);
+ x_scale = y_scale = 13;
+ hb_font_get_scale (font, &x_scale, NULL);
+ g_assert_cmpint (x_scale, ==, 0);
+ x_scale = y_scale = 13;
+ hb_font_get_scale (font, NULL, &y_scale);
+ g_assert_cmpint (y_scale, ==, 0);
+ x_scale = y_scale = 13;
+ hb_font_get_scale (font, &x_scale, &y_scale);
+ g_assert_cmpint (x_scale, ==, 0);
+ g_assert_cmpint (y_scale, ==, 0);
+
+ hb_font_set_scale (font, 17, 19);
+
+ x_scale = y_scale = 13;
+ hb_font_get_scale (font, &x_scale, &y_scale);
+ g_assert_cmpint (x_scale, ==, 17);
+ g_assert_cmpint (y_scale, ==, 19);
+
+
+ /* Check ppem */
+
+ hb_font_get_ppem (font, NULL, NULL);
+ x_ppem = y_ppem = 13;
+ hb_font_get_ppem (font, &x_ppem, NULL);
+ g_assert_cmpint (x_ppem, ==, 0);
+ x_ppem = y_ppem = 13;
+ hb_font_get_ppem (font, NULL, &y_ppem);
+ g_assert_cmpint (y_ppem, ==, 0);
+ x_ppem = y_ppem = 13;
+ hb_font_get_ppem (font, &x_ppem, &y_ppem);
+ g_assert_cmpint (x_ppem, ==, 0);
+ g_assert_cmpint (y_ppem, ==, 0);
+
+ hb_font_set_ppem (font, 17, 19);
+
+ x_ppem = y_ppem = 13;
+ hb_font_get_ppem (font, &x_ppem, &y_ppem);
+ g_assert_cmpint (x_ppem, ==, 17);
+ g_assert_cmpint (y_ppem, ==, 19);
+
+
+ /* Check immutable */
+
+ g_assert (!hb_font_is_immutable (font));
+ hb_font_make_immutable (font);
+ g_assert (hb_font_is_immutable (font));
+
+ hb_font_set_scale (font, 10, 12);
+ x_scale = y_scale = 13;
+ hb_font_get_scale (font, &x_scale, &y_scale);
+ g_assert_cmpint (x_scale, ==, 17);
+ g_assert_cmpint (y_scale, ==, 19);
+
+ hb_font_set_ppem (font, 10, 12);
+ x_ppem = y_ppem = 13;
+ hb_font_get_ppem (font, &x_ppem, &y_ppem);
+ g_assert_cmpint (x_ppem, ==, 17);
+ g_assert_cmpint (y_ppem, ==, 19);
+
+
+ /* sub_font now */
+ subfont = hb_font_create_sub_font (font);
+ hb_font_destroy (font);
+
+ g_assert (hb_font_get_parent (subfont) == font);
+ g_assert (hb_font_get_face (subfont) == face);
+
+ /* scale */
+ x_scale = y_scale = 13;
+ hb_font_get_scale (subfont, &x_scale, &y_scale);
+ g_assert_cmpint (x_scale, ==, 17);
+ g_assert_cmpint (y_scale, ==, 19);
+ hb_font_set_scale (subfont, 10, 12);
+ x_scale = y_scale = 13;
+ hb_font_get_scale (subfont, &x_scale, &y_scale);
+ g_assert_cmpint (x_scale, ==, 10);
+ g_assert_cmpint (y_scale, ==, 12);
+ x_scale = y_scale = 13;
+ hb_font_get_scale (font, &x_scale, &y_scale);
+ g_assert_cmpint (x_scale, ==, 17);
+ g_assert_cmpint (y_scale, ==, 19);
+
+ /* ppem */
+ x_ppem = y_ppem = 13;
+ hb_font_get_ppem (subfont, &x_ppem, &y_ppem);
+ g_assert_cmpint (x_ppem, ==, 17);
+ g_assert_cmpint (y_ppem, ==, 19);
+ hb_font_set_ppem (subfont, 10, 12);
+ x_ppem = y_ppem = 13;
+ hb_font_get_ppem (subfont, &x_ppem, &y_ppem);
+ g_assert_cmpint (x_ppem, ==, 10);
+ g_assert_cmpint (y_ppem, ==, 12);
+ x_ppem = y_ppem = 13;
+ hb_font_get_ppem (font, &x_ppem, &y_ppem);
+ g_assert_cmpint (x_ppem, ==, 17);
+ g_assert_cmpint (y_ppem, ==, 19);
+
+ hb_font_destroy (subfont);
+}
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_face_empty);
+ hb_test_add (test_face_create);
+ hb_test_add (test_face_createfortables);
+
+ hb_test_add (test_fontfuncs_empty);
+ hb_test_add (test_fontfuncs_nil);
+ hb_test_add (test_fontfuncs_subclassing);
+
+ hb_test_add (test_font_empty);
+ hb_test_add (test_font_properties);
+
+ return hb_test_run();
+}
diff --git a/test/api/test-object.c b/test/api/test-object.c
new file mode 100644
index 0000000..66e8d33
--- /dev/null
+++ b/test/api/test-object.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright © 2011 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"
+
+/* Unit tests for hb-object-private.h */
+
+
+static void *
+create_blob (void)
+{
+ static char data[] = "test data";
+ return hb_blob_create (data, sizeof (data), HB_MEMORY_MODE_READONLY, NULL, NULL);
+}
+static void *
+create_blob_inert (void)
+{
+ return hb_blob_create (NULL, 0, HB_MEMORY_MODE_DUPLICATE, NULL, NULL);
+}
+
+static void *
+create_buffer (void)
+{
+ return hb_buffer_create ();
+}
+static void *
+create_buffer_inert (void)
+{
+ return NULL;
+}
+
+static void *
+create_face (void)
+{
+ hb_blob_t *blob = (hb_blob_t *) create_blob ();
+ hb_face_t *face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+ return face;
+}
+static void *
+create_face_inert (void)
+{
+ return hb_face_create (hb_blob_get_empty (), 0);
+}
+
+static void *
+create_font (void)
+{
+ hb_face_t *face = (hb_face_t *) create_face ();
+ hb_font_t *font = hb_font_create (face);
+ hb_face_destroy (face);
+ return font;
+}
+static void *
+create_font_inert (void)
+{
+ return hb_font_create (hb_face_get_empty ());
+}
+
+static void *
+create_font_funcs (void)
+{
+ return hb_font_funcs_create ();
+}
+static void *
+create_font_funcs_inert (void)
+{
+ return NULL;
+}
+
+static void *
+create_unicode_funcs (void)
+{
+ return hb_unicode_funcs_create (NULL);
+}
+static void *
+create_unicode_funcs_inert (void)
+{
+ return hb_unicode_funcs_get_default ();
+}
+
+
+
+typedef void *(*create_func_t) (void);
+typedef void *(*reference_func_t) (void *obj);
+typedef void (*destroy_func_t) (void *obj);
+typedef hb_bool_t (*set_user_data_func_t) (void *obj, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace);
+typedef void * (*get_user_data_func_t) (void *obj, hb_user_data_key_t *key);
+typedef void (*make_immutable_func_t) (void *obj);
+typedef hb_bool_t (*is_immutable_func_t) (void *obj);
+
+typedef struct {
+ create_func_t create;
+ create_func_t create_inert;
+ create_func_t get_empty;
+ reference_func_t reference;
+ destroy_func_t destroy;
+ set_user_data_func_t set_user_data;
+ get_user_data_func_t get_user_data;
+ make_immutable_func_t make_immutable;
+ is_immutable_func_t is_immutable;
+ const char *name;
+} object_t;
+
+#define OBJECT_WITHOUT_IMMUTABILITY(name) \
+ { \
+ (create_func_t) create_##name, \
+ (create_func_t) create_##name##_inert, \
+ (create_func_t) hb_##name##_get_empty, \
+ (reference_func_t) hb_##name##_reference, \
+ (destroy_func_t) hb_##name##_destroy, \
+ (set_user_data_func_t) hb_##name##_set_user_data, \
+ (get_user_data_func_t) hb_##name##_get_user_data, \
+ (make_immutable_func_t) NULL, \
+ (is_immutable_func_t) NULL, \
+ #name, \
+ }
+#define OBJECT_WITH_IMMUTABILITY(name) \
+ { \
+ (create_func_t) create_##name, \
+ (create_func_t) create_##name##_inert, \
+ (create_func_t) hb_##name##_get_empty, \
+ (reference_func_t) hb_##name##_reference, \
+ (destroy_func_t) hb_##name##_destroy, \
+ (set_user_data_func_t) hb_##name##_set_user_data, \
+ (get_user_data_func_t) hb_##name##_get_user_data, \
+ (make_immutable_func_t) hb_##name##_make_immutable, \
+ (is_immutable_func_t) hb_##name##_is_immutable, \
+ #name, \
+ }
+static const object_t objects[] =
+{
+ OBJECT_WITHOUT_IMMUTABILITY (buffer),
+ OBJECT_WITH_IMMUTABILITY (blob),
+ OBJECT_WITH_IMMUTABILITY (face),
+ OBJECT_WITH_IMMUTABILITY (font),
+ OBJECT_WITH_IMMUTABILITY (font_funcs),
+ OBJECT_WITH_IMMUTABILITY (unicode_funcs)
+};
+#undef OBJECT
+
+
+#define MAGIC0 0x12345678
+#define MAGIC1 0x76543210
+
+typedef struct {
+ int value;
+ gboolean freed;
+} data_t;
+
+static int global_data;
+
+static void global_free_up (void *p G_GNUC_UNUSED)
+{
+ global_data++;
+}
+
+static void free_up0 (void *p)
+{
+ data_t *data = (data_t *) p;
+
+ g_assert_cmphex (data->value, ==, MAGIC0);
+ g_assert (!data->freed);
+ data->freed = TRUE;
+}
+
+static void free_up1 (void *p)
+{
+ data_t *data = (data_t *) p;
+
+ g_assert_cmphex (data->value, ==, MAGIC1);
+ g_assert (!data->freed);
+ data->freed = TRUE;
+}
+
+
+typedef struct {
+ const object_t *klass;
+ void *object;
+ hb_user_data_key_t key;
+} deadlock_test_t;
+
+static void free_deadlock_test (void *p)
+{
+ deadlock_test_t *t = (deadlock_test_t *) p;
+
+ g_assert (NULL == t->klass->get_user_data (t->object, &t->key));
+}
+
+
+static void
+test_object (void)
+{
+ unsigned int i;
+
+ for (i = 0; i < G_N_ELEMENTS (objects); i++) {
+ const object_t *o = &objects[i];
+ void *obj;
+ hb_user_data_key_t key[2];
+
+ {
+ unsigned int j;
+ data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
+ deadlock_test_t deadlock_test;
+
+ g_test_message ("Testing object %s", o->name);
+
+ g_test_message ("->create()");
+ obj = o->create ();
+ g_assert (obj);
+
+ g_assert (obj == o->reference (obj));
+ o->destroy (obj);
+
+ if (o->is_immutable)
+ g_assert (!o->is_immutable (obj));
+
+ g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
+ g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
+
+ if (o->is_immutable) {
+ o->make_immutable (obj);
+ g_assert (o->is_immutable (obj));
+ }
+
+ /* Should still work even if object is made immutable */
+ g_assert (o->set_user_data (obj, &key[1], &data[1], free_up1, TRUE));
+ g_assert (o->get_user_data (obj, &key[1]) == &data[1]);
+
+ g_assert (!o->set_user_data (obj, NULL, &data[0], free_up0, TRUE));
+ g_assert (o->get_user_data (obj, &key[0]) == &data[0]);
+ g_assert (o->set_user_data (obj, &key[0], &data[1], NULL, TRUE));
+ g_assert (data[0].freed);
+ g_assert (o->get_user_data (obj, &key[0]) == &data[1]);
+ g_assert (!data[1].freed);
+
+ data[0].freed = FALSE;
+ g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
+ g_assert (!data[0].freed);
+ g_assert (o->set_user_data (obj, &key[0], NULL, NULL, TRUE));
+ g_assert (data[0].freed);
+
+ data[0].freed = FALSE;
+ global_data = 0;
+ g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
+ g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, FALSE));
+ g_assert_cmpuint (global_data, ==, 0);
+ g_assert (o->set_user_data (obj, &key[0], NULL, global_free_up, TRUE));
+ g_assert_cmpuint (global_data, ==, 0);
+ g_assert (o->set_user_data (obj, &key[0], NULL, NULL, TRUE));
+ g_assert_cmpuint (global_data, ==, 1);
+
+ global_data = 0;
+ for (j = 2; j < 1000; j++)
+ g_assert (o->set_user_data (obj, &key[j], &data[j], global_free_up, TRUE));
+ for (j = 2; j < 1000; j++)
+ g_assert (o->get_user_data (obj, &key[j]) == &data[j]);
+ for (j = 100; j < 1000; j++)
+ g_assert (o->set_user_data (obj, &key[j], NULL, NULL, TRUE));
+ for (j = 2; j < 100; j++)
+ g_assert (o->get_user_data (obj, &key[j]) == &data[j]);
+ for (j = 100; j < 1000; j++)
+ g_assert (!o->get_user_data (obj, &key[j]));
+ g_assert_cmpuint (global_data, ==, 900);
+
+ /* Test set_user_data where the destroy() func calls user_data functions.
+ * Make sure it doesn't deadlock or corrupt memory. */
+ deadlock_test.klass = o;
+ deadlock_test.object = obj;
+ g_assert (o->set_user_data (obj, &deadlock_test.key, &deadlock_test, free_deadlock_test, TRUE));
+ g_assert (o->set_user_data (obj, &deadlock_test.key, NULL, NULL, TRUE));
+
+ g_assert (!data[1].freed);
+ o->destroy (obj);
+ g_assert (data[0].freed);
+ g_assert (data[1].freed);
+ g_assert_cmpuint (global_data, ==, 1000-2);
+ }
+
+ {
+ data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
+
+ g_test_message ("->get_empty()");
+ obj = o->get_empty ();
+ g_assert (obj);
+
+ g_assert (obj == o->reference (obj));
+ o->destroy (obj);
+
+ if (o->is_immutable)
+ g_assert (o->is_immutable (obj));
+
+ g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
+ g_assert (!o->get_user_data (obj, &key[0]));
+
+ o->destroy (obj);
+ o->destroy (obj);
+ o->destroy (obj);
+ o->destroy (obj);
+ o->destroy (obj);
+
+ g_assert (!data[0].freed);
+ }
+
+ {
+ data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
+
+ g_test_message ("->create_inert()");
+ obj = o->create_inert ();
+ if (!obj)
+ continue;
+ if (obj == o->get_empty ())
+ continue; /* Tested already */
+
+ g_assert (obj == o->reference (obj));
+ o->destroy (obj);
+
+ if (o->is_immutable)
+ g_assert (o->is_immutable (obj));
+
+ g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
+ g_assert (!o->get_user_data (obj, &key[0]));
+
+ o->destroy (obj);
+ o->destroy (obj);
+ o->destroy (obj);
+ o->destroy (obj);
+ o->destroy (obj);
+
+ g_assert (!data[0].freed);
+ }
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_object);
+
+ return hb_test_run ();
+}
diff --git a/test/api/test-ot-tag.c b/test/api/test-ot-tag.c
new file mode 100644
index 0000000..81b6678
--- /dev/null
+++ b/test/api/test-ot-tag.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright © 2011 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"
+
+#include <hb-ot.h>
+
+/* Unit tests for hb-ot-tag.h */
+
+
+/* https://www.microsoft.com/typography/otspec/scripttags.htm */
+
+static void
+test_simple_tags (const char *s, hb_script_t script)
+{
+ hb_script_t tag;
+ hb_script_t t1, t2;
+
+ g_test_message ("Testing script %c%c%c%c: tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s);
+ tag = hb_tag_from_string (s, -1);
+
+ hb_ot_tags_from_script (script, &t1, &t2);
+
+ g_assert_cmphex (t1, ==, tag);
+ g_assert_cmphex (t2, ==, HB_OT_TAG_DEFAULT_SCRIPT);
+
+ g_assert_cmphex (hb_ot_tag_to_script (tag), ==, script);
+}
+
+static void
+test_indic_tags (const char *s1, const char *s2, hb_script_t script)
+{
+ hb_script_t tag1, tag2;
+ hb_script_t t1, t2;
+
+ g_test_message ("Testing script %c%c%c%c: new tag %s, old tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s1, s2);
+ tag1 = hb_tag_from_string (s1, -1);
+ tag2 = hb_tag_from_string (s2, -1);
+
+ hb_ot_tags_from_script (script, &t1, &t2);
+
+ g_assert_cmphex (t1, ==, tag1);
+ g_assert_cmphex (t2, ==, tag2);
+
+ g_assert_cmphex (hb_ot_tag_to_script (tag1), ==, script);
+ g_assert_cmphex (hb_ot_tag_to_script (tag2), ==, script);
+}
+
+static void
+test_ot_tag_script_degenerate (void)
+{
+ hb_script_t t1, t2;
+
+ g_assert_cmphex (HB_TAG_CHAR4 ("DFLT"), ==, HB_OT_TAG_DEFAULT_SCRIPT);
+
+ /* HIRAGANA and KATAKANA both map to 'kana' */
+ test_simple_tags ("kana", HB_SCRIPT_KATAKANA);
+ hb_ot_tags_from_script (HB_SCRIPT_HIRAGANA, &t1, &t2);
+ g_assert_cmphex (t1, ==, HB_TAG_CHAR4 ("kana"));
+ g_assert_cmphex (t2, ==, HB_OT_TAG_DEFAULT_SCRIPT);
+
+ test_simple_tags ("DFLT", HB_SCRIPT_INVALID);
+
+ /* Spaces are replaced */
+ g_assert_cmphex (hb_ot_tag_to_script (HB_TAG_CHAR4 ("be ")), ==, hb_script_from_string ("Beee", -1));
+}
+
+static void
+test_ot_tag_script_simple (void)
+{
+ /* Arbitrary non-existent script */
+ test_simple_tags ("wwyz", hb_script_from_string ("wWyZ", -1));
+
+ /* These we don't really care about */
+ test_simple_tags ("zyyy", HB_SCRIPT_COMMON);
+ test_simple_tags ("zinh", HB_SCRIPT_INHERITED);
+ test_simple_tags ("zzzz", HB_SCRIPT_UNKNOWN);
+
+ test_simple_tags ("arab", HB_SCRIPT_ARABIC);
+ test_simple_tags ("copt", HB_SCRIPT_COPTIC);
+ test_simple_tags ("kana", HB_SCRIPT_KATAKANA);
+ test_simple_tags ("latn", HB_SCRIPT_LATIN);
+
+ /* These are trickier since their OT script tags have space. */
+ test_simple_tags ("lao ", HB_SCRIPT_LAO);
+ test_simple_tags ("yi ", HB_SCRIPT_YI);
+ /* Unicode-5.0 additions */
+ test_simple_tags ("nko ", HB_SCRIPT_NKO);
+ /* Unicode-5.1 additions */
+ test_simple_tags ("vai ", HB_SCRIPT_VAI);
+
+ /* https://www.microsoft.com/typography/otspec160/scripttagsProposed.htm */
+
+ /* Unicode-5.2 additions */
+ test_simple_tags ("mtei", HB_SCRIPT_MEETEI_MAYEK);
+ /* Unicode-6.0 additions */
+ test_simple_tags ("mand", HB_SCRIPT_MANDAIC);
+}
+
+static void
+test_ot_tag_script_indic (void)
+{
+ test_indic_tags ("bng2", "beng", HB_SCRIPT_BENGALI);
+ test_indic_tags ("dev2", "deva", HB_SCRIPT_DEVANAGARI);
+ test_indic_tags ("gjr2", "gujr", HB_SCRIPT_GUJARATI);
+ test_indic_tags ("gur2", "guru", HB_SCRIPT_GURMUKHI);
+ test_indic_tags ("knd2", "knda", HB_SCRIPT_KANNADA);
+ test_indic_tags ("mlm2", "mlym", HB_SCRIPT_MALAYALAM);
+ test_indic_tags ("ory2", "orya", HB_SCRIPT_ORIYA);
+ test_indic_tags ("tml2", "taml", HB_SCRIPT_TAMIL);
+ test_indic_tags ("tel2", "telu", HB_SCRIPT_TELUGU);
+}
+
+
+
+/* https://www.microsoft.com/typography/otspec/languagetags.htm */
+
+static void
+test_language_two_way (const char *tag_s, const char *lang_s)
+{
+ hb_language_t lang = hb_language_from_string (lang_s, -1);
+ hb_tag_t tag = hb_tag_from_string (tag_s, -1);
+
+ g_test_message ("Testing language %s <-> tag %s", lang_s, tag_s);
+
+ g_assert_cmphex (tag, ==, hb_ot_tag_from_language (lang));
+ g_assert (lang == hb_ot_tag_to_language (tag));
+}
+
+static void
+test_tag_from_language (const char *tag_s, const char *lang_s)
+{
+ hb_language_t lang = hb_language_from_string (lang_s, -1);
+ hb_tag_t tag = hb_tag_from_string (tag_s, -1);
+
+ g_test_message ("Testing language %s -> tag %s", lang_s, tag_s);
+
+ g_assert_cmphex (tag, ==, hb_ot_tag_from_language (lang));
+}
+
+static void
+test_tag_to_language (const char *tag_s, const char *lang_s)
+{
+ hb_language_t lang = hb_language_from_string (lang_s, -1);
+ hb_tag_t tag = hb_tag_from_string (tag_s, -1);
+
+ g_test_message ("Testing tag %s -> language %s", tag_s, lang_s);
+
+ g_assert (lang == hb_ot_tag_to_language (tag));
+}
+
+static void
+test_ot_tag_language (void)
+{
+ g_assert_cmphex (HB_TAG_CHAR4 ("dflt"), ==, HB_OT_TAG_DEFAULT_LANGUAGE);
+ test_language_two_way ("dflt", NULL);
+
+ test_language_two_way ("ARA", "ar");
+
+ test_language_two_way ("AZE", "az");
+ test_tag_from_language ("AZE", "az-ir");
+ test_tag_from_language ("AZE", "az-az");
+
+ test_language_two_way ("ENG", "en");
+ test_tag_from_language ("ENG", "en_US");
+
+ test_language_two_way ("EVN", "eve");
+
+ test_language_two_way ("FAR", "fa");
+ test_tag_from_language ("FAR", "fa_IR");
+
+ test_language_two_way ("ZHH", "zh-hk"); /* Chinese (Hong Kong) */
+
+ test_tag_from_language ("ZHS", "zh-cn"); /* Chinese (China) */
+ test_tag_from_language ("ZHS", "zh-sg"); /* Chinese (Singapore) */
+ test_tag_from_language ("ZHT", "zh-mo"); /* Chinese (Macao) */
+ test_tag_from_language ("ZHT", "zh-tw"); /* Chinese (Taiwan) */
+
+ test_tag_from_language ("ZHS", "zh"); /* Chinese */
+ test_tag_from_language ("ZHS", "zh-xx");
+
+ test_tag_to_language ("ZHS", "zh-x-hbotzhs");
+ test_tag_to_language ("ZHT", "zh-x-hbotzht");
+ test_tag_to_language ("ZHP", "zh-x-hbotzhp");
+
+ test_language_two_way ("ABC", "x-hbotabc");
+ test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc-zxc");
+ test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc");
+ test_tag_from_language ("ABCD", "asdf-asdf-wer-x-hbotabcd");
+
+ test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-zxc");
+
+ test_tag_from_language ("dflt", "xy");
+ test_tag_from_language ("XYZ", "xyz"); /* Unknown ISO 639-3 */
+ test_tag_from_language ("XYZ", "xyz-qw"); /* Unknown ISO 639-3 */
+
+ /* Test that x-hbot overrides the base language */
+ test_tag_from_language ("ABC", "fa-x-hbotabc-zxc");
+ test_tag_from_language ("ABC", "fa-ir-x-hbotabc-zxc");
+ test_tag_from_language ("ABC", "zh-x-hbotabc-zxc");
+ test_tag_from_language ("ABC", "zh-cn-x-hbotabc-zxc");
+ test_tag_from_language ("ABC", "zh-xy-x-hbotabc-zxc");
+ test_tag_from_language ("ABC", "xyz-xy-x-hbotabc-zxc");
+}
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_ot_tag_script_degenerate);
+ hb_test_add (test_ot_tag_script_simple);
+ hb_test_add (test_ot_tag_script_indic);
+
+ hb_test_add (test_ot_tag_language);
+
+ return hb_test_run();
+}
diff --git a/test/api/test-shape.c b/test/api/test-shape.c
new file mode 100644
index 0000000..ccf6eed
--- /dev/null
+++ b/test/api/test-shape.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright © 2011 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"
+
+/* Unit tests for hb-shape.h */
+
+/*
+ * This test provides a framework to test aspects of hb_shape() that are
+ * font-independent. Please add tests for any feature that fits that
+ * description.
+ */
+
+/* TODO Make this test data-driven and add some real test data */
+/* TODO Test positions too. And test non-native direction. Test commit 2e18c6dbdfb */
+
+
+static const char test_data[] = "test\0data";
+
+static hb_position_t
+glyph_h_advance_func (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ void *user_data)
+{
+ switch (glyph) {
+ case 1: return 10;
+ case 2: return 6;
+ case 3: return 5;
+ }
+ return 0;
+}
+
+static hb_bool_t
+glyph_func (hb_font_t *font, void *font_data,
+ hb_codepoint_t unicode, hb_codepoint_t variant_selector,
+ hb_codepoint_t *glyph,
+ void *user_data)
+{
+ switch (unicode) {
+ case 'T': *glyph = 1; return TRUE;
+ case 'e': *glyph = 2; return TRUE;
+ case 's': *glyph = 3; return TRUE;
+ }
+ return FALSE;
+}
+
+static hb_position_t
+glyph_h_kerning_func (hb_font_t *font, void *font_data,
+ hb_codepoint_t left, hb_codepoint_t right,
+ void *user_data)
+{
+ if (left == 1 && right == 2)
+ return -2;
+
+ return 0;
+}
+
+static const char TesT[] = "TesT";
+
+static void
+test_shape (void)
+{
+ hb_blob_t *blob;
+ hb_face_t *face;
+ hb_font_funcs_t *ffuncs;
+ hb_font_t *font;
+ hb_buffer_t *buffer;
+ unsigned int len;
+ hb_glyph_info_t *glyphs;
+ hb_glyph_position_t *positions;
+
+ blob = hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL);
+ face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+ font = hb_font_create (face);
+ hb_face_destroy (face);
+ hb_font_set_scale (font, 10, 10);
+
+ ffuncs = hb_font_funcs_create ();
+ hb_font_funcs_set_glyph_h_advance_func (ffuncs, glyph_h_advance_func, NULL, NULL);
+ hb_font_funcs_set_glyph_func (ffuncs, glyph_func, NULL, NULL);
+ hb_font_funcs_set_glyph_h_kerning_func (ffuncs, glyph_h_kerning_func, NULL, NULL);
+ hb_font_set_funcs (font, ffuncs, NULL, NULL);
+ hb_font_funcs_destroy (ffuncs);
+
+ buffer = hb_buffer_create ();
+ hb_buffer_set_direction (buffer, HB_DIRECTION_LTR);
+ hb_buffer_add_utf8 (buffer, TesT, 4, 0, 4);
+
+ hb_shape (font, buffer, NULL, 0);
+
+ len = hb_buffer_get_length (buffer);
+ glyphs = hb_buffer_get_glyph_infos (buffer, NULL);
+ positions = hb_buffer_get_glyph_positions (buffer, NULL);
+
+ {
+ const hb_codepoint_t output_glyphs[] = {1, 2, 3, 1};
+ const hb_position_t output_x_advances[] = {9, 5, 5, 10};
+ const hb_position_t output_x_offsets[] = {0, -1, 0, 0};
+ unsigned int i;
+ g_assert_cmpint (len, ==, 4);
+ for (i = 0; i < len; i++) {
+ g_assert_cmphex (glyphs[i].codepoint, ==, output_glyphs[i]);
+ g_assert_cmphex (glyphs[i].cluster, ==, i);
+ }
+ for (i = 0; i < len; i++) {
+ g_assert_cmpint (output_x_advances[i], ==, positions[i].x_advance);
+ g_assert_cmpint (output_x_offsets [i], ==, positions[i].x_offset);
+ g_assert_cmpint (0, ==, positions[i].y_advance);
+ g_assert_cmpint (0, ==, positions[i].y_offset);
+ }
+ }
+
+ hb_buffer_destroy (buffer);
+ hb_font_destroy (font);
+}
+
+static void
+test_shape_list (void)
+{
+ const char **shapers = hb_shape_list_shapers ();
+
+ unsigned int i;
+ for (i = 0; shapers[i]; i++)
+ ;
+
+ g_assert_cmpint (i, >, 1);
+ g_assert (!strcmp (shapers[i - 1], "fallback"));
+}
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_shape);
+ /* TODO test fallback shaper */
+ /* TODO test shaper_full */
+ hb_test_add (test_shape_list);
+
+ return hb_test_run();
+}
diff --git a/test/api/test-unicode.c b/test/api/test-unicode.c
new file mode 100644
index 0000000..96c61dd
--- /dev/null
+++ b/test/api/test-unicode.c
@@ -0,0 +1,937 @@
+/*
+ * Copyright © 2011 Codethink Limited
+ * Copyright © 2011 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.
+ *
+ * Codethink Author(s): Ryan Lortie
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-test.h"
+
+/* Unit tests for hb-unicode.h */
+/* Unit tests for hb-glib.h */
+/* Unit tests for hb-icu.h */
+
+
+#ifdef HAVE_GLIB
+#include <hb-glib.h>
+#endif
+#ifdef HAVE_ICU
+#include <hb-icu.h>
+#endif
+
+
+/* Some useful stuff */
+
+#define MAGIC0 0x12345678
+#define MAGIC1 0x76543210
+
+typedef struct {
+ int value;
+ gboolean freed;
+} data_t;
+
+static void free_up (void *p)
+{
+ data_t *data = (data_t *) p;
+
+ g_assert (data->value == MAGIC0 || data->value == MAGIC1);
+ g_assert (!data->freed);
+ data->freed = TRUE;
+}
+
+static hb_script_t
+simple_get_script (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t codepoint,
+ void *user_data)
+{
+ data_t *data = (data_t *) user_data;
+
+ g_assert (hb_unicode_funcs_get_parent (ufuncs) != NULL);
+ g_assert_cmphex (data->value, ==, MAGIC0);
+ g_assert (!data->freed);
+
+ if ('a' <= codepoint && codepoint <= 'z')
+ return HB_SCRIPT_LATIN;
+ else
+ return HB_SCRIPT_UNKNOWN;
+}
+
+static hb_script_t
+a_is_for_arabic_get_script (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t codepoint,
+ void *user_data)
+{
+ data_t *data = (data_t *) user_data;
+
+ g_assert (hb_unicode_funcs_get_parent (ufuncs) != NULL);
+ g_assert_cmphex (data->value, ==, MAGIC1);
+ g_assert (!data->freed);
+
+ if (codepoint == 'a') {
+ return HB_SCRIPT_ARABIC;
+ } else {
+ hb_unicode_funcs_t *parent = hb_unicode_funcs_get_parent (ufuncs);
+
+ return hb_unicode_script (parent, codepoint);
+ }
+}
+
+
+
+/* Check all properties */
+
+/* Some of the following tables where adapted from glib/glib/tests/utf8-misc.c.
+ * The license is compatible. */
+
+typedef struct {
+ hb_codepoint_t unicode;
+ unsigned int value;
+} test_pair_t;
+
+static const test_pair_t combining_class_tests[] =
+{
+ { 0x0020, 0 },
+ { 0x0334, 1 },
+ { 0x093C, 7 },
+ { 0x3099, 8 },
+ { 0x094D, 9 },
+ { 0x05B0, 10 },
+ { 0x05B1, 11 },
+ { 0x05B2, 12 },
+ { 0x05B3, 13 },
+ { 0x05B4, 14 },
+ { 0x05B5, 15 },
+ { 0x05B6, 16 },
+ { 0x05B7, 17 },
+ { 0x05B8, 18 },
+ { 0x05B9, 19 },
+ { 0x05BB, 20 },
+ { 0x05BC, 21 },
+ { 0x05BD, 22 },
+ { 0x05BF, 23 },
+ { 0x05C1, 24 },
+ { 0x05C2, 25 },
+ { 0xFB1E, 26 },
+ { 0x064B, 27 },
+ { 0x064C, 28 },
+ { 0x064D, 29 },
+ /* ... */
+ { 0x05AE, 228 },
+ { 0x0300, 230 },
+ { 0x302C, 232 },
+ { 0x0362, 233 },
+ { 0x0360, 234 },
+ { 0x0345, 240 },
+
+ { 0x111111, 0 }
+};
+static const test_pair_t combining_class_tests_more[] =
+{
+ /* Unicode-5.1 character additions */
+ { 0x1DCD, 234 },
+
+ /* Unicode-5.2 character additions */
+ { 0xA8E0, 230 },
+
+ /* Unicode-6.0 character additions */
+ { 0x135D, 230 },
+
+ { 0x111111, 0 }
+};
+
+static const test_pair_t eastasian_width_tests[] =
+{
+ /* Neutral */
+ { 0x0000, 1 },
+ { 0x0483, 1 },
+ { 0x0641, 1 },
+ { 0xFFFC, 1 },
+ { 0x10000, 1 },
+ { 0xE0001, 1 },
+
+ /* Narrow */
+ { 0x0020, 1 },
+ { 0x0041, 1 },
+ { 0x27E6, 1 },
+
+ /* Halfwidth */
+ { 0x20A9, 1 },
+ { 0xFF61, 1 },
+ { 0xFF69, 1 },
+ { 0xFFEE, 1 },
+
+ /* Ambiguous */
+ { 0x00A1, 1 },
+ { 0x00D8, 1 },
+ { 0x02DD, 1 },
+ { 0xE0100, 1 },
+ { 0x100000, 1 },
+
+ /* Fullwidth */
+ { 0x3000, 2 },
+ { 0xFF60, 2 },
+
+ /* Wide */
+ { 0x2329, 2 },
+ { 0x3001, 2 },
+ { 0xFE69, 2 },
+ { 0x30000, 2 },
+ { 0x3FFFD, 2 },
+
+ { 0x111111, 1 }
+};
+static const test_pair_t eastasian_width_tests_more[] =
+{
+ /* Default Wide blocks */
+ { 0x4DBF, 2 },
+ { 0x9FFF, 2 },
+ { 0xFAFF, 2 },
+ { 0x2A6DF, 2 },
+ { 0x2B73F, 2 },
+ { 0x2B81F, 2 },
+ { 0x2FA1F, 2 },
+
+ /* Uniode-5.2 character additions */
+ /* Wide */
+ { 0x115F, 2 },
+
+ /* Uniode-6.0 character additions */
+ /* Wide */
+ { 0x2B740, 2 },
+ { 0x1B000, 2 },
+
+ { 0x111111, 1 }
+};
+
+static const test_pair_t general_category_tests[] =
+{
+ { 0x000D, HB_UNICODE_GENERAL_CATEGORY_CONTROL },
+ { 0x200E, HB_UNICODE_GENERAL_CATEGORY_FORMAT },
+ { 0x0378, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED },
+ { 0xE000, HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE },
+ { 0xD800, HB_UNICODE_GENERAL_CATEGORY_SURROGATE },
+ { 0x0061, HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER },
+ { 0x02B0, HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER },
+ { 0x3400, HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER },
+ { 0x01C5, HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER },
+ { 0xFF21, HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER },
+ { 0x0903, HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK },
+ { 0x20DD, HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK },
+ { 0xA806, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK },
+ { 0xFF10, HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER },
+ { 0x16EE, HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER },
+ { 0x17F0, HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER },
+ { 0x005F, HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION },
+ { 0x058A, HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION },
+ { 0x0F3B, HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION },
+ { 0x2019, HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION },
+ { 0x2018, HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION },
+ { 0x2016, HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION },
+ { 0x0F3A, HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION },
+ { 0x20A0, HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL },
+ { 0x309B, HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL },
+ { 0xFB29, HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL },
+ { 0x00A6, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL },
+ { 0x2028, HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR },
+ { 0x2029, HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR },
+ { 0x202F, HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR },
+
+ { 0x111111, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED }
+};
+static const test_pair_t general_category_tests_more[] =
+{
+ /* Unicode-5.2 character additions */
+ { 0x1F131, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL },
+
+ /* Unicode-6.0 character additions */
+ { 0x0620, HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER },
+
+ { 0x111111, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED }
+};
+
+static const test_pair_t mirroring_tests[] =
+{
+ /* Some characters that do NOT mirror */
+ { 0x0020, 0x0020 },
+ { 0x0041, 0x0041 },
+ { 0x00F0, 0x00F0 },
+ { 0x27CC, 0x27CC },
+ { 0xE01EF, 0xE01EF },
+ { 0x1D7C3, 0x1D7C3 },
+ { 0x100000, 0x100000 },
+
+ /* Some characters that do mirror */
+ { 0x0029, 0x0028 },
+ { 0x0028, 0x0029 },
+ { 0x003E, 0x003C },
+ { 0x003C, 0x003E },
+ { 0x005D, 0x005B },
+ { 0x005B, 0x005D },
+ { 0x007D, 0x007B },
+ { 0x007B, 0x007D },
+ { 0x00BB, 0x00AB },
+ { 0x00AB, 0x00BB },
+ { 0x226B, 0x226A },
+ { 0x226A, 0x226B },
+ { 0x22F1, 0x22F0 },
+ { 0x22F0, 0x22F1 },
+ { 0xFF60, 0xFF5F },
+ { 0xFF5F, 0xFF60 },
+ { 0xFF63, 0xFF62 },
+ { 0xFF62, 0xFF63 },
+
+ { 0x111111, 0x111111 },
+};
+static const test_pair_t mirroring_tests_more[] =
+{
+ /* No new mirroring characters have been encoded in recent Unicode versions. */
+ { 0x111111, 0x111111 }
+};
+
+static const test_pair_t script_tests[] =
+{
+ { 0x002A, HB_SCRIPT_COMMON },
+ { 0x0670, HB_SCRIPT_INHERITED },
+ { 0x060D, HB_SCRIPT_ARABIC },
+ { 0x0559, HB_SCRIPT_ARMENIAN },
+ { 0x09CD, HB_SCRIPT_BENGALI },
+ { 0x31B6, HB_SCRIPT_BOPOMOFO },
+ { 0x13A2, HB_SCRIPT_CHEROKEE },
+ { 0x2CFD, HB_SCRIPT_COPTIC },
+ { 0x0482, HB_SCRIPT_CYRILLIC },
+ { 0x10401, HB_SCRIPT_DESERET },
+ { 0x094D, HB_SCRIPT_DEVANAGARI },
+ { 0x1258, HB_SCRIPT_ETHIOPIC },
+ { 0x10FC, HB_SCRIPT_GEORGIAN },
+ { 0x10341, HB_SCRIPT_GOTHIC },
+ { 0x0375, HB_SCRIPT_GREEK },
+ { 0x0A83, HB_SCRIPT_GUJARATI },
+ { 0x0A3C, HB_SCRIPT_GURMUKHI },
+ { 0x3005, HB_SCRIPT_HAN },
+ { 0x1100, HB_SCRIPT_HANGUL },
+ { 0x05BF, HB_SCRIPT_HEBREW },
+ { 0x309F, HB_SCRIPT_HIRAGANA },
+ { 0x0CBC, HB_SCRIPT_KANNADA },
+ { 0x30FF, HB_SCRIPT_KATAKANA },
+ { 0x17DD, HB_SCRIPT_KHMER },
+ { 0x0EDD, HB_SCRIPT_LAO },
+ { 0x0061, HB_SCRIPT_LATIN },
+ { 0x0D3D, HB_SCRIPT_MALAYALAM },
+ { 0x1843, HB_SCRIPT_MONGOLIAN },
+ { 0x1031, HB_SCRIPT_MYANMAR },
+ { 0x169C, HB_SCRIPT_OGHAM },
+ { 0x10322, HB_SCRIPT_OLD_ITALIC },
+ { 0x0B3C, HB_SCRIPT_ORIYA },
+ { 0x16EF, HB_SCRIPT_RUNIC },
+ { 0x0DBD, HB_SCRIPT_SINHALA },
+ { 0x0711, HB_SCRIPT_SYRIAC },
+ { 0x0B82, HB_SCRIPT_TAMIL },
+ { 0x0C03, HB_SCRIPT_TELUGU },
+ { 0x07B1, HB_SCRIPT_THAANA },
+ { 0x0E31, HB_SCRIPT_THAI },
+ { 0x0FD4, HB_SCRIPT_TIBETAN },
+ { 0x1401, HB_SCRIPT_CANADIAN_ABORIGINAL },
+ { 0xA015, HB_SCRIPT_YI },
+ { 0x1700, HB_SCRIPT_TAGALOG },
+ { 0x1720, HB_SCRIPT_HANUNOO },
+ { 0x1740, HB_SCRIPT_BUHID },
+ { 0x1760, HB_SCRIPT_TAGBANWA },
+
+ /* Unicode-4.0 additions */
+ { 0x2800, HB_SCRIPT_BRAILLE },
+ { 0x10808, HB_SCRIPT_CYPRIOT },
+ { 0x1932, HB_SCRIPT_LIMBU },
+ { 0x10480, HB_SCRIPT_OSMANYA },
+ { 0x10450, HB_SCRIPT_SHAVIAN },
+ { 0x10000, HB_SCRIPT_LINEAR_B },
+ { 0x1950, HB_SCRIPT_TAI_LE },
+ { 0x1039F, HB_SCRIPT_UGARITIC },
+
+ /* Unicode-4.1 additions */
+ { 0x1980, HB_SCRIPT_NEW_TAI_LUE },
+ { 0x1A1F, HB_SCRIPT_BUGINESE },
+ { 0x2C00, HB_SCRIPT_GLAGOLITIC },
+ { 0x2D6F, HB_SCRIPT_TIFINAGH },
+ { 0xA800, HB_SCRIPT_SYLOTI_NAGRI },
+ { 0x103D0, HB_SCRIPT_OLD_PERSIAN },
+ { 0x10A3F, HB_SCRIPT_KHAROSHTHI },
+
+ /* Unicode-5.0 additions */
+ { 0x0378, HB_SCRIPT_UNKNOWN },
+ { 0x1B04, HB_SCRIPT_BALINESE },
+ { 0x12000, HB_SCRIPT_CUNEIFORM },
+ { 0x10900, HB_SCRIPT_PHOENICIAN },
+ { 0xA840, HB_SCRIPT_PHAGS_PA },
+ { 0x07C0, HB_SCRIPT_NKO },
+
+ /* Unicode-5.1 additions */
+ { 0xA900, HB_SCRIPT_KAYAH_LI },
+ { 0x1C00, HB_SCRIPT_LEPCHA },
+ { 0xA930, HB_SCRIPT_REJANG },
+ { 0x1B80, HB_SCRIPT_SUNDANESE },
+ { 0xA880, HB_SCRIPT_SAURASHTRA },
+ { 0xAA00, HB_SCRIPT_CHAM },
+ { 0x1C50, HB_SCRIPT_OL_CHIKI },
+ { 0xA500, HB_SCRIPT_VAI },
+ { 0x102A0, HB_SCRIPT_CARIAN },
+ { 0x10280, HB_SCRIPT_LYCIAN },
+ { 0x1093F, HB_SCRIPT_LYDIAN },
+
+ { 0x111111, HB_SCRIPT_UNKNOWN }
+};
+static const test_pair_t script_tests_more[] =
+{
+ /* Unicode-5.2 additions */
+ { 0x10B00, HB_SCRIPT_AVESTAN },
+ { 0xA6A0, HB_SCRIPT_BAMUM },
+ { 0x13000, HB_SCRIPT_EGYPTIAN_HIEROGLYPHS },
+ { 0x10840, HB_SCRIPT_IMPERIAL_ARAMAIC },
+ { 0x10B60, HB_SCRIPT_INSCRIPTIONAL_PAHLAVI },
+ { 0x10B40, HB_SCRIPT_INSCRIPTIONAL_PARTHIAN },
+ { 0xA980, HB_SCRIPT_JAVANESE },
+ { 0x11082, HB_SCRIPT_KAITHI },
+ { 0xA4D0, HB_SCRIPT_LISU },
+ { 0xABE5, HB_SCRIPT_MEETEI_MAYEK },
+ { 0x10A60, HB_SCRIPT_OLD_SOUTH_ARABIAN },
+ { 0x10C00, HB_SCRIPT_OLD_TURKIC },
+ { 0x0800, HB_SCRIPT_SAMARITAN },
+ { 0x1A20, HB_SCRIPT_TAI_THAM },
+ { 0xAA80, HB_SCRIPT_TAI_VIET },
+
+ /* Unicode-6.0 additions */
+ { 0x1BC0, HB_SCRIPT_BATAK },
+ { 0x11000, HB_SCRIPT_BRAHMI },
+ { 0x0840, HB_SCRIPT_MANDAIC },
+
+ /* Unicode-5.2 character additions */
+ { 0x1CED, HB_SCRIPT_INHERITED },
+ { 0x1400, HB_SCRIPT_CANADIAN_ABORIGINAL },
+
+ { 0x111111, HB_SCRIPT_UNKNOWN }
+};
+
+
+typedef unsigned int (*get_func_t) (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode,
+ void *user_data);
+typedef unsigned int (*func_setter_func_t) (hb_unicode_funcs_t *ufuncs,
+ get_func_t func,
+ void *user_data,
+ hb_destroy_func_t destroy);
+typedef unsigned int (*getter_func_t) (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+typedef struct {
+ const char *name;
+ func_setter_func_t func_setter;
+ getter_func_t getter;
+ const test_pair_t *tests;
+ unsigned int num_tests;
+ const test_pair_t *tests_more;
+ unsigned int num_tests_more;
+ unsigned int default_value;
+} property_t;
+
+#define RETURNS_UNICODE_ITSELF ((unsigned int) -1)
+
+#define PROPERTY(name, DEFAULT) \
+ { \
+ #name, \
+ (func_setter_func_t) hb_unicode_funcs_set_##name##_func, \
+ (getter_func_t) hb_unicode_##name, \
+ name##_tests, \
+ G_N_ELEMENTS (name##_tests), \
+ name##_tests_more, \
+ G_N_ELEMENTS (name##_tests_more), \
+ DEFAULT \
+ }
+static const property_t properties[] =
+{
+ PROPERTY (combining_class, 0),
+ PROPERTY (eastasian_width, 1),
+ PROPERTY (general_category, (unsigned int) HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER),
+ PROPERTY (mirroring, RETURNS_UNICODE_ITSELF),
+ PROPERTY (script, (unsigned int) HB_SCRIPT_UNKNOWN)
+};
+#undef PROPERTY
+
+static void
+test_unicode_properties (gconstpointer user_data)
+{
+ hb_unicode_funcs_t *uf = (hb_unicode_funcs_t *) user_data;
+ unsigned int i, j;
+ gboolean failed = TRUE;
+
+ g_assert (hb_unicode_funcs_is_immutable (uf));
+ g_assert (hb_unicode_funcs_get_parent (uf));
+
+ for (i = 0; i < G_N_ELEMENTS (properties); i++) {
+ const property_t *p = &properties[i];
+ const test_pair_t *tests;
+
+ g_test_message ("Testing property %s", p->name);
+ tests = p->tests;
+ for (j = 0; j < p->num_tests; j++) {
+ g_test_message ("Test %s #%d: U+%04X", p->name, j, tests[j].unicode);
+ g_assert_cmphex (p->getter (uf, tests[j].unicode), ==, tests[j].value);
+ }
+ /* These tests are from Unicode 5.2 onward and older glib/ICU
+ * don't get them right. Just warn instead of assert. */
+ tests = p->tests_more;
+ for (j = 0; j < p->num_tests_more; j++) {
+ g_test_message ("Test %s more #%d: U+%04X", p->name, j, tests[j].unicode);
+ if (p->getter (uf, tests[j].unicode) != tests[j].value) {
+ g_test_message ("Soft fail: Received %x, expected %x", p->getter (uf, tests[j].unicode), tests[j].value);
+ failed = TRUE;
+ }
+ }
+ }
+
+ if (failed)
+ g_test_message ("Some property tests failed. You probably have an old version of one of the libraries used.");
+}
+
+static hb_codepoint_t
+default_value (hb_codepoint_t _default_value, hb_codepoint_t unicode)
+{
+ return _default_value == RETURNS_UNICODE_ITSELF ? unicode : _default_value;
+}
+
+static void
+_test_unicode_properties_nil (hb_unicode_funcs_t *uf)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < G_N_ELEMENTS (properties); i++) {
+ const property_t *p = &properties[i];
+ const test_pair_t *tests;
+
+ g_test_message ("Testing property %s", p->name);
+ tests = p->tests;
+ for (j = 0; j < p->num_tests; j++) {
+ g_test_message ("Test %s #%d: U+%04X", p->name, j, tests[j].unicode);
+ g_assert_cmphex (p->getter (uf, tests[j].unicode), ==, default_value (p->default_value, tests[j].unicode));
+ }
+ tests = p->tests_more;
+ for (j = 0; j < p->num_tests_more; j++) {
+ g_test_message ("Test %s more #%d: U+%04X", p->name, j, tests[j].unicode);
+ g_assert_cmphex (p->getter (uf, tests[j].unicode), ==, default_value (p->default_value, tests[j].unicode));
+ }
+ }
+}
+
+static void
+test_unicode_properties_nil (void)
+{
+ hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
+
+ g_assert (!hb_unicode_funcs_is_immutable (uf));
+ _test_unicode_properties_nil (uf);
+
+ hb_unicode_funcs_destroy (uf);
+}
+
+static void
+test_unicode_properties_empty (void)
+{
+ hb_unicode_funcs_t *uf = hb_unicode_funcs_get_empty ();
+
+ g_assert (uf);
+ g_assert (hb_unicode_funcs_is_immutable (uf));
+ _test_unicode_properties_nil (uf);
+}
+
+
+static void
+test_unicode_chainup (void)
+{
+ hb_unicode_funcs_t *uf, *uf2;
+
+ /* Chain-up to nil */
+
+ uf = hb_unicode_funcs_create (NULL);
+ g_assert (!hb_unicode_funcs_is_immutable (uf));
+
+ uf2 = hb_unicode_funcs_create (uf);
+ g_assert (hb_unicode_funcs_is_immutable (uf));
+ hb_unicode_funcs_destroy (uf);
+
+ g_assert (!hb_unicode_funcs_is_immutable (uf2));
+ _test_unicode_properties_nil (uf2);
+
+ hb_unicode_funcs_destroy (uf2);
+
+ /* Chain-up to default */
+
+ uf = hb_unicode_funcs_create (hb_unicode_funcs_get_default ());
+ g_assert (!hb_unicode_funcs_is_immutable (uf));
+
+ uf2 = hb_unicode_funcs_create (uf);
+ g_assert (hb_unicode_funcs_is_immutable (uf));
+ hb_unicode_funcs_destroy (uf);
+
+ g_assert (!hb_unicode_funcs_is_immutable (uf2));
+ hb_unicode_funcs_make_immutable (uf2);
+ test_unicode_properties (uf2);
+
+ hb_unicode_funcs_destroy (uf2);
+
+}
+
+static void
+test_unicode_setters (void)
+{
+ hb_unicode_funcs_t *uf;
+ unsigned int i;
+
+ /* This is cruel: we use script-returning functions to test all properties,
+ * but it works. */
+
+ for (i = 0; i < G_N_ELEMENTS (properties); i++) {
+ const property_t *p = &properties[i];
+ data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
+
+ g_test_message ("Testing property %s", p->name);
+
+ uf = hb_unicode_funcs_create (NULL);
+ g_assert (!hb_unicode_funcs_is_immutable (uf));
+
+ p->func_setter (uf, (get_func_t) simple_get_script, &data[0], free_up);
+
+ g_assert_cmphex (p->getter (uf, 'a'), ==, HB_SCRIPT_LATIN);
+ g_assert_cmphex (p->getter (uf, '0'), ==, HB_SCRIPT_UNKNOWN);
+
+ p->func_setter (uf, (get_func_t) NULL, NULL, NULL);
+ g_assert (data[0].freed && !data[1].freed);
+
+ g_assert (!hb_unicode_funcs_is_immutable (uf));
+ hb_unicode_funcs_make_immutable (uf);
+ g_assert (hb_unicode_funcs_is_immutable (uf));
+
+ /* Since uf is immutable now, the following setter should do nothing. */
+ p->func_setter (uf, (get_func_t) a_is_for_arabic_get_script, &data[1], free_up);
+
+ g_assert (data[0].freed && !data[1].freed);
+ hb_unicode_funcs_destroy (uf);
+ g_assert (data[0].freed && !data[1].freed);
+ }
+}
+
+
+
+typedef struct {
+ data_t data[2];
+} data_fixture_t;
+
+static void
+data_fixture_init (data_fixture_t *f, gconstpointer user_data)
+{
+ f->data[0].value = MAGIC0;
+ f->data[1].value = MAGIC1;
+}
+static void
+data_fixture_finish (data_fixture_t *f, gconstpointer user_data)
+{
+}
+
+static void
+test_unicode_subclassing_nil (data_fixture_t *f, gconstpointer user_data)
+{
+ hb_unicode_funcs_t *uf, *aa;
+
+ uf = hb_unicode_funcs_create (NULL);
+
+ aa = hb_unicode_funcs_create (uf);
+
+ hb_unicode_funcs_destroy (uf);
+
+ hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
+ &f->data[1], free_up);
+
+ g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
+ g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_UNKNOWN);
+
+ g_assert (!f->data[0].freed && !f->data[1].freed);
+ hb_unicode_funcs_destroy (aa);
+ g_assert (!f->data[0].freed && f->data[1].freed);
+}
+
+static void
+test_unicode_subclassing_default (data_fixture_t *f, gconstpointer user_data)
+{
+ hb_unicode_funcs_t *uf, *aa;
+
+ uf = hb_unicode_funcs_get_default ();
+ aa = hb_unicode_funcs_create (uf);
+
+ hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
+ &f->data[1], free_up);
+
+ g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
+ g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
+
+ g_assert (!f->data[0].freed && !f->data[1].freed);
+ hb_unicode_funcs_destroy (aa);
+ g_assert (!f->data[0].freed && f->data[1].freed);
+}
+
+static void
+test_unicode_subclassing_deep (data_fixture_t *f, gconstpointer user_data)
+{
+ hb_unicode_funcs_t *uf, *aa;
+
+ uf = hb_unicode_funcs_create (NULL);
+
+ hb_unicode_funcs_set_script_func (uf, simple_get_script,
+ &f->data[0], free_up);
+
+ aa = hb_unicode_funcs_create (uf);
+
+ hb_unicode_funcs_destroy (uf);
+
+ /* make sure the 'uf' didn't get freed, since 'aa' holds a ref */
+ g_assert (!f->data[0].freed);
+
+ hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
+ &f->data[1], free_up);
+
+ g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
+ g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
+ g_assert_cmphex (hb_unicode_script (aa, '0'), ==, HB_SCRIPT_UNKNOWN);
+
+ g_assert (!f->data[0].freed && !f->data[1].freed);
+ hb_unicode_funcs_destroy (aa);
+ g_assert (f->data[0].freed && f->data[1].freed);
+}
+
+
+static hb_script_t
+script_roundtrip_default (hb_script_t script)
+{
+ return hb_script_from_iso15924_tag (hb_script_to_iso15924_tag (script));
+}
+
+#ifdef HAVE_GLIB
+static hb_script_t
+script_roundtrip_glib (hb_script_t script)
+{
+ return hb_glib_script_to_script (hb_glib_script_from_script (script));
+}
+#endif
+
+#ifdef HAVE_ICU
+static hb_script_t
+script_roundtrip_icu (hb_script_t script)
+{
+ return hb_icu_script_to_script (hb_icu_script_from_script (script));
+}
+#endif
+
+static void
+test_unicode_script_roundtrip (gconstpointer user_data)
+{
+ typedef hb_script_t (*roundtrip_func_t) (hb_script_t);
+ roundtrip_func_t roundtrip_func = (roundtrip_func_t) user_data;
+ unsigned int i;
+ gboolean failed = FALSE;
+
+ for (i = 0; i < G_N_ELEMENTS (script_tests); i++) {
+ const test_pair_t *test = &script_tests[i];
+ hb_script_t script = test->value;
+
+ g_test_message ("Test script roundtrip #%d: %x", i, script);
+ g_assert_cmphex (script, ==, roundtrip_func (script));
+ }
+ for (i = 0; i < G_N_ELEMENTS (script_tests_more); i++) {
+ const test_pair_t *test = &script_tests_more[i];
+ hb_script_t script = test->value;
+
+ g_test_message ("Test script roundtrip more #%d: %x", i, script);
+ if (script != roundtrip_func (script)) {
+ g_test_message ("Soft fail: Received %x, expected %x", roundtrip_func (script), script);
+ failed = TRUE;
+ }
+ }
+
+ g_assert_cmphex (HB_SCRIPT_INVALID, ==, roundtrip_func (HB_SCRIPT_INVALID));
+
+ if (failed)
+ g_test_message ("Some script roundtrip tests failed. You probably have an old version of one of the libraries used.");
+}
+
+
+static void
+test_unicode_normalization (gconstpointer user_data)
+{
+ hb_unicode_funcs_t *uf = (hb_unicode_funcs_t *) user_data;
+ gunichar a, b, ab;
+ hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN];
+
+
+ /* Test compose() */
+
+ /* Not composable */
+ g_assert (!hb_unicode_compose (uf, 0x0041, 0x0042, &ab) && ab == 0);
+ g_assert (!hb_unicode_compose (uf, 0x0041, 0, &ab) && ab == 0);
+ g_assert (!hb_unicode_compose (uf, 0x0066, 0x0069, &ab) && ab == 0);
+
+ /* Singletons should not compose */
+ g_assert (!hb_unicode_compose (uf, 0x212B, 0, &ab) && ab == 0);
+ g_assert (!hb_unicode_compose (uf, 0x00C5, 0, &ab) && ab == 0);
+ g_assert (!hb_unicode_compose (uf, 0x2126, 0, &ab) && ab == 0);
+ g_assert (!hb_unicode_compose (uf, 0x03A9, 0, &ab) && ab == 0);
+
+ /* Non-starter pairs should not compose */
+ g_assert (!hb_unicode_compose (uf, 0x0308, 0x0301, &ab) && ab == 0); /* !0x0344 */
+ g_assert (!hb_unicode_compose (uf, 0x0F71, 0x0F72, &ab) && ab == 0); /* !0x0F73 */
+
+ /* Pairs */
+ g_assert (hb_unicode_compose (uf, 0x0041, 0x030A, &ab) && ab == 0x00C5);
+ g_assert (hb_unicode_compose (uf, 0x006F, 0x0302, &ab) && ab == 0x00F4);
+ g_assert (hb_unicode_compose (uf, 0x1E63, 0x0307, &ab) && ab == 0x1E69);
+ g_assert (hb_unicode_compose (uf, 0x0073, 0x0323, &ab) && ab == 0x1E63);
+ g_assert (hb_unicode_compose (uf, 0x0064, 0x0307, &ab) && ab == 0x1E0B);
+ g_assert (hb_unicode_compose (uf, 0x0064, 0x0323, &ab) && ab == 0x1E0D);
+
+ /* Hangul */
+ g_assert (hb_unicode_compose (uf, 0xD4CC, 0x11B6, &ab) && ab == 0xD4DB);
+ g_assert (hb_unicode_compose (uf, 0x1111, 0x1171, &ab) && ab == 0xD4CC);
+ g_assert (hb_unicode_compose (uf, 0xCE20, 0x11B8, &ab) && ab == 0xCE31);
+ g_assert (hb_unicode_compose (uf, 0x110E, 0x1173, &ab) && ab == 0xCE20);
+
+
+ /* Test decompose() */
+
+ /* Not decomposable */
+ g_assert (!hb_unicode_decompose (uf, 0x0041, &a, &b) && a == 0x0041 && b == 0);
+ g_assert (!hb_unicode_decompose (uf, 0xFB01, &a, &b) && a == 0xFB01 && b == 0);
+ g_assert (!hb_unicode_decompose (uf, 0x1F1EF, &a, &b) && a == 0x1F1EF && b == 0);
+
+ /* Singletons */
+ g_assert (hb_unicode_decompose (uf, 0x212B, &a, &b) && a == 0x00C5 && b == 0);
+ g_assert (hb_unicode_decompose (uf, 0x2126, &a, &b) && a == 0x03A9 && b == 0);
+
+ /* Non-starter pairs decompose, but not compose */
+ g_assert (hb_unicode_decompose (uf, 0x0344, &a, &b) && a == 0x0308 && b == 0x0301);
+ g_assert (hb_unicode_decompose (uf, 0x0F73, &a, &b) && a == 0x0F71 && b == 0x0F72);
+
+ /* Pairs */
+ g_assert (hb_unicode_decompose (uf, 0x00C5, &a, &b) && a == 0x0041 && b == 0x030A);
+ g_assert (hb_unicode_decompose (uf, 0x00F4, &a, &b) && a == 0x006F && b == 0x0302);
+ g_assert (hb_unicode_decompose (uf, 0x1E69, &a, &b) && a == 0x1E63 && b == 0x0307);
+ g_assert (hb_unicode_decompose (uf, 0x1E63, &a, &b) && a == 0x0073 && b == 0x0323);
+ g_assert (hb_unicode_decompose (uf, 0x1E0B, &a, &b) && a == 0x0064 && b == 0x0307);
+ g_assert (hb_unicode_decompose (uf, 0x1E0D, &a, &b) && a == 0x0064 && b == 0x0323);
+
+ /* Hangul */
+ g_assert (hb_unicode_decompose (uf, 0xD4DB, &a, &b) && a == 0xD4CC && b == 0x11B6);
+ g_assert (hb_unicode_decompose (uf, 0xD4CC, &a, &b) && a == 0x1111 && b == 0x1171);
+ g_assert (hb_unicode_decompose (uf, 0xCE31, &a, &b) && a == 0xCE20 && b == 0x11B8);
+ g_assert (hb_unicode_decompose (uf, 0xCE20, &a, &b) && a == 0x110E && b == 0x1173);
+
+
+ /* Test decompose_compatibility() */
+
+ /* Not decomposable */
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x0041, decomposed) == 0);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x1F632, decomposed) == 0);
+
+ /* Singletons */
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x00B5, decomposed) == 1 && decomposed[0] == 0x03BC);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x03D6, decomposed) == 1 && decomposed[0] == 0x03C0);
+
+ /* Arabic compatibility */
+ g_assert (hb_unicode_decompose_compatibility (uf, 0xFB54, decomposed) == 1 && decomposed[0] == 0x067B);
+
+ /* Longest decomposition ever */
+ g_assert (18 <= HB_UNICODE_MAX_DECOMPOSITION_LEN);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0xFDFA, decomposed) == 18 && decomposed[17] == 0x0645);
+
+ /* Note: we deliberately don't test characters that have canonical decompositions but no
+ * compatibility decomposition against the decompose_compatibility() function as that we
+ * leave up to implementations (for now). */
+
+ /* Spaces */
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2002, decomposed) == 1 && decomposed[0] == 0x0020);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2003, decomposed) == 1 && decomposed[0] == 0x0020);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2004, decomposed) == 1 && decomposed[0] == 0x0020);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2005, decomposed) == 1 && decomposed[0] == 0x0020);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2006, decomposed) == 1 && decomposed[0] == 0x0020);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2008, decomposed) == 1 && decomposed[0] == 0x0020);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2009, decomposed) == 1 && decomposed[0] == 0x0020);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x200A, decomposed) == 1 && decomposed[0] == 0x0020);
+
+ /* Pairs */
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x0587, decomposed) == 2 &&
+ decomposed[0] == 0x0565 && decomposed[1] == 0x0582);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2017, decomposed) == 2 &&
+ decomposed[0] == 0x0020 && decomposed[1] == 0x0333);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2025, decomposed) == 2 &&
+ decomposed[0] == 0x002E && decomposed[1] == 0x002E);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2033, decomposed) == 2 &&
+ decomposed[0] == 0x2032 && decomposed[1] == 0x2032);
+
+ /* Triples */
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2026, decomposed) == 3 &&
+ decomposed[0] == 0x002E && decomposed[1] == 0x002E && decomposed[2] == 0x002E);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x2034, decomposed) == 3 &&
+ decomposed[0] == 0x2032 && decomposed[1] == 0x2032 && decomposed[2] == 0x2032);
+ g_assert (hb_unicode_decompose_compatibility (uf, 0x213B, decomposed) == 3 &&
+ decomposed[0] == 0x0046 && decomposed[1] == 0x0041 && decomposed[2] == 0x0058);
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_unicode_properties_nil);
+ hb_test_add (test_unicode_properties_empty);
+
+ hb_test_add_data_flavor (hb_unicode_funcs_get_default (), "default", test_unicode_properties);
+ hb_test_add_data_flavor (hb_unicode_funcs_get_default (), "default", test_unicode_normalization);
+ hb_test_add_data_flavor ((gconstpointer) script_roundtrip_default, "default", test_unicode_script_roundtrip);
+#ifdef HAVE_GLIB
+ hb_test_add_data_flavor (hb_glib_get_unicode_funcs (), "glib", test_unicode_properties);
+ hb_test_add_data_flavor (hb_glib_get_unicode_funcs (), "glib", test_unicode_normalization);
+ hb_test_add_data_flavor ((gconstpointer) script_roundtrip_glib, "glib", test_unicode_script_roundtrip);
+#endif
+#ifdef HAVE_ICU
+ hb_test_add_data_flavor (hb_icu_get_unicode_funcs (), "icu", test_unicode_properties);
+ hb_test_add_data_flavor (hb_icu_get_unicode_funcs (), "icu", test_unicode_normalization);
+ hb_test_add_data_flavor ((gconstpointer) script_roundtrip_icu, "icu", test_unicode_script_roundtrip);
+#endif
+
+ hb_test_add (test_unicode_chainup);
+
+ hb_test_add (test_unicode_setters);
+
+ hb_test_add_fixture (data_fixture, NULL, test_unicode_subclassing_nil);
+ hb_test_add_fixture (data_fixture, NULL, test_unicode_subclassing_default);
+ hb_test_add_fixture (data_fixture, NULL, test_unicode_subclassing_deep);
+
+ return hb_test_run ();
+}
diff --git a/test/api/test-version.c b/test/api/test-version.c
new file mode 100644
index 0000000..4c9bd37
--- /dev/null
+++ b/test/api/test-version.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2011 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"
+
+/* Unit tests for hb-version.h */
+
+
+static void
+test_version (void)
+{
+ unsigned int major, minor, micro;
+ char *s;
+
+ hb_version (&major, &minor, &micro);
+
+ g_assert_cmpint (major, ==, HB_VERSION_MAJOR);
+ g_assert_cmpint (minor, ==, HB_VERSION_MINOR);
+ g_assert_cmpint (micro, ==, HB_VERSION_MICRO);
+
+ s = g_strdup_printf ("%u.%u.%u", major, minor, micro);
+ g_assert (0 == strcmp (HB_VERSION_STRING, s));
+ g_free (s);
+ g_assert (0 == strcmp (HB_VERSION_STRING, hb_version_string ()));
+
+ g_assert (HB_VERSION_CHECK (major, minor, micro));
+ g_assert (HB_VERSION_CHECK (major+1, minor, micro));
+ g_assert (HB_VERSION_CHECK (major, minor+1, micro));
+ g_assert (HB_VERSION_CHECK (major, minor, micro+1));
+ if (major)
+ g_assert (!HB_VERSION_CHECK (major-1, minor, micro));
+ if (minor)
+ g_assert (!HB_VERSION_CHECK (major, minor-1, micro));
+ if (micro)
+ g_assert (!HB_VERSION_CHECK (major, minor, micro-1));
+
+ g_assert (hb_version_check (major, minor, micro));
+ g_assert (hb_version_check (major+1, minor, micro));
+ g_assert (hb_version_check (major, minor+1, micro));
+ g_assert (hb_version_check (major, minor, micro+1));
+ if (major)
+ g_assert (!hb_version_check (major-1, minor, micro));
+ if (minor)
+ g_assert (!hb_version_check (major, minor-1, micro));
+ if (micro)
+ g_assert (!hb_version_check (major, minor, micro-1));
+}
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_version);
+
+ return hb_test_run();
+}
diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am
new file mode 100644
index 0000000..4fb762c
--- /dev/null
+++ b/test/shaping/Makefile.am
@@ -0,0 +1,35 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+EXTRA_DIST =
+CLEANFILES =
+DISTCLEANFILES =
+MAINTAINERCLEANFILES =
+
+manifests:
+ @$(srcdir)/hb-manifest-update "$(srcdir)/texts" "$(srcdir)/fonts"
+
+EXTRA_DIST += \
+ hb-diff \
+ hb-diff-colorize \
+ hb-diff-filter-failures \
+ hb-diff-ngrams \
+ hb-diff-stat \
+ hb-manifest-read \
+ hb-manifest-update \
+ hb-unicode-decode \
+ hb-unicode-encode \
+ hb-unicode-prettyname \
+ $(NULL)
+
+# TODO Figure out Python stuff
+EXTRA_DIST += \
+ hb_test_tools.py \
+ $(NULL)
+CLEANFILES += \
+ hb_test_tools.py[co] \
+ $(NULL)
+
+.PHONY: manifests
+
+-include $(top_srcdir)/git.mk
diff --git a/test/shaping/Makefile.in b/test/shaping/Makefile.in
new file mode 100644
index 0000000..6273f9d
--- /dev/null
+++ b/test/shaping/Makefile.in
@@ -0,0 +1,408 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Process this file with automake to produce Makefile.in
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = test/shaping
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_FT_CFLAGS = @CAIRO_FT_CFLAGS@
+CAIRO_FT_LIBS = @CAIRO_FT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CORETEXT_CFLAGS = @CORETEXT_CFLAGS@
+CORETEXT_LIBS = @CORETEXT_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GRAPHITE2_CFLAGS = @GRAPHITE2_CFLAGS@
+GRAPHITE2_LIBS = @GRAPHITE2_LIBS@
+GREP = @GREP@
+GTHREAD_CFLAGS = @GTHREAD_CFLAGS@
+GTHREAD_LIBS = @GTHREAD_LIBS@
+HB_LIBTOOL_VERSION_INFO = @HB_LIBTOOL_VERSION_INFO@
+HB_VERSION = @HB_VERSION@
+HB_VERSION_MAJOR = @HB_VERSION_MAJOR@
+HB_VERSION_MICRO = @HB_VERSION_MICRO@
+HB_VERSION_MINOR = @HB_VERSION_MINOR@
+ICU_CFLAGS = @ICU_CFLAGS@
+ICU_LIBS = @ICU_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
+UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+NULL =
+
+# TODO Figure out Python stuff
+EXTRA_DIST = hb-diff hb-diff-colorize hb-diff-filter-failures \
+ hb-diff-ngrams hb-diff-stat hb-manifest-read \
+ hb-manifest-update hb-unicode-decode hb-unicode-encode \
+ hb-unicode-prettyname $(NULL) hb_test_tools.py $(NULL)
+CLEANFILES = hb_test_tools.py[co] $(NULL)
+DISTCLEANFILES =
+MAINTAINERCLEANFILES =
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits test/shaping/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnits test/shaping/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+manifests:
+ @$(srcdir)/hb-manifest-update "$(srcdir)/texts" "$(srcdir)/fonts"
+
+.PHONY: manifests
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/shaping/hb-diff b/test/shaping/hb-diff
new file mode 100755
index 0000000..6a13fa2
--- /dev/null
+++ b/test/shaping/hb-diff
@@ -0,0 +1,10 @@
+#!/usr/bin/python
+
+from hb_test_tools import *
+import sys, os
+
+if len (sys.argv) < 2:
+ print "usage: %s FILES..." % sys.argv[0]
+ sys.exit (1)
+
+ZipDiffer.diff_files (FileHelpers.open_file_or_stdin (f) for f in sys.argv[1:])
diff --git a/test/shaping/hb-diff-colorize b/test/shaping/hb-diff-colorize
new file mode 100755
index 0000000..4e045d2
--- /dev/null
+++ b/test/shaping/hb-diff-colorize
@@ -0,0 +1,7 @@
+#!/usr/bin/python
+
+from hb_test_tools import *
+
+formatter = ColorFormatter.Auto (sys.argv)
+colorizer = DiffColorizer (formatter=formatter)
+UtilMains.process_multiple_files (FilterHelpers.filter_printer_function_no_newline (colorizer.colorize_diff))
diff --git a/test/shaping/hb-diff-filter-failures b/test/shaping/hb-diff-filter-failures
new file mode 100755
index 0000000..4fe218a
--- /dev/null
+++ b/test/shaping/hb-diff-filter-failures
@@ -0,0 +1,5 @@
+#!/usr/bin/python
+
+from hb_test_tools import *
+
+UtilMains.process_multiple_files (FilterHelpers.filter_printer_function_no_newline (DiffFilters.filter_failures))
diff --git a/test/shaping/hb-diff-ngrams b/test/shaping/hb-diff-ngrams
new file mode 100755
index 0000000..a496447
--- /dev/null
+++ b/test/shaping/hb-diff-ngrams
@@ -0,0 +1,5 @@
+#!/usr/bin/python
+
+from hb_test_tools import *
+
+UtilMains.process_multiple_files (DiffSinks.print_ngrams)
diff --git a/test/shaping/hb-diff-stat b/test/shaping/hb-diff-stat
new file mode 100755
index 0000000..81626e1
--- /dev/null
+++ b/test/shaping/hb-diff-stat
@@ -0,0 +1,5 @@
+#!/usr/bin/python
+
+from hb_test_tools import *
+
+UtilMains.process_multiple_files (DiffSinks.print_stat)
diff --git a/test/shaping/hb-manifest-read b/test/shaping/hb-manifest-read
new file mode 100755
index 0000000..f486bcc
--- /dev/null
+++ b/test/shaping/hb-manifest-read
@@ -0,0 +1,5 @@
+#!/usr/bin/python
+
+from hb_test_tools import *
+
+UtilMains.process_multiple_args (FilterHelpers.filter_printer_function (Manifest.read), mnemonic="DIR")
diff --git a/test/shaping/hb-manifest-update b/test/shaping/hb-manifest-update
new file mode 100755
index 0000000..b963f22
--- /dev/null
+++ b/test/shaping/hb-manifest-update
@@ -0,0 +1,5 @@
+#!/usr/bin/python
+
+from hb_test_tools import *
+
+UtilMains.process_multiple_args (Manifest.update_recursive, mnemonic="DIR")
diff --git a/test/shaping/hb-unicode-decode b/test/shaping/hb-unicode-decode
new file mode 100755
index 0000000..5b00eae
--- /dev/null
+++ b/test/shaping/hb-unicode-decode
@@ -0,0 +1,5 @@
+#!/usr/bin/python
+
+from hb_test_tools import *
+
+UtilMains.filter_multiple_strings_or_stdin (Unicode.decode, "UNICODE_STRING")
diff --git a/test/shaping/hb-unicode-encode b/test/shaping/hb-unicode-encode
new file mode 100755
index 0000000..11bf365
--- /dev/null
+++ b/test/shaping/hb-unicode-encode
@@ -0,0 +1,5 @@
+#!/usr/bin/python
+
+from hb_test_tools import *
+
+UtilMains.filter_multiple_strings_or_stdin (Unicode.encode, "UNICODE_STRING", '')
diff --git a/test/shaping/hb-unicode-prettyname b/test/shaping/hb-unicode-prettyname
new file mode 100755
index 0000000..ecc26cc
--- /dev/null
+++ b/test/shaping/hb-unicode-prettyname
@@ -0,0 +1,6 @@
+#!/usr/bin/python
+
+from hb_test_tools import *
+
+UtilMains.filter_multiple_strings_or_stdin (Unicode.pretty_names, "UNICODE_CODEPOINTS", \
+ concat_separator = ' ')
diff --git a/test/shaping/hb_test_tools.py b/test/shaping/hb_test_tools.py
new file mode 100644
index 0000000..ce46588
--- /dev/null
+++ b/test/shaping/hb_test_tools.py
@@ -0,0 +1,516 @@
+#!/usr/bin/python
+
+import sys, os, re, difflib, unicodedata, errno, cgi
+from itertools import *
+
+diff_symbols = "-+=*&^%$#@!~/"
+diff_colors = ['red', 'green', 'blue']
+
+class ColorFormatter:
+
+ class Null:
+ @staticmethod
+ def start_color (c): return ''
+ @staticmethod
+ def end_color (): return ''
+ @staticmethod
+ def escape (s): return s
+ @staticmethod
+ def newline (): return '\n'
+
+ class ANSI:
+ @staticmethod
+ def start_color (c):
+ return {
+ 'red': '\033[41;37;1m',
+ 'green': '\033[42;37;1m',
+ 'blue': '\033[44;37;1m',
+ }[c]
+ @staticmethod
+ def end_color ():
+ return '\033[m'
+ @staticmethod
+ def escape (s): return s
+ @staticmethod
+ def newline (): return '\n'
+
+ class HTML:
+ @staticmethod
+ def start_color (c):
+ return '<span style="background:%s">' % c
+ @staticmethod
+ def end_color ():
+ return '</span>'
+ @staticmethod
+ def escape (s): return cgi.escape (s)
+ @staticmethod
+ def newline (): return '<br/>\n'
+
+ @staticmethod
+ def Auto (argv = [], out = sys.stdout):
+ format = ColorFormatter.ANSI
+ if "--format" in argv:
+ argv.remove ("--format")
+ format = ColorFormatter.ANSI
+ if "--format=ansi" in argv:
+ argv.remove ("--format=ansi")
+ format = ColorFormatter.ANSI
+ if "--format=html" in argv:
+ argv.remove ("--format=html")
+ format = ColorFormatter.HTML
+ if "--no-format" in argv:
+ argv.remove ("--no-format")
+ format = ColorFormatter.Null
+ return format
+
+
+class DiffColorizer:
+
+ diff_regex = re.compile ('([a-za-z0-9_]*)([^a-za-z0-9_]?)')
+
+ def __init__ (self, formatter, colors=diff_colors, symbols=diff_symbols):
+ self.formatter = formatter
+ self.colors = colors
+ self.symbols = symbols
+
+ def colorize_lines (self, lines):
+ lines = (l if l else '' for l in lines)
+ ss = [self.diff_regex.sub (r'\1\n\2\n', l).splitlines (True) for l in lines]
+ oo = ["",""]
+ st = [False, False]
+ for l in difflib.Differ().compare (*ss):
+ if l[0] == '?':
+ continue
+ if l[0] == ' ':
+ for i in range(2):
+ if st[i]:
+ oo[i] += self.formatter.end_color ()
+ st[i] = False
+ oo = [o + self.formatter.escape (l[2:]) for o in oo]
+ continue
+ if l[0] in self.symbols:
+ i = self.symbols.index (l[0])
+ if not st[i]:
+ oo[i] += self.formatter.start_color (self.colors[i])
+ st[i] = True
+ oo[i] += self.formatter.escape (l[2:])
+ continue
+ for i in range(2):
+ if st[i]:
+ oo[i] += self.formatter.end_color ()
+ st[i] = False
+ oo = [o.replace ('\n', '') for o in oo]
+ return [s1+s2+self.formatter.newline () for (s1,s2) in zip (self.symbols, oo) if s2]
+
+ def colorize_diff (self, f):
+ lines = [None, None]
+ for l in f:
+ if l[0] not in self.symbols:
+ yield self.formatter.escape (l).replace ('\n', self.formatter.newline ())
+ continue
+ i = self.symbols.index (l[0])
+ if lines[i]:
+ # Flush
+ for line in self.colorize_lines (lines):
+ yield line
+ lines = [None, None]
+ lines[i] = l[1:]
+ if (all (lines)):
+ # Flush
+ for line in self.colorize_lines (lines):
+ yield line
+ lines = [None, None]
+ if (any (lines)):
+ # Flush
+ for line in self.colorize_lines (lines):
+ yield line
+
+
+class ZipDiffer:
+
+ @staticmethod
+ def diff_files (files, symbols=diff_symbols):
+ files = tuple (files) # in case it's a generator, copy it
+ try:
+ for lines in izip_longest (*files):
+ if all (lines[0] == line for line in lines[1:]):
+ sys.stdout.writelines ([" ", lines[0]])
+ continue
+
+ for i, l in enumerate (lines):
+ if l:
+ sys.stdout.writelines ([symbols[i], l])
+ except IOError as e:
+ if e.errno != errno.EPIPE:
+ print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)
+ sys.exit (1)
+
+
+class DiffFilters:
+
+ @staticmethod
+ def filter_failures (f):
+ for key, lines in DiffHelpers.separate_test_cases (f):
+ lines = list (lines)
+ if not DiffHelpers.test_passed (lines):
+ for l in lines: yield l
+
+class Stat:
+
+ def __init__ (self):
+ self.count = 0
+ self.freq = 0
+
+ def add (self, test):
+ self.count += 1
+ self.freq += test.freq
+
+class Stats:
+
+ def __init__ (self):
+ self.passed = Stat ()
+ self.failed = Stat ()
+ self.total = Stat ()
+
+ def add (self, test):
+ self.total.add (test)
+ if test.passed:
+ self.passed.add (test)
+ else:
+ self.failed.add (test)
+
+ def mean (self):
+ return float (self.passed.count) / self.total.count
+
+ def variance (self):
+ return (float (self.passed.count) / self.total.count) * \
+ (float (self.failed.count) / self.total.count)
+
+ def stddev (self):
+ return self.variance () ** .5
+
+ def zscore (self, population):
+ """Calculate the standard score.
+ Population is the Stats for population.
+ Self is Stats for sample.
+ Returns larger absolute value if sample is highly unlikely to be random.
+ Anything outside of -3..+3 is very unlikely to be random.
+ See: http://en.wikipedia.org/wiki/Standard_score"""
+
+ return (self.mean () - population.mean ()) / population.stddev ()
+
+
+
+
+class DiffSinks:
+
+ @staticmethod
+ def print_stat (f):
+ passed = 0
+ failed = 0
+ # XXX port to Stats, but that would really slow us down here
+ for key, lines in DiffHelpers.separate_test_cases (f):
+ if DiffHelpers.test_passed (lines):
+ passed += 1
+ else:
+ failed += 1
+ total = passed + failed
+ print "%d out of %d tests passed. %d failed (%g%%)" % (passed, total, failed, 100. * failed / total)
+
+ @staticmethod
+ def print_ngrams (f, ns=(1,2,3)):
+ gens = tuple (Ngram.generator (n) for n in ns)
+ allstats = Stats ()
+ allgrams = {}
+ for key, lines in DiffHelpers.separate_test_cases (f):
+ test = Test (lines)
+ allstats.add (test)
+
+ for gen in gens:
+ for ngram in gen (test.unicodes):
+ if ngram not in allgrams:
+ allgrams[ngram] = Stats ()
+ allgrams[ngram].add (test)
+
+ importantgrams = {}
+ for ngram, stats in allgrams.iteritems ():
+ if stats.failed.count >= 30: # for statistical reasons
+ importantgrams[ngram] = stats
+ allgrams = importantgrams
+ del importantgrams
+
+ for ngram, stats in allgrams.iteritems ():
+ print "zscore: %9f failed: %6d passed: %6d ngram: <%s>" % (stats.zscore (allstats), stats.failed.count, stats.passed.count, ','.join ("U+%04X" % u for u in ngram))
+
+
+
+class Test:
+
+ def __init__ (self, lines):
+ self.freq = 1
+ self.passed = True
+ self.identifier = None
+ self.text = None
+ self.unicodes = None
+ self.glyphs = None
+ for l in lines:
+ symbol = l[0]
+ if symbol != ' ':
+ self.passed = False
+ i = 1
+ if ':' in l:
+ i = l.index (':')
+ if not self.identifier:
+ self.identifier = l[1:i]
+ i = i + 2 # Skip colon and space
+ j = -1
+ if l[j] == '\n':
+ j -= 1
+ brackets = l[i] + l[j]
+ l = l[i+1:-2]
+ if brackets == '()':
+ self.text = l
+ elif brackets == '<>':
+ self.unicodes = Unicode.parse (l)
+ elif brackets == '[]':
+ # XXX we don't handle failed tests here
+ self.glyphs = l
+
+
+class DiffHelpers:
+
+ @staticmethod
+ def separate_test_cases (f):
+ '''Reads lines from f, and if the lines have identifiers, ie.
+ have a colon character, groups them by identifier,
+ yielding lists of all lines with the same identifier.'''
+
+ def identifier (l):
+ if ':' in l[1:]:
+ return l[1:l.index (':')]
+ return l
+ return groupby (f, key=identifier)
+
+ @staticmethod
+ def test_passed (lines):
+ lines = list (lines)
+ # XXX This is a hack, but does the job for now.
+ if any (l.find("space|space") >= 0 for l in lines): return True
+ if any (l.find("uni25CC") >= 0 for l in lines): return True
+ if any (l.find("dottedcircle") >= 0 for l in lines): return True
+ return all (l[0] == ' ' for l in lines)
+
+
+class FilterHelpers:
+
+ @staticmethod
+ def filter_printer_function (filter_callback):
+ def printer (f):
+ for line in filter_callback (f):
+ print line
+ return printer
+
+ @staticmethod
+ def filter_printer_function_no_newline (filter_callback):
+ def printer (f):
+ for line in filter_callback (f):
+ sys.stdout.writelines ([line])
+ return printer
+
+
+class Ngram:
+
+ @staticmethod
+ def generator (n):
+
+ def gen (f):
+ l = []
+ for x in f:
+ l.append (x)
+ if len (l) == n:
+ yield tuple (l)
+ l[:1] = []
+
+ gen.n = n
+ return gen
+
+
+class UtilMains:
+
+ @staticmethod
+ def process_multiple_files (callback, mnemonic = "FILE"):
+
+ if "--help" in sys.argv:
+ print "Usage: %s %s..." % (sys.argv[0], mnemonic)
+ sys.exit (1)
+
+ try:
+ files = sys.argv[1:] if len (sys.argv) > 1 else ['-']
+ for s in files:
+ callback (FileHelpers.open_file_or_stdin (s))
+ except IOError as e:
+ if e.errno != errno.EPIPE:
+ print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)
+ sys.exit (1)
+
+ @staticmethod
+ def process_multiple_args (callback, mnemonic):
+
+ if len (sys.argv) == 1 or "--help" in sys.argv:
+ print "Usage: %s %s..." % (sys.argv[0], mnemonic)
+ sys.exit (1)
+
+ try:
+ for s in sys.argv[1:]:
+ callback (s)
+ except IOError as e:
+ if e.errno != errno.EPIPE:
+ print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)
+ sys.exit (1)
+
+ @staticmethod
+ def filter_multiple_strings_or_stdin (callback, mnemonic, \
+ separator = " ", \
+ concat_separator = False):
+
+ if "--help" in sys.argv:
+ print "Usage:\n %s %s...\nor:\n %s\n\nWhen called with no arguments, input is read from standard input." \
+ % (sys.argv[0], mnemonic, sys.argv[0])
+ sys.exit (1)
+
+ try:
+ if len (sys.argv) == 1:
+ while (1):
+ line = sys.stdin.readline ()
+ if not len (line):
+ break
+ if line[-1] == '\n':
+ line = line[:-1]
+ print callback (line)
+ else:
+ args = sys.argv[1:]
+ if concat_separator != False:
+ args = [concat_separator.join (args)]
+ print separator.join (callback (x) for x in (args))
+ except IOError as e:
+ if e.errno != errno.EPIPE:
+ print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)
+ sys.exit (1)
+
+
+class Unicode:
+
+ @staticmethod
+ def decode (s):
+ return '<' + u','.join ("U+%04X" % ord (u) for u in unicode (s, 'utf-8')).encode ('utf-8') + '>'
+
+ @staticmethod
+ def parse (s):
+ s = re.sub (r"[<+>,\\uU\n ]", " ", s)
+ s = re.sub (r"0[xX]", " ", s)
+ return [int (x, 16) for x in s.split (' ') if len (x)]
+
+ @staticmethod
+ def encode (s):
+ return u''.join (unichr (x) for x in Unicode.parse (s)).encode ('utf-8')
+
+ shorthands = {
+ "ZERO WIDTH NON-JOINER": "ZWNJ",
+ "ZERO WIDTH JOINER": "ZWJ",
+ "NARROW NO-BREAK SPACE": "NNBSP",
+ "COMBINING GRAPHEME JOINER": "CGJ",
+ "LEFT-TO-RIGHT MARK": "LRM",
+ "RIGHT-TO-LEFT MARK": "RLM",
+ "LEFT-TO-RIGHT EMBEDDING": "LRE",
+ "RIGHT-TO-LEFT EMBEDDING": "RLE",
+ "POP DIRECTIONAL FORMATTING": "PDF",
+ "LEFT-TO-RIGHT OVERRIDE": "LRO",
+ "RIGHT-TO-LEFT OVERRIDE": "RLO",
+ }
+
+ @staticmethod
+ def pretty_name (u):
+ try:
+ s = unicodedata.name (u)
+ except ValueError:
+ return "XXX"
+ s = re.sub (".* LETTER ", "", s)
+ s = re.sub (".* VOWEL SIGN (.*)", r"\1-MATRA", s)
+ s = re.sub (".* SIGN ", "", s)
+ s = re.sub (".* COMBINING ", "", s)
+ if re.match (".* VIRAMA", s):
+ s = "HALANT"
+ if s in Unicode.shorthands:
+ s = Unicode.shorthands[s]
+ return s
+
+ @staticmethod
+ def pretty_names (s):
+ s = re.sub (r"[<+>\\uU]", " ", s)
+ s = re.sub (r"0[xX]", " ", s)
+ s = [unichr (int (x, 16)) for x in re.split ('[, \n]', s) if len (x)]
+ return u' + '.join (Unicode.pretty_name (x) for x in s).encode ('utf-8')
+
+
+class FileHelpers:
+
+ @staticmethod
+ def open_file_or_stdin (f):
+ if f == '-':
+ return sys.stdin
+ return file (f)
+
+
+class Manifest:
+
+ @staticmethod
+ def read (s, strict = True):
+
+ if not os.path.exists (s):
+ if strict:
+ print >> sys.stderr, "%s: %s does not exist" % (sys.argv[0], s)
+ sys.exit (1)
+ return
+
+ s = os.path.normpath (s)
+
+ if os.path.isdir (s):
+
+ try:
+ m = file (os.path.join (s, "MANIFEST"))
+ items = [x.strip () for x in m.readlines ()]
+ for f in items:
+ for p in Manifest.read (os.path.join (s, f)):
+ yield p
+ except IOError:
+ if strict:
+ print >> sys.stderr, "%s: %s does not exist" % (sys.argv[0], os.path.join (s, "MANIFEST"))
+ sys.exit (1)
+ return
+ else:
+ yield s
+
+ @staticmethod
+ def update_recursive (s):
+
+ for dirpath, dirnames, filenames in os.walk (s, followlinks=True):
+
+ for f in ["MANIFEST", "README", "LICENSE", "COPYING", "AUTHORS", "SOURCES", "ChangeLog"]:
+ if f in dirnames:
+ dirnames.remove (f)
+ if f in filenames:
+ filenames.remove (f)
+ dirnames.sort ()
+ filenames.sort ()
+ ms = os.path.join (dirpath, "MANIFEST")
+ print " GEN %s" % ms
+ m = open (ms, "w")
+ for f in filenames:
+ print >> m, f
+ for f in dirnames:
+ print >> m, f
+ for f in dirnames:
+ Manifest.update_recursive (os.path.join (dirpath, f))
+
+if __name__ == '__main__':
+ pass