#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
#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.
hb_codepoint_t unicode,
void *user_data);
typedef unsigned int (*func_setter_func_t) (hb_unicode_funcs_t *ufuncs,
- get_func_t *func,
+ get_func_t func,
void *user_data,
hb_destroy_func_t destroy);
typedef unsigned int (*getter_func_t) (hb_unicode_funcs_t *ufuncs,
{ \
#name, \
(func_setter_func_t) hb_unicode_funcs_set_##name##_func, \
- (getter_func_t) hb_unicode_get_##name, \
+ (getter_func_t) hb_unicode_##name, \
name##_tests, \
G_N_ELEMENTS (name##_tests), \
name##_tests_more, \
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),
+ PROPERTY (script, (unsigned int) HB_SCRIPT_UNKNOWN)
};
#undef PROPERTY
{
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];
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)
+default_value (hb_codepoint_t _default_value, hb_codepoint_t unicode)
{
- return default_value == RETURNS_UNICODE_ITSELF ? unicode : default_value;
+ return _default_value == RETURNS_UNICODE_ITSELF ? unicode : _default_value;
}
static void
-test_unicode_properties_nil (void)
+_test_unicode_properties_nil (hb_unicode_funcs_t *uf)
{
- hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
unsigned int i, j;
- g_assert (!hb_unicode_funcs_is_immutable (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++)
+ 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));
+ }
}
-
- hb_unicode_funcs_destroy (uf);
}
-#define MAGIC0 0x12345678
-#define MAGIC1 0x76543210
-
-typedef struct {
- int value;
- gboolean freed;
-} data_t;
-
-typedef struct {
- data_t data[2];
-} data_fixture_t;
static void
-data_fixture_init (data_fixture_t *f, gconstpointer user_data)
+test_unicode_properties_nil (void)
{
- f->data[0].value = MAGIC0;
- f->data[1].value = MAGIC1;
+ 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
-data_fixture_finish (data_fixture_t *f, gconstpointer user_data)
+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 free_up (void *p)
+
+static void
+test_unicode_chainup (void)
{
- data_t *data = (data_t *) p;
+ hb_unicode_funcs_t *uf, *uf2;
- g_assert (data->value == MAGIC0 || data->value == MAGIC1);
- g_assert (data->freed == FALSE);
- data->freed = TRUE;
-}
+ /* Chain-up to nil */
-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;
+ uf = hb_unicode_funcs_create (NULL);
+ g_assert (!hb_unicode_funcs_is_immutable (uf));
- g_assert (hb_unicode_funcs_get_parent (ufuncs) == NULL);
- g_assert (data->value == MAGIC0);
- g_assert (data->freed == FALSE);
+ uf2 = hb_unicode_funcs_create (uf);
+ g_assert (hb_unicode_funcs_is_immutable (uf));
+ hb_unicode_funcs_destroy (uf);
- if ('a' <= codepoint && codepoint <= 'z')
- return HB_SCRIPT_LATIN;
- else
- return HB_SCRIPT_UNKNOWN;
-}
+ g_assert (!hb_unicode_funcs_is_immutable (uf2));
+ _test_unicode_properties_nil (uf2);
-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;
+ hb_unicode_funcs_destroy (uf2);
- g_assert (hb_unicode_funcs_get_parent (ufuncs) != NULL);
- g_assert (data->value == MAGIC1);
- g_assert (data->freed == FALSE);
+ /* Chain-up to default */
- if (codepoint == 'a') {
- return HB_SCRIPT_ARABIC;
- } else {
- hb_unicode_funcs_t *parent = hb_unicode_funcs_get_parent (ufuncs);
+ 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);
- return hb_unicode_get_script (parent, codepoint);
- }
}
static void
-test_unicode_custom (data_fixture_t *f, gconstpointer user_data)
+test_unicode_setters (void)
{
- hb_unicode_funcs_t *uf = hb_unicode_funcs_create (NULL);
+ hb_unicode_funcs_t *uf;
+ unsigned int i;
- hb_unicode_funcs_set_script_func (uf, simple_get_script,
- &f->data[0], free_up);
+ /* This is cruel: we use script-returning functions to test all properties,
+ * but it works. */
- g_assert_cmpint (hb_unicode_get_script (uf, 'a'), ==, HB_SCRIPT_LATIN);
- g_assert_cmpint (hb_unicode_get_script (uf, '0'), ==, HB_SCRIPT_UNKNOWN);
+ for (i = 0; i < G_N_ELEMENTS (properties); i++) {
+ const property_t *p = &properties[i];
+ data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
- g_assert (!hb_unicode_funcs_is_immutable (uf));
- hb_unicode_funcs_make_immutable (uf);
- g_assert (hb_unicode_funcs_is_immutable (uf));
+ g_test_message ("Testing property %s", p->name);
- /* Since uf is immutable now, the following setter should do nothing. */
- hb_unicode_funcs_set_script_func (uf, a_is_for_arabic_get_script,
- &f->data[1], free_up);
+ uf = hb_unicode_funcs_create (NULL);
+ g_assert (!hb_unicode_funcs_is_immutable (uf));
- g_assert (!f->data[0].freed && !f->data[1].freed);
- hb_unicode_funcs_destroy (uf);
- g_assert (f->data[0].freed && !f->data[1].freed);
+ 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
hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
&f->data[1], free_up);
- g_assert_cmpint (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
- g_assert_cmpint (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_UNKNOWN);
+ 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);
hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
&f->data[1], free_up);
- g_assert_cmpint (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
- g_assert_cmpint (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
+ 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);
hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
&f->data[1], free_up);
- g_assert_cmpint (hb_unicode_get_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
- g_assert_cmpint (hb_unicode_get_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
- g_assert_cmpint (hb_unicode_get_script (aa, '0'), ==, HB_SCRIPT_UNKNOWN);
+ 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);
}
+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.");
+}
+
+
+/* TODO test compose() and decompose() */
+static void
+test_unicode_normalization (gconstpointer user_data)
+{
+ hb_unicode_funcs_t *uf = (hb_unicode_funcs_t *) user_data;
+ gunichar a, b, ab;
+
+
+ /* 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);
+
+ /* 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);
+
+ /* Singletons */
+ g_assert (hb_unicode_decompose (uf, 0x212B, &a, &b));
+ g_assert_cmphex (a, ==, 0x00C5);
+ g_assert_cmphex (b, ==, 0);
+ 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);
+
+ /* 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);
+
+}
+
+
+
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_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_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_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_fixture (data_fixture, NULL, test_unicode_custom);
+ 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);
- /* XXX test icu ufuncs */
- /* XXX test _more tests (warn?) */
- /* XXX test chainup */
- /* XXX test glib & icu two-way script conversion */
-
return hb_test_run ();
}