• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2011  Google, Inc.
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Google Author(s): Behdad Esfahbod
25  */
26 
27 #include "hb-test.h"
28 
29 #include <hb-ot.h>
30 
31 /* Unit tests for hb-ot-tag.h */
32 
33 
34 /* https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags */
35 
36 static void
test_simple_tags(const char * s,hb_script_t script)37 test_simple_tags (const char *s, hb_script_t script)
38 {
39   hb_script_t tag;
40   unsigned int count = 2;
41   hb_tag_t t[2];
42 
43   g_test_message ("Testing script %c%c%c%c: tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s);
44   tag = hb_tag_from_string (s, -1);
45 
46   hb_ot_tags_from_script_and_language (script,
47 				       HB_LANGUAGE_INVALID,
48 				       &count, t, NULL, NULL);
49 
50   if (count)
51     g_assert_cmphex (t[0], ==, tag);
52   else
53     g_assert_cmphex (HB_TAG_CHAR4 ("DFLT"), ==, tag);
54 
55   g_assert_cmphex (hb_ot_tag_to_script (tag), ==, script);
56 }
57 
58 static void
test_script_tags_from_language(const char * s,const char * lang_s,hb_script_t script)59 test_script_tags_from_language (const char *s, const char *lang_s, hb_script_t script)
60 {
61   hb_script_t tag;
62   unsigned int count = 1;
63   hb_tag_t t;
64 
65   g_test_message ("Testing script %c%c%c%c: script tag %s, language tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s, lang_s);
66   tag = hb_tag_from_string (s, -1);
67 
68   hb_ot_tags_from_script_and_language (script, hb_language_from_string (lang_s, -1), &count, &t, NULL, NULL);
69 
70   if (count != 0)
71   {
72     g_assert_cmpuint (count, ==, 1);
73     g_assert_cmphex (t, ==, tag);
74   }
75 }
76 
77 static void
test_indic_tags(const char * s1,const char * s2,const char * s3,hb_script_t script)78 test_indic_tags (const char *s1, const char *s2, const char *s3, hb_script_t script)
79 {
80   hb_script_t tag1, tag2, tag3;
81   hb_tag_t t[3];
82   unsigned int count = 3;
83 
84   g_test_message ("Testing script %c%c%c%c: USE tag %s, new tag %s, old tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s1, s2, s3);
85   tag1 = hb_tag_from_string (s1, -1);
86   tag2 = hb_tag_from_string (s2, -1);
87   tag3 = hb_tag_from_string (s3, -1);
88 
89   hb_ot_tags_from_script_and_language (script,
90 				       HB_LANGUAGE_INVALID,
91 				       &count, t, NULL, NULL);
92 
93   g_assert_cmpuint (count, ==, 3);
94   g_assert_cmphex (t[0], ==, tag1);
95   g_assert_cmphex (t[1], ==, tag2);
96   g_assert_cmphex (t[2], ==, tag3);
97 
98   g_assert_cmphex (hb_ot_tag_to_script (tag1), ==, script);
99   g_assert_cmphex (hb_ot_tag_to_script (tag2), ==, script);
100   g_assert_cmphex (hb_ot_tag_to_script (tag3), ==, script);
101 }
102 
103 static void
test_ot_tag_script_degenerate(void)104 test_ot_tag_script_degenerate (void)
105 {
106   hb_tag_t t[2];
107   unsigned int count = 2;
108 
109   g_assert_cmphex (HB_TAG_CHAR4 ("DFLT"), ==, HB_OT_TAG_DEFAULT_SCRIPT);
110 
111   /* HIRAGANA and KATAKANA both map to 'kana' */
112   test_simple_tags ("kana", HB_SCRIPT_KATAKANA);
113 
114   hb_ot_tags_from_script_and_language (HB_SCRIPT_HIRAGANA,
115 				       HB_LANGUAGE_INVALID,
116 				       &count, t, NULL, NULL);
117 
118   g_assert_cmpuint (count, ==, 1);
119   g_assert_cmphex (t[0], ==, HB_TAG_CHAR4 ("kana"));
120 
121   test_simple_tags ("DFLT", HB_SCRIPT_INVALID);
122 
123   /* Spaces are replaced */
124   g_assert_cmphex (hb_ot_tag_to_script (HB_TAG_CHAR4 ("be  ")), ==, hb_script_from_string ("Beee", -1));
125 }
126 
127 static void
test_ot_tag_script_simple(void)128 test_ot_tag_script_simple (void)
129 {
130   /* Arbitrary non-existent script */
131   test_simple_tags ("wwyz", hb_script_from_string ("wWyZ", -1));
132 
133   /* These we don't really care about */
134   test_simple_tags ("zyyy", HB_SCRIPT_COMMON);
135   test_simple_tags ("zinh", HB_SCRIPT_INHERITED);
136   test_simple_tags ("zzzz", HB_SCRIPT_UNKNOWN);
137 
138   test_simple_tags ("arab", HB_SCRIPT_ARABIC);
139   test_simple_tags ("copt", HB_SCRIPT_COPTIC);
140   test_simple_tags ("kana", HB_SCRIPT_KATAKANA);
141   test_simple_tags ("latn", HB_SCRIPT_LATIN);
142 
143   /* These are trickier since their OT script tags have space. */
144   test_simple_tags ("lao ", HB_SCRIPT_LAO);
145   test_simple_tags ("yi  ", HB_SCRIPT_YI);
146   /* Unicode-5.0 additions */
147   test_simple_tags ("nko ", HB_SCRIPT_NKO);
148   /* Unicode-5.1 additions */
149   test_simple_tags ("vai ", HB_SCRIPT_VAI);
150 
151   /* https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags */
152 
153   /* Unicode-5.2 additions */
154   test_simple_tags ("mtei", HB_SCRIPT_MEETEI_MAYEK);
155   /* Unicode-6.0 additions */
156   test_simple_tags ("mand", HB_SCRIPT_MANDAIC);
157 }
158 
159 static void
test_ot_tag_script_from_language(void)160 test_ot_tag_script_from_language (void)
161 {
162   test_script_tags_from_language (NULL, NULL, HB_SCRIPT_INVALID);
163   test_script_tags_from_language (NULL, "en", HB_SCRIPT_INVALID);
164   test_script_tags_from_language ("copt", "en", HB_SCRIPT_COPTIC);
165   test_script_tags_from_language (NULL, "x-hbsc", HB_SCRIPT_INVALID);
166   test_script_tags_from_language ("copt", "x-hbsc", HB_SCRIPT_COPTIC);
167   test_script_tags_from_language (NULL, "x-hbsc-", HB_SCRIPT_INVALID);
168   test_script_tags_from_language (NULL, "x-hbsc-1", HB_SCRIPT_INVALID);
169   test_script_tags_from_language (NULL, "x-hbsc-1a", HB_SCRIPT_INVALID);
170   test_script_tags_from_language (NULL, "x-hbsc-1a2b3c4x", HB_SCRIPT_INVALID);
171   test_script_tags_from_language ("2lon", "x-hbsc-326c6f6e67", HB_SCRIPT_INVALID);
172   test_script_tags_from_language ("abc ", "x-hbscabc", HB_SCRIPT_INVALID);
173   test_script_tags_from_language ("deva", "x-hbscdeva", HB_SCRIPT_INVALID);
174   test_script_tags_from_language ("dev2", "x-hbscdev2", HB_SCRIPT_INVALID);
175   test_script_tags_from_language ("dev3", "x-hbscdev3", HB_SCRIPT_INVALID);
176   test_script_tags_from_language ("dev3", "x-hbsc-64657633", HB_SCRIPT_INVALID);
177   test_script_tags_from_language ("copt", "x-hbotpap0-hbsccopt", HB_SCRIPT_INVALID);
178   test_script_tags_from_language (NULL, "en-x-hbsc", HB_SCRIPT_INVALID);
179   test_script_tags_from_language ("copt", "en-x-hbsc", HB_SCRIPT_COPTIC);
180   test_script_tags_from_language ("abc ", "en-x-hbscabc", HB_SCRIPT_INVALID);
181   test_script_tags_from_language ("deva", "en-x-hbscdeva", HB_SCRIPT_INVALID);
182   test_script_tags_from_language ("dev2", "en-x-hbscdev2", HB_SCRIPT_INVALID);
183   test_script_tags_from_language ("dev3", "en-x-hbscdev3", HB_SCRIPT_INVALID);
184   test_script_tags_from_language ("dev3", "en-x-hbsc-64657633", HB_SCRIPT_INVALID);
185   test_script_tags_from_language ("copt", "en-x-hbotpap0-hbsccopt", HB_SCRIPT_INVALID);
186 }
187 
188 static void
test_ot_tag_script_indic(void)189 test_ot_tag_script_indic (void)
190 {
191   test_indic_tags ("bng3", "bng2", "beng", HB_SCRIPT_BENGALI);
192   test_indic_tags ("dev3", "dev2", "deva", HB_SCRIPT_DEVANAGARI);
193   test_indic_tags ("gjr3", "gjr2", "gujr", HB_SCRIPT_GUJARATI);
194   test_indic_tags ("gur3", "gur2", "guru", HB_SCRIPT_GURMUKHI);
195   test_indic_tags ("knd3", "knd2", "knda", HB_SCRIPT_KANNADA);
196   test_indic_tags ("mlm3", "mlm2", "mlym", HB_SCRIPT_MALAYALAM);
197   test_indic_tags ("ory3", "ory2", "orya", HB_SCRIPT_ORIYA);
198   test_indic_tags ("tml3", "tml2", "taml", HB_SCRIPT_TAMIL);
199   test_indic_tags ("tel3", "tel2", "telu", HB_SCRIPT_TELUGU);
200 }
201 
202 
203 
204 /* https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags */
205 
206 static void
test_language_two_way(const char * tag_s,const char * lang_s)207 test_language_two_way (const char *tag_s, const char *lang_s)
208 {
209   hb_language_t lang = hb_language_from_string (lang_s, -1);
210   hb_tag_t tag = hb_tag_from_string (tag_s, -1);
211   hb_tag_t tag2;
212   unsigned int count = 1;
213 
214   g_test_message ("Testing language %s <-> tag %s", lang_s, tag_s);
215 
216   hb_ot_tags_from_script_and_language (HB_SCRIPT_INVALID,
217 				       lang,
218 				       NULL, NULL, &count, &tag2);
219 
220   if (count)
221     g_assert_cmphex (tag, ==, tag2);
222   else
223     g_assert_cmphex (tag, ==, HB_TAG_CHAR4 ("dflt"));
224   g_assert (lang == hb_ot_tag_to_language (tag));
225 }
226 
227 static void
test_tag_from_language(const char * tag_s,const char * lang_s)228 test_tag_from_language (const char *tag_s, const char *lang_s)
229 {
230   hb_language_t lang = hb_language_from_string (lang_s, -1);
231   hb_tag_t tag = hb_tag_from_string (tag_s, -1);
232   hb_tag_t tag2;
233   unsigned int count = 1;
234 
235   g_test_message ("Testing language %s -> tag %s", lang_s, tag_s);
236 
237   hb_ot_tags_from_script_and_language (HB_SCRIPT_INVALID,
238 				       lang,
239 				       NULL, NULL, &count, &tag2);
240 
241   if (count)
242     g_assert_cmphex (tag, ==, tag2);
243   else
244     g_assert_cmphex (tag, ==, HB_TAG_CHAR4 ("dflt"));
245 }
246 
247 static void
test_tag_to_language(const char * tag_s,const char * lang_s)248 test_tag_to_language (const char *tag_s, const char *lang_s)
249 {
250   hb_language_t lang = hb_language_from_string (lang_s, -1);
251   hb_tag_t tag = hb_tag_from_string (tag_s, -1);
252 
253   g_test_message ("Testing tag %s -> language %s", tag_s, lang_s);
254 
255   g_assert (lang == hb_ot_tag_to_language (tag));
256 }
257 
258 static void
test_tags_to_script_and_language(const char * script_tag_s,const char * lang_tag_s,const char * script_s,const char * lang_s)259 test_tags_to_script_and_language (const char *script_tag_s,
260 				  const char *lang_tag_s,
261 				  const char *script_s,
262 				  const char *lang_s)
263 {
264   hb_script_t actual_script[1];
265   hb_language_t actual_lang[1];
266   hb_tag_t script_tag = hb_tag_from_string (script_tag_s, -1);
267   hb_tag_t lang_tag = hb_tag_from_string (lang_tag_s, -1);
268   hb_ot_tags_to_script_and_language (script_tag, lang_tag, actual_script, actual_lang);
269   g_assert_cmphex (*actual_script, ==, hb_tag_from_string (script_s, -1));
270   g_assert_cmpstr (hb_language_to_string (*actual_lang), ==, lang_s);
271 }
272 
273 static void
test_ot_tags_to_script_and_language(void)274 test_ot_tags_to_script_and_language (void)
275 {
276   test_tags_to_script_and_language ("DFLT", "ENG", "", "en-x-hbsc-44464c54");
277   test_tags_to_script_and_language ("latn", "ENG", "Latn", "en");
278   test_tags_to_script_and_language ("deva", "MAR", "Deva", "mr-x-hbsc-64657661");
279   test_tags_to_script_and_language ("dev2", "MAR", "Deva", "mr-x-hbsc-64657632");
280   test_tags_to_script_and_language ("dev3", "MAR", "Deva", "mr");
281   test_tags_to_script_and_language ("qaa", "QTZ0", "Qaaa", "x-hbot-51545a30-hbsc-71616120");
282 }
283 
284 static void
test_ot_tag_language(void)285 test_ot_tag_language (void)
286 {
287   g_assert_cmphex (HB_TAG_CHAR4 ("dflt"), ==, HB_OT_TAG_DEFAULT_LANGUAGE);
288   test_language_two_way ("dflt", NULL);
289 
290   test_language_two_way ("ALT", "alt");
291 
292   test_language_two_way ("ARA", "ar");
293 
294   test_language_two_way ("AZE", "az");
295   test_tag_from_language ("AZE", "az-ir");
296   test_tag_from_language ("AZE", "az-az");
297 
298   test_language_two_way ("ENG", "en");
299   test_tag_from_language ("ENG", "en_US");
300 
301   test_language_two_way ("CJA", "cja-x-hbot-434a4120"); /* Western Cham */
302   test_language_two_way ("CJM", "cjm-x-hbot-434a4d20"); /* Eastern Cham */
303   test_tag_from_language ("CJM", "cjm");
304   test_language_two_way ("EVN", "eve");
305 
306   test_language_two_way ("HAL", "cfm"); /* BCP47 and current ISO639-3 code for Halam/Falam Chin */
307   test_tag_from_language ("HAL", "flm"); /* Retired ISO639-3 code for Halam/Falam Chin */
308 
309   test_language_two_way ("HYE0", "hy");
310   test_language_two_way ("HYE", "hyw");
311 
312   test_tag_from_language ("QIN", "bgr"); /* Bawm Chin */
313   test_tag_from_language ("QIN", "cbl"); /* Bualkhaw Chin */
314   test_tag_from_language ("QIN", "cka"); /* Khumi Awa Chin */
315   test_tag_from_language ("QIN", "cmr"); /* Mro-Khimi Chin */
316   test_tag_from_language ("QIN", "cnb"); /* Chinbon Chin */
317   test_tag_from_language ("QIN", "cnh"); /* Hakha Chin */
318   test_tag_from_language ("QIN", "cnk"); /* Khumi Chin */
319   test_tag_from_language ("QIN", "cnw"); /* Ngawn Chin */
320   test_tag_from_language ("QIN", "csh"); /* Asho Chin */
321   test_tag_from_language ("QIN", "csy"); /* Siyin Chin */
322   test_tag_from_language ("QIN", "ctd"); /* Tedim Chin */
323   test_tag_from_language ("QIN", "czt"); /* Zotung Chin */
324   test_tag_from_language ("QIN", "dao"); /* Daai Chin */
325   test_tag_from_language ("QIN", "hlt"); /* Matu Chin */
326   test_tag_from_language ("QIN", "mrh"); /* Mara Chin */
327   test_tag_from_language ("QIN", "pck"); /* Paite Chin */
328   test_tag_from_language ("QIN", "sez"); /* Senthang Chin */
329   test_tag_from_language ("QIN", "tcp"); /* Tawr Chin */
330   test_tag_from_language ("QIN", "tcz"); /* Thado Chin */
331   test_tag_from_language ("QIN", "yos"); /* Yos, deprecated by IANA in favor of Zou [zom] */
332   test_tag_from_language ("QIN", "zom"); /* Zou */
333   test_tag_to_language ("QIN", "bgr");   /* no single BCP47 tag for Chin; picking Bawm Chin */
334 
335   test_language_two_way ("FAR", "fa");
336   test_tag_from_language ("FAR", "fa_IR");
337 
338   test_language_two_way ("MNK", "man"); /* Mandingo [macrolanguage] */
339 
340   test_language_two_way ("SWA", "aii"); /* Swadaya Aramaic */
341 
342   test_language_two_way ("SYR", "syr"); /* Syriac [macrolanguage] */
343   test_tag_from_language ("SYR", "amw"); /* Western Neo-Aramaic */
344   test_tag_from_language ("SYR", "cld"); /* Chaldean Neo-Aramaic */
345   test_tag_from_language ("SYR", "syc"); /* Classical Syriac */
346 
347   test_language_two_way ("TUA", "tru"); /* Turoyo Aramaic */
348 
349   test_tag_from_language ("ZHS", "zh"); /* Chinese */
350   test_tag_from_language ("ZHS", "zh-cn"); /* Chinese (China) */
351   test_tag_from_language ("ZHS", "zh-sg"); /* Chinese (Singapore) */
352   test_tag_from_language ("ZHTM", "zh-mo"); /* Chinese (Macao) */
353   test_tag_from_language ("ZHTM", "zh-hant-mo"); /* Chinese (Macao) */
354   test_tag_from_language ("ZHS", "zh-hans-mo"); /* Chinese (Simplified, Macao) */
355   test_language_two_way ("ZHH", "zh-HK"); /* Chinese (Hong Kong) */
356   test_tag_from_language ("ZHH", "zH-HanT-hK"); /* Chinese (Hong Kong) */
357   test_tag_from_language ("ZHS", "zH-HanS-hK"); /* Chinese (Simplified, Hong Kong) */
358   test_tag_from_language ("ZHT", "zh-tw"); /* Chinese (Taiwan) */
359   test_language_two_way ("ZHS", "zh-Hans"); /* Chinese (Simplified) */
360   test_language_two_way ("ZHT", "zh-Hant"); /* Chinese (Traditional) */
361   test_tag_from_language ("ZHS", "zh-xx"); /* Chinese (Other) */
362 
363   test_tag_from_language ("ZHS", "zh-Hans-TW");
364 
365   test_tag_from_language ("ZHH", "yue");
366   test_tag_from_language ("ZHH", "yue-Hant");
367   test_tag_from_language ("ZHS", "yue-Hans");
368 
369   test_language_two_way ("ABC", "abc-x-hbot-41424320");
370   test_language_two_way ("ABCD", "x-hbot-41424344");
371   test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc-zxc");
372   test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc");
373   test_tag_from_language ("ABCD", "asdf-asdf-wer-x-hbotabcd");
374   test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbot-41424320-zxc");
375   test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbot-41424320");
376   test_tag_from_language ("ABCD", "asdf-asdf-wer-x-hbot-41424344");
377 
378   test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot");
379   test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-zxc");
380   test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-zxc-414243");
381   test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-414243");
382   test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-4142432");
383 
384   test_tag_from_language ("dflt", "xy");
385   test_tag_from_language ("XYZ", "xyz"); /* Unknown ISO 639-3 */
386   test_tag_from_language ("XYZ", "xyz-qw"); /* Unknown ISO 639-3 */
387 
388   /*
389    * Invalid input. The precise answer does not matter, as long as it
390    * does not crash or get into an infinite loop.
391    */
392   test_tag_from_language ("IPPH", "-fonipa");
393 
394   /*
395    * Tags that contain "-fonipa" as a substring but which do not contain
396    * the subtag "fonipa".
397    */
398   test_tag_from_language ("ENG", "en-fonipax");
399   test_tag_from_language ("ENG", "en-x-fonipa");
400   test_tag_from_language ("ENG", "en-a-fonipa");
401   test_tag_from_language ("ENG", "en-a-qwe-b-fonipa");
402 
403   /* International Phonetic Alphabet */
404   test_tag_from_language ("IPPH", "en-fonipa");
405   test_tag_from_language ("IPPH", "en-fonipax-fonipa");
406   test_tag_from_language ("IPPH", "rm-CH-fonipa-sursilv-x-foobar");
407   test_language_two_way ("IPPH", "und-fonipa");
408   test_tag_from_language ("IPPH", "zh-fonipa");
409 
410   /* North American Phonetic Alphabet (Americanist Phonetic Notation) */
411   test_tag_from_language ("APPH", "en-fonnapa");
412   test_tag_from_language ("APPH", "chr-fonnapa");
413   test_language_two_way ("APPH", "und-fonnapa");
414 
415   /* Khutsuri Georgian */
416   test_tag_from_language ("KGE", "ka-Geok");
417   test_language_two_way ("KGE", "und-Geok");
418 
419   /* Irish Traditional */
420   test_language_two_way ("IRT", "ga-Latg");
421 
422   /* Moldavian */
423   test_language_two_way ("MOL", "ro-MD");
424 
425   /* Polytonic Greek */
426   test_language_two_way ("PGR", "el-polyton");
427   test_tag_from_language ("PGR", "el-CY-polyton");
428 
429   /* Estrangela Syriac */
430   test_tag_from_language ("SYRE", "aii-Syre");
431   test_tag_from_language ("SYRE", "de-Syre");
432   test_tag_from_language ("SYRE", "syr-Syre");
433   test_language_two_way ("SYRE", "und-Syre");
434 
435   /* Western Syriac */
436   test_tag_from_language ("SYRJ", "aii-Syrj");
437   test_tag_from_language ("SYRJ", "de-Syrj");
438   test_tag_from_language ("SYRJ", "syr-Syrj");
439   test_language_two_way ("SYRJ", "und-Syrj");
440 
441   /* Eastern Syriac */
442   test_tag_from_language ("SYRN", "aii-Syrn");
443   test_tag_from_language ("SYRN", "de-Syrn");
444   test_tag_from_language ("SYRN", "syr-Syrn");
445   test_language_two_way ("SYRN", "und-Syrn");
446 
447   /* Test that x-hbot overrides the base language */
448   test_tag_from_language ("ABC", "fa-x-hbotabc-hbot-41686121-zxc");
449   test_tag_from_language ("ABC", "fa-ir-x-hbotabc-hbot-41686121-zxc");
450   test_tag_from_language ("ABC", "zh-x-hbotabc-hbot-41686121-zxc");
451   test_tag_from_language ("ABC", "zh-cn-x-hbotabc-hbot-41686121-zxc");
452   test_tag_from_language ("ABC", "zh-xy-x-hbotabc-hbot-41686121-zxc");
453   test_tag_from_language ("ABC", "xyz-xy-x-hbotabc-hbot-41686121-zxc");
454 
455   test_tag_from_language ("Aha!", "fa-x-hbot-41686121-hbotabc-zxc");
456   test_tag_from_language ("Aha!", "fa-ir-x-hbot-41686121-hbotabc-zxc");
457   test_tag_from_language ("Aha!", "zh-x-hbot-41686121-hbotabc-zxc");
458   test_tag_from_language ("Aha!", "zh-cn-x-hbot-41686121-hbotabc-zxc");
459   test_tag_from_language ("Aha!", "zh-xy-x-hbot-41686121-hbotabc-zxc");
460   test_tag_from_language ("Aha!", "xyz-xy-x-hbot-41686121-hbotabc-zxc");
461 
462   /* Invalid x-hbot */
463   test_tag_from_language ("dflt", "x-hbot");
464   test_tag_from_language ("dflt", "x-hbot-");
465   test_tag_from_language ("dflt", "x-hbot-1");
466   test_tag_from_language ("dflt", "x-hbot-1a");
467   test_tag_from_language ("dflt", "x-hbot-1a2b3c4x");
468   test_tag_from_language ("2lon", "x-hbot-326c6f6e67");
469 
470   /* Unnormalized BCP 47 tags */
471   test_tag_from_language ("ARA", "ar-aao");
472   test_tag_from_language ("JBO", "art-lojban");
473   test_tag_from_language ("KOK", "kok-gom");
474   test_tag_from_language ("LTZ", "i-lux");
475   test_tag_from_language ("MNG", "drh");
476   test_tag_from_language ("MOR", "ar-ary");
477   test_tag_from_language ("MOR", "ar-ary-DZ");
478   test_tag_from_language ("NOR", "no-bok");
479   test_tag_from_language ("NYN", "no-nyn");
480   test_tag_from_language ("ZHS", "i-hak");
481   test_tag_from_language ("ZHS", "zh-guoyu");
482   test_tag_from_language ("ZHS", "zh-min");
483   test_tag_from_language ("ZHS", "zh-min-nan");
484   test_tag_from_language ("ZHS", "zh-xiang");
485 
486   /* BCP 47 tags that look similar to unrelated language system tags */
487   test_tag_from_language ("SQI", "als");
488   test_tag_from_language ("dflt", "far");
489 
490   /* A UN M.49 region code, not an extended language subtag */
491   test_tag_from_language ("ARA", "ar-001");
492 
493   /* An invalid tag */
494   test_tag_from_language ("TRK", "tr@foo=bar");
495 }
496 
497 static void
test_tags(hb_script_t script,const char * lang_s,unsigned int script_count,unsigned int language_count,unsigned int expected_script_count,unsigned int expected_language_count,...)498 test_tags (hb_script_t  script,
499 	   const char  *lang_s,
500 	   unsigned int script_count,
501 	   unsigned int language_count,
502 	   unsigned int expected_script_count,
503 	   unsigned int expected_language_count,
504 	   ...)
505 {
506   va_list expected_tags;
507   unsigned int i;
508   hb_tag_t *script_tags = malloc (script_count * sizeof (hb_tag_t));
509   hb_tag_t *language_tags = malloc (language_count * sizeof (hb_tag_t));
510   hb_language_t lang;
511   g_assert (script_tags);
512   g_assert (language_tags);
513   lang = hb_language_from_string (lang_s, -1);
514   va_start (expected_tags, expected_language_count);
515 
516   hb_ot_tags_from_script_and_language (script, lang, &script_count, script_tags, &language_count, language_tags);
517 
518   g_assert_cmpuint (script_count, ==, expected_script_count);
519   g_assert_cmpuint (language_count, ==, expected_language_count);
520 
521   for (i = 0; i < script_count + language_count; i++)
522   {
523     hb_tag_t expected_tag = hb_tag_from_string (va_arg (expected_tags, const char *), -1);
524     hb_tag_t actual_tag = i < script_count ? script_tags[i] : language_tags[i - script_count];
525     g_assert_cmphex (actual_tag, ==, expected_tag);
526   }
527 
528   free (script_tags);
529   free (language_tags);
530   va_end (expected_tags);
531 }
532 
533 static void
test_ot_tag_full(void)534 test_ot_tag_full (void)
535 {
536   test_tags (HB_SCRIPT_INVALID, "en", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "ENG");
537   test_tags (HB_SCRIPT_INVALID, "en-x-hbscdflt", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "DFLT", "ENG");
538   test_tags (HB_SCRIPT_LATIN, "en", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "latn", "ENG");
539   test_tags (HB_SCRIPT_LATIN, "en", 0, 0, 0, 0);
540   test_tags (HB_SCRIPT_INVALID, "und-fonnapa", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "APPH");
541   test_tags (HB_SCRIPT_INVALID, "en-fonnapa", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "APPH");
542   test_tags (HB_SCRIPT_INVALID, "x-hbot1234-hbsc5678", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "5678", "1234");
543   test_tags (HB_SCRIPT_INVALID, "x-hbsc5678-hbot1234", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "5678", "1234");
544   test_tags (HB_SCRIPT_MALAYALAM, "ml", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 3, 2, "mlm3", "mlm2", "mlym", "MAL", "MLR");
545   test_tags (HB_SCRIPT_MALAYALAM, "ml", 1, 1, 1, 1, "mlm3", "MAL");
546   test_tags (HB_SCRIPT_MYANMAR, "und", HB_OT_MAX_TAGS_PER_SCRIPT, 0, 2, 0, "mym2", "mymr");
547   test_tags (HB_SCRIPT_INVALID, "xyz", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "XYZ");
548   test_tags (HB_SCRIPT_INVALID, "xy", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 0);
549 }
550 
551 int
main(int argc,char ** argv)552 main (int argc, char **argv)
553 {
554   hb_test_init (&argc, &argv);
555 
556   hb_test_add (test_ot_tag_script_degenerate);
557   hb_test_add (test_ot_tag_script_simple);
558   hb_test_add (test_ot_tag_script_from_language);
559   hb_test_add (test_ot_tag_script_indic);
560 
561   hb_test_add (test_ot_tags_to_script_and_language);
562 
563   hb_test_add (test_ot_tag_language);
564 
565   hb_test_add (test_ot_tag_full);
566 
567   return hb_test_run();
568 }
569