| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146 |
- /*
- * Copyright © 2020 Red Hat, Inc.
- * SPDX-License-Identifier: MIT
- */
- #include "config.h"
- #include "test-config.h"
- #include <assert.h>
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <stdarg.h>
- #include <stdio.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <libxml/parser.h>
- #include <libxml/tree.h>
- #include "xkbcommon/xkbregistry.h"
- #include "utils.h"
- #include "test.h"
- #define NO_VARIANT NULL
- enum {
- MODEL = 78,
- LAYOUT,
- VARIANT,
- OPTION,
- };
- enum popularity {
- POPULARITY_UNDEFINED = 0, /* Not member of enum rxkb_popularity */
- POPULARITY_STANDARD = RXKB_POPULARITY_STANDARD,
- POPULARITY_EXOTIC = RXKB_POPULARITY_EXOTIC,
- };
- struct test_model {
- const char *name; /* required */
- const char *vendor;
- const char *description;
- };
- struct test_layout {
- const char *name; /* required */
- const char *variant;
- const char *brief;
- const char *description;
- const char *iso639[3]; /* language list (iso639 three letter codes), 3 is enough for our test */
- const char *iso3166[3]; /* country list (iso3166 two letter codes), 3 is enough for our tests */
- enum popularity popularity;
- };
- struct test_option {
- const char *name;
- const char *description;
- };
- struct test_option_group {
- const char *name;
- const char *description;
- bool allow_multiple_selection;
- struct test_option options[10];
- };
- static const char *
- popularity_attr(enum popularity popularity)
- {
- switch (popularity) {
- case POPULARITY_UNDEFINED:
- return "";
- case RXKB_POPULARITY_STANDARD:
- return " popularity=\"standard\"";
- case RXKB_POPULARITY_EXOTIC:
- return " popularity=\"exotic\"";
- default:
- fprintf(stderr, "ERROR: unsupported popularity: %d\n", popularity);
- assert(false);
- }
- }
- static void
- fprint_config_item(FILE *fp,
- const char *name,
- const char *vendor,
- const char *brief,
- const char *description,
- const char * const iso639[3],
- const char * const iso3166[3],
- enum popularity popularity)
- {
- fprintf(fp, " <configItem%s>\n"
- " <name>%s</name>\n", popularity_attr(popularity), name);
- if (brief)
- fprintf(fp, " <shortDescription>%s</shortDescription>\n", brief);
- if (description)
- fprintf(fp, " <description>%s</description>\n", description);
- if (vendor)
- fprintf(fp, " <vendor>%s</vendor>\n", vendor);
- if (iso3166 && iso3166[0]) {
- fprintf(fp, " <countryList>\n");
- for (int i = 0; i < 3; i++) {
- const char *iso = iso3166[i];
- if (!iso)
- break;
- fprintf(fp, " <iso3166Id>%s</iso3166Id>\n", iso);
- }
- fprintf(fp, " </countryList>\n");
- }
- if (iso639 && iso639[0]) {
- fprintf(fp, " <languageList>\n");
- for (int i = 0; i < 3; i++) {
- const char *iso = iso639[i];
- if (!iso)
- break;
- fprintf(fp, " <iso639Id>%s</iso639Id>\n", iso);
- }
- fprintf(fp, " </languageList>\n");
- }
- fprintf(fp, " </configItem>\n");
- }
- /**
- * Create a directory populated with a rules/<ruleset>.xml that contains the
- * given items.
- *
- * @return the XKB base directory
- */
- static char *
- test_create_rules(const char *ruleset,
- const struct test_model *test_models,
- const struct test_layout *test_layouts,
- const struct test_option_group *test_groups)
- {
- static int iteration;
- char *tmpdir;
- char buf[PATH_MAX];
- int rc;
- FILE *fp;
- char *template = asprintf_safe("%s.%d.XXXXXX", ruleset, iteration++);
- assert(template != NULL);
- tmpdir = test_maketempdir(template);
- free(template);
- free(test_makedir(tmpdir, "rules"));
- rc = snprintf_safe(buf, sizeof(buf), "%s/rules/%s.xml", tmpdir, ruleset);
- assert(rc);
- fp = fopen(buf, "w");
- assert(fp);
- fprintf(fp,
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<!DOCTYPE xkbConfigRegistry SYSTEM \"xkb.dtd\">\n"
- "<xkbConfigRegistry version=\"1.1\">\n");
- if (test_models) {
- fprintf(fp, "<modelList>\n");
- for (const struct test_model *m = test_models; m->name; m++) {
- fprintf(fp, "<model>\n");
- fprint_config_item(fp, m->name, m->vendor, NULL, m->description,
- NULL, NULL, POPULARITY_UNDEFINED);
- fprintf(fp, "</model>\n");
- }
- fprintf(fp, "</modelList>\n");
- }
- if (test_layouts) {
- const struct test_layout *l, *next;
- fprintf(fp, "<layoutList>\n");
- l = test_layouts;
- next = l + 1;
- assert(l->variant == NULL);
- while (l->name) {
- fprintf(fp, "<layout>\n");
- fprint_config_item(fp, l->name, NULL, l->brief, l->description, l->iso639, l->iso3166, l->popularity);
- if (next->name && streq(next->name, l->name)) {
- fprintf(fp, "<variantList>\n");
- do {
- fprintf(fp, "<variant>\n");
- fprint_config_item(fp, next->variant, NULL, next->brief, next->description, next->iso639, next->iso3166, next->popularity);
- fprintf(fp, "</variant>\n");
- l = next;
- next++;
- } while (next->name && streq(next->name, l->name));
- fprintf(fp, "</variantList>\n");
- }
- fprintf(fp, "</layout>\n");
- l++;
- next = l + 1;
- }
- fprintf(fp, "</layoutList>\n");
- }
- if (test_groups) {
- fprintf(fp, "<optionList>\n");
- for (const struct test_option_group *g = test_groups; g->name; g++) {
- fprintf(fp, "<group allowMultipleSelection=\"%s\">\n",
- g->allow_multiple_selection ? "true" : "false");
- fprint_config_item(fp, g->name, NULL, NULL, g->description,
- NULL, NULL, POPULARITY_UNDEFINED);
- for (const struct test_option *o = g->options; o->name; o++) {
- fprintf(fp, " <option>\n");
- fprint_config_item(fp, o->name, NULL, NULL, o->description,
- NULL, NULL, POPULARITY_UNDEFINED);
- fprintf(fp, "</option>\n");
- }
- fprintf(fp, "</group>\n");
- }
- fprintf(fp, "</optionList>\n");
- }
- fprintf(fp, "</xkbConfigRegistry>\n");
- fclose(fp);
- return tmpdir;
- }
- static void
- test_remove_rules(char *basedir, const char *ruleset)
- {
- char path[PATH_MAX];
- int rc;
- rc = snprintf_safe(path, sizeof(path), "%s/rules/%s.xml", basedir,
- ruleset);
- assert(rc);
- unlink(path);
- rc = snprintf_safe(path, sizeof(path), "%s/xkb/rules", basedir);
- assert(rc);
- rmdir(path);
- rmdir(basedir);
- free(basedir);
- }
- static struct rxkb_context *
- test_setup_context_for(const char *ruleset,
- struct test_model *system_models,
- struct test_model *user_models,
- struct test_layout *system_layouts,
- struct test_layout *user_layouts,
- struct test_option_group *system_groups,
- struct test_option_group *user_groups)
- {
- char *sysdir = NULL, *userdir = NULL;
- struct rxkb_context *ctx;
- sysdir = test_create_rules(ruleset, system_models, system_layouts,
- system_groups);
- if (user_models || user_layouts || user_groups)
- userdir = test_create_rules(ruleset, user_models, user_layouts,
- user_groups);
- ctx = rxkb_context_new(RXKB_CONTEXT_NO_DEFAULT_INCLUDES);
- assert(ctx);
- if (userdir)
- assert(rxkb_context_include_path_append(ctx, userdir));
- assert(rxkb_context_include_path_append(ctx, sysdir));
- assert(rxkb_context_parse(ctx, ruleset));
- test_remove_rules(sysdir, ruleset);
- if (userdir)
- test_remove_rules(userdir, ruleset);
- return ctx;
- }
- static struct rxkb_context *
- test_setup_context(struct test_model *system_models,
- struct test_model *user_models,
- struct test_layout *system_layouts,
- struct test_layout *user_layouts,
- struct test_option_group *system_groups,
- struct test_option_group *user_groups)
- {
- const char *ruleset = "xkbtests";
- return test_setup_context_for(ruleset, system_models,
- user_models, system_layouts,
- user_layouts, system_groups,
- user_groups);
- }
- static struct rxkb_model *
- fetch_model(struct rxkb_context *ctx, const char *model)
- {
- struct rxkb_model *m = rxkb_model_first(ctx);
- while (m) {
- if (streq(rxkb_model_get_name(m), model))
- return rxkb_model_ref(m);
- m = rxkb_model_next(m);
- }
- return NULL;
- }
- static bool
- find_model(struct rxkb_context *ctx, const char *model)
- {
- struct rxkb_model *m = fetch_model(ctx, model);
- rxkb_model_unref(m);
- return m != NULL;
- }
- static bool
- find_models(struct rxkb_context *ctx, ...)
- {
- va_list args;
- const char *name;
- int idx = 0;
- bool rc = false;
- va_start(args, ctx);
- name = va_arg(args, const char *);
- while(name) {
- ++idx;
- assert(idx < 20); /* safety guard */
- if (!find_model(ctx, name))
- goto out;
- name = va_arg(args, const char *);
- };
- rc = true;
- out:
- va_end(args);
- return rc;
- }
- static struct rxkb_layout *
- fetch_layout(struct rxkb_context *ctx, const char *layout, const char *variant)
- {
- struct rxkb_layout *l = rxkb_layout_first(ctx);
- while (l) {
- const char *v = rxkb_layout_get_variant(l);
- if (streq(rxkb_layout_get_name(l), layout) &&
- ((v == NULL && variant == NULL) ||
- (v != NULL && variant != NULL && streq(v, variant))))
- return rxkb_layout_ref(l);
- l = rxkb_layout_next(l);
- }
- return NULL;
- }
- static bool
- find_layout(struct rxkb_context *ctx, const char *layout, const char *variant)
- {
- struct rxkb_layout *l = fetch_layout(ctx, layout, variant);
- rxkb_layout_unref(l);
- return l != NULL;
- }
- static bool
- find_layouts(struct rxkb_context *ctx, ...)
- {
- va_list args;
- const char *name, *variant;
- int idx = 0;
- bool rc = false;
- va_start(args, ctx);
- name = va_arg(args, const char *);
- variant = va_arg(args, const char *);
- while(name) {
- ++idx;
- assert(idx < 20); /* safety guard */
- if (!find_layout(ctx, name, variant))
- goto out;
- name = va_arg(args, const char *);
- if (name)
- variant = va_arg(args, const char *);
- };
- rc = true;
- out:
- va_end(args);
- return rc;
- }
- static bool
- check_layouts_order(struct rxkb_context *ctx, ...)
- {
- va_list args;
- const char *layout, *variant;
- int idx = 0;
- bool rc = false;
- struct rxkb_layout *l = rxkb_layout_first(ctx);
- va_start(args, ctx);
- layout = va_arg(args, const char *);
- variant = va_arg(args, const char *);
- while(layout) {
- ++idx;
- assert(idx < 20); /* safety guard */
- if (!l) {
- fprintf(stderr, "ERROR: expected layout #%d \"%s(%s)\", got none\n",
- idx, layout, variant ? variant : "-");
- goto out;
- }
- const char *v = rxkb_layout_get_variant(l);
- if (!streq(rxkb_layout_get_name(l), layout) || !streq_null(v, variant)) {
- fprintf(stderr, "ERROR: expected layout #%d \"%s(%s)\", got \"%s(%s)\"\n",
- idx, layout, variant ? variant : "-",
- rxkb_layout_get_name(l), v ? v : "-");
- goto out;
- }
- layout = va_arg(args, const char *);
- if (layout)
- variant = va_arg(args, const char *);
- l = rxkb_layout_next(l);
- };
- if (l) {
- const char *v = rxkb_layout_get_variant(l);
- fprintf(stderr, "ERROR: unexpected layout at #%d: \"%s(%s)\"\n",
- idx + 1, rxkb_layout_get_name(l), v ? v : "-");
- }
- rc = l == NULL;
- out:
- va_end(args);
- return rc;
- }
- static struct rxkb_option_group *
- fetch_option_group(struct rxkb_context *ctx, const char *grp)
- {
- struct rxkb_option_group *g = rxkb_option_group_first(ctx);
- while (g) {
- if (streq(grp, rxkb_option_group_get_name(g)))
- return rxkb_option_group_ref(g);
- g = rxkb_option_group_next(g);
- }
- return NULL;
- }
- static struct rxkb_option *
- fetch_option(struct rxkb_context *ctx, const char *grp, const char *opt)
- {
- struct rxkb_option_group *g = rxkb_option_group_first(ctx);
- while (g) {
- if (streq(grp, rxkb_option_group_get_name(g))) {
- struct rxkb_option *o = rxkb_option_first(g);
- while (o) {
- if (streq(opt, rxkb_option_get_name(o)))
- return rxkb_option_ref(o);
- o = rxkb_option_next(o);
- }
- }
- g = rxkb_option_group_next(g);
- }
- return NULL;
- }
- static bool
- find_option(struct rxkb_context *ctx, const char *grp, const char *opt)
- {
- struct rxkb_option *o = fetch_option(ctx, grp, opt);
- rxkb_option_unref(o);
- return o != NULL;
- }
- static bool
- find_options(struct rxkb_context *ctx, ...)
- {
- va_list args;
- const char *grp, *opt;
- int idx = 0;
- bool rc = false;
- va_start(args, ctx);
- grp = va_arg(args, const char *);
- opt = va_arg(args, const char *);
- while(grp) {
- ++idx;
- assert(idx < 20); /* safety guard */
- if (!find_option(ctx, grp, opt))
- goto out;
- grp = va_arg(args, const char *);
- if (grp)
- opt = va_arg(args, const char *);
- };
- rc = true;
- out:
- va_end(args);
- return rc;
- }
- static bool
- cmp_models(struct test_model *tm, struct rxkb_model *m)
- {
- if (!tm || !m)
- return false;
- if (!streq(tm->name, rxkb_model_get_name(m)))
- return false;
- if (!streq_null(tm->vendor, rxkb_model_get_vendor(m)))
- return false;
- if (!streq_null(tm->description, rxkb_model_get_description(m)))
- return false;
- return true;
- }
- static bool
- cmp_layouts(struct test_layout *tl, struct rxkb_layout *l)
- {
- struct rxkb_iso3166_code *iso3166 = NULL;
- struct rxkb_iso639_code *iso639 = NULL;
- if (!tl || !l)
- return false;
- if (!streq(tl->name, rxkb_layout_get_name(l)))
- return false;
- if (!streq_null(tl->variant, rxkb_layout_get_variant(l)))
- return false;
- if (!streq_null(tl->brief, rxkb_layout_get_brief(l)))
- return false;
- if (!streq_null(tl->description, rxkb_layout_get_description(l)))
- return false;
- iso3166 = rxkb_layout_get_iso3166_first(l);
- for (size_t i = 0; i < ARRAY_SIZE(tl->iso3166); i++) {
- const char *iso = tl->iso3166[i];
- if (iso == NULL && iso3166 == NULL)
- break;
- if (!streq_null(iso, rxkb_iso3166_code_get_code(iso3166)))
- return false;
- iso3166 = rxkb_iso3166_code_next(iso3166);
- }
- if (iso3166 != NULL)
- return false;
- iso639 = rxkb_layout_get_iso639_first(l);
- for (size_t i = 0; i < ARRAY_SIZE(tl->iso639); i++) {
- const char *iso = tl->iso639[i];
- if (iso == NULL && iso639 == NULL)
- break;
- if (!streq_null(iso, rxkb_iso639_code_get_code(iso639)))
- return false;
- iso639 = rxkb_iso639_code_next(iso639);
- }
- if (iso639 != NULL)
- return false;
- return true;
- }
- static bool
- cmp_options(struct test_option *to, struct rxkb_option *o)
- {
- if (!to || !o)
- return false;
- if (!streq(to->name, rxkb_option_get_name(o)))
- return false;
- if (!streq_null(to->description, rxkb_option_get_description(o)))
- return false;
- return true;
- }
- enum cmp_type {
- CMP_EXACT,
- CMP_MATCHING_ONLY,
- };
- static bool
- cmp_option_groups(struct test_option_group *tg, struct rxkb_option_group *g,
- enum cmp_type cmp)
- {
- struct rxkb_option *o;
- struct test_option *to;
- if (!tg || !g)
- return false;
- if (!streq(tg->name, rxkb_option_group_get_name(g)))
- return false;
- if (!streq_null(tg->description, rxkb_option_group_get_description(g)))
- return false;
- if (tg->allow_multiple_selection != rxkb_option_group_allows_multiple(g))
- return false;
- to = tg->options;
- o = rxkb_option_first(g);
- while (o && to->name) {
- if (!cmp_options(to, o))
- return false;
- to++;
- o = rxkb_option_next(o);
- }
- if (cmp == CMP_EXACT && (o || to->name))
- return false;
- return true;
- }
- static void
- test_load_basic(void)
- {
- struct test_model system_models[] = {
- {"m1"},
- {"m2"},
- {NULL},
- };
- struct test_layout system_layouts[] = {
- {"l1"},
- {"l1", "v1"},
- {NULL},
- };
- struct test_option_group system_groups[] = {
- {"grp1", NULL, true,
- { {"grp1:1"}, {"grp1:2"} } },
- {"grp2", NULL, false,
- { {"grp2:1"}, {"grp2:2"} } },
- { NULL },
- };
- struct rxkb_context *ctx;
- ctx = test_setup_context(system_models, NULL,
- system_layouts, NULL,
- system_groups, NULL);
- assert(find_models(ctx, "m1", "m2", NULL));
- assert(find_layouts(ctx, "l1", NO_VARIANT,
- "l1", "v1", NULL));
- assert(find_options(ctx, "grp1", "grp1:1",
- "grp1", "grp1:2",
- "grp2", "grp2:1",
- "grp2", "grp2:2", NULL));
- rxkb_context_unref(ctx);
- }
- static void
- test_load_full(void)
- {
- struct test_model system_models[] = {
- {"m1", "vendor1", "desc1"},
- {"m2", "vendor2", "desc2"},
- {NULL},
- };
- struct test_layout system_layouts[] = {
- {"l1", NO_VARIANT, "lbrief1", "ldesc1"},
- {"l1", "v1", "vbrief1", "vdesc1"},
- {"l1", "v2", NULL, "vdesc2"},
- {NULL},
- };
- struct test_option_group system_groups[] = {
- {"grp1", "gdesc1", true,
- { {"grp1:1", "odesc11"}, {"grp1:2", "odesc12"} } },
- {"grp2", "gdesc2", false,
- { {"grp2:1", "odesc21"}, {"grp2:2", "odesc22"} } },
- { NULL },
- };
- struct rxkb_context *ctx;
- struct rxkb_model *m;
- struct rxkb_layout *l;
- struct rxkb_option_group *g;
- ctx = test_setup_context(system_models, NULL,
- system_layouts, NULL,
- system_groups, NULL);
- m = fetch_model(ctx, "m1");
- assert(cmp_models(&system_models[0], m));
- rxkb_model_unref(m);
- m = fetch_model(ctx, "m2");
- assert(cmp_models(&system_models[1], m));
- rxkb_model_unref(m);
- l = fetch_layout(ctx, "l1", NO_VARIANT);
- assert(cmp_layouts(&system_layouts[0], l));
- rxkb_layout_unref(l);
- l = fetch_layout(ctx, "l1", "v1");
- assert(cmp_layouts(&system_layouts[1], l));
- rxkb_layout_unref(l);
- l = fetch_layout(ctx, "l1", "v2");
- struct test_layout expected = {"l1", "v2", "lbrief1", "vdesc2"};
- assert(cmp_layouts(&expected, l));
- rxkb_layout_unref(l);
- g = fetch_option_group(ctx, "grp1");
- assert(cmp_option_groups(&system_groups[0], g, CMP_EXACT));
- rxkb_option_group_unref(g);
- g = fetch_option_group(ctx, "grp2");
- assert(cmp_option_groups(&system_groups[1], g, CMP_EXACT));
- rxkb_option_group_unref(g);
- rxkb_context_unref(ctx);
- }
- static void
- test_load_languages(void)
- {
- struct test_model system_models[] = {
- {"m1", "vendor1", "desc1"},
- {NULL},
- };
- struct test_layout system_layouts[] = {
- {"l1", NO_VARIANT, "lbrief1", "ldesc1",
- .iso639 = { "abc", "def" },
- .iso3166 = { "uv", "wx" }},
- {"l1", "v1", "vbrief1", "vdesc1",
- .iso639 = {"efg"},
- .iso3166 = {"yz"}},
- {"l2", NO_VARIANT, "lbrief1", "ldesc1",
- .iso639 = { "hij", "klm" },
- .iso3166 = { "op", "qr" }},
- {"l2", "v2", "lbrief1", "ldesc1",
- .iso639 = { NULL }, /* inherit from parent */
- .iso3166 = { NULL }}, /* inherit from parent */
- {NULL},
- };
- struct test_option_group system_groups[] = {
- {"grp1", "gdesc1", true,
- { {"grp1:1", "odesc11"}, {"grp1:2", "odesc12"} } },
- { NULL },
- };
- struct rxkb_context *ctx;
- struct rxkb_layout *l;
- struct rxkb_iso3166_code *iso3166;
- struct rxkb_iso639_code *iso639;
- ctx = test_setup_context(system_models, NULL,
- system_layouts, NULL,
- system_groups, NULL);
- l = fetch_layout(ctx, "l1", NO_VARIANT);
- assert(cmp_layouts(&system_layouts[0], l));
- rxkb_layout_unref(l);
- l = fetch_layout(ctx, "l1", "v1");
- assert(cmp_layouts(&system_layouts[1], l));
- rxkb_layout_unref(l);
- l = fetch_layout(ctx, "l2", "v2");
- iso3166 = rxkb_layout_get_iso3166_first(l);
- assert(streq(rxkb_iso3166_code_get_code(iso3166), "op"));
- iso3166 = rxkb_iso3166_code_next(iso3166);
- assert(streq(rxkb_iso3166_code_get_code(iso3166), "qr"));
- iso639 = rxkb_layout_get_iso639_first(l);
- assert(streq(rxkb_iso639_code_get_code(iso639), "hij"));
- iso639 = rxkb_iso639_code_next(iso639);
- assert(streq(rxkb_iso639_code_get_code(iso639), "klm"));
- rxkb_layout_unref(l);
- rxkb_context_unref(ctx);
- }
- static void
- test_load_invalid_languages(void)
- {
- struct test_model system_models[] = {
- {"m1", "vendor1", "desc1"},
- {NULL},
- };
- struct test_layout system_layouts[] = {
- {"l1", NO_VARIANT, "lbrief1", "ldesc1",
- .iso639 = { "ab", "def" },
- .iso3166 = { "uvw", "xz" }},
- {NULL},
- };
- struct test_option_group system_groups[] = {
- {"grp1", "gdesc1", true,
- { {"grp1:1", "odesc11"}, {"grp1:2", "odesc12"} } },
- { NULL },
- };
- struct rxkb_context *ctx;
- struct rxkb_layout *l;
- struct rxkb_iso3166_code *iso3166;
- struct rxkb_iso639_code *iso639;
- ctx = test_setup_context(system_models, NULL,
- system_layouts, NULL,
- system_groups, NULL);
- l = fetch_layout(ctx, "l1", NO_VARIANT);
- /* uvw is invalid, we expect 2 letters, verify it was ignored */
- iso3166 = rxkb_layout_get_iso3166_first(l);
- assert(streq(rxkb_iso3166_code_get_code(iso3166), "xz"));
- assert(rxkb_iso3166_code_next(iso3166) == NULL);
- /* ab is invalid, we expect 3 letters, verify it was ignored */
- iso639 = rxkb_layout_get_iso639_first(l);
- assert(streq(rxkb_iso639_code_get_code(iso639), "def"));
- assert(rxkb_iso639_code_next(iso639) == NULL);
- rxkb_layout_unref(l);
- rxkb_context_unref(ctx);
- }
- static void
- test_popularity(void)
- {
- static_assert(POPULARITY_UNDEFINED != POPULARITY_STANDARD, "");
- static_assert(POPULARITY_UNDEFINED != POPULARITY_EXOTIC, "");
- struct test_layout system_layouts[] = {
- {.name = "l1", .variant = NO_VARIANT }, /* Default popularity */
- {.name = "l1", .variant = "v1" }, /* Default popularity */
- {.name = "l2", .popularity = POPULARITY_STANDARD },
- {.name = "l3", .popularity = POPULARITY_EXOTIC },
- {NULL},
- };
- struct rxkb_context *ctx;
- struct rxkb_layout *l;
- struct ruleset_conf {
- const char *ruleset;
- enum rxkb_context_flags flags;
- enum rxkb_popularity popularity; /* Default popularity */
- };
- struct ruleset_conf rulesets[] = {
- { /* Rules with “standard” popularity */
- .ruleset="xkbtests",
- .flags=RXKB_CONTEXT_NO_DEFAULT_INCLUDES,
- .popularity=RXKB_POPULARITY_STANDARD
- },
- { /* Rules with “exotic” popularity (hack, see below) */
- .ruleset="xkbtests.extras",
- .flags=RXKB_CONTEXT_NO_DEFAULT_INCLUDES |
- RXKB_CONTEXT_LOAD_EXOTIC_RULES,
- .popularity=RXKB_POPULARITY_EXOTIC
- }
- };
- for (size_t k = 0; k < ARRAY_SIZE(rulesets); k++) {
- struct ruleset_conf *conf = &rulesets[k];
- char *dir = NULL;
- dir = test_create_rules(conf->ruleset, NULL, system_layouts, NULL);
- ctx = rxkb_context_new(conf->flags);
- assert(ctx);
- assert(rxkb_context_include_path_append(ctx, dir));
- /* Hack: ruleset "xkbtests.extras" above generates xkbtests.extras.xml,
- * loading "xkbtests" means the extras file counts as exotic */
- assert(rxkb_context_parse(ctx, "xkbtests"));
- /* Test implicit popularity */
- l = fetch_layout(ctx, "l1", NO_VARIANT);
- assert(rxkb_layout_get_popularity(l) == conf->popularity);
- rxkb_layout_unref(l);
- l = fetch_layout(ctx, "l1", "v1");
- assert(rxkb_layout_get_popularity(l) == conf->popularity);
- rxkb_layout_unref(l);
- /* Test explicit popularity */
- l = fetch_layout(ctx, "l2", NO_VARIANT);
- assert(rxkb_layout_get_popularity(l) == RXKB_POPULARITY_STANDARD);
- rxkb_layout_unref(l);
- l = fetch_layout(ctx, "l3", NO_VARIANT);
- assert(rxkb_layout_get_popularity(l) == RXKB_POPULARITY_EXOTIC);
- rxkb_layout_unref(l);
- test_remove_rules(dir, conf->ruleset);
- rxkb_context_unref(ctx);
- }
- }
- static void
- test_load_merge(void)
- {
- struct test_model system_models[] = {
- {"m1", "vendor1", "desc1"},
- {"m2", "vendor2", "desc2"},
- {NULL},
- };
- struct test_model user_models[] = {
- {"m3", "vendor3", "desc3"},
- {"m4", "vendor4", "desc4"},
- {NULL},
- };
- struct test_layout system_layouts[] = {
- {"l1", NO_VARIANT, "lbrief1", "ldesc1"},
- {"l1", "v1", "vbrief1", "vdesc1"},
- {NULL},
- };
- struct test_layout user_layouts[] = {
- {"l2", NO_VARIANT, "lbrief2", "ldesc2"},
- {"l2", "v2", "vbrief2", "vdesc2"},
- // Duplicate with system
- {"l1", NO_VARIANT, "lbrief1bis", "ldesc1bis"},
- {"l1", "v1", "vbrief1bis", "vdesc1bis"},
- {NULL},
- };
- struct test_option_group system_groups[] = {
- {"grp1", NULL, true,
- { {"grp1:1"}, {"grp1:2"} } },
- {"grp2", NULL, false,
- { {"grp2:1"}, {"grp2:2"} } },
- { NULL },
- };
- struct test_option_group user_groups[] = {
- {"grp3", NULL, true,
- { {"grp3:1"}, {"grp3:2"} } },
- {"grp4", NULL, false,
- { {"grp4:1"}, {"grp4:2"} } },
- { NULL },
- };
- struct rxkb_context *ctx;
- struct rxkb_model *m;
- struct rxkb_layout *l;
- struct rxkb_option_group *g;
- ctx = test_setup_context(system_models, user_models,
- system_layouts, user_layouts,
- system_groups, user_groups);
- assert(find_models(ctx, "m1", "m2", "m3", "m4", NULL));
- assert(find_layouts(ctx, "l1", NO_VARIANT,
- "l1", "v1",
- "l2", NO_VARIANT,
- "l2", "v2", NULL));
- m = fetch_model(ctx, "m1");
- assert(cmp_models(&system_models[0], m));
- rxkb_model_unref(m);
- m = fetch_model(ctx, "m2");
- assert(cmp_models(&system_models[1], m));
- rxkb_model_unref(m);
- m = fetch_model(ctx, "m3");
- assert(cmp_models(&user_models[0], m));
- rxkb_model_unref(m);
- m = fetch_model(ctx, "m4");
- assert(cmp_models(&user_models[1], m));
- rxkb_model_unref(m);
- l = fetch_layout(ctx, "l1", NO_VARIANT);
- assert(cmp_layouts(&system_layouts[0], l));
- rxkb_layout_unref(l);
- l = fetch_layout(ctx, "l1", "v1");
- assert(cmp_layouts(&system_layouts[1], l));
- rxkb_layout_unref(l);
- l = fetch_layout(ctx, "l2", NO_VARIANT);
- assert(cmp_layouts(&user_layouts[0], l));
- rxkb_layout_unref(l);
- l = fetch_layout(ctx, "l2", "v2");
- assert(cmp_layouts(&user_layouts[1], l));
- rxkb_layout_unref(l);
- /* Check that the duplicate layouts are skipped */
- assert(check_layouts_order(ctx,
- "l1", NO_VARIANT, "l1", "v1",
- "l2", NO_VARIANT, "l2", "v2",
- NULL));
- g = fetch_option_group(ctx, "grp1");
- assert(cmp_option_groups(&system_groups[0], g, CMP_EXACT));
- rxkb_option_group_unref(g);
- g = fetch_option_group(ctx, "grp2");
- assert(cmp_option_groups(&system_groups[1], g, CMP_EXACT));
- rxkb_option_group_unref(g);
- g = fetch_option_group(ctx, "grp3");
- assert(cmp_option_groups(&user_groups[0], g, CMP_EXACT));
- rxkb_option_group_unref(g);
- g = fetch_option_group(ctx, "grp4");
- assert(cmp_option_groups(&user_groups[1], g, CMP_EXACT));
- rxkb_option_group_unref(g);
- rxkb_context_unref(ctx);
- }
- static void
- test_load_merge_no_overwrite(void)
- {
- struct test_model system_models[] = {
- {"m1", "vendor1", "desc1"},
- {"m2", "vendor2", "desc2"},
- {NULL},
- };
- struct test_model user_models[] = {
- {"m1", "vendor3", "desc3"}, /* must not overwrite */
- {"m4", "vendor4", "desc4"},
- {NULL},
- };
- struct test_layout system_layouts[] = {
- {"l1", NO_VARIANT, "lbrief1", "ldesc1"},
- {"l1", "v1", "vbrief1", "vdesc1"},
- {NULL},
- };
- struct test_layout user_layouts[] = {
- {"l2", NO_VARIANT, "lbrief2", "ldesc2"},
- {"l2", "v2", "vbrief2", "vdesc2"},
- {"l1", NO_VARIANT, "lbrief3", "ldesc3"}, /* must not overwrite */
- {"l1", "v2", "vbrief3", "vdesc3"}, /* must not overwrite */
- {NULL},
- };
- struct test_option_group system_groups[] = {
- {"grp1", "gdesc1", true,
- { {"grp1:1", "odesc11"}, {"grp1:2", "odesc12"} } },
- {"grp2", "gdesc2", false,
- { {"grp2:1", "odesc21"}, {"grp2:2", "odesc22"} } },
- { NULL },
- };
- struct test_option_group user_groups[] = {
- {"grp1", "XXXXX", false, /* must not overwrite */
- { {"grp1:1", "YYYYYYY"}, /* must not overwrite */
- {"grp1:3", "ZZZZZZ"} } }, /* append */
- {"grp4", "gdesc4", false,
- { {"grp4:1", "odesc41"}, {"grp4:2", "odesc42"} } },
- { NULL },
- };
- struct rxkb_context *ctx;
- struct rxkb_model *m;
- struct rxkb_layout *l;
- struct rxkb_option_group *g;
- ctx = test_setup_context(system_models, user_models,
- system_layouts, user_layouts,
- system_groups, user_groups);
- m = fetch_model(ctx, "m1");
- assert(cmp_models(&system_models[0], m));
- rxkb_model_unref(m);
- l = fetch_layout(ctx, "l1", NO_VARIANT);
- assert(cmp_layouts(&system_layouts[0], l));
- rxkb_layout_unref(l);
- l = fetch_layout(ctx, "l1", "v1");
- assert(cmp_layouts(&system_layouts[1], l));
- rxkb_layout_unref(l);
- assert(find_option(ctx, "grp1", "grp1:3"));
- g = fetch_option_group(ctx, "grp1");
- assert(cmp_option_groups(&system_groups[0], g, CMP_MATCHING_ONLY));
- rxkb_option_group_unref(g);
- rxkb_context_unref(ctx);
- }
- static void
- test_no_include_paths(void)
- {
- struct rxkb_context *ctx;
- ctx = rxkb_context_new(RXKB_CONTEXT_NO_DEFAULT_INCLUDES);
- assert(ctx);
- assert(!rxkb_context_parse_default_ruleset(ctx));
- rxkb_context_unref(ctx);
- }
- static void
- test_invalid_include(void)
- {
- struct rxkb_context *ctx;
- ctx = rxkb_context_new(RXKB_CONTEXT_NO_DEFAULT_INCLUDES);
- assert(ctx);
- assert(!rxkb_context_include_path_append(ctx, "/foo/bar/baz/bat"));
- assert(!rxkb_context_parse_default_ruleset(ctx));
- rxkb_context_unref(ctx);
- }
- /* Check that libxml2 error handler is reset after parsing */
- static void
- test_xml_error_handler(void)
- {
- struct test_model system_models[] = { {NULL} };
- struct test_layout system_layouts[] = { {NULL} };
- struct test_option_group system_groups[] = { { NULL } };
- struct rxkb_context *ctx;
- ctx = test_setup_context(system_models, NULL,
- system_layouts, NULL,
- system_groups, NULL);
- assert(ctx);
- rxkb_context_unref(ctx);
- const char invalid_xml[] = "<test";
- /* This should trigger a segfault if error handler is not reset, because
- * else it would use our error handler with an invalid (freed) context. */
- xmlDocPtr doc = xmlParseMemory (invalid_xml, strlen(invalid_xml));
- assert(!doc);
- xmlFreeDoc (doc);
- xmlCleanupParser();
- }
- int
- main(void)
- {
- test_init();
- /* Reject unsupported flags */
- assert(!rxkb_context_new(-1));
- assert(!rxkb_context_new(0xffff));
- test_xml_error_handler();
- test_no_include_paths();
- test_invalid_include();
- test_load_basic();
- test_load_full();
- test_load_merge();
- test_load_merge_no_overwrite();
- test_load_languages();
- test_load_invalid_languages();
- test_popularity();
- return 0;
- }
|