lib/fold: Add support for multibyte strings
[petitboot] / test / lib / test-fold.c
1
2 #define _GNU_SOURCE
3
4 #include <stdlib.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <locale.h>
8 #include <wchar.h>
9 #include <langinfo.h>
10
11 #include <fold/fold.h>
12 #include <list/list.h>
13 #include <talloc/talloc.h>
14
15 struct line {
16         const char              *buf;
17         unsigned int            len;
18         struct list_item        list;
19 };
20
21 struct ctx {
22         struct list             lines;
23 };
24
25 struct test {
26         const char      *in;
27         unsigned int    linelen;
28         const char      *out[];
29 };
30
31 /* split on newline boundaries, no actual folding */
32 struct test test_split = {
33         .in     = "Lorem ipsum dolor\nsit amet,\nconsectetuer\n",
34         .linelen = 20,
35         .out = {
36                 "Lorem ipsum dolor",
37                 "sit amet,",
38                 "consectetuer",
39                 "",
40                 NULL,
41         },
42 };
43
44 /* fold a long line */
45 struct test test_fold_line = {
46         .in = "Lorem ipsum dolor sit amet, consectetuer adipiscing "
47                 "elit, sed diam nonummy nibh euismod tincidunt ut "
48                 "laoreet dolore magna aliquam erat volutpat.",
49         .linelen = 20,
50         .out = {
51                 "Lorem ipsum dolor",
52                 "sit amet,",
53                 "consectetuer",
54                 "adipiscing elit,",
55                 "sed diam nonummy",
56                 "nibh euismod",
57                 "tincidunt ut",
58                 "laoreet dolore",
59                 "magna aliquam erat",
60                 "volutpat.",
61                 NULL
62         },
63 };
64
65 /* break a word */
66 struct test test_break = {
67         .in = "Lorem ipsum dolor sit amet, consectetuer",
68         .linelen = 10,
69         .out = {
70                 "Lorem",
71                 "ipsum",
72                 "dolor sit",
73                 "amet,",
74                 "consectetu",
75                 "er",
76                 NULL
77         },
78 };
79
80 struct test test_mbs = {
81         .in = "從主功能表畫面中,選取啟動選項。",
82         .linelen = 15,
83         .out = {
84                 "從主功能表畫面",
85                 "中,選取啟動選",
86                 "項。",
87                 NULL,
88         },
89 };
90
91 static struct test *tests[] = {
92         &test_split, &test_fold_line, &test_break, &test_mbs,
93 };
94
95 static void __attribute__((noreturn)) fail(struct ctx *ctx,
96                 struct test *test, const char *msg)
97 {
98         struct line *line;
99         int i;
100
101         fprintf(stderr, "%s\n", msg);
102         fprintf(stderr, "input, split at %d:\n%s\n", test->linelen, test->in);
103
104         fprintf(stderr, "expected:\n");
105         for (i = 0; test->out[i]; i++)
106                 fprintf(stderr, "  '%s'\n", test->out[i]);
107
108         fprintf(stderr, "actual:\n");
109         list_for_each_entry(&ctx->lines, line, list) {
110                 char *buf = talloc_strndup(ctx, line->buf, line->len);
111                 fprintf(stderr, "  '%s'\n", buf);
112                 talloc_free(buf);
113         }
114
115         exit(EXIT_FAILURE);
116 }
117
118 static int fold_line_cb(void *arg, const char *start, int len)
119 {
120         struct ctx *ctx = arg;
121         struct line *line;
122
123         line = talloc(ctx, struct line);
124         line->buf = start;
125         line->len = len;
126         list_add_tail(&ctx->lines, &line->list);
127
128         return 0;
129 }
130
131 static void run_test(struct test *test)
132 {
133         struct line *line;
134         struct ctx *ctx;
135         wchar_t *wcs;
136         int i, n;
137
138         ctx = talloc(NULL, struct ctx);
139         n = strlen(test->in) + 1;
140         list_init(&ctx->lines);
141         fold_text(test->in, test->linelen, fold_line_cb, ctx);
142
143
144         i = 0;
145         list_for_each_entry(&ctx->lines, line, list) {
146                 size_t wcslen;
147                 char *buf;
148                 int width;
149
150                 if (!test->out[i])
151                         fail(ctx, test,
152                                 "fold_text returned more lines than expected");
153
154                 buf = talloc_strndup(ctx, line->buf, line->len);
155                 wcslen = mbstowcs(NULL, buf, 0);
156
157                 if (wcslen == (size_t)-1)
158                         fail(ctx, test, "invalid mutlibyte sequence");
159
160                 wcs = talloc_array(ctx, wchar_t, wcslen + 1);
161                 wcslen = mbstowcs(wcs, buf, n);
162
163                 width = wcswidth(wcs, wcslen);
164                 if (width == -1)
165                         fail(ctx, test, "nonprintable characters present");
166
167                 if (width > (signed int)test->linelen)
168                         fail(ctx, test, "line too long");
169
170                 if (line->len != strlen(test->out[i]))
171                         fail(ctx, test, "line lengths differ");
172
173                 if (strncmp(line->buf, test->out[i], line->len))
174                         fail(ctx, test, "line data differs");
175
176                 i++;
177         }
178
179         if (test->out[i])
180                 fail(ctx, test, "fold_text returned fewer lines than expected");
181
182         talloc_free(ctx);
183 }
184
185 int main(void)
186 {
187         unsigned int i;
188         char *charset;
189
190         setlocale(LC_CTYPE, "");
191
192         charset = nl_langinfo(CODESET);
193         if (strcmp(charset, "UTF-8")) {
194                 fprintf(stderr, "Current charset is %s, tests require UTF-8\n",
195                                 charset);
196                 return EXIT_FAILURE;
197         }
198
199         for (i = 0; i < ARRAY_SIZE(tests); i++)
200                 run_test(tests[i]);
201
202         return EXIT_SUCCESS;
203 }