blob: 52cdbfcdea96b8078927bac464726a4560f285f3 [file] [log] [blame]
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <fontconfig/fontconfig.h>
#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 *) ""
"<fontconfig>\n"
" <match>\n"
"";
const FcChar8 *xml_post = (const FcChar8 *) ""
" <edit name=\""FC_TEST_RESULT"\">\n"
" <bool>true</bool>\n"
" </edit>\n"
" </match>\n"
"</fontconfig>\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 = "<test qual=\"all\" name=\"family\" compare=\"not_eq\">\n"
" <string>foo</string>\n"
"</test>\n"
"";
SHOULD_MATCH(pat, test);
test = ""
"<test qual=\"all\" name=\"family\" compare=\"not_eq\">\n"
" <string>family2</string>\n"
"</test>\n"
"";
SHOULD_NOT_MATCH(pat, test);
test = ""
"<test qual=\"any\" name=\"family\" compare=\"eq\">\n"
" <string>family3</string>\n"
"</test>\n"
"";
SHOULD_MATCH(pat, test);
test = ""
"<test qual=\"any\" name=\"family\" compare=\"eq\">\n"
" <string>foo</string>\n"
"</test>\n"
"";
SHOULD_NOT_MATCH(pat, test);
FcPatternDestroy (pat);
return res;
}
int
main (void)
{
return (TestFamily ());
}