1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <getopt.h>
4
5 #include <check.h>
6 #include <fcft/fcft.h>
7
8 static struct fcft_font *font = NULL;
9
10 static void
core_setup(void)11 core_setup(void)
12 {
13 font = fcft_from_name(1, (const char *[]){"Serif"}, NULL);
14 ck_assert_ptr_nonnull(font);
15 }
16
17 static void
core_teardown(void)18 core_teardown(void)
19 {
20 fcft_destroy(font);
21 font = NULL;
22 }
23
START_TEST(test_capabilities)24 START_TEST(test_capabilities)
25 {
26 enum fcft_capabilities caps = fcft_capabilities();
27
28 #if defined(FCFT_HAVE_HARFBUZZ)
29 ck_assert(caps & FCFT_CAPABILITY_GRAPHEME_SHAPING);
30 caps &= ~FCFT_CAPABILITY_GRAPHEME_SHAPING;
31 #endif
32 #if defined(FCFT_HAVE_HARFBUZZ) && defined(FCFT_HAVE_UTF8PROC)
33 ck_assert(caps & FCFT_CAPABILITY_TEXT_RUN_SHAPING);
34 caps &= ~FCFT_CAPABILITY_TEXT_RUN_SHAPING;
35 #endif
36
37 ck_assert_int_eq(caps, 0);
38 }
39 END_TEST
40
START_TEST(test_from_name)41 START_TEST(test_from_name)
42 {
43 ck_assert_int_gt(font->height, 0);
44 ck_assert_int_gt(font->max_advance.x, 0);
45 ck_assert_int_gt(font->underline.thickness, 0);
46 ck_assert_int_gt(font->strikeout.thickness, 0);
47 }
48 END_TEST
49
START_TEST(test_glyph_rasterize)50 START_TEST(test_glyph_rasterize)
51 {
52 const struct fcft_glyph *glyph = fcft_glyph_rasterize(
53 font, L'A', FCFT_SUBPIXEL_NONE);
54 ck_assert_ptr_nonnull(glyph);
55 ck_assert_ptr_nonnull(glyph->pix);
56 ck_assert_int_eq(glyph->wc, L'A');
57 ck_assert_int_eq(glyph->cols, 1);
58 ck_assert_int_gt(glyph->width, 0);
59 ck_assert_int_gt(glyph->height, 0);
60 ck_assert_int_gt(glyph->advance.x, 0);
61 }
62 END_TEST
63
64 #pragma GCC diagnostic push
65 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
START_TEST(test_size_adjust)66 START_TEST(test_size_adjust)
67 {
68 struct fcft_font *larger = fcft_size_adjust(font, 50.0);
69 ck_assert_ptr_nonnull(larger);
70 ck_assert_int_gt(larger->height, font->height);
71 ck_assert_int_gt(larger->max_advance.x, font->max_advance.x);
72 fcft_destroy(larger);
73 }
74 END_TEST
75 #pragma GCC diagnostic pop
76
START_TEST(test_precompose)77 START_TEST(test_precompose)
78 {
79 wchar_t ret = fcft_precompose(font, L'a', L'\U00000301', NULL, NULL, NULL);
80
81 /* All western fonts _should_ have this pre-composed character */
82 ck_assert_int_eq(ret, L'á');
83
84 /* Can't verify *_is_from_primary since we don't know which font
85 * we're using */
86
87 ret = fcft_precompose(font, L'X', L'Y', NULL, NULL, NULL);
88 ck_assert_int_eq(ret, (wchar_t)-1);
89 }
90 END_TEST
91
START_TEST(test_set_scaling_filter)92 START_TEST(test_set_scaling_filter)
93 {
94 ck_assert(fcft_set_scaling_filter(FCFT_SCALING_FILTER_NONE));
95 ck_assert(fcft_set_scaling_filter(FCFT_SCALING_FILTER_NEAREST));
96 ck_assert(fcft_set_scaling_filter(FCFT_SCALING_FILTER_BILINEAR));
97 ck_assert(fcft_set_scaling_filter(FCFT_SCALING_FILTER_CUBIC));
98 ck_assert(fcft_set_scaling_filter(FCFT_SCALING_FILTER_LANCZOS3));
99
100 ck_assert(!fcft_set_scaling_filter(FCFT_SCALING_FILTER_LANCZOS3 + 120));
101 }
102 END_TEST
103
104 #if defined(FCFT_HAVE_HARFBUZZ)
105
106 static struct fcft_font *emoji_font = NULL;
107
108 static void
text_shaping_setup(void)109 text_shaping_setup(void)
110 {
111 core_setup();
112 emoji_font = fcft_from_name(1, (const char *[]){"emoji"}, NULL);
113 ck_assert_ptr_nonnull(emoji_font);
114 }
115
116 static void
text_shaping_teardown(void)117 text_shaping_teardown(void)
118 {
119 core_teardown();
120 fcft_destroy(emoji_font);
121 emoji_font = NULL;
122 }
123
124
START_TEST(test_emoji_zwj)125 START_TEST(test_emoji_zwj)
126 {
127 const wchar_t *const emoji = L"";
128 const struct fcft_grapheme *grapheme = fcft_grapheme_rasterize(
129 emoji_font, wcslen(emoji), emoji, 0, NULL, FCFT_SUBPIXEL_DEFAULT);
130 ck_assert_ptr_nonnull(grapheme);
131 ck_assert_int_eq(grapheme->count, 1);
132
133 /* Verify grapheme was cached */
134 const struct fcft_grapheme *grapheme2 = fcft_grapheme_rasterize(
135 emoji_font, wcslen(emoji), emoji, 0, NULL, FCFT_SUBPIXEL_DEFAULT);
136 ck_assert_ptr_eq(grapheme, grapheme2);
137 }
138 END_TEST
139 #endif
140
141 Suite *
fcft_suite(bool run_text_shaping_tests)142 fcft_suite(bool run_text_shaping_tests)
143 {
144 Suite *suite = suite_create("fcft");
145
146 TCase *core = tcase_create("core");
147 tcase_add_checked_fixture(core, &core_setup, &core_teardown);
148
149 /* Slow systems, like the Pinebook Pro, with a *lot* of fonts, *will* be slow */
150 tcase_set_timeout(core, 60);
151
152 tcase_add_test(core, test_capabilities);
153 tcase_add_test(core, test_from_name);
154 tcase_add_test(core, test_glyph_rasterize);
155 tcase_add_test(core, test_size_adjust);
156 tcase_add_test(core, test_precompose);
157 tcase_add_test(core, test_set_scaling_filter);
158 suite_add_tcase(suite, core);
159
160 #if defined(FCFT_HAVE_HARFBUZZ)
161 if (run_text_shaping_tests) {
162 TCase *text_shaping = tcase_create("text-shaping");
163 tcase_set_timeout(text_shaping, 60);
164 tcase_add_checked_fixture(
165 text_shaping, &text_shaping_setup, &text_shaping_teardown);
166 tcase_add_test(text_shaping, test_emoji_zwj);
167 suite_add_tcase(suite, text_shaping);
168 }
169 #endif
170
171 suite_add_tcase(suite, core);
172 return suite;
173 }
174
175 static void
print_usage(const char * prog_name)176 print_usage(const char *prog_name)
177 {
178 printf(
179 "Usage: %s [OPTIONS...]\n"
180 "\n"
181 "Options:\n"
182 #if defined(FCFT_HAVE_HARFBUZZ)
183 " -s,--text-shaping run text shaping tests (requires an emoji font to be installed)\n"
184 #endif
185 ,
186 prog_name);
187 }
188
189 int
main(int argc,char * const * argv)190 main(int argc, char *const *argv)
191 {
192 const char *const prog_name = argv[0];
193
194 static const struct option longopts[] = {
195 #if defined(FCFT_HAVE_HARFBUZZ)
196 {"text-shaping", no_argument, NULL, 's'},
197 #endif
198 {NULL, no_argument, NULL, 0},
199 };
200
201 bool run_text_shaping_tests = false;
202
203 while (true) {
204 int c = getopt_long(argc, argv, "sh", longopts, NULL);
205 if (c == -1)
206 break;
207
208 switch (c) {
209 case 's':
210 run_text_shaping_tests = true;
211 break;
212
213 case 'h':
214 print_usage(prog_name);
215 return EXIT_SUCCESS;
216
217 case '?':
218 return EXIT_FAILURE;
219 }
220 }
221
222 fcft_log_init(FCFT_LOG_COLORIZE_AUTO, false, FCFT_LOG_CLASS_DEBUG);
223
224 Suite *suite = fcft_suite(run_text_shaping_tests);
225 SRunner *runner = srunner_create(suite);
226
227 srunner_run_all(runner, CK_NORMAL);
228 int failed = srunner_ntests_failed(runner);
229
230 srunner_free(runner);
231 return failed;
232 }
233