From b246edc688228ef5149e396d2ded8341cc60e748 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Mon, 2 Dec 2013 14:16:45 +0200 Subject: [PATCH] test/atom: add test for atom table Mostly a random test. Signed-off-by: Ran Benita --- Makefile.am | 4 +- test/.gitignore | 1 + test/atom.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 test/atom.c diff --git a/Makefile.am b/Makefile.am index 0d13625..fd6ca09 100644 --- a/Makefile.am +++ b/Makefile.am @@ -130,7 +130,8 @@ TESTS = \ test/rules-file \ test/stringcomp \ test/buffercomp \ - test/log + test/log \ + test/atom TESTS_LDADD = libtest.la test_keysym_LDADD = $(TESTS_LDADD) @@ -142,6 +143,7 @@ test_rules_file_LDADD = $(TESTS_LDADD) -lrt test_stringcomp_LDADD = $(TESTS_LDADD) test_buffercomp_LDADD = $(TESTS_LDADD) test_log_LDADD = $(TESTS_LDADD) +test_atom_LDADD = $(TESTS_LDADD) test_rmlvo_to_kccgst_LDADD = $(TESTS_LDADD) test_print_compiled_keymap_LDADD = $(TESTS_LDADD) test_bench_key_proc_LDADD = $(TESTS_LDADD) -lrt diff --git a/test/.gitignore b/test/.gitignore index d4bb051..a5fb250 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -14,3 +14,4 @@ interactive rmlvo-to-kccgst print-compiled-keymap bench-key-proc +atom diff --git a/test/atom.c b/test/atom.c new file mode 100644 index 0000000..a6794e0 --- /dev/null +++ b/test/atom.c @@ -0,0 +1,181 @@ +/* + * Copyright © 2012 Ran Benita + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "test.h" +#include "atom.h" + +#define INTERN_LITERAL(table, literal) \ + atom_intern(table, literal, sizeof(literal) - 1, false) + +#define LOOKUP_LITERAL(table, literal) \ + atom_lookup(table, literal, sizeof(literal) - 1) + +static void +random_string(char **str_out, size_t *len_out) +{ + /* Keep this small, so collisions might happen. */ + static const char random_chars[] = { + 'a', 'b', 'c', 'd', 'e', 'f', 'g' + }; + + size_t len; + char *str; + + len = rand() % 15; + str = malloc(len + 1); + assert(str); + + for (int i = 0; i < len; i++) + str[i] = random_chars[rand() % ARRAY_SIZE(random_chars)]; + /* Don't always terminate it; should work without. */ + if (rand() % 2 == 0) + str[len] = '\0'; + + *str_out = str; + *len_out = len; +} + +static void +test_random_strings(void) +{ + struct atom_string { + xkb_atom_t atom; + char *string; + size_t len; + }; + + struct atom_table *table; + struct atom_string *arr; + int N; + xkb_atom_t atom; + const char *string; + + table = atom_table_new(); + assert(table); + + srand(clock()); + + N = 1 + rand() % 1500; + arr = calloc(N, sizeof(*arr)); + assert(arr); + + for (int i = 0; i < N; i++) { + random_string(&arr[i].string, &arr[i].len); + + atom = atom_lookup(table, arr[i].string, arr[i].len); + if (atom != XKB_ATOM_NONE) { + string = atom_text(table, atom); + assert(string); + + if (arr[i].len != strlen(string) || + strncmp(string, arr[i].string, arr[i].len) != 0) { + fprintf(stderr, "got a collision, but strings don't match!\n"); + fprintf(stderr, "existing length %lu, string %s\n", + strlen(string), string); + fprintf(stderr, "new length %lu, string %.*s\n", + arr[i].len, (int) arr[i].len, arr[i].string); + assert(false); + } + + /* OK, got a real collision. */ + free(arr[i].string); + i--; + continue; + } + + arr[i].atom = atom_intern(table, arr[i].string, arr[i].len, false); + if (arr[i].atom == XKB_ATOM_NONE) { + fprintf(stderr, "failed to intern! len: %lu, string: %.*s\n", + arr[i].len, (int) arr[i].len, arr[i].string); + assert(false); + } + } + + for (int i = 0; i < N; i++) { + string = atom_text(table, arr[i].atom); + assert(string); + + if (arr[i].len != strlen(string) || + strncmp(string, arr[i].string, arr[i].len) != 0) { + fprintf(stderr, "looked-up string doesn't match!\n"); + fprintf(stderr, "found length %lu, string %s\n", + strlen(string), string); + fprintf(stderr, "expected length %lu, string %.*s\n", + arr[i].len, (int) arr[i].len, arr[i].string); + + /* Since this is random, we need to dump the failing data, + * so we might have some chance to reproduce. */ + fprintf(stderr, "START dump of arr, N=%d\n", N); + for (int j = 0; j < N; j++) { + fprintf(stderr, "%u\t\t%lu\t\t%.*s\n", arr[i].atom, + arr[i].len, (int) arr[i].len, arr[i].string); + } + fprintf(stderr, "END\n"); + + assert(false); + } + } + + for (int i = 0; i < N; i++) + free(arr[i].string); + free(arr); + atom_table_free(table); +} + +int +main(void) +{ + struct atom_table *table; + xkb_atom_t atom1, atom2, atom3; + + table = atom_table_new(); + assert(table); + + assert(atom_text(table, XKB_ATOM_NONE) == NULL); + assert(atom_lookup(table, NULL, 0) == XKB_ATOM_NONE); + + atom1 = INTERN_LITERAL(table, "hello"); + assert(atom1 != XKB_ATOM_NONE); + assert(atom1 == LOOKUP_LITERAL(table, "hello")); + assert(streq(atom_text(table, atom1), "hello")); + + atom2 = atom_intern(table, "hello", 3, false); + assert(atom2 != XKB_ATOM_NONE); + assert(atom1 != atom2); + assert(streq(atom_text(table, atom2), "hel")); + assert(LOOKUP_LITERAL(table, "hel") == atom2); + assert(LOOKUP_LITERAL(table, "hell") == XKB_ATOM_NONE); + assert(LOOKUP_LITERAL(table, "hello") == atom1); + + atom3 = atom_intern(table, "", 0, false); + assert(atom3 != XKB_ATOM_NONE); + assert(LOOKUP_LITERAL(table, "") == atom3); + + atom_table_free(table); + + test_random_strings(); + + return 0; +} -- 2.7.4