blob: 8a1d00ea59a62656570d8e6f74be62b9bc341ba7 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <proton/object.h>
#define assert(E) ((E) ? 0 : (abort(), 0))
static char mem;
static void *END = &mem;
static pn_list_t *build_list(size_t capacity, ...)
{
pn_list_t *result = pn_list(PN_OBJECT, capacity);
va_list ap;
va_start(ap, capacity);
while (true) {
void *arg = va_arg(ap, void *);
if (arg == END) {
break;
}
pn_list_add(result, arg);
pn_class_decref(PN_OBJECT, arg);
}
va_end(ap);
return result;
}
static pn_map_t *build_map(float load_factor, size_t capacity, ...)
{
pn_map_t *result = pn_map(PN_OBJECT, PN_OBJECT, capacity, load_factor);
va_list ap;
void *prev = NULL;
va_start(ap, capacity);
int count = 0;
while (true) {
void *arg = va_arg(ap, void *);
bool last = arg == END;
if (arg == END) {
arg = NULL;
}
if (count % 2) {
pn_map_put(result, prev, arg);
pn_class_decref(PN_OBJECT, prev);
pn_class_decref(PN_OBJECT, arg);
} else {
prev = arg;
}
if (last) {
break;
}
count++;
}
va_end(ap);
return result;
}
static void noop(void *o) {}
static uintptr_t zero(void *o) { return 0; }
static intptr_t delta(void *a, void *b) { return (uintptr_t) b - (uintptr_t) a; }
#define CID_noop CID_pn_object
#define noop_initialize noop
#define noop_finalize noop
#define noop_hashcode zero
#define noop_compare delta
#define noop_inspect NULL
static const pn_class_t noop_class = PN_CLASS(noop);
static void test_class(const pn_class_t *clazz, size_t size)
{
void *a = pn_class_new(clazz, size);
void *b = pn_class_new(clazz, size);
assert(!pn_class_equals(clazz, a, b));
assert(pn_class_equals(clazz, a, a));
assert(pn_class_equals(clazz, b, b));
assert(!pn_class_equals(clazz, a, NULL));
assert(!pn_class_equals(clazz, NULL, a));
int rca = pn_class_refcount(clazz, a);
int rcb = pn_class_refcount(clazz, b);
assert(rca == -1 || rca == 1);
assert(rcb == -1 || rcb == 1);
pn_class_incref(clazz, a);
rca = pn_class_refcount(clazz, a);
assert(rca == -1 || rca == 2);
pn_class_decref(clazz, a);
rca = pn_class_refcount(clazz, a);
assert(rca == -1 || rca == 1);
pn_class_free(clazz, a);
pn_class_free(clazz, b);
}
static void test_new(size_t size, const pn_class_t *clazz)
{
void *obj = pn_class_new(clazz, size);
assert(obj);
assert(pn_class_refcount(PN_OBJECT, obj) == 1);
assert(pn_class(obj) == clazz);
char *bytes = (char *) obj;
for (size_t i = 0; i < size; i++) {
// touch everything for valgrind
bytes[i] = i;
}
pn_free(obj);
}
static void finalizer(void *object)
{
int **called = (int **) object;
(**called)++;
}
#define CID_finalizer CID_pn_object
#define finalizer_initialize NULL
#define finalizer_finalize finalizer
#define finalizer_hashcode NULL
#define finalizer_compare NULL
#define finalizer_inspect NULL
static void test_finalize(void)
{
static pn_class_t clazz = PN_CLASS(finalizer);
int **obj = (int **) pn_class_new(&clazz, sizeof(int *));
assert(obj);
int called = 0;
*obj = &called;
pn_free(obj);
assert(called == 1);
}
static void test_free(void)
{
// just to make sure it doesn't seg fault or anything
pn_free(NULL);
}
static uintptr_t hashcode(void *obj) { return (uintptr_t) obj; }
#define CID_hashcode CID_pn_object
#define hashcode_initialize NULL
#define hashcode_finalize NULL
#define hashcode_compare NULL
#define hashcode_hashcode hashcode
#define hashcode_inspect NULL
static void test_hashcode(void)
{
static pn_class_t clazz = PN_CLASS(hashcode);
void *obj = pn_class_new(&clazz, 0);
assert(obj);
assert(pn_hashcode(obj) == (uintptr_t) obj);
assert(pn_hashcode(NULL) == 0);
pn_free(obj);
}
#define CID_compare CID_pn_object
#define compare_initialize NULL
#define compare_finalize NULL
#define compare_compare delta
#define compare_hashcode NULL
#define compare_inspect NULL
static void test_compare(void)
{
static pn_class_t clazz = PN_CLASS(compare);
void *a = pn_class_new(&clazz, 0);
assert(a);
void *b = pn_class_new(&clazz, 0);
assert(b);
assert(pn_compare(a, b));
assert(!pn_equals(a, b));
assert(!pn_compare(a, a));
assert(pn_equals(a, a));
assert(!pn_compare(b, b));
assert(pn_equals(b, b));
assert(pn_compare(a, b) == (intptr_t) ((uintptr_t) b - (uintptr_t) a));
assert(pn_compare(NULL, b));
assert(!pn_equals(NULL, b));
assert(pn_compare(a, NULL));
assert(!pn_equals(a, NULL));
assert(!pn_compare(NULL, NULL));
assert(pn_equals(NULL, NULL));
pn_free(a);
pn_free(b);
}
static void test_refcounting(int refs)
{
void *obj = pn_class_new(PN_OBJECT, 0);
assert(pn_refcount(obj) == 1);
for (int i = 0; i < refs; i++) {
pn_incref(obj);
assert(pn_refcount(obj) == i + 2);
}
assert(pn_refcount(obj) == refs + 1);
for (int i = 0; i < refs; i++) {
pn_decref(obj);
assert(pn_refcount(obj) == refs - i);
}
assert(pn_refcount(obj) == 1);
pn_free(obj);
}
static void test_list(size_t capacity)
{
pn_list_t *list = pn_list(PN_WEAKREF, 0);
assert(pn_list_size(list) == 0);
assert(!pn_list_add(list, (void *) 0));
assert(!pn_list_add(list, (void *) 1));
assert(!pn_list_add(list, (void *) 2));
assert(!pn_list_add(list, (void *) 3));
assert(pn_list_get(list, 0) == (void *) 0);
assert(pn_list_get(list, 1) == (void *) 1);
assert(pn_list_get(list, 2) == (void *) 2);
assert(pn_list_get(list, 3) == (void *) 3);
assert(pn_list_size(list) == 4);
pn_list_del(list, 1, 2);
assert(pn_list_size(list) == 2);
assert(pn_list_get(list, 0) == (void *) 0);
assert(pn_list_get(list, 1) == (void *) 3);
pn_decref(list);
}
static void test_list_refcount(size_t capacity)
{
void *one = pn_class_new(PN_OBJECT, 0);
void *two = pn_class_new(PN_OBJECT, 0);
void *three = pn_class_new(PN_OBJECT, 0);
void *four = pn_class_new(PN_OBJECT, 0);
pn_list_t *list = pn_list(PN_OBJECT, 0);
assert(!pn_list_add(list, one));
assert(!pn_list_add(list, two));
assert(!pn_list_add(list, three));
assert(!pn_list_add(list, four));
assert(pn_list_get(list, 0) == one);
assert(pn_list_get(list, 1) == two);
assert(pn_list_get(list, 2) == three);
assert(pn_list_get(list, 3) == four);
assert(pn_list_size(list) == 4);
assert(pn_refcount(one) == 2);
assert(pn_refcount(two) == 2);
assert(pn_refcount(three) == 2);
assert(pn_refcount(four) == 2);
pn_list_del(list, 1, 2);
assert(pn_list_size(list) == 2);
assert(pn_refcount(one) == 2);
assert(pn_refcount(two) == 1);
assert(pn_refcount(three) == 1);
assert(pn_refcount(four) == 2);
assert(pn_list_get(list, 0) == one);
assert(pn_list_get(list, 1) == four);
assert(!pn_list_add(list, one));
assert(pn_list_size(list) == 3);
assert(pn_refcount(one) == 3);
pn_decref(list);
assert(pn_refcount(one) == 1);
assert(pn_refcount(two) == 1);
assert(pn_refcount(three) == 1);
assert(pn_refcount(four) == 1);
pn_decref(one);
pn_decref(two);
pn_decref(three);
pn_decref(four);
}
static void check_list_index(pn_list_t *list, void *value, ssize_t idx)
{
assert(pn_list_index(list, value) == idx);
}
static void test_list_index(void)
{
pn_list_t *l = pn_list(PN_WEAKREF, 0);
void *one = pn_string("one");
void *two = pn_string("two");
void *three = pn_string("three");
void *dup1 = pn_string("dup");
void *dup2 = pn_string("dup");
void *last = pn_string("last");
pn_list_add(l, one);
pn_list_add(l, two);
pn_list_add(l, three);
pn_list_add(l, dup1);
pn_list_add(l, dup2);
pn_list_add(l, last);
check_list_index(l, one, 0);
check_list_index(l, two, 1);
check_list_index(l, three, 2);
check_list_index(l, dup1, 3);
check_list_index(l, dup2, 3);
check_list_index(l, last, 5);
void *nonexistent = pn_string("nonexistent");
check_list_index(l, nonexistent, -1);
pn_free(l);
pn_free(one);
pn_free(two);
pn_free(three);
pn_free(dup1);
pn_free(dup2);
pn_free(last);
pn_free(nonexistent);
}
static bool pn_strequals(const char *a, const char *b)
{
return !strcmp(a, b);
}
static void test_build_list(void)
{
pn_list_t *l = build_list(0,
pn_string("one"),
pn_string("two"),
pn_string("three"),
END);
assert(pn_list_size(l) == 3);
assert(pn_strequals(pn_string_get((pn_string_t *) pn_list_get(l, 0)),
"one"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_list_get(l, 1)),
"two"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_list_get(l, 2)),
"three"));
pn_free(l);
}
static void test_build_map(void)
{
pn_map_t *m = build_map(0.75, 0,
pn_string("key"),
pn_string("value"),
pn_string("key2"),
pn_string("value2"),
END);
assert(pn_map_size(m) == 2);
pn_string_t *key = pn_string(NULL);
pn_string_set(key, "key");
assert(pn_strequals(pn_string_get((pn_string_t *) pn_map_get(m, key)),
"value"));
pn_string_set(key, "key2");
assert(pn_strequals(pn_string_get((pn_string_t *) pn_map_get(m, key)),
"value2"));
pn_free(m);
pn_free(key);
}
static void test_build_map_odd(void)
{
pn_map_t *m = build_map(0.75, 0,
pn_string("key"),
pn_string("value"),
pn_string("key2"),
pn_string("value2"),
pn_string("key3"),
END);
assert(pn_map_size(m) == 3);
pn_string_t *key = pn_string(NULL);
pn_string_set(key, "key");
assert(pn_strequals(pn_string_get((pn_string_t *) pn_map_get(m, key)),
"value"));
pn_string_set(key, "key2");
assert(pn_strequals(pn_string_get((pn_string_t *) pn_map_get(m, key)),
"value2"));
pn_string_set(key, "key3");
assert(pn_map_get(m, key) == NULL);
pn_free(m);
pn_free(key);
}
static void test_map(void)
{
void *one = pn_class_new(PN_OBJECT, 0);
void *two = pn_class_new(PN_OBJECT, 0);
void *three = pn_class_new(PN_OBJECT, 0);
pn_map_t *map = pn_map(PN_OBJECT, PN_OBJECT, 4, 0.75);
assert(pn_map_size(map) == 0);
pn_string_t *key = pn_string("key");
pn_string_t *dup = pn_string("key");
pn_string_t *key1 = pn_string("key1");
pn_string_t *key2 = pn_string("key2");
assert(!pn_map_put(map, key, one));
assert(pn_map_size(map) == 1);
assert(!pn_map_put(map, key1, two));
assert(pn_map_size(map) == 2);
assert(!pn_map_put(map, key2, three));
assert(pn_map_size(map) == 3);
assert(pn_map_get(map, dup) == one);
assert(!pn_map_put(map, dup, one));
assert(pn_map_size(map) == 3);
assert(!pn_map_put(map, dup, two));
assert(pn_map_size(map) == 3);
assert(pn_map_get(map, dup) == two);
assert(pn_refcount(key) == 2);
assert(pn_refcount(dup) == 1);
assert(pn_refcount(key1) == 2);
assert(pn_refcount(key2) == 2);
assert(pn_refcount(one) == 1);
assert(pn_refcount(two) == 3);
assert(pn_refcount(three) == 2);
pn_map_del(map, key1);
assert(pn_map_size(map) == 2);
assert(pn_refcount(key) == 2);
assert(pn_refcount(dup) == 1);
assert(pn_refcount(key1) == 1);
assert(pn_refcount(key2) == 2);
assert(pn_refcount(one) == 1);
assert(pn_refcount(two) == 2);
assert(pn_refcount(three) == 2);
pn_decref(one);
pn_decref(two);
pn_decref(three);
pn_decref(key);
pn_decref(dup);
pn_decref(key1);
pn_decref(key2);
pn_decref(map);
}
static void test_hash(void)
{
void *one = pn_class_new(PN_OBJECT, 0);
void *two = pn_class_new(PN_OBJECT, 0);
void *three = pn_class_new(PN_OBJECT, 0);
pn_hash_t *hash = pn_hash(PN_OBJECT, 4, 0.75);
pn_hash_put(hash, 0, NULL);
pn_hash_put(hash, 1, one);
pn_hash_put(hash, 2, two);
pn_hash_put(hash, 3, three);
pn_hash_put(hash, 4, one);
pn_hash_put(hash, 5, two);
pn_hash_put(hash, 6, three);
pn_hash_put(hash, 7, one);
pn_hash_put(hash, 8, two);
pn_hash_put(hash, 9, three);
pn_hash_put(hash, 10, one);
pn_hash_put(hash, 11, two);
pn_hash_put(hash, 12, three);
pn_hash_put(hash, 18, one);
assert(pn_hash_get(hash, 2) == two);
assert(pn_hash_get(hash, 5) == two);
assert(pn_hash_get(hash, 18) == one);
assert(pn_hash_get(hash, 0) == NULL);
assert(pn_hash_size(hash) == 14);
pn_hash_del(hash, 5);
assert(pn_hash_get(hash, 5) == NULL);
assert(pn_hash_size(hash) == 13);
pn_hash_del(hash, 18);
assert(pn_hash_get(hash, 18) == NULL);
assert(pn_hash_size(hash) == 12);
pn_decref(hash);
pn_decref(one);
pn_decref(two);
pn_decref(three);
}
// collider class: all objects have same hash, no two objects compare equal
static intptr_t collider_compare(void *a, void *b)
{
if (a == b) return 0;
return (a > b) ? 1 : -1;
}
static uintptr_t collider_hashcode(void *obj)
{
return 23;
}
#define CID_collider CID_pn_object
#define collider_initialize NULL
#define collider_finalize NULL
#define collider_inspect NULL
static void test_map_links(void)
{
const pn_class_t collider_clazz = PN_CLASS(collider);
void *keys[3];
for (int i = 0; i < 3; i++)
keys[i] = pn_class_new(&collider_clazz, 0);
// test deleting a head, middle link, tail
for (int delete_idx=0; delete_idx < 3; delete_idx++) {
pn_map_t *map = pn_map(PN_WEAKREF, PN_WEAKREF, 0, 0.75);
// create a chain of entries that have same head (from identical key hashcode)
for (int i = 0; i < 3; i++) {
pn_map_put(map, keys[i], keys[i]);
}
pn_map_del(map, keys[delete_idx]);
for (int i = 0; i < 3; i++) {
void *value = (i == delete_idx) ? NULL : keys[i];
assert (pn_map_get(map, keys[i]) == value);
}
pn_free(map);
}
for (int i = 0; i < 3; i++)
pn_free(keys[i]);
}
static bool equals(const char *a, const char *b)
{
if (a == NULL && b == NULL) {
return true;
}
if (a == NULL || b == NULL) {
return false;
}
return !strcmp(a, b);
}
static void test_string(const char *value)
{
size_t size = value ? strlen(value) : 0;
pn_string_t *str = pn_string(value);
assert(equals(pn_string_get(str), value));
assert(pn_string_size(str) == size);
pn_string_t *strn = pn_stringn(value, size);
assert(equals(pn_string_get(strn), value));
assert(pn_string_size(strn) == size);
pn_string_t *strset = pn_string(NULL);
pn_string_set(strset, value);
assert(equals(pn_string_get(strset), value));
assert(pn_string_size(strset) == size);
pn_string_t *strsetn = pn_string(NULL);
pn_string_setn(strsetn, value, size);
assert(equals(pn_string_get(strsetn), value));
assert(pn_string_size(strsetn) == size);
assert(pn_hashcode(str) == pn_hashcode(strn));
assert(pn_hashcode(str) == pn_hashcode(strset));
assert(pn_hashcode(str) == pn_hashcode(strsetn));
assert(!pn_compare(str, str));
assert(!pn_compare(str, strn));
assert(!pn_compare(str, strset));
assert(!pn_compare(str, strsetn));
pn_free(str);
pn_free(strn);
pn_free(strset);
pn_free(strsetn);
}
static void test_stringn(const char *value, size_t size)
{
pn_string_t *strn = pn_stringn(value, size);
assert(equals(pn_string_get(strn), value));
assert(pn_string_size(strn) == size);
pn_string_t *strsetn = pn_string(NULL);
pn_string_setn(strsetn, value, size);
assert(equals(pn_string_get(strsetn), value));
assert(pn_string_size(strsetn) == size);
assert(pn_hashcode(strn) == pn_hashcode(strsetn));
assert(!pn_compare(strn, strsetn));
pn_free(strn);
pn_free(strsetn);
}
static void test_string_format(void)
{
pn_string_t *str = pn_string("");
assert(str);
int err = pn_string_format(str, "%s", "this is a string that should be long "
"enough to force growth but just in case we'll "
"tack this other really long string on for the "
"heck of it");
assert(err == 0);
pn_free(str);
}
static void test_string_addf(void)
{
pn_string_t *str = pn_string("hello ");
assert(str);
int err = pn_string_addf(str, "%s", "this is a string that should be long "
"enough to force growth but just in case we'll "
"tack this other really long string on for the "
"heck of it");
assert(err == 0);
pn_free(str);
}
static void test_map_iteration(int n)
{
pn_list_t *pairs = pn_list(PN_OBJECT, 2*n);
for (int i = 0; i < n; i++) {
void *key = pn_class_new(PN_OBJECT, 0);
void *value = pn_class_new(PN_OBJECT, 0);
pn_list_add(pairs, key);
pn_list_add(pairs, value);
pn_decref(key);
pn_decref(value);
}
pn_map_t *map = pn_map(PN_OBJECT, PN_OBJECT, 0, 0.75);
assert(pn_map_head(map) == 0);
for (int i = 0; i < n; i++) {
pn_map_put(map, pn_list_get(pairs, 2*i), pn_list_get(pairs, 2*i + 1));
}
for (pn_handle_t entry = pn_map_head(map); entry; entry = pn_map_next(map, entry))
{
void *key = pn_map_key(map, entry);
void *value = pn_map_value(map, entry);
ssize_t idx = pn_list_index(pairs, key);
assert(idx >= 0);
assert(pn_list_get(pairs, idx) == key);
assert(pn_list_get(pairs, idx + 1) == value);
pn_list_del(pairs, idx, 2);
}
assert(pn_list_size(pairs) == 0);
pn_decref(map);
pn_decref(pairs);
}
void test_inspect(void *o, const char *expected)
{
pn_string_t *dst = pn_string(NULL);
pn_inspect(o, dst);
assert(pn_strequals(pn_string_get(dst), expected));
pn_free(dst);
}
void test_list_inspect(void)
{
pn_list_t *l = build_list(0, END);
test_inspect(l, "[]");
pn_free(l);
l = build_list(0, pn_string("one"), END);
test_inspect(l, "[\"one\"]");
pn_free(l);
l = build_list(0,
pn_string("one"),
pn_string("two"),
END);
test_inspect(l, "[\"one\", \"two\"]");
pn_free(l);
l = build_list(0,
pn_string("one"),
pn_string("two"),
pn_string("three"),
END);
test_inspect(l, "[\"one\", \"two\", \"three\"]");
pn_free(l);
}
void test_map_inspect(void)
{
// note that when there is more than one entry in a map, the order
// of the entries is dependent on the hashes involved, it will be
// deterministic though
pn_map_t *m = build_map(0.75, 0, END);
test_inspect(m, "{}");
pn_free(m);
m = build_map(0.75, 0,
pn_string("key"), pn_string("value"),
END);
test_inspect(m, "{\"key\": \"value\"}");
pn_free(m);
m = build_map(0.75, 0,
pn_string("k1"), pn_string("v1"),
pn_string("k2"), pn_string("v2"),
END);
test_inspect(m, "{\"k1\": \"v1\", \"k2\": \"v2\"}");
pn_free(m);
m = build_map(0.75, 0,
pn_string("k1"), pn_string("v1"),
pn_string("k2"), pn_string("v2"),
pn_string("k3"), pn_string("v3"),
END);
test_inspect(m, "{\"k3\": \"v3\", \"k1\": \"v1\", \"k2\": \"v2\"}");
pn_free(m);
}
void test_map_coalesced_chain(void)
{
pn_hash_t *map = pn_hash(PN_OBJECT, 16, 0.75);
pn_string_t *values[9] = {
pn_string("a"),
pn_string("b"),
pn_string("c"),
pn_string("d"),
pn_string("e"),
pn_string("f"),
pn_string("g"),
pn_string("h"),
pn_string("i")
};
//add some items:
pn_hash_put(map, 1, values[0]);
pn_hash_put(map, 2, values[1]);
pn_hash_put(map, 3, values[2]);
//use up all non-addressable elements:
pn_hash_put(map, 14, values[3]);
pn_hash_put(map, 15, values[4]);
pn_hash_put(map, 16, values[5]);
//use an addressable element for a key that doesn't map to it:
pn_hash_put(map, 4, values[6]);
pn_hash_put(map, 17, values[7]);
assert(pn_hash_size(map) == 8);
//free up one non-addressable entry:
pn_hash_del(map, 16);
assert(pn_hash_get(map, 16) == NULL);
assert(pn_hash_size(map) == 7);
//add a key whose addressable slot is already taken (by 17),
//generating a coalesced chain:
pn_hash_put(map, 12, values[8]);
//remove an entry from the coalesced chain:
pn_hash_del(map, 4);
assert(pn_hash_get(map, 4) == NULL);
//test lookup of all entries:
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 1)), "a"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 2)), "b"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 3)), "c"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 14)), "d"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 15)), "e"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 17)), "h"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 12)), "i"));
assert(pn_hash_size(map) == 7);
//cleanup:
for (pn_handle_t i = pn_hash_head(map); i; i = pn_hash_head(map)) {
pn_hash_del(map, pn_hash_key(map, i));
}
assert(pn_hash_size(map) == 0);
for (size_t i = 0; i < 9; ++i) {
pn_free(values[i]);
}
pn_free(map);
}
void test_map_coalesced_chain2(void)
{
pn_hash_t *map = pn_hash(PN_OBJECT, 16, 0.75);
pn_string_t *values[10] = {
pn_string("a"),
pn_string("b"),
pn_string("c"),
pn_string("d"),
pn_string("e"),
pn_string("f"),
pn_string("g"),
pn_string("h"),
pn_string("i"),
pn_string("j")
};
//add some items:
pn_hash_put(map, 1, values[0]);//a
pn_hash_put(map, 2, values[1]);//b
pn_hash_put(map, 3, values[2]);//c
//use up all non-addressable elements:
pn_hash_put(map, 14, values[3]);//d
pn_hash_put(map, 15, values[4]);//e
pn_hash_put(map, 16, values[5]);//f
//take slot from addressable region
pn_hash_put(map, 29, values[6]);//g, goes into slot 12
//free up one non-addressable entry:
pn_hash_del(map, 14);
assert(pn_hash_get(map, 14) == NULL);
//add a key whose addressable slot is already taken (by 29),
//generating a coalesced chain:
pn_hash_put(map, 12, values[7]);//h
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 12)), "h"));
//delete from tail of coalesced chain:
pn_hash_del(map, 12);
assert(pn_hash_get(map, 12) == NULL);
//extend chain into cellar again, then coalesce again extending back
//into addressable region
pn_hash_put(map, 42, values[8]);//i
pn_hash_put(map, 25, values[9]);//j
//delete entry from coalesced chain, where next element in chain is
//in cellar:
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 29)), "g"));
pn_hash_del(map, 29);
//test lookup of all entries:
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 1)), "a"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 2)), "b"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 3)), "c"));
//d was deleted
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 15)), "e"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 16)), "f"));
//g was deleted, h was deleted
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 42)), "i"));
assert(pn_strequals(pn_string_get((pn_string_t *) pn_hash_get(map, 25)), "j"));
assert(pn_hash_size(map) == 7);
//cleanup:
for (pn_handle_t i = pn_hash_head(map); i; i = pn_hash_head(map)) {
pn_hash_del(map, pn_hash_key(map, i));
}
assert(pn_hash_size(map) == 0);
for (size_t i = 0; i < 10; ++i) {
pn_free(values[i]);
}
pn_free(map);
}
void test_list_compare(void)
{
pn_list_t *a = pn_list(PN_OBJECT, 0);
pn_list_t *b = pn_list(PN_OBJECT, 0);
assert(pn_equals(a, b));
void *one = pn_class_new(PN_OBJECT, 0);
void *two = pn_class_new(PN_OBJECT, 0);
void *three = pn_class_new(PN_OBJECT, 0);
pn_list_add(a, one);
assert(!pn_equals(a, b));
pn_list_add(b, one);
assert(pn_equals(a, b));
pn_list_add(b, two);
assert(!pn_equals(a, b));
pn_list_add(a, two);
assert(pn_equals(a, b));
pn_list_add(a, three);
assert(!pn_equals(a, b));
pn_list_add(b, three);
assert(pn_equals(a, b));
pn_free(a); pn_free(b);
pn_free(one); pn_free(two); pn_free(three);
}
typedef struct {
pn_list_t *list;
size_t index;
} pn_it_state_t;
static void *pn_it_next(void *state) {
pn_it_state_t *it = (pn_it_state_t *) state;
if (it->index < pn_list_size(it->list)) {
return pn_list_get(it->list, it->index++);
} else {
return NULL;
}
}
void test_iterator(void)
{
pn_list_t *list = build_list(0,
pn_string("one"),
pn_string("two"),
pn_string("three"),
pn_string("four"),
END);
pn_iterator_t *it = pn_iterator();
pn_it_state_t *state = (pn_it_state_t *) pn_iterator_start
(it, pn_it_next, sizeof(pn_it_state_t));
state->list = list;
state->index = 0;
void *obj;
int index = 0;
while ((obj = pn_iterator_next(it))) {
assert(obj == pn_list_get(list, index));
++index;
}
assert(index == 4);
pn_free(list);
pn_free(it);
}
void test_heap(int seed, int size)
{
srand(seed);
pn_list_t *list = pn_list(PN_VOID, 0);
intptr_t min = 0;
intptr_t max = 0;
for (int i = 0; i < size; i++) {
intptr_t r = rand();
if (i == 0) {
min = r;
max = r;
} else {
if (r < min) {
min = r;
}
if (r > max) {
max = r;
}
}
pn_list_minpush(list, (void *) r);
}
intptr_t prev = (intptr_t) pn_list_minpop(list);
assert(prev == min);
assert(pn_list_size(list) == (size_t)(size - 1));
int count = 0;
while (pn_list_size(list)) {
intptr_t r = (intptr_t) pn_list_minpop(list);
assert(r >= prev);
prev = r;
count++;
}
assert(count == size - 1);
assert(prev == max);
pn_free(list);
}
int main(int argc, char **argv)
{
for (size_t i = 0; i < 128; i++) {
test_class(PN_OBJECT, i);
test_class(PN_VOID, i);
test_class(&noop_class, i);
}
for (size_t i = 0; i < 128; i++) {
test_new(i, PN_OBJECT);
test_new(i, &noop_class);
}
test_finalize();
test_free();
test_hashcode();
test_compare();
for (int i = 0; i < 1024; i++) {
test_refcounting(i);
}
for (size_t i = 0; i < 4; i++) {
test_list(i);
}
for (size_t i = 0; i < 4; i++) {
test_list_refcount(i);
}
test_list_index();
test_map();
test_map_links();
test_hash();
test_string(NULL);
test_string("");
test_string("this is a test");
test_string("012345678910111213151617181920212223242526272829303132333435363"
"738394041424344454647484950515253545556575859606162636465666768");
test_string("this has an embedded \000 in it");
test_stringn("this has an embedded \000 in it", 28);
test_string_format();
test_string_addf();
test_build_list();
test_build_map();
test_build_map_odd();
for (int i = 0; i < 64; i++)
{
test_map_iteration(i);
}
test_list_inspect();
test_map_inspect();
test_list_compare();
test_iterator();
for (int seed = 0; seed < 64; seed++) {
for (int size = 1; size <= 64; size++) {
test_heap(seed, size);
}
}
test_map_coalesced_chain();
test_map_coalesced_chain2();
return 0;
}