Commit b246edc688228ef5149e396d2ded8341cc60e748

Ran Benita 2013-12-02T14:16:45

test/atom: add test for atom table Mostly a random test. Signed-off-by: Ran Benita <ran234@gmail.com>

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 <ran234@gmail.com>
+ *
+ * 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 <time.h>
+
+#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;
+}