Clean up spec file for packaging
[profile/ivi/pango.git] / tests / testboundaries.c
1 /* Pango
2  * testboundaries.c: Test text boundary algorithms
3  *
4  * Copyright (C) 1999-2000 Red Hat Software
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <unistd.h>
26
27 #include <pango/pango.h>
28
29 #define CHFORMAT "%0#6x"
30
31 /* FIXME for now this just tests that the breaking of some sample
32  * text conforms to certain rules and invariants. But eventually
33  * we should also have test-result pairs, i.e. a string and some
34  * encoding of the correct way to break the string, to check
35  * more precisely that things worked
36  */
37
38
39 /* "virama script" is just an optimization; it includes a bunch of
40  * scripts without viramas in them
41  */
42 #define VIRAMA_SCRIPT(wc)        ((wc) >= 0x0901 && (wc) <= 0x17FF)
43 #define VIRAMA(wc) ((wc) == 0x094D || \
44                     (wc) == 0x09CD || \
45                     (wc) == 0x0A4D || \
46                     (wc) == 0x0ACD || \
47                     (wc) == 0x0B4D || \
48                     (wc) == 0x0BCD || \
49                     (wc) == 0x0C4D || \
50                     (wc) == 0x0CCD || \
51                     (wc) == 0x0D4D || \
52                     (wc) == 0x0DCA || \
53                     (wc) == 0x0E3A || \
54                     (wc) == 0x0F84 || \
55                     (wc) == 0x1039 || \
56                     (wc) == 0x17D2)
57 /* Types of Japanese characters */
58 #define JAPANESE(wc) ((wc) >= 0x2F00 && (wc) <= 0x30FF)
59 #define KANJI(wc)    ((wc) >= 0x2F00 && (wc) <= 0x2FDF)
60 #define HIRAGANA(wc) ((wc) >= 0x3040 && (wc) <= 0x309F)
61 #define KATAKANA(wc) ((wc) >= 0x30A0 && (wc) <= 0x30FF)
62
63 static int offset = 0;
64 static int line = 0;
65 static gunichar current_wc = 0;
66 static const char *line_start = NULL;
67 static const char *line_end = NULL;
68
69 static void fail (const char *format, ...) G_GNUC_PRINTF (1, 2) G_GNUC_NORETURN;
70 static void fail (const char *format, ...)
71 {
72   char *str;
73   char *line_text;
74
75   va_list args;
76
77   va_start (args, format);
78   str = g_strdup_vprintf (format, args);
79   va_end (args);
80
81   line_text = g_strndup (line_start, line_end - line_start);
82
83   fprintf (stderr, "line %d offset %d char is " CHFORMAT ": %s\n (line is '%s')\n", line, offset, current_wc, str, line_text);
84   g_free (str);
85   g_free (line_text);
86
87   exit (1);
88 }
89
90 typedef void (* CharForeachFunc) (gunichar      wc,
91                                   gunichar      prev_wc,
92                                   gunichar      next_wc,
93                                   GUnicodeType  type,
94                                   GUnicodeType  prev_type,
95                                   GUnicodeType  next_type,
96                                   PangoLogAttr *attr,
97                                   PangoLogAttr *prev_attr,
98                                   PangoLogAttr *next_attr,
99                                   gpointer      data);
100
101 static void
102 log_attr_foreach (const char     *text,
103                   PangoLogAttr   *attrs,
104                   CharForeachFunc func,
105                   gpointer        data)
106 {
107   const gchar *next = text;
108   gint length = strlen (text);
109   const gchar *end = text + length;
110   gint i = 0;
111   gunichar prev_wc;
112   gunichar next_wc;
113   GUnicodeType prev_type;
114   GUnicodeType next_type;
115
116   if (next == end)
117     return;
118
119   offset = 0;
120   line = 0;
121
122   prev_type = (GUnicodeType) -1;
123   prev_wc = 0;
124
125   next_wc = g_utf8_get_char (next);
126   next_type = g_unichar_type (next_wc);
127
128   line_start = text;
129   line_end = text;
130
131   while (next_wc != 0)
132     {
133       GUnicodeType type;
134       gunichar wc;
135
136       wc = next_wc;
137       type = next_type;
138
139       current_wc = wc;
140
141       next = g_utf8_next_char (next);
142       line_end = next;
143
144       if (next >= end)
145         next_wc = 0;
146       else
147         next_wc = g_utf8_get_char (next);
148
149       if (next_wc)
150         next_type = g_unichar_type (next_wc);
151
152       (* func) (wc, prev_wc, next_wc,
153                 type, prev_type, next_type,
154                 &attrs[i],
155                 i != 0 ? &attrs[i-1] : NULL,
156                 next_wc != 0 ? &attrs[i+1] : NULL,
157                 data);
158
159       prev_type = type;
160       prev_wc = wc;
161       ++i;
162       ++offset;
163       if (wc == '\n')
164         {
165           ++line;
166           offset = 0;
167           line_start = next;
168           line_end = next;
169         }
170     }
171 }
172
173 static void
174 check_line_char (gunichar      wc,
175                  gunichar      prev_wc,
176                  gunichar      next_wc,
177                  GUnicodeType  type,
178                  GUnicodeType  prev_type,
179                  GUnicodeType  next_type,
180                  PangoLogAttr *attr,
181                  PangoLogAttr *prev_attr,
182                  PangoLogAttr *next_attr,
183                  gpointer      data)
184 {
185   GUnicodeBreakType break_type;
186   GUnicodeBreakType prev_break_type;
187
188   break_type = g_unichar_break_type (wc);
189   if (prev_wc)
190     prev_break_type = g_unichar_break_type (prev_wc);
191   else
192     prev_break_type = G_UNICODE_BREAK_UNKNOWN;
193
194   if (wc == '\n')
195     {
196       if (prev_wc == '\r')
197         {
198           if (attr->is_line_break)
199             fail ("line break between \\r and \\n");
200         }
201
202       if (next_attr && !next_attr->is_line_break)
203         fail ("no line break after \\n");
204     }
205
206   if (attr->is_line_break && prev_wc == 0)
207     fail ("first char in string should not be marked as a line break");
208
209   if (break_type == G_UNICODE_BREAK_SPACE)
210     {
211       if (attr->is_line_break && prev_attr != NULL &&
212           !attr->is_mandatory_break &&
213           !(next_wc && g_unichar_break_type (next_wc) == G_UNICODE_BREAK_COMBINING_MARK))
214         fail ("can't break lines before a space unless a mandatory break char precedes it or a combining mark follows; prev char was " CHFORMAT, prev_wc);
215     }
216
217   if (attr->is_mandatory_break && !attr->is_line_break)
218     fail ("mandatory breaks must also be marked as regular breaks");
219
220
221
222   /* FIXME use the break tables from break.c to automatically
223    * check invariants for each cell in the table. Shouldn't
224    * be that hard to do.
225    */
226
227   if (break_type == G_UNICODE_BREAK_OPEN_PUNCTUATION &&
228       prev_break_type == G_UNICODE_BREAK_OPEN_PUNCTUATION &&
229       attr->is_line_break &&
230       !attr->is_mandatory_break)
231     fail ("can't break between two open punctuation chars");
232
233   if (break_type == G_UNICODE_BREAK_CLOSE_PUNCTUATION &&
234       prev_break_type == G_UNICODE_BREAK_CLOSE_PUNCTUATION &&
235       attr->is_line_break &&
236       !attr->is_mandatory_break)
237     fail ("can't break between two close punctuation chars");
238
239   if (break_type == G_UNICODE_BREAK_QUOTATION &&
240       prev_break_type == G_UNICODE_BREAK_ALPHABETIC &&
241       attr->is_line_break &&
242       !attr->is_mandatory_break)
243     fail ("can't break letter-quotemark sequence");
244 }
245
246 static void
247 check_line_invariants (const char   *text,
248                        PangoLogAttr *attrs)
249 {
250   log_attr_foreach (text, attrs, check_line_char, NULL);
251 }
252
253 static void
254 check_word_invariants (const char   *text,
255                        PangoLogAttr *attrs)
256 {
257
258
259 }
260
261 static void
262 check_sentence_invariants (const char   *text,
263                            PangoLogAttr *attrs)
264 {
265
266
267 }
268
269 static void
270 check_grapheme_invariants (const char   *text,
271                            PangoLogAttr *attrs)
272 {
273
274
275 }
276
277 static void print_sentences (const char   *text,
278                              PangoLogAttr *attrs);
279 static void
280 print_sentences (const char   *text,
281                  PangoLogAttr *attrs)
282 {
283   const char *p;
284   const char *last;
285   int i = 0;
286
287   last = text;
288   p = text;
289
290   while (*p)
291     {
292       if (attrs[i].is_sentence_boundary)
293         {
294           char *s = g_strndup (last, p - last);
295           printf ("%s\n", s);
296           g_free (s);
297           last = p;
298         }
299
300       p = g_utf8_next_char (p);
301       ++i;
302     }
303 }
304
305 static void
306 check_invariants (const char *text)
307 {
308   int len;
309   PangoLogAttr *attrs;
310
311   if (!g_utf8_validate (text, -1, NULL))
312     fail ("Invalid UTF-8 in test text");
313
314   len = g_utf8_strlen (text, -1);
315   attrs = g_new0 (PangoLogAttr, len + 1);
316
317   pango_get_log_attrs (text,
318                        -1,
319                        0,
320                        pango_language_from_string ("C"),
321                        attrs,
322                        len + 1);
323
324   check_line_invariants (text, attrs);
325   check_sentence_invariants (text, attrs);
326   check_grapheme_invariants (text, attrs);
327   check_word_invariants (text, attrs);
328
329 #if 0
330   print_sentences (text, attrs);
331 #endif
332
333   g_free (attrs);
334 }
335
336 int
337 main (int argc, char *argv[])
338 {
339   gchar *text;
340   const gchar *srcdir;
341   const gchar *filename;
342
343   g_setenv ("PANGO_RC_FILE", "./pangorc", TRUE);
344
345   srcdir = getenv ("srcdir");
346   if (!srcdir)
347     srcdir = ".";
348
349   filename = g_strdup_printf ("%s/boundaries.utf8", srcdir);
350
351   if (!g_file_get_contents (filename, &text, NULL, NULL))
352     fail ("Couldn't open sample text file");
353
354   check_invariants (text);
355
356   g_free (text);
357
358   printf ("testboundaries passed\n");
359
360   return 0;
361 }
362