summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/libwapcaplet.c57
-rw-r--r--test/basictests.c417
3 files changed, 447 insertions, 29 deletions
diff --git a/Makefile b/Makefile
index d15458a..d5db551 100644
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,7 @@ CFLAGS := -Iinclude -Wall -Werror
ifeq ($(TARGET),debug)
CFLAGS += -O0 -g
else
-CFLAGS += -O2
+CFLAGS += -O2 -DNDEBUG
endif
diff --git a/src/libwapcaplet.c b/src/libwapcaplet.c
index cc80627..7b9817a 100644
--- a/src/libwapcaplet.c
+++ b/src/libwapcaplet.c
@@ -30,29 +30,6 @@ lwc_calculate_hash(const char *str, size_t len)
return z;
}
-static inline char
-dolower(const char c)
-{
- if (c >= 'A' && c <= 'Z')
- return c + 'a' - 'A';
- return c;
-}
-
-static inline lwc_hash
-lwc_calculate_lcase_hash(const char *str, size_t len)
-{
- lwc_hash z = 0x811c9dc5;
-
-
- while (len > 0) {
- z *= 0x01000193;
- z ^= dolower(*str++);
- len--;
- }
-
- return z;
-}
-
struct lwc_string_s {
lwc_string ** prevptr;
lwc_string * next;
@@ -161,7 +138,7 @@ __lwc_context_intern(lwc_context *ctx,
while (str != NULL) {
if ((str->hash == h) && (str->len == slen)) {
- if (compare(s, CSTR_OF(str), slen) == 0) {
+ if (compare(CSTR_OF(str), s, slen) == 0) {
str->refcnt++;
*ret = str;
return lwc_error_ok;
@@ -177,7 +154,8 @@ __lwc_context_intern(lwc_context *ctx,
str->prevptr = &(ctx->buckets[bucket]);
str->next = ctx->buckets[bucket];
- ctx->buckets[bucket]->prevptr = &(str->next);
+ if (str->next != NULL)
+ str->next->prevptr = &(str->next);
ctx->buckets[bucket] = str;
str->len = slen;
@@ -239,7 +217,9 @@ lwc_context_string_unref(lwc_context *ctx, lwc_string *str)
return;
*(str->prevptr) = str->next;
- str->next->prevptr = str->prevptr;
+
+ if (str->next != NULL)
+ str->next->prevptr = str->prevptr;
if (str->insensitive != NULL)
lwc_context_string_unref(ctx, str->insensitive);
@@ -247,6 +227,31 @@ lwc_context_string_unref(lwc_context *ctx, lwc_string *str)
LWC_FREE(str);
}
+/**** Shonky caseless bits ****/
+
+static inline char
+dolower(const char c)
+{
+ if (c >= 'A' && c <= 'Z')
+ return c + 'a' - 'A';
+ return c;
+}
+
+static inline lwc_hash
+lwc_calculate_lcase_hash(const char *str, size_t len)
+{
+ lwc_hash z = 0x811c9dc5;
+
+
+ while (len > 0) {
+ z *= 0x01000193;
+ z ^= dolower(*str++);
+ len--;
+ }
+
+ return z;
+}
+
static int
lwc_lcase_strcmp(const char *s1, const char *s2, size_t n)
{
diff --git a/test/basictests.c b/test/basictests.c
index 1e0a828..ee7c2cb 100644
--- a/test/basictests.c
+++ b/test/basictests.c
@@ -11,7 +11,17 @@
#include "tests.h"
-START_TEST (test_lwc_context_creation_bad_alloc)
+static void *last_pw = NULL;
+static void *
+trivial_alloc_fn(void *p, size_t s, void *pw)
+{
+ last_pw = pw;
+ return realloc(p, s);
+}
+
+#ifndef NDEBUG
+/* All the basic assert() tests */
+START_TEST (test_lwc_context_creation_bad_alloc_aborts)
{
lwc_context *ctx = NULL;
lwc_error err;
@@ -20,7 +30,336 @@ START_TEST (test_lwc_context_creation_bad_alloc)
}
END_TEST
+START_TEST (test_lwc_context_destruction_aborts)
+{
+ lwc_context_unref(NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_ref_aborts)
+{
+ lwc_context_ref(NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_unref_aborts)
+{
+ lwc_context_unref(NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_intern_aborts1)
+{
+ lwc_context_intern(NULL, NULL, 0, NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_intern_aborts2)
+{
+ lwc_context *ctx;
+
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok,
+ "Unable to create context");
+
+ lwc_context_intern(ctx, NULL, 0, NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_intern_aborts3)
+{
+ lwc_context *ctx;
+
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok,
+ "Unable to create context");
+
+ lwc_context_intern(ctx, "A", 1, NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_intern_substring_aborts1)
+{
+ lwc_context_intern_substring(NULL, NULL, 0, 0, NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_intern_substring_aborts2)
+{
+ lwc_context *ctx;
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok,
+ "Unable to create context");
+
+ lwc_context_intern_substring(ctx, NULL, 0, 0, NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_intern_substring_aborts3)
+{
+ lwc_context *ctx;
+ lwc_string *str;
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok,
+ "Unable to create context");
+ fail_unless(lwc_context_intern(ctx, "Jam", 3, &str) == lwc_error_ok,
+ "unable to intern 'Jam'");
+
+ lwc_context_intern_substring(ctx, str, 100, 1, NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_intern_substring_aborts4)
+{
+ lwc_context *ctx;
+ lwc_string *str;
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok,
+ "Unable to create context");
+ fail_unless(lwc_context_intern(ctx, "Jam", 3, &str) == lwc_error_ok,
+ "unable to intern 'Jam'");
+
+ lwc_context_intern_substring(ctx, str, 1, 10, NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_intern_substring_aborts5)
+{
+ lwc_context *ctx;
+ lwc_string *str;
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok,
+ "Unable to create context");
+ fail_unless(lwc_context_intern(ctx, "Jam", 3, &str) == lwc_error_ok,
+ "unable to intern 'Jam'");
+
+ lwc_context_intern_substring(ctx, str, 1, 2, NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_string_ref_aborts1)
+{
+ lwc_context_string_ref(NULL, NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_string_ref_aborts2)
+{
+ lwc_context *ctx;
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok,
+ "Unable to create context");
+ lwc_context_string_ref(ctx, NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_string_unref_aborts1)
+{
+ lwc_context_string_unref(NULL, NULL);
+}
+END_TEST
+
+START_TEST (test_lwc_context_string_unref_aborts2)
+{
+ lwc_context *ctx;
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok,
+ "Unable to create context");
+ lwc_context_string_unref(ctx, NULL);
+}
+END_TEST
+
+#endif
+
+START_TEST (test_lwc_context_creation_ok)
+{
+ lwc_context *ctx = NULL;
+ lwc_error err;
+
+ err = lwc_create_context(trivial_alloc_fn, NULL, &ctx);
+ fail_unless(ctx != NULL,
+ "Unable to create context");
+ fail_unless(err == lwc_error_ok,
+ "Created context but returned !ok");
+}
+END_TEST
+
+START_TEST (test_lwc_context_destruction_ok)
+{
+ lwc_context *ctx = NULL;
+
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok,
+ "Unable to create context");
+
+ lwc_context_unref(ctx);
+}
+END_TEST
+
+START_TEST (test_lwc_reffed_context_destruction_ok)
+{
+ lwc_context *ctx = NULL;
+
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok,
+ "Unable to create context");
+
+ lwc_context_ref(ctx); /* make the weak ref strong */
+
+ lwc_context_unref(ctx);
+}
+END_TEST
+
+/**** The next set of tests need a fixture set ****/
+
+static lwc_context *shared_ctx;
+
+static void
+with_simple_context_setup(void)
+{
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL,
+ &shared_ctx) == lwc_error_ok,
+ "Unable to create context");
+ lwc_context_ref(shared_ctx);
+}
+
+static void
+with_simple_context_teardown(void)
+{
+ lwc_context_unref(shared_ctx);
+}
+
+START_TEST (test_lwc_context_intern_ok)
+{
+ lwc_string *str = NULL;
+ fail_unless(lwc_context_intern(shared_ctx, "A", 1, &str) == lwc_error_ok,
+ "Unable to intern a simple string");
+ fail_unless(str != NULL,
+ "Returned OK but str was still NULL");
+}
+END_TEST
+
+START_TEST (test_lwc_context_intern_twice_ok)
+{
+ lwc_string *str1 = NULL, *str2 = NULL;
+ fail_unless(lwc_context_intern(shared_ctx, "A", 1, &str1) == lwc_error_ok,
+ "Unable to intern a simple string");
+ fail_unless(str1 != NULL,
+ "Returned OK but str was still NULL");
+ fail_unless(lwc_context_intern(shared_ctx, "B", 1, &str2) == lwc_error_ok,
+ "Unable to intern a simple string");
+ fail_unless(str2 != NULL,
+ "Returned OK but str was still NULL");
+}
+END_TEST
+
+START_TEST (test_lwc_context_intern_twice_same_ok)
+{
+ lwc_string *str1 = NULL, *str2 = NULL;
+ fail_unless(lwc_context_intern(shared_ctx, "A", 1, &str1) == lwc_error_ok,
+ "Unable to intern a simple string");
+ fail_unless(str1 != NULL,
+ "Returned OK but str was still NULL");
+ fail_unless(lwc_context_intern(shared_ctx, "A", 1, &str2) == lwc_error_ok,
+ "Unable to intern a simple string");
+ fail_unless(str2 != NULL,
+ "Returned OK but str was still NULL");
+}
+END_TEST
+
+/**** The next set of tests need a fixture set with some strings ****/
+
+static lwc_string *intern_one = NULL, *intern_two = NULL, *intern_three = NULL;
+
+static void
+with_filled_context_setup(void)
+{
+ fail_unless(lwc_create_context(trivial_alloc_fn, NULL,
+ &shared_ctx) == lwc_error_ok,
+ "Unable to create context");
+ lwc_context_ref(shared_ctx);
+
+ fail_unless(lwc_context_intern(shared_ctx, "one", 3, &intern_one) == lwc_error_ok,
+ "Unable to intern 'one'");
+ fail_unless(lwc_context_intern(shared_ctx, "two", 3, &intern_two) == lwc_error_ok,
+ "Unable to intern 'one'");
+ fail_unless(lwc_context_intern(shared_ctx, "three", 5, &intern_three) == lwc_error_ok,
+ "Unable to intern 'one'");
+
+ fail_unless(intern_one != intern_two, "'one' == 'two'");
+ fail_unless(intern_one != intern_three, "'one' == 'three'");
+ fail_unless(intern_two != intern_three, "'two' == 'three'");
+}
+
+static void
+with_filled_context_teardown(void)
+{
+ lwc_context_unref(shared_ctx);
+}
+
+START_TEST (test_lwc_interning_works)
+{
+ lwc_string *new_one = NULL;
+
+ fail_unless(lwc_context_intern(shared_ctx, "one", 3, &new_one) == lwc_error_ok,
+ "Unable to re-intern 'one'");
+
+ fail_unless(new_one == intern_one,
+ "Internalising of the string failed");
+}
+END_TEST
+
+START_TEST (test_lwc_intern_substring)
+{
+ lwc_string *new_hre = NULL, *sub_hre = NULL;
+
+ fail_unless(lwc_context_intern(shared_ctx, "hre", 3,
+ &new_hre) == lwc_error_ok,
+ "Unable to intern 'hre'");
+ fail_unless(lwc_context_intern_substring(shared_ctx, intern_three,
+ 1, 3, &sub_hre) == lwc_error_ok,
+ "Unable to re-intern 'hre' by substring");
+ fail_unless(new_hre == sub_hre,
+ "'hre' != 'hre' -- wow!");
+}
+END_TEST
+
+START_TEST (test_lwc_context_string_ref_ok)
+{
+ fail_unless(lwc_context_string_ref(shared_ctx, intern_one) == intern_one,
+ "Oddly, reffing a string didn't return it");
+}
+END_TEST
+
+START_TEST (test_lwc_context_string_unref_ok)
+{
+ lwc_context_string_unref(shared_ctx, intern_one);
+}
+END_TEST
+
+START_TEST (test_lwc_context_string_isequal_ok)
+{
+ bool result = true;
+ fail_unless((lwc_context_string_isequal(shared_ctx, intern_one,
+ intern_two, &result)) == lwc_error_ok,
+ "Failure comparing 'one' and 'two'");
+ fail_unless(result == false,
+ "'one' == 'two' ?!");
+}
+END_TEST
+
+START_TEST (test_lwc_context_string_caseless_isequal_ok)
+{
+ bool result = true;
+ lwc_string *new_ONE;
+
+ fail_unless(lwc_context_intern(shared_ctx, "ONE", 3, &new_ONE) == lwc_error_ok,
+ "Failure interning 'ONE'");
+
+ fail_unless((lwc_context_string_isequal(shared_ctx, intern_one, new_ONE,
+ &result)) == lwc_error_ok);
+ fail_unless(result == false,
+ "'one' == 'ONE' ?!");
+
+ fail_unless((lwc_context_string_caseless_isequal(shared_ctx, intern_one,
+ new_ONE, &result)) == lwc_error_ok,
+ "Failure comparing 'one' and 'two'");
+ fail_unless(result == true,
+ "'one' !~= 'ONE' ?!");
+}
+END_TEST
+/**** And the suites are set up here ****/
void
lwc_basic_suite(SRunner *sr)
@@ -28,8 +367,82 @@ lwc_basic_suite(SRunner *sr)
Suite *s = suite_create("libwapcaplet: Basic tests");
TCase *tc_basic = tcase_create("Creation/Destruction");
- tcase_add_test_raise_signal(tc_basic, test_lwc_context_creation_bad_alloc, SIGABRT);
+#ifndef NDEBUG
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_creation_bad_alloc_aborts,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_destruction_aborts,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_ref_aborts,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_unref_aborts,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_intern_aborts1,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_intern_aborts2,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_intern_aborts3,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_intern_substring_aborts1,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_intern_substring_aborts2,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_intern_substring_aborts3,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_intern_substring_aborts4,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_intern_substring_aborts5,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_string_ref_aborts1,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_string_ref_aborts2,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_string_unref_aborts1,
+ SIGABRT);
+ tcase_add_test_raise_signal(tc_basic,
+ test_lwc_context_string_unref_aborts2,
+ SIGABRT);
+#endif
+
+ tcase_add_test(tc_basic, test_lwc_context_creation_ok);
+ tcase_add_test(tc_basic, test_lwc_context_destruction_ok);
+ tcase_add_test(tc_basic, test_lwc_reffed_context_destruction_ok);
+ suite_add_tcase(s, tc_basic);
+
+ tc_basic = tcase_create("Ops with a context");
+ tcase_add_checked_fixture(tc_basic, with_simple_context_setup,
+ with_simple_context_teardown);
+ tcase_add_test(tc_basic, test_lwc_context_intern_ok);
+ tcase_add_test(tc_basic, test_lwc_context_intern_twice_ok);
+ tcase_add_test(tc_basic, test_lwc_context_intern_twice_same_ok);
suite_add_tcase(s, tc_basic);
+
+ tc_basic = tcase_create("Ops with a filled context");
+
+ tcase_add_checked_fixture(tc_basic, with_filled_context_setup,
+ with_filled_context_teardown);
+ tcase_add_test(tc_basic, test_lwc_interning_works);
+ tcase_add_test(tc_basic, test_lwc_intern_substring);
+ tcase_add_test(tc_basic, test_lwc_context_string_ref_ok);
+ tcase_add_test(tc_basic, test_lwc_context_string_unref_ok);
+ tcase_add_test(tc_basic, test_lwc_context_string_isequal_ok);
+ tcase_add_test(tc_basic, test_lwc_context_string_caseless_isequal_ok);
+ suite_add_tcase(s, tc_basic);
+
srunner_add_suite(sr, s);
}