test-conf.c revision a32e9e42
1/* 2 * fontconfig/test/test-conf.c 3 * 4 * Copyright © 2000 Keith Packard 5 * Copyright © 2018 Akira TAGOH 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and its 8 * documentation for any purpose is hereby granted without fee, provided that 9 * the above copyright notice appear in all copies and that both that 10 * copyright notice and this permission notice appear in supporting 11 * documentation, and that the name of the author(s) not be used in 12 * advertising or publicity pertaining to distribution of the software without 13 * specific, written prior permission. The authors make no 14 * representations about the suitability of this software for any purpose. It 15 * is provided "as is" without express or implied warranty. 16 * 17 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 19 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 23 * PERFORMANCE OF THIS SOFTWARE. 24 */ 25#include <stdio.h> 26#include <string.h> 27#include <fontconfig/fontconfig.h> 28#include <json.h> 29 30struct _FcConfig { 31 FcStrSet *configDirs; /* directories to scan for fonts */ 32 FcStrSet *fontDirs; 33 FcStrSet *cacheDirs; 34 FcStrSet *configFiles; /* config files loaded */ 35 void *subst[FcMatchKindEnd]; 36 int maxObjects; /* maximum number of tests in all substs */ 37 FcStrSet *acceptGlobs; 38 FcStrSet *rejectGlobs; 39 FcFontSet *acceptPatterns; 40 FcFontSet *rejectPatterns; 41 FcFontSet *fonts[FcSetApplication + 1]; 42}; 43 44static FcPattern * 45build_pattern (json_object *obj) 46{ 47 json_object_iter iter; 48 FcPattern *pat = FcPatternCreate (); 49 50 json_object_object_foreachC (obj, iter) 51 { 52 FcValue v; 53 54 if (json_object_get_type (iter.val) == json_type_boolean) 55 { 56 v.type = FcTypeBool; 57 v.u.b = json_object_get_boolean (iter.val); 58 } 59 else if (json_object_get_type (iter.val) == json_type_double) 60 { 61 v.type = FcTypeDouble; 62 v.u.d = json_object_get_double (iter.val); 63 } 64 else if (json_object_get_type (iter.val) == json_type_int) 65 { 66 v.type = FcTypeInteger; 67 v.u.i = json_object_get_int (iter.val); 68 } 69 else if (json_object_get_type (iter.val) == json_type_string) 70 { 71 v.type = FcTypeString; 72 v.u.s = json_object_get_string (iter.val); 73 } 74 else if (json_object_get_type (iter.val) == json_type_null) 75 { 76 v.type = FcTypeVoid; 77 } 78 else 79 { 80 fprintf (stderr, "W: unexpected object to build a pattern: (%s %s)", iter.key, json_type_to_name (json_object_get_type (iter.val))); 81 continue; 82 } 83 FcPatternAdd (pat, iter.key, v, FcTrue); 84 } 85 return pat; 86} 87 88static FcBool 89build_fonts (FcConfig *config, json_object *root) 90{ 91 json_object *fonts; 92 FcFontSet *fs; 93 int i, n; 94 95 if (!json_object_object_get_ex (root, "fonts", &fonts) || 96 json_object_get_type (fonts) != json_type_array) 97 { 98 fprintf (stderr, "W: No fonts defined\n"); 99 return FcFalse; 100 } 101 fs = FcFontSetCreate (); 102 n = json_object_array_length (fonts); 103 for (i = 0; i < n; i++) 104 { 105 json_object *obj = json_object_array_get_idx (fonts, i); 106 FcPattern *pat; 107 108 if (json_object_get_type (obj) != json_type_object) 109 continue; 110 pat = build_pattern (obj); 111 FcFontSetAdd (fs, pat); 112 } 113 /* FcConfigSetFonts (config, fs, FcSetSystem); */ 114 if (config->fonts[FcSetSystem]) 115 FcFontSetDestroy (config->fonts[FcSetSystem]); 116 config->fonts[FcSetSystem] = fs; 117 118 return FcTrue; 119} 120 121static FcBool 122run_test (FcConfig *config, json_object *root) 123{ 124 json_object *tests; 125 FcFontSet *fs; 126 int i, n, fail = 0; 127 128 if (!json_object_object_get_ex (root, "tests", &tests) || 129 json_object_get_type (tests) != json_type_array) 130 { 131 fprintf (stderr, "W: No test cases defined\n"); 132 return FcFalse; 133 } 134 fs = FcFontSetCreate (); 135 n = json_object_array_length (tests); 136 for (i = 0; i < n; i++) 137 { 138 json_object *obj = json_object_array_get_idx (tests, i); 139 json_object_iter iter; 140 FcPattern *query, *result; 141 const char *method; 142 143 if (json_object_get_type (obj) != json_type_object) 144 continue; 145 json_object_object_foreachC (obj, iter) 146 { 147 if (strcmp (iter.key, "method") == 0) 148 { 149 if (json_object_get_type (iter.val) != json_type_string) 150 { 151 fprintf (stderr, "W: invalid type of method: (%s)\n", json_type_to_name (json_object_get_type (iter.val))); 152 continue; 153 } 154 method = json_object_get_string (iter.val); 155 } 156 else if (strcmp (iter.key, "query") == 0) 157 { 158 if (json_object_get_type (iter.val) != json_type_object) 159 { 160 fprintf (stderr, "W: invalid type of query: (%s)\n", json_type_to_name (json_object_get_type (iter.val))); 161 continue; 162 } 163 query = build_pattern (iter.val); 164 } 165 else if (strcmp (iter.key, "result") == 0) 166 { 167 if (json_object_get_type (iter.val) != json_type_object) 168 { 169 fprintf (stderr, "W: invalid type of result: (%s)\n", json_type_to_name (json_object_get_type (iter.val))); 170 continue; 171 } 172 result = build_pattern (iter.val); 173 } 174 else 175 { 176 fprintf (stderr, "W: unknown object: %s\n", iter.key); 177 } 178 } 179 if (strcmp (method, "match") == 0) 180 { 181 FcPattern *match; 182 FcResult res; 183 184 FcConfigSubstitute (config, query, FcMatchPattern); 185 FcDefaultSubstitute (query); 186 match = FcFontMatch (config, query, &res); 187 if (match) 188 { 189 FcPatternIter iter; 190 int x, vc; 191 192 FcPatternIterStart (result, &iter); 193 do 194 { 195 vc = FcPatternIterValueCount (result, &iter); 196 for (x = 0; x < vc; x++) 197 { 198 FcValue vr, vm; 199 200 if (FcPatternIterGetValue (result, &iter, x, &vr, NULL) != FcResultMatch) 201 { 202 fprintf (stderr, "E: unable to obtain a value from the expected result\n"); 203 fail++; 204 goto bail; 205 } 206 if (FcPatternGet (match, FcPatternIterGetObject (result, &iter), x, &vm) != FcResultMatch) 207 { 208 vm.type = FcTypeVoid; 209 } 210 if (!FcValueEqual (vm, vr)) 211 { 212 printf ("E: failed to compare %s:\n", FcPatternIterGetObject (result, &iter)); 213 printf (" actual result:"); 214 FcValuePrint (vm); 215 printf ("\n expected result:"); 216 FcValuePrint (vr); 217 printf ("\n"); 218 fail++; 219 goto bail; 220 } 221 } 222 } while (FcPatternIterNext (result, &iter)); 223 bail:; 224 } 225 else 226 { 227 fprintf (stderr, "E: no match\n"); 228 fail++; 229 } 230 } 231 else 232 { 233 fprintf (stderr, "W: unknown testing method: %s\n", method); 234 } 235 } 236 237 return fail == 0; 238} 239 240static FcBool 241run_scenario (FcConfig *config, char *file) 242{ 243 FcBool ret = FcTrue; 244 json_object *root, *scenario; 245 246 root = json_object_from_file (file); 247 if (!root) 248 { 249 fprintf (stderr, "E: Unable to read the file: %s\n", file); 250 return FcFalse; 251 } 252 if (!build_fonts (config, root)) 253 { 254 ret = FcFalse; 255 goto bail1; 256 } 257 if (!run_test (config, root)) 258 { 259 ret = FcFalse; 260 goto bail1; 261 } 262 263bail1: 264 json_object_put (root); 265 266 return ret; 267} 268 269static FcBool 270load_config (FcConfig *config, char *file) 271{ 272 FILE *fp; 273 long len; 274 char *buf = NULL; 275 FcBool ret = FcTrue; 276 277 if ((fp = fopen(file, "rb")) == NULL) 278 return FcFalse; 279 fseek (fp, 0L, SEEK_END); 280 len = ftell (fp); 281 fseek (fp, 0L, SEEK_SET); 282 buf = malloc (sizeof (char) * (len + 1)); 283 if (!buf) 284 { 285 ret = FcFalse; 286 goto bail1; 287 } 288 fread (buf, (size_t)len, sizeof (char), fp); 289 buf[len] = 0; 290 291 ret = FcConfigParseAndLoadFromMemory (config, buf, FcTrue); 292bail1: 293 fclose (fp); 294 if (buf) 295 free (buf); 296 297 return ret; 298} 299 300int 301main (int argc, char **argv) 302{ 303 FcConfig *config; 304 int retval = 0; 305 306 if (argc < 3) 307 { 308 fprintf(stderr, "Usage: %s <conf file> <test scenario>\n", argv[0]); 309 return 1; 310 } 311 312 config = FcConfigCreate (); 313 if (!load_config (config, argv[1])) 314 { 315 fprintf(stderr, "E: Failed to load config\n"); 316 retval = 1; 317 goto bail1; 318 } 319 if (!run_scenario (config, argv[2])) 320 { 321 retval = 1; 322 goto bail1; 323 } 324bail1: 325 FcConfigDestroy (config); 326 327 return retval; 328} 329