src/fccfg.c | 16 ++- test/Makefile.am | 4 test/meson.build | 1 test/test-family-matching.c | 228 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 248 insertions(+), 1 deletion(-) New commits: commit df29933e1a06b7aa7af229bd7cd03c62d957f15f Author: Szunti <Szunti@xxxxxxxxxxxxxxxxxxxxxxxx> Date: Sun Dec 6 12:52:44 2020 +0100 Check qual and compare for family tests Fixes #267. Hash table lookups assumed qual="any" compare="eq". Add a test too. diff --git a/src/fccfg.c b/src/fccfg.c index 7b857bf..00a94e5 100644 --- a/src/fccfg.c +++ b/src/fccfg.c @@ -1714,6 +1714,7 @@ FcConfigMatchValueList (FcPattern *p, FcExpr *e = t->expr; FcValue value; FcValueList *v; + FcOp op; while (e) { @@ -1731,10 +1732,23 @@ FcConfigMatchValueList (FcPattern *p, if (t->object == FC_FAMILY_OBJECT && table) { - if (!FamilyTableLookup (table, t->op, FcValueString (&value))) + op = FC_OP_GET_OP (t->op); + if (op == FcOpEqual || op == FcOpListing) { + if (!FamilyTableLookup (table, t->op, FcValueString (&value))) + { ret = 0; goto done; + } + } + if (op == FcOpNotEqual && t->qual == FcQualAll) + { + ret = 0; + if (!FamilyTableLookup (table, t->op, FcValueString (&value))) + { + ret = values; + } + goto done; } } for (v = values; v; v = FcValueListNext(v)) diff --git a/test/Makefile.am b/test/Makefile.am index 1a9b293..30d8c2a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -167,6 +167,10 @@ check_PROGRAMS += test-issue180 test_issue180_LDADD = $(top_builddir)/src/libfontconfig.la TESTS += test-issue180 +check_PROGRAMS += test-family-matching +test_family_matching_LDADD = $(top_builddir)/src/libfontconfig.la +TESTS += test-family-matching + EXTRA_DIST=run-test.sh run-test-conf.sh $(LOG_COMPILER) $(TESTDATA) out.expected-long-family-names out.expected-no-long-family-names CLEANFILES = \ diff --git a/test/meson.build b/test/meson.build index 96b30a9..59de427 100644 --- a/test/meson.build +++ b/test/meson.build @@ -6,6 +6,7 @@ tests = [ ['test-bz106618.c'], ['test-bz1744377.c'], ['test-issue180.c'], + ['test-family-matching.c'], ] if host_machine.system() != 'windows' diff --git a/test/test-family-matching.c b/test/test-family-matching.c new file mode 100644 index 0000000..9fab36c --- /dev/null +++ b/test/test-family-matching.c @@ -0,0 +1,228 @@ +/* + * 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" + ""; + + FcChar8 *xml, *concat; + FcConfig *cfg; + FcResult result; + FcBool dummy; + TestResult ret = TestMatchError; + + FcPattern *pat = FcPatternDuplicate (p); + if (!pat) + { + fprintf (stderr, "Unable to duplicate pattern.\n"); + goto bail0; + } + + concat = FcStrPlus (xml_pre, (const FcChar8 *) test); + if (!concat) + { + fprintf (stderr, "Concatenation failed.\n"); + goto bail0; + } + + xml = FcStrPlus (concat, xml_post); + FcStrFree (concat); + if (!xml) + { + fprintf (stderr, "Concatenation failed.\n"); + goto bail0; + } + + cfg = FcConfigCreate (); + if (!cfg) + { + fprintf (stderr, "Unable to create a new empty config.\n"); + return TestMatchError; + } + + if (!FcConfigParseAndLoadFromMemory (cfg, xml, FcTrue)) + { + fprintf (stderr, "Unable to load a config from memory.\n"); + goto bail1; + } + + if (!FcConfigSubstitute (cfg, pat, FcMatchPattern)) + { + fprintf (stderr, "Unable to substitute config.\n"); + goto bail1; + } + + 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; + } + +bail1: + FcConfigDestroy (cfg); +bail0: + 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); + + return res; +} + +int +main (void) +{ + return (TestFamily ()); +} _______________________________________________ Fontconfig mailing list Fontconfig@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/fontconfig