/* * fontconfig/test/test-family-matching.c * * Copyright © 2020 Zoltan Vandrus * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of the author(s) not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. The authors make no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #define FC_TEST_RESULT "testresult" typedef enum _TestMatchResult { TestMatch, TestNoMatch, TestMatchError } TestMatchResult; typedef enum _TestResult { TestPassed, TestFailed, TestError } TestResult; static TestMatchResult TestMatchPattern (const char *test, FcPattern *p) { const FcChar8 *xml_pre = (const FcChar8 *) "" "\n" " \n" ""; const FcChar8 *xml_post = (const FcChar8 *) "" " \n" " true\n" " \n" " \n" "\n" ""; FcPattern *pat = NULL; FcChar8 *concat = NULL; FcChar8 *xml = NULL; FcConfig *cfg = NULL; FcResult result; FcBool dummy; TestMatchResult ret = TestMatchError; pat = FcPatternDuplicate (p); if (!pat) { fprintf (stderr, "Unable to duplicate pattern.\n"); goto bail; } concat = FcStrPlus (xml_pre, (const FcChar8 *) test); if (!concat) { fprintf (stderr, "Concatenation failed.\n"); goto bail; } xml = FcStrPlus (concat, xml_post); if (!xml) { fprintf (stderr, "Concatenation failed.\n"); goto bail; } cfg = FcConfigCreate (); if (!cfg) { fprintf (stderr, "Unable to create a new empty config.\n"); goto bail; } if (!FcConfigParseAndLoadFromMemory (cfg, xml, FcTrue)) { fprintf (stderr, "Unable to load a config from memory.\n"); goto bail; } if (!FcConfigSubstitute (cfg, pat, FcMatchPattern)) { fprintf (stderr, "Unable to substitute config.\n"); goto bail; } result = FcPatternGetBool (pat, FC_TEST_RESULT, 0, &dummy); switch (result) { case FcResultMatch: ret = TestMatch; break; case FcResultNoMatch: ret = TestNoMatch; break; default: fprintf (stderr, "Unable to check pattern.\n"); break; } bail: if (cfg) FcConfigDestroy (cfg); if (xml) FcStrFree (xml); if (concat) FcStrFree (concat); if (pat) FcPatternDestroy (pat); return ret; } static TestResult TestShouldMatchPattern(const char* test, FcPattern *pat, int negate) { switch (TestMatchPattern (test, pat)) { case TestMatch: if (!negate) { return TestPassed; } else { printf ("Following test unexpectedly matched:\n%s", test); printf ("on\n"); FcPatternPrint (pat); return TestFailed; } break; case TestNoMatch: if (!negate) { printf ("Following test should have matched:\n%s", test); printf ("on\n"); FcPatternPrint (pat); return TestFailed; } else { return TestPassed; } break; case TestMatchError: return TestError; break; default: fprintf (stderr, "This shouldn't have been reached.\n"); return TestError; } } #define MAX(a,b) ((a) > (b) ? (a) : (b)) static TestResult UpdateResult (TestResult* res, TestResult resNew) { *res = MAX(*res, resNew); return *res; } static TestResult TestFamily (void) { const char *test; TestResult res = TestPassed; FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "family1", FC_FAMILY, FcTypeString, "family2", FC_FAMILY, FcTypeString, "family3", NULL); if (!pat) { fprintf (stderr, "Unable to build pattern.\n"); return TestError; } #define SHOULD_MATCH(p,t) \ UpdateResult (&res, TestShouldMatchPattern (t, p, 0)) #define SHOULD_NOT_MATCH(p,t) \ UpdateResult (&res, TestShouldMatchPattern (t, p, 1)) test = "\n" " foo\n" "\n" ""; SHOULD_MATCH(pat, test); test = "" "\n" " family2\n" "\n" ""; SHOULD_NOT_MATCH(pat, test); test = "" "\n" " family3\n" "\n" ""; SHOULD_MATCH(pat, test); test = "" "\n" " foo\n" "\n" ""; SHOULD_NOT_MATCH(pat, test); FcPatternDestroy (pat); return res; } int main (void) { return (TestFamily ()); }