1/* 2 * fontconfig/test/test-family-matching.c 3 * 4 * Copyright © 2020 Zoltan Vandrus 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of the author(s) not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. The authors make no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24#include <stdio.h> 25#include <stdlib.h> 26#include <fontconfig/fontconfig.h> 27 28#define FC_TEST_RESULT "testresult" 29 30typedef enum _TestMatchResult { 31 TestMatch, 32 TestNoMatch, 33 TestMatchError 34} TestMatchResult; 35 36typedef enum _TestResult { 37 TestPassed, 38 TestFailed, 39 TestError 40} TestResult; 41 42static TestMatchResult 43TestMatchPattern (const char *test, FcPattern *p) 44{ 45 const FcChar8 *xml_pre = (const FcChar8 *) "" 46 "<fontconfig>\n" 47 " <match>\n" 48 ""; 49 50 const FcChar8 *xml_post = (const FcChar8 *) "" 51 " <edit name=\""FC_TEST_RESULT"\">\n" 52 " <bool>true</bool>\n" 53 " </edit>\n" 54 " </match>\n" 55 "</fontconfig>\n" 56 ""; 57 58 FcPattern *pat = NULL; 59 FcChar8 *concat = NULL; 60 FcChar8 *xml = NULL; 61 FcConfig *cfg = NULL; 62 FcResult result; 63 FcBool dummy; 64 TestMatchResult ret = TestMatchError; 65 66 pat = FcPatternDuplicate (p); 67 if (!pat) 68 { 69 fprintf (stderr, "Unable to duplicate pattern.\n"); 70 goto bail; 71 } 72 73 concat = FcStrPlus (xml_pre, (const FcChar8 *) test); 74 if (!concat) 75 { 76 fprintf (stderr, "Concatenation failed.\n"); 77 goto bail; 78 } 79 80 xml = FcStrPlus (concat, xml_post); 81 if (!xml) 82 { 83 fprintf (stderr, "Concatenation failed.\n"); 84 goto bail; 85 } 86 87 cfg = FcConfigCreate (); 88 if (!cfg) 89 { 90 fprintf (stderr, "Unable to create a new empty config.\n"); 91 goto bail; 92 } 93 94 if (!FcConfigParseAndLoadFromMemory (cfg, xml, FcTrue)) 95 { 96 fprintf (stderr, "Unable to load a config from memory.\n"); 97 goto bail; 98 } 99 100 if (!FcConfigSubstitute (cfg, pat, FcMatchPattern)) 101 { 102 fprintf (stderr, "Unable to substitute config.\n"); 103 goto bail; 104 } 105 106 result = FcPatternGetBool (pat, FC_TEST_RESULT, 0, &dummy); 107 switch (result) { 108 case FcResultMatch: 109 ret = TestMatch; 110 break; 111 case FcResultNoMatch: 112 ret = TestNoMatch; 113 break; 114 default: 115 fprintf (stderr, "Unable to check pattern.\n"); 116 break; 117 } 118 119bail: 120 if (cfg) 121 FcConfigDestroy (cfg); 122 if (xml) 123 FcStrFree (xml); 124 if (concat) 125 FcStrFree (concat); 126 if (pat) 127 FcPatternDestroy (pat); 128 return ret; 129} 130 131static TestResult 132TestShouldMatchPattern(const char* test, FcPattern *pat, int negate) 133{ 134 switch (TestMatchPattern (test, pat)) { 135 case TestMatch: 136 if (!negate) { 137 return TestPassed; 138 } 139 else 140 { 141 printf ("Following test unexpectedly matched:\n%s", test); 142 printf ("on\n"); 143 FcPatternPrint (pat); 144 return TestFailed; 145 } 146 break; 147 case TestNoMatch: 148 if (!negate) { 149 printf ("Following test should have matched:\n%s", test); 150 printf ("on\n"); 151 FcPatternPrint (pat); 152 return TestFailed; 153 } 154 else 155 { 156 return TestPassed; 157 } 158 break; 159 case TestMatchError: 160 return TestError; 161 break; 162 default: 163 fprintf (stderr, "This shouldn't have been reached.\n"); 164 return TestError; 165 } 166} 167 168#define MAX(a,b) ((a) > (b) ? (a) : (b)) 169 170static TestResult 171UpdateResult (TestResult* res, TestResult resNew) 172{ 173 *res = MAX(*res, resNew); 174 return *res; 175} 176 177static TestResult 178TestFamily (void) 179{ 180 const char *test; 181 TestResult res = TestPassed; 182 183 FcPattern *pat = FcPatternBuild (NULL, 184 FC_FAMILY, FcTypeString, "family1", 185 FC_FAMILY, FcTypeString, "family2", 186 FC_FAMILY, FcTypeString, "family3", 187 NULL); 188 189 if (!pat) 190 { 191 fprintf (stderr, "Unable to build pattern.\n"); 192 return TestError; 193 } 194 195 #define SHOULD_MATCH(p,t) \ 196 UpdateResult (&res, TestShouldMatchPattern (t, p, 0)) 197 #define SHOULD_NOT_MATCH(p,t) \ 198 UpdateResult (&res, TestShouldMatchPattern (t, p, 1)) 199 200 test = "<test qual=\"all\" name=\"family\" compare=\"not_eq\">\n" 201 " <string>foo</string>\n" 202 "</test>\n" 203 ""; 204 SHOULD_MATCH(pat, test); 205 206 test = "" 207 "<test qual=\"all\" name=\"family\" compare=\"not_eq\">\n" 208 " <string>family2</string>\n" 209 "</test>\n" 210 ""; 211 SHOULD_NOT_MATCH(pat, test); 212 213 test = "" 214 "<test qual=\"any\" name=\"family\" compare=\"eq\">\n" 215 " <string>family3</string>\n" 216 "</test>\n" 217 ""; 218 SHOULD_MATCH(pat, test); 219 220 test = "" 221 "<test qual=\"any\" name=\"family\" compare=\"eq\">\n" 222 " <string>foo</string>\n" 223 "</test>\n" 224 ""; 225 SHOULD_NOT_MATCH(pat, test); 226 227 FcPatternDestroy (pat); 228 return res; 229} 230 231int 232main (void) 233{ 234 return (TestFamily ()); 235} 236