diff options
author | Daniel Silverstone <dsilvers@netsurf-browser.org> | 2010-03-27 14:45:09 +0000 |
---|---|---|
committer | Daniel Silverstone <dsilvers@netsurf-browser.org> | 2010-03-27 14:45:09 +0000 |
commit | 02fdaeaf41359941559dd63e24805e78a9ee27e5 (patch) | |
tree | 609a59135c5a3f605f5f57ae6786fff719e9510d | |
parent | 470b8a37ecade509f16dad398d4d33000b05ddfb (diff) | |
download | libwapcaplet-02fdaeaf41359941559dd63e24805e78a9ee27e5.tar.gz |
Simplify libwapcaplet and remove context objects.
Remove the lwc_context type from the API and ensure that all strings belong to
the one internment context. This removes a lot of API and simplifies a lot of
function calls, however it does mean that clients of the library *MUST* be
better at reffing and unreffing strings or it'll explode.
svn path=/trunk/libwapcaplet/; revision=10159
-rw-r--r-- | include/libwapcaplet/libwapcaplet.h | 174 | ||||
-rw-r--r-- | src/libwapcaplet.c | 188 | ||||
-rw-r--r-- | test/Makefile | 2 | ||||
-rw-r--r-- | test/basictests.c | 538 | ||||
-rw-r--r-- | test/memorytests.c | 246 | ||||
-rw-r--r-- | test/testmain.c | 2 |
6 files changed, 383 insertions, 767 deletions
diff --git a/include/libwapcaplet/libwapcaplet.h b/include/libwapcaplet/libwapcaplet.h index 3b0899d..b71306c 100644 --- a/include/libwapcaplet/libwapcaplet.h +++ b/include/libwapcaplet/libwapcaplet.h @@ -14,135 +14,189 @@ #include <stdint.h> /** - * Memory allocator type + * Memory allocator function type + * + * @param ptr The old pointer to reallocate (NULL for new allocations). + * @param size The size of block to allocate. + * @param pw The private pointer for the allocator. + * @return The newly allocated/resized pointer or NULL on error. */ typedef void *(*lwc_allocator_fn)(void *ptr, size_t size, void *pw); /** - * A string internment context. - */ -typedef struct lwc_context_s lwc_context; - -/** * An interned string. */ typedef struct lwc_string_s lwc_string; /** - * Error codes which libwapcaplet might return. + * Result codes which libwapcaplet might return. */ typedef enum lwc_error_e { - lwc_error_ok = 0, - lwc_error_oom = 1, - lwc_error_range = 2 + lwc_error_ok = 0, /**< No error. */ + lwc_error_initialised = 1, /**< Library already initialised. */ + lwc_error_oom = 2, /**< Out of memory. */ + lwc_error_range = 3, /**< Substring internment out of range. */ } lwc_error; /** - * Create an internment context. - * - * This creates an internment context with a weak ref of one. - * - * You should reference the context with lwc_context_ref to convert - * that to a strong reference when you decide where to store it. + * The type of a hash value used in libwapcaplet. */ -extern lwc_error lwc_create_context(lwc_allocator_fn alloc, void *pw, - lwc_context **ret); +typedef uint32_t lwc_hash; /** - * Increment the reference count for an internment context. - */ -extern lwc_context *lwc_context_ref(lwc_context *ctx); - -/** - * Decrement the reference count for an internment context. + * Initialise the library. + * + * Initialise the library with an allocator function. All strings + * interned will be allocated via this function, as will any + * structures required to manage libwapcaplet. In this manner, all + * interned strings are directly comparable, no matter what interned + * them. * - * @note If the reference count reaches zero, the context will be freed. + * @note If you require to know how much memory libwapcaplet is using + * then you should use a counting allocator function. + * + * @param alloc The allocator to use for libwapcaplet allocations. + * @param pw The private word to pass to \a alloc. + * @param buckets The number of buckets to use by default, or zero to + * allow the implementation to choose for itself. + * @return The result of initialising. If not OK do not use + * any further wapcaplet functions. */ -extern void lwc_context_unref(lwc_context *ctx); +extern lwc_error lwc_initialise(lwc_allocator_fn alloc, void *pw, lwc_hash buckets); /** * Intern a string. * - * If the string was already present, its reference count is incremented. + * Take a copy of the string data referred to by \a s and \a slen and + * intern it. The resulting ::lwc_string can be used for simple and + * caseless comparisons by ::lwc_string_isequal and + * ::lwc_string_caseless_isequal respectively. + * + * @param s Pointer to the start of the string to intern. + * @param slen Length of the string in characters. (Not including any + * terminators) + * @param ret Pointer to ::lwc_string pointer to fill out. + * @return Result of operation, if not OK then the value pointed + * to by \a ret will not be valid. + * + * @note The memory pointed to by \a s is not referenced by the result. + * @note If the string was already present, its reference count is + * incremented rather than allocating more memory. * - * The returned string is guaranteed to be NUL-terminated. + * @note The returned string is currently NULL-terminated but this + * will not necessarily be the case in future. Try not to rely + * on it. */ -extern lwc_error lwc_context_intern(lwc_context *ctx, - const char *s, size_t slen, - lwc_string **ret); +extern lwc_error lwc_intern_string(const char *s, size_t slen, + lwc_string **ret); /** * Intern a substring. + * + * Intern a subsequence of the provided ::lwc_string. + * + * @param str String to acquire substring from. + * @param ssoffset Substring offset into \a str. + * @param sslen Substring length. + * @param ret Pointer to pointer to ::lwc_string to fill out. + * @return Result of operation, if not OK then the value + * pointed to by \a ret will not be valid. */ -extern lwc_error lwc_context_intern_substring(lwc_context *ctx, - lwc_string *str, - size_t ssoffset, size_t sslen, - lwc_string **ret); +extern lwc_error lwc_intern_substring(lwc_string *str, + size_t ssoffset, size_t sslen, + lwc_string **ret); /** * Increment the reference count on an lwc_string. * - * Use this if copying the string and intending both sides to retain + * This increases the reference count on the given string. You should + * use this when copying a string pointer into a persistent data + * structure. + * + * @verb + * myobject->str = lwc_string_ref(myparent->str); + * @endverb + * + * @param str The string to create another reference to. + * @return The string pointer to use in your new data structure. + * + * @note Use this if copying the string and intending both sides to retain * ownership. */ -extern lwc_string *lwc_context_string_ref(lwc_context *ctx, lwc_string *str); +extern lwc_string *lwc_string_ref(lwc_string *str); /** * Release a reference on an lwc_string. * - * If the reference count reaches zero then the string will be freed. + * This decreases the reference count on the given ::lwc_string. + * + * @param str The string to unref. + * @return The result of the operation, if not OK then the string + * was not unreffed. + * + * @note If the reference count reaches zero then the string will be + * freed. */ -extern void lwc_context_string_unref(lwc_context *ctx, lwc_string *str); +extern void lwc_string_unref(lwc_string *str); /** * Check if two interned strings are equal. * - * @note The strings must be from the same intern context and that - * must be the context passed in. + * @param str1 The first string in the comparison. + * @param str2 The second string in the comparison. + * @param ret A pointer to a boolean to be filled out with the result. + * @return Result of operation, if not ok then value pointed to + * by \a ret will not be valid. */ -#define lwc_context_string_isequal(ctx, str1, str2, ret) \ +#define lwc_string_isequal(str1, str2, ret) \ (*ret = (str1 == str2)), lwc_error_ok /** * Check if two interned strings are case-insensitively equal. * - * @note The strings must be from the same intern context and that - * must be the context passed in. + * @param str1 The first string in the comparison. + * @param str2 The second string in the comparison. + * @param ret A pointer to a boolean to be filled out with the result. + * @return Result of operation, if not ok then value pointed to + * by \a ret will not be valid. */ -extern lwc_error lwc_context_string_caseless_isequal(lwc_context *ctx, - lwc_string *str1, - lwc_string *str2, - bool *ret); +extern lwc_error lwc_string_caseless_isequal(lwc_string *str1, + lwc_string *str2, + bool *ret); /** * Retrieve the data pointer for an interned string. * + * @param str The string to retrieve the data pointer for. + * @return The C string data pointer for \a str. + * * @note The data we point at belongs to the string and will - * die with the string. Keep a ref if you need it. + * die with the string. Keep a ref if you need it. + * @note You may not rely on the NULL termination of the strings + * in future. Any code relying on it currently should be + * modified to use ::lwc_string_length if possible. */ extern const char *lwc_string_data(lwc_string *str); /** * Retrieve the data length for an interned string. * - * @note The data we point at belongs to the string and will - * die with the string. Keep a ref if you need it. + * @param str The string to retrieve the length of. + * @return The length of \a str. */ extern size_t lwc_string_length(lwc_string *str); /** * Retrieve (or compute if unavailable) a hash value for the content of the string. * + * @param str The string to get the hash for. + * @return The 32 bit hash of \a str. + * * @note This API should only be used as a convenient way to retrieve a hash - * value for the string. This hash value should not be relied on to be - * unique within an invocation of the program, nor should it be relied upon - * to be stable between invocations of the program. Never use the hash - * value as a way to directly identify the value of the string. + * value for the string. This hash value should not be relied on to be + * unique within an invocation of the program, nor should it be relied upon + * to be stable between invocations of the program. Never use the hash + * value as a way to directly identify the value of the string. */ extern uint32_t lwc_string_hash_value(lwc_string *str); -/** - * Retrieve the size, in bytes, of internment context \a ctx. - */ -extern size_t lwc_context_size(lwc_context *ctx); - #endif /* libwapcaplet_h_ */ diff --git a/src/libwapcaplet.c b/src/libwapcaplet.c index 4996c6f..c452889 100644 --- a/src/libwapcaplet.c +++ b/src/libwapcaplet.c @@ -1,4 +1,4 @@ -/* libwapcaplet.h +/* libwapcaplet.c * * String internment and management tools. * @@ -15,7 +15,6 @@ #define UNUSED(x) ((x) = (x)) #endif -typedef uint32_t lwc_hash; typedef uint32_t lwc_refcounter; static inline lwc_hash @@ -45,101 +44,70 @@ struct lwc_string_s { #define STR_OF(str) ((char *)(str + 1)) #define CSTR_OF(str) ((const char *)(str + 1)) -#define NR_BUCKETS (4091) +#define NR_BUCKETS_DEFAULT (4091) -struct lwc_context_s { +typedef struct lwc_context_s { lwc_allocator_fn alloc; void * alloc_pw; - lwc_string * buckets[NR_BUCKETS]; - lwc_refcounter refcnt; - bool refweak; - size_t size; -}; + lwc_string ** buckets; + lwc_hash bucketcount; +} lwc_context; + +static lwc_context *ctx = NULL; + +#define LWC_ALLOC(s) ctx->alloc(NULL, s, ctx->alloc_pw) +#define LWC_FREE(p) ctx->alloc(p, 0, ctx->alloc_pw) + +typedef lwc_hash (*lwc_hasher)(const char *, size_t); +typedef int (*lwc_strncmp)(const char *, const char *, size_t); +typedef void (*lwc_memcpy)(char *, const char *, size_t); lwc_error -lwc_create_context(lwc_allocator_fn alloc, void *pw, - lwc_context **ret) +lwc_initialise(lwc_allocator_fn alloc, void *pw, lwc_hash buckets) { assert(alloc); - - *ret = alloc(NULL, sizeof(lwc_context), pw); - - if (*ret == NULL) - return lwc_error_oom; - - memset(*ret, 0, sizeof(lwc_context)); - (*ret)->alloc = alloc; - (*ret)->alloc_pw = pw; - (*ret)->refcnt = 1; - (*ret)->refweak = true; - (*ret)->size = sizeof(lwc_context); + if (ctx != NULL) + return lwc_error_initialised; - return lwc_error_ok; -} - -lwc_context * -lwc_context_ref(lwc_context *ctx) -{ - assert(ctx); + ctx = alloc(NULL, sizeof(lwc_context), pw); - if (ctx->refweak == true) - ctx->refweak = false; - else - ctx->refcnt++; - - return ctx; -} - -#define LWC_ALLOC(s) ctx->alloc(NULL, s, ctx->alloc_pw) -#define LWC_FREE(p) ctx->alloc(p, 0, ctx->alloc_pw) - -void -lwc_context_unref(lwc_context *ctx) -{ - int bucket_nr; - lwc_string *s, *s_next; + if (ctx == NULL) + return lwc_error_oom; - assert(ctx); + memset(ctx, 0, sizeof(lwc_context)); - if (--(ctx->refcnt)) - return; + ctx->bucketcount = (buckets > 0) ? buckets : NR_BUCKETS_DEFAULT; + ctx->alloc = alloc; + ctx->alloc_pw = pw; + ctx->buckets = alloc(NULL, sizeof(lwc_string *) * ctx->bucketcount, pw); - for (bucket_nr = 0; bucket_nr < NR_BUCKETS; ++bucket_nr) { - s = ctx->buckets[bucket_nr]; - while (s != NULL) { - s_next = s->next; - LWC_FREE(s); - s = s_next; - } + if (ctx->buckets == NULL) { + alloc(ctx, 0, pw); + return lwc_error_oom; } - LWC_FREE(ctx); + memset(ctx->buckets, 0, sizeof(lwc_string *) * ctx->bucketcount); + + return lwc_error_ok; } -typedef lwc_hash (*lwc_hasher)(const char *, size_t); -typedef int (*lwc_strncmp)(const char *, const char *, size_t); -typedef void (*lwc_memcpy)(char *, const char *, size_t); - static lwc_error -__lwc_context_intern(lwc_context *ctx, - const char *s, size_t slen, - lwc_string **ret, - lwc_hasher hasher, - lwc_strncmp compare, - lwc_memcpy copy) +__lwc_intern(const char *s, size_t slen, + lwc_string **ret, + lwc_hasher hasher, + lwc_strncmp compare, + lwc_memcpy copy) { lwc_hash h; lwc_hash bucket; lwc_string *str; - size_t required_size; - assert(ctx); assert((s != NULL) || (slen == 0)); assert(ret); h = hasher(s, slen); - bucket = h % NR_BUCKETS; + bucket = h % ctx->bucketcount; str = ctx->buckets[bucket]; while (str != NULL) { @@ -154,9 +122,7 @@ __lwc_context_intern(lwc_context *ctx, } /* Add one for the additional NUL. */ - required_size = sizeof(lwc_string) + slen + 1; - - *ret = str = LWC_ALLOC(required_size); + *ret = str = LWC_ALLOC(sizeof(lwc_string) + slen + 1); if (str == NULL) return lwc_error_oom; @@ -167,9 +133,6 @@ __lwc_context_intern(lwc_context *ctx, str->next->prevptr = &(str->next); ctx->buckets[bucket] = str; - /* Keep context size in sync */ - ctx->size += required_size; - str->len = slen; str->hash = h; str->refcnt = 1; @@ -184,22 +147,19 @@ __lwc_context_intern(lwc_context *ctx, } lwc_error -lwc_context_intern(lwc_context *ctx, - const char *s, size_t slen, - lwc_string **ret) +lwc_intern_string(const char *s, size_t slen, + lwc_string **ret) { - return __lwc_context_intern(ctx, s, slen, ret, - lwc_calculate_hash, - strncmp, (lwc_memcpy)memcpy); + return __lwc_intern(s, slen, ret, + lwc_calculate_hash, + strncmp, (lwc_memcpy)memcpy); } lwc_error -lwc_context_intern_substring(lwc_context *ctx, - lwc_string *str, - size_t ssoffset, size_t sslen, - lwc_string **ret) +lwc_intern_substring(lwc_string *str, + size_t ssoffset, size_t sslen, + lwc_string **ret) { - assert(ctx); assert(str); assert(ret); @@ -208,15 +168,12 @@ lwc_context_intern_substring(lwc_context *ctx, if ((ssoffset + sslen) > str->len) return lwc_error_range; - return lwc_context_intern(ctx, CSTR_OF(str) + ssoffset, sslen, ret); + return lwc_intern_string(CSTR_OF(str) + ssoffset, sslen, ret); } lwc_string * -lwc_context_string_ref(lwc_context *ctx, lwc_string *str) +lwc_string_ref(lwc_string *str) { - UNUSED(ctx); - - assert(ctx); assert(str); str->refcnt++; @@ -225,9 +182,8 @@ lwc_context_string_ref(lwc_context *ctx, lwc_string *str) } void -lwc_context_string_unref(lwc_context *ctx, lwc_string *str) +lwc_string_unref(lwc_string *str) { - assert(ctx); assert(str); if (--(str->refcnt) > 1) @@ -242,11 +198,8 @@ lwc_context_string_unref(lwc_context *ctx, lwc_string *str) str->next->prevptr = str->prevptr; if (str->insensitive != NULL && str->refcnt == 0) - lwc_context_string_unref(ctx, str->insensitive); + lwc_string_unref(str->insensitive); - /* Reduce context size by appropriate amount (+1 for trailing NUL) */ - ctx->size -= sizeof(lwc_string) + str->len + 1; - #ifndef NDEBUG memset(str, 0xA5, sizeof(*str) + str->len); #endif @@ -280,10 +233,11 @@ lwc_calculate_lcase_hash(const char *str, size_t len) } static int -lwc_lcase_strcmp(const char *s1, const char *s2, size_t n) +lwc_lcase_strncmp(const char *s1, const char *s2, size_t n) { while (n--) { if (*s1++ != dolower(*s2++)) + /** @todo Test this somehow? */ return 1; } return 0; @@ -298,39 +252,34 @@ lwc_lcase_memcpy(char *target, const char *source, size_t n) } static lwc_error -lwc_context_intern_caseless(lwc_context *ctx, - lwc_string *str) +lwc_intern_caseless_string(lwc_string *str) { - assert(ctx); assert(str); assert(str->insensitive == NULL); - return __lwc_context_intern(ctx, CSTR_OF(str), - str->len, &(str->insensitive), - lwc_calculate_lcase_hash, - lwc_lcase_strcmp, - lwc_lcase_memcpy); - + return __lwc_intern(CSTR_OF(str), + str->len, &(str->insensitive), + lwc_calculate_lcase_hash, + lwc_lcase_strncmp, + lwc_lcase_memcpy); } lwc_error -lwc_context_string_caseless_isequal(lwc_context *ctx, - lwc_string *str1, - lwc_string *str2, - bool *ret) +lwc_string_caseless_isequal(lwc_string *str1, + lwc_string *str2, + bool *ret) { lwc_error err; - assert(ctx); assert(str1); assert(str2); if (str1->insensitive == NULL) { - err = lwc_context_intern_caseless(ctx, str1); + err = lwc_intern_caseless_string(str1); if (err != lwc_error_ok) return err; } if (str2->insensitive == NULL) { - err = lwc_context_intern_caseless(ctx, str2); + err = lwc_intern_caseless_string(str2); if (err != lwc_error_ok) return err; } @@ -364,12 +313,3 @@ lwc_string_hash_value(lwc_string *str) return str->hash; } - -size_t -lwc_context_size(lwc_context *ctx) -{ - assert(ctx); - - return ctx->size; -} - diff --git a/test/Makefile b/test/Makefile index 9ce2c1c..2ba343a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,3 +1,3 @@ -DIR_TEST_ITEMS := testrunner:testmain.c;basictests.c;memorytests.c +DIR_TEST_ITEMS := testrunner:testmain.c;basictests.c include build/makefiles/Makefile.subdir diff --git a/test/basictests.c b/test/basictests.c index cedb0c3..210b82c 100644 --- a/test/basictests.c +++ b/test/basictests.c @@ -12,6 +12,10 @@ #include "tests.h" +#ifndef UNUSED +#define UNUSED(x) (void)(x) +#endif + static void *last_pw = NULL; static void * trivial_alloc_fn(void *p, size_t s, void *pw) @@ -22,383 +26,225 @@ trivial_alloc_fn(void *p, size_t s, void *pw) #ifndef NDEBUG /* All the basic assert() tests */ -START_TEST (test_lwc_context_creation_bad_alloc_aborts) -{ - lwc_context *ctx = NULL; - lwc_error err; - - err = lwc_create_context(NULL, NULL, &ctx); -} -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) +START_TEST (test_lwc_intern_string_aborts1) { - 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); + lwc_intern_string(NULL, 0, NULL); } END_TEST -START_TEST (test_lwc_context_intern_aborts3) +START_TEST (test_lwc_intern_string_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, "A", 1, NULL); + lwc_intern_string("A", 1, NULL); } END_TEST -START_TEST (test_lwc_context_intern_substring_aborts1) +START_TEST (test_lwc_intern_substring_aborts1) { - lwc_context_intern_substring(NULL, NULL, 0, 0, NULL); + lwc_intern_substring(NULL, 0, 0, NULL); } END_TEST -START_TEST (test_lwc_context_intern_substring_aborts2) +START_TEST (test_lwc_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, + fail_unless(lwc_initialise(trivial_alloc_fn, NULL, 0) == lwc_error_ok, + "unable to initialise the library"); + fail_unless(lwc_intern_string("Jam", 3, &str) == lwc_error_ok, "unable to intern 'Jam'"); - lwc_context_intern_substring(ctx, str, 100, 1, NULL); + lwc_intern_substring(str, 88, 77, NULL); } END_TEST -START_TEST (test_lwc_context_intern_substring_aborts4) +START_TEST (test_lwc_string_ref_aborts) { - 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); + lwc_string_ref(NULL); } END_TEST -START_TEST (test_lwc_context_intern_substring_aborts5) +START_TEST (test_lwc_string_unref_aborts) { - 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); + lwc_string_unref(NULL); } END_TEST -START_TEST (test_lwc_context_string_ref_aborts1) +START_TEST (test_lwc_string_data_aborts) { - lwc_context_string_ref(NULL, NULL); + lwc_string_data(NULL); } END_TEST -START_TEST (test_lwc_context_string_ref_aborts2) +START_TEST (test_lwc_string_length_aborts) { - 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); + lwc_string_length(NULL); } END_TEST -START_TEST (test_lwc_context_string_unref_aborts1) +START_TEST (test_lwc_string_hash_value_aborts) { - lwc_context_string_unref(NULL, NULL); + lwc_string_hash_value(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_string_data_aborts) +START_TEST (test_lwc_double_initialise_fails) { - lwc_string_data(NULL); + fail_unless(lwc_initialise(trivial_alloc_fn, NULL, 0) == lwc_error_ok, + "Unable to initialise library"); + fail_unless(lwc_initialise(trivial_alloc_fn, NULL, 0) == lwc_error_initialised, + "Able to initialise library a second time"); } END_TEST -START_TEST (test_lwc_string_length_aborts) +static void *enomem_allocator(void *ptr, size_t n, void *pw) { - lwc_string_length(NULL); + int *pi = (int*)pw; + UNUSED(ptr); + UNUSED(n); + + if (*pi > 0) { + *pi -= 1; + return realloc(ptr, n); + } + + return NULL; } -END_TEST -START_TEST (test_lwc_string_hash_value_aborts) +START_TEST (test_lwc_initialise_fails_with_no_memory) { - lwc_string_hash_value(NULL); + int permitted = 0; + fail_unless(lwc_initialise(enomem_allocator, &permitted, 0) == lwc_error_oom, + "Able to initialise library with no memory available?!"); } END_TEST -START_TEST (test_lwc_context_size_aborts) +START_TEST (test_lwc_initialise_fails_with_low_memory) { - lwc_context_size(NULL); + int permitted = 1; + fail_unless(lwc_initialise(enomem_allocator, &permitted, 0) == lwc_error_oom, + "Able to initialise library with no memory available?!"); } END_TEST -#endif - -START_TEST (test_lwc_context_creation_ok) +START_TEST (test_lwc_intern_fails_with_no_memory) { - lwc_context *ctx = NULL; - lwc_error err; + int permitted = 2; /* context and buckets */ + lwc_string *str; + + fail_unless(lwc_initialise(enomem_allocator, &permitted, 0) == lwc_error_ok, + "Unable to initialise library"); + fail_unless(lwc_intern_string("Hello", 5, &str) == lwc_error_oom, + "Able to allocate string despite enomem."); - 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) +START_TEST (test_lwc_caseless_compare_fails_with_no_memory1) { - lwc_context *ctx = NULL; + int permitted = 3; /* ctx, buckets, 1 string */ + lwc_string *str; + bool result = true; - fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok, - "Unable to create context"); + fail_unless(lwc_initialise(enomem_allocator, &permitted, 0) == lwc_error_ok, + "Unable to initialise library"); + fail_unless(lwc_intern_string("Hello", 5, &str) == lwc_error_ok, + "Unable to allocate string."); + fail_unless(lwc_string_caseless_isequal(str, str, &result) == lwc_error_oom, + "Able to caselessly compare despite no memory"); - lwc_context_unref(ctx); } END_TEST -START_TEST (test_lwc_reffed_context_destruction_ok) +START_TEST (test_lwc_caseless_compare_fails_with_no_memory2) { - lwc_context *ctx = NULL; - - fail_unless(lwc_create_context(trivial_alloc_fn, NULL, &ctx) == lwc_error_ok, - "Unable to create context"); + int permitted = 5; /* ctx, buckets, 3 strings */ + lwc_string *str1, *str2; + bool result = true; - lwc_context_ref(ctx); /* make the weak ref strong */ + fail_unless(lwc_initialise(enomem_allocator, &permitted, 0) == lwc_error_ok, + "Unable to initialise library"); + fail_unless(lwc_intern_string("Hello", 5, &str1) == lwc_error_ok, + "Unable to allocate string."); + fail_unless(lwc_intern_string("World", 5, &str2) == lwc_error_ok, + "Unable to allocate string."); + fail_unless(lwc_string_caseless_isequal(str1, str2, &result) == lwc_error_oom, + "Able to caselessly compare despite no memory"); - 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); + fail_unless(lwc_initialise(trivial_alloc_fn, NULL, 0) == lwc_error_ok, + "Unable to initialise library"); } static void with_simple_context_teardown(void) { - lwc_context_unref(shared_ctx); + /* Nothing to do to tear down */ } -START_TEST (test_lwc_context_intern_ok) +START_TEST (test_lwc_intern_string_ok) { lwc_string *str = NULL; - fail_unless(lwc_context_intern(shared_ctx, "A", 1, &str) == lwc_error_ok, + fail_unless(lwc_intern_string("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) +START_TEST (test_lwc_intern_string_twice_ok) { lwc_string *str1 = NULL, *str2 = NULL; - fail_unless(lwc_context_intern(shared_ctx, "A", 1, &str1) == lwc_error_ok, + fail_unless(lwc_intern_string("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, + fail_unless(lwc_intern_string("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) +START_TEST (test_lwc_intern_string_twice_same_ok) { lwc_string *str1 = NULL, *str2 = NULL; - fail_unless(lwc_context_intern(shared_ctx, "A", 1, &str1) == lwc_error_ok, + fail_unless(lwc_intern_string("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, + fail_unless(lwc_intern_string("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 -START_TEST (test_lwc_context_size_non_zero) -{ - fail_unless(lwc_context_size(shared_ctx) > 0, - "Size of empty context is zero"); -} -END_TEST - -START_TEST (test_lwc_context_size_updated_on_string_intern) -{ - size_t empty_size = lwc_context_size(shared_ctx); - lwc_string *str; - - fail_unless(empty_size > 0, - "Size of empty context is zero"); - - fail_unless(lwc_context_intern(shared_ctx, "one", 3, &str) == lwc_error_ok, - "Unable to intern a simple string"); - - fail_unless(lwc_context_size(shared_ctx) > empty_size, - "Post-intern context size is same or smaller than empty size"); -} -END_TEST - -START_TEST (test_lwc_context_size_updated_on_string_unref) -{ - size_t empty_size = lwc_context_size(shared_ctx); - lwc_string *str; - - fail_unless(empty_size > 0, - "Size of empty context is zero"); - - fail_unless(lwc_context_intern(shared_ctx, "one", 3, &str) == lwc_error_ok, - "Unable to intern a simple string"); - - fail_unless(lwc_context_size(shared_ctx) > empty_size, - "Post-intern context size is same or smaller than empty size"); - - lwc_context_string_unref(shared_ctx, str); - - fail_unless(lwc_context_size(shared_ctx) == empty_size, - "Post-unref context size is not the same as empty size"); -} -END_TEST - -START_TEST (test_lwc_context_size_updated_on_substring_intern) -{ - size_t empty_size = lwc_context_size(shared_ctx); - size_t post_intern_size = 0; - lwc_string *str, *str2; - - fail_unless(empty_size > 0, - "Size of empty context is zero"); - - fail_unless(lwc_context_intern(shared_ctx, "one", 3, &str) == lwc_error_ok, - "Unable to intern a simple string"); - - post_intern_size = lwc_context_size(shared_ctx); - - fail_unless(post_intern_size > empty_size, - "Post-intern context size is same or smaller than empty size"); - - fail_unless(lwc_context_intern_substring(shared_ctx, str, 0, 1, &str2) == lwc_error_ok, - "Failed to intern substring"); - - fail_unless(lwc_context_size(shared_ctx) > post_intern_size, - "Post-substring-intern context size is same or smaller than pre-substring-intern size"); -} -END_TEST - -START_TEST (test_lwc_context_size_updated_on_substring_unref) -{ - size_t empty_size = lwc_context_size(shared_ctx); - size_t post_intern_size = 0; - lwc_string *str, *str2; - - fail_unless(empty_size > 0, - "Size of empty context is zero"); - - fail_unless(lwc_context_intern(shared_ctx, "one", 3, &str) == lwc_error_ok, - "Unable to intern a simple string"); - - post_intern_size = lwc_context_size(shared_ctx); - - fail_unless(post_intern_size > empty_size, - "Post-intern context size is same or smaller than empty size"); - - fail_unless(lwc_context_intern_substring(shared_ctx, str, 0, 1, &str2) == lwc_error_ok, - "Failed to intern substring"); - - fail_unless(lwc_context_size(shared_ctx) > post_intern_size, - "Post-substring-intern context size is same or smaller than pre-substring-intern size"); - - lwc_context_string_unref(shared_ctx, str2); - - fail_unless(lwc_context_size(shared_ctx) == post_intern_size, - "Post-substring-unref size is not the same as pre-substring-intern size"); -} -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 lwc_string *intern_one = NULL, *intern_two = NULL, *intern_three = NULL, *intern_YAY = 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_initialise(trivial_alloc_fn, NULL, 2) == lwc_error_ok, + "Unable to initialise library"); - 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, + fail_unless(lwc_intern_string("one", 3, &intern_one) == lwc_error_ok, "Unable to intern 'one'"); + fail_unless(lwc_intern_string("two", 3, &intern_two) == lwc_error_ok, + "Unable to intern 'two'"); + fail_unless(lwc_intern_string("three", 5, &intern_three) == lwc_error_ok, + "Unable to intern 'three'"); + fail_unless(lwc_intern_string("YAY", 3, &intern_YAY) == lwc_error_ok, + "Unable to intern 'YAY'"); fail_unless(intern_one != intern_two, "'one' == 'two'"); fail_unless(intern_one != intern_three, "'one' == 'three'"); @@ -408,14 +254,17 @@ with_filled_context_setup(void) static void with_filled_context_teardown(void) { - lwc_context_unref(shared_ctx); + lwc_string_unref(intern_one); + lwc_string_unref(intern_two); + lwc_string_unref(intern_three); + lwc_string_unref(intern_YAY); } 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, + fail_unless(lwc_intern_string("one", 3, &new_one) == lwc_error_ok, "Unable to re-intern 'one'"); fail_unless(new_one == intern_one, @@ -427,62 +276,113 @@ 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, + fail_unless(lwc_intern_string("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, + fail_unless(lwc_intern_substring(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) +START_TEST (test_lwc_intern_substring_bad_offset) { - fail_unless(lwc_context_string_ref(shared_ctx, intern_one) == intern_one, + lwc_string *str; + + fail_unless(lwc_intern_substring(intern_three, 100, 1, &str) == lwc_error_range, + "Able to intern substring starting out of range"); +} +END_TEST + +START_TEST (test_lwc_intern_substring_bad_size) +{ + lwc_string *str; + + fail_unless(lwc_intern_substring(intern_three, 1, 100, &str) == lwc_error_range, + "Able to intern substring ending out of range"); +} +END_TEST + +START_TEST (test_lwc_string_ref_ok) +{ + fail_unless(lwc_string_ref(intern_one) == intern_one, "Oddly, reffing a string didn't return it"); } END_TEST -START_TEST (test_lwc_context_string_unref_ok) +START_TEST (test_lwc_string_unref_ok) +{ + lwc_string_unref(intern_one); +} +END_TEST + +START_TEST (test_lwc_string_ref_unref_ok) { - lwc_context_string_unref(shared_ctx, intern_one); + lwc_string_ref(intern_one); + lwc_string_unref(intern_one); } END_TEST -START_TEST (test_lwc_context_string_isequal_ok) +START_TEST (test_lwc_string_isequal_ok) { bool result = true; - fail_unless((lwc_context_string_isequal(shared_ctx, intern_one, - intern_two, &result)) == lwc_error_ok, + fail_unless((lwc_string_isequal(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) +START_TEST (test_lwc_string_caseless_isequal_ok1) { bool result = true; lwc_string *new_ONE; - fail_unless(lwc_context_intern(shared_ctx, "ONE", 3, &new_ONE) == lwc_error_ok, + fail_unless(lwc_intern_string("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((lwc_string_isequal(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((lwc_string_caseless_isequal(intern_one, new_ONE, &result)) == lwc_error_ok, + "Failure comparing 'one' and 'ONE' caselessly"); fail_unless(result == true, "'one' !~= 'ONE' ?!"); } END_TEST +START_TEST (test_lwc_string_caseless_isequal_ok2) +{ + bool result = true; + lwc_string *new_yay; + + fail_unless(lwc_intern_string("yay", 3, &new_yay) == lwc_error_ok, + "Failure interning 'yay'"); + + fail_unless((lwc_string_isequal(intern_YAY, new_yay, &result)) == lwc_error_ok); + fail_unless(result == false, + "'yay' == 'YAY' ?!"); + + fail_unless((lwc_string_caseless_isequal(intern_YAY, new_yay, &result)) == lwc_error_ok, + "Failure comparing 'yay' and 'YAY' caselessly"); + fail_unless(result == true, + "'yay' !~= 'YAY' ?!"); +} +END_TEST + +START_TEST (test_lwc_string_caseless_isequal_bad) +{ + bool result = true; + + fail_unless(lwc_string_caseless_isequal(intern_YAY, intern_one, &result) == lwc_error_ok, + "Failure comparing 'YAY' and 'one' caselessly"); + fail_unless(result == false, + "'YAY' ~= 'one' ?!"); +} +END_TEST + START_TEST (test_lwc_extract_data_ok) { fail_unless(memcmp("one", @@ -502,7 +402,7 @@ START_TEST (test_lwc_string_is_nul_terminated) { lwc_string *new_ONE; - fail_unless(lwc_context_intern(shared_ctx, "ONE", 3, &new_ONE) == lwc_error_ok, + fail_unless(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok, "Failure interning 'ONE'"); fail_unless(lwc_string_data(new_ONE)[lwc_string_length(new_ONE)] == '\0', @@ -515,10 +415,10 @@ START_TEST (test_lwc_substring_is_nul_terminated) lwc_string *new_ONE; lwc_string *new_O; - fail_unless(lwc_context_intern(shared_ctx, "ONE", 3, &new_ONE) == lwc_error_ok, + fail_unless(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok, "Failure interning 'ONE'"); - fail_unless(lwc_context_intern_substring(shared_ctx, new_ONE, 0, 1, &new_O) == lwc_error_ok, + fail_unless(lwc_intern_substring(new_ONE, 0, 1, &new_O) == lwc_error_ok, "Failure interning substring 'O'"); fail_unless(lwc_string_data(new_O)[lwc_string_length(new_O)] == '\0', @@ -536,52 +436,22 @@ lwc_basic_suite(SRunner *sr) #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, + test_lwc_intern_string_aborts1, SIGABRT); tcase_add_test_raise_signal(tc_basic, - test_lwc_context_ref_aborts, + test_lwc_intern_string_aborts2, SIGABRT); tcase_add_test_raise_signal(tc_basic, - test_lwc_context_unref_aborts, + test_lwc_intern_substring_aborts1, SIGABRT); tcase_add_test_raise_signal(tc_basic, - test_lwc_context_intern_aborts1, + test_lwc_intern_substring_aborts2, SIGABRT); tcase_add_test_raise_signal(tc_basic, - test_lwc_context_intern_aborts2, + test_lwc_string_ref_aborts, 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, + test_lwc_string_unref_aborts, SIGABRT); tcase_add_test_raise_signal(tc_basic, test_lwc_string_data_aborts, @@ -592,31 +462,24 @@ lwc_basic_suite(SRunner *sr) tcase_add_test_raise_signal(tc_basic, test_lwc_string_hash_value_aborts, SIGABRT); - tcase_add_test_raise_signal(tc_basic, - test_lwc_context_size_aborts, - 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); + tcase_add_test(tc_basic, test_lwc_double_initialise_fails); + tcase_add_test(tc_basic, test_lwc_initialise_fails_with_no_memory); + tcase_add_test(tc_basic, test_lwc_initialise_fails_with_low_memory); + tcase_add_test(tc_basic, test_lwc_intern_fails_with_no_memory); + tcase_add_test(tc_basic, test_lwc_caseless_compare_fails_with_no_memory1); + tcase_add_test(tc_basic, test_lwc_caseless_compare_fails_with_no_memory2); + 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); - tcase_add_test(tc_basic, test_lwc_context_size_non_zero); - tcase_add_test(tc_basic, - test_lwc_context_size_updated_on_string_intern); - tcase_add_test(tc_basic, test_lwc_context_size_updated_on_string_unref); - tcase_add_test(tc_basic, - test_lwc_context_size_updated_on_substring_intern); - tcase_add_test(tc_basic, - test_lwc_context_size_updated_on_substring_unref); + tcase_add_test(tc_basic, test_lwc_intern_string_ok); + tcase_add_test(tc_basic, test_lwc_intern_string_twice_ok); + tcase_add_test(tc_basic, test_lwc_intern_string_twice_same_ok); suite_add_tcase(s, tc_basic); tc_basic = tcase_create("Ops with a filled context"); @@ -625,14 +488,19 @@ lwc_basic_suite(SRunner *sr) 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); + tcase_add_test(tc_basic, test_lwc_string_ref_ok); + tcase_add_test(tc_basic, test_lwc_string_ref_unref_ok); + tcase_add_test(tc_basic, test_lwc_string_unref_ok); + tcase_add_test(tc_basic, test_lwc_string_isequal_ok); + tcase_add_test(tc_basic, test_lwc_string_caseless_isequal_ok1); + tcase_add_test(tc_basic, test_lwc_string_caseless_isequal_ok2); + tcase_add_test(tc_basic, test_lwc_string_caseless_isequal_bad); tcase_add_test(tc_basic, test_lwc_extract_data_ok); tcase_add_test(tc_basic, test_lwc_string_hash_value_ok); tcase_add_test(tc_basic, test_lwc_string_is_nul_terminated); tcase_add_test(tc_basic, test_lwc_substring_is_nul_terminated); + tcase_add_test(tc_basic, test_lwc_intern_substring_bad_size); + tcase_add_test(tc_basic, test_lwc_intern_substring_bad_offset); suite_add_tcase(s, tc_basic); srunner_add_suite(sr, s); diff --git a/test/memorytests.c b/test/memorytests.c deleted file mode 100644 index 7c55cce..0000000 --- a/test/memorytests.c +++ /dev/null @@ -1,246 +0,0 @@ -/* test/basictests.c - * - * Basic tests for the test suite for libwapcaplet - * - * Copyright 2009 The NetSurf Browser Project - * Daniel Silverstone <dsilvers@netsurf-browser.org> - */ - -#include <check.h> -#include <stdlib.h> - -#include "tests.h" - -/**** Simple tracking allocator ****/ - -typedef enum { - NONE, ALLOC, FREE -} alloc_op; - -static unsigned long bytes = 0; -static unsigned long allocs = 0; -static void *last_pw = NULL; -static alloc_op last_op = NONE; - -static void * -tracking_allocator(void *ptr, size_t len, void *pw) -{ - void *ret; - last_pw = pw; - if (ptr == NULL) { - last_op = ALLOC; - bytes += len; - allocs++; - ret = malloc(len + sizeof(size_t)); - *(size_t *)ret = len; - return ((char *) ret) + sizeof(size_t); - } - last_op = FREE; - allocs--; - bytes -= *(((size_t *)ptr) - 1); - free((((size_t *)ptr) - 1)); - return NULL; -} - -static lwc_context *ctx = NULL; - -static void -with_tracked_alloc_setup(void) -{ - fail_unless(lwc_create_context(tracking_allocator, NULL, &ctx) == lwc_error_ok, - "Unable to create context"); - fail_unless(allocs == 1, - "Creating a context used more than one alloc?"); - fail_unless(lwc_context_ref(ctx) == ctx, - "Reffing the context failed to return the context."); -} - -static void -with_tracked_alloc_teardown(void) -{ - lwc_context_unref(ctx); - fail_unless(allocs == 0, - "Unreffing the context failed to free everything left."); -} - -START_TEST (test_tracking_one_intern) -{ - lwc_string *str; - fail_unless(lwc_context_intern(ctx, "one", 3, &str) == lwc_error_ok, - "Unable to intern 'one'"); - fail_unless(allocs == 2, - "Interning a string into a fresh context didn't."); -} -END_TEST - -START_TEST (test_tracking_one_intern_twice) -{ - lwc_string *str; - fail_unless(lwc_context_intern(ctx, "one", 3, &str) == lwc_error_ok, - "Unable to intern 'one'"); - fail_unless(allocs == 2, - "Interning a string into a fresh context didn't."); - fail_unless(lwc_context_intern(ctx, "one", 3, &str) == lwc_error_ok, - "Unable to intern 'one' again"); - fail_unless(allocs == 2, - "Interning a string again still did."); -} -END_TEST - -START_TEST (test_tracking_two_interns) -{ - lwc_string *one, *ONE; - fail_unless(lwc_context_intern(ctx, "one", 3, &one) == lwc_error_ok, - "Unable to intern 'one'"); - fail_unless(allocs == 2, - "Interning a string into a fresh context didn't."); - fail_unless(lwc_context_intern(ctx, "ONE", 3, &ONE) == lwc_error_ok, - "Unable to intern 'one' again"); - fail_unless(allocs == 3, - "Interning a new string didn't."); -} -END_TEST - -START_TEST (test_tracking_two_interns_caseless1) -{ - lwc_string *one, *ONE; - bool comp = false; - fail_unless(lwc_context_intern(ctx, "one", 3, &one) == lwc_error_ok, - "Unable to intern 'one'"); - fail_unless(allocs == 2, - "Interning a string into a fresh context didn't."); - fail_unless(lwc_context_intern(ctx, "ONE", 3, &ONE) == lwc_error_ok, - "Unable to intern 'ONE'"); - fail_unless(allocs == 3, - "Interning a new string didn't."); - fail_unless(lwc_context_string_caseless_isequal(ctx, one, ONE, &comp) == lwc_error_ok, - "Unable to caseless compare"); - fail_unless(allocs == 3, - "Caseless compare created worthless new values"); - fail_unless(comp == true, - "Caseless compare failed to spot that 'one' and 'ONE' are the same"); -} -END_TEST - -START_TEST (test_tracking_two_interns_caseless2) -{ - lwc_string *one, *ONE; - bool comp = false; - fail_unless(lwc_context_intern(ctx, "oNe", 3, &one) == lwc_error_ok, - "Unable to intern 'oNe'"); - fail_unless(allocs == 2, - "Interning a string into a fresh context didn't."); - fail_unless(lwc_context_intern(ctx, "ONE", 3, &ONE) == lwc_error_ok, - "Unable to intern 'ONE'"); - fail_unless(allocs == 3, - "Interning a new string didn't."); - fail_unless(lwc_context_string_caseless_isequal(ctx, one, ONE, &comp) == lwc_error_ok, - "Unable to caseless compare"); - fail_unless(allocs == 4, - "Caseless compare didn't make one caseless 'one'"); - fail_unless(comp == true, - "Caseless compare failed to spot that 'oNe' and 'ONE' are the same"); -} -END_TEST - -START_TEST (test_tracking_caseless_unref1) -{ - lwc_string *one, *ONE; - bool comp = false; - fail_unless(lwc_context_intern(ctx, "one", 3, &one) == lwc_error_ok, - "Unable to intern 'one'"); - fail_unless(allocs == 2, - "Interning a string into a fresh context didn't."); - fail_unless(lwc_context_intern(ctx, "ONE", 3, &ONE) == lwc_error_ok, - "Unable to intern 'ONE'"); - fail_unless(allocs == 3, - "Interning a new string didn't."); - fail_unless(lwc_context_string_caseless_isequal(ctx, one, ONE, &comp) == lwc_error_ok, - "Unable to caseless compare"); - fail_unless(allocs == 3, - "Caseless compare made pointless additional 'one'"); - fail_unless(comp == true, - "Caseless compare failed to spot that 'oNe' and 'ONE' are the same"); - - lwc_context_string_unref(ctx, ONE); - fail_unless(allocs == 2, "Unreffing 'ONE' failed to free something"); -} -END_TEST - -START_TEST (test_tracking_caseless_unref2) -{ - lwc_string *one, *ONE; - bool comp = false; - fail_unless(lwc_context_intern(ctx, "one", 3, &one) == lwc_error_ok, - "Unable to intern 'one'"); - fail_unless(allocs == 2, - "Interning a string into a fresh context didn't."); - fail_unless(lwc_context_intern(ctx, "ONE", 3, &ONE) == lwc_error_ok, - "Unable to intern 'ONE'"); - fail_unless(allocs == 3, - "Interning a new string didn't."); - fail_unless(lwc_context_string_caseless_isequal(ctx, one, ONE, &comp) == lwc_error_ok, - "Unable to caseless compare"); - fail_unless(allocs == 3, - "Caseless compare made pointless additional 'one'"); - fail_unless(comp == true, - "Caseless compare failed to spot that 'oNe' and 'ONE' are the same"); - - lwc_context_string_unref(ctx, ONE); - fail_unless(allocs == 2, "Unreffing 'ONE' failed to free something"); - - lwc_context_string_unref(ctx, one); - fail_unless(allocs == 1, "Unreffing 'one' failed to free something"); -} -END_TEST - -START_TEST (test_tracking_caseless_unref3) -{ - lwc_string *one, *ONE; - bool comp = false; - fail_unless(lwc_context_intern(ctx, "one", 3, &one) == lwc_error_ok, - "Unable to intern 'one'"); - fail_unless(allocs == 2, - "Interning a string into a fresh context didn't."); - fail_unless(lwc_context_intern(ctx, "ONE", 3, &ONE) == lwc_error_ok, - "Unable to intern 'ONE'"); - fail_unless(allocs == 3, - "Interning a new string didn't."); - fail_unless(lwc_context_string_caseless_isequal(ctx, one, ONE, &comp) == lwc_error_ok, - "Unable to caseless compare"); - fail_unless(allocs == 3, - "Caseless compare made pointless additional 'one'"); - fail_unless(comp == true, - "Caseless compare failed to spot that 'oNe' and 'ONE' are the same"); - - lwc_context_string_unref(ctx, one); - fail_unless(allocs == 3, "Unreffing 'one' freed something"); - - lwc_context_string_unref(ctx, ONE); - fail_unless(allocs == 1, "Unreffing 'ONE' failed to free both things"); -} -END_TEST - -/**** And the suites are set up here ****/ - -void -lwc_memory_suite(SRunner *sr) -{ - Suite *s = suite_create("libwapcaplet: Memory allocation tests"); - TCase *tc_mem = tcase_create("memory"); - - tcase_add_checked_fixture(tc_mem, with_tracked_alloc_setup, - with_tracked_alloc_teardown); - - tcase_add_test(tc_mem, test_tracking_one_intern); - tcase_add_test(tc_mem, test_tracking_one_intern_twice); - tcase_add_test(tc_mem, test_tracking_two_interns); - tcase_add_test(tc_mem, test_tracking_two_interns_caseless1); - tcase_add_test(tc_mem, test_tracking_two_interns_caseless2); - tcase_add_test(tc_mem, test_tracking_caseless_unref1); - tcase_add_test(tc_mem, test_tracking_caseless_unref2); - tcase_add_test(tc_mem, test_tracking_caseless_unref3); - - suite_add_tcase(s, tc_mem); - srunner_add_suite(sr, s); -} diff --git a/test/testmain.c b/test/testmain.c index 7c5aee9..95fd6d2 100644 --- a/test/testmain.c +++ b/test/testmain.c @@ -31,7 +31,7 @@ main(int argc, char **argv) sr = srunner_create(suite_create("Test suite for libwapcaplet")); lwc_basic_suite(sr); - lwc_memory_suite(sr); +// lwc_memory_suite(sr); srunner_set_fork_status(sr, CK_FORK); srunner_run_all(sr, CK_ENV); |