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
30 typedef enum _TestMatchResult {
31 TestMatch,
32 TestNoMatch,
33 TestMatchError
34 } TestMatchResult;
35
36 typedef enum _TestResult {
37 TestPassed,
38 TestFailed,
39 TestError
40 } TestResult;
41
42 static TestMatchResult
43 TestMatchPattern (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
119 bail:
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
131 static TestResult
132 TestShouldMatchPattern(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
170 static TestResult
171 UpdateResult (TestResult* res, TestResult resNew)
172 {
173 *res = MAX(*res, resNew);
174 return *res;
175 }
176
177 static TestResult
178 TestFamily (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
231 int
232 main (void)
233 {
234 return (TestFamily ());
235 }