You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2018/11/19 22:53:35 UTC
[5/6] qpid-proton git commit: PROTON-1887: [c] Convert C tests to use
Catch2 harness.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0bdba37d/c/tests/event_test.cpp
----------------------------------------------------------------------
diff --git a/c/tests/event_test.cpp b/c/tests/event_test.cpp
new file mode 100644
index 0000000..0a93b5c
--- /dev/null
+++ b/c/tests/event_test.cpp
@@ -0,0 +1,105 @@
+/*
+ *
+ * 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 "./pn_test.hpp"
+
+#include <proton/event.h>
+#include <proton/object.h>
+
+TEST_CASE("event_collector") {
+ pn_collector_t *collector = pn_collector();
+ REQUIRE(collector);
+ pn_free(collector);
+}
+
+#define SETUP_COLLECTOR \
+ void *obj = pn_class_new(PN_OBJECT, 0); \
+ pn_collector_t *collector = pn_collector(); \
+ REQUIRE(collector); \
+ pn_event_t *event = \
+ pn_collector_put(collector, PN_OBJECT, obj, (pn_event_type_t)0); \
+ pn_decref(obj);
+
+TEST_CASE("event_collector_put") {
+ SETUP_COLLECTOR;
+ REQUIRE(event);
+ REQUIRE(pn_event_context(event) == obj);
+ pn_free(collector);
+}
+
+TEST_CASE("event_collector_peek") {
+ SETUP_COLLECTOR;
+ pn_event_t *head = pn_collector_peek(collector);
+ REQUIRE(head == event);
+ pn_free(collector);
+}
+
+TEST_CASE("event_collector_pop") {
+ SETUP_COLLECTOR;
+ pn_event_t *head = pn_collector_peek(collector);
+ REQUIRE(head == event);
+ pn_collector_pop(collector);
+ head = pn_collector_peek(collector);
+ REQUIRE(!head);
+ pn_free(collector);
+}
+
+TEST_CASE("event_collector_pool") {
+ SETUP_COLLECTOR;
+ pn_event_t *head = pn_collector_peek(collector);
+ REQUIRE(head == event);
+ pn_collector_pop(collector);
+ head = pn_collector_peek(collector);
+ REQUIRE(!head);
+ void *obj2 = pn_class_new(PN_OBJECT, 0);
+ pn_event_t *event2 =
+ pn_collector_put(collector, PN_OBJECT, obj2, (pn_event_type_t)0);
+ pn_decref(obj2);
+ REQUIRE(event == event2);
+ pn_free(collector);
+}
+
+void test_event_incref(bool eventfirst) {
+ INFO("eventfirst = " << eventfirst);
+ SETUP_COLLECTOR;
+ pn_event_t *head = pn_collector_peek(collector);
+ REQUIRE(head == event);
+ pn_incref(head);
+ pn_collector_pop(collector);
+ REQUIRE(!pn_collector_peek(collector));
+ void *obj2 = pn_class_new(PN_OBJECT, 0);
+ pn_event_t *event2 =
+ pn_collector_put(collector, PN_OBJECT, obj2, (pn_event_type_t)0);
+ pn_decref(obj2);
+ REQUIRE(head != event2);
+ if (eventfirst) {
+ pn_decref(head);
+ pn_free(collector);
+ } else {
+ pn_free(collector);
+ pn_decref(head);
+ }
+}
+
+TEST_CASE("event_incref") {
+ test_event_incref(true);
+ test_event_incref(false);
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0bdba37d/c/tests/message.c
----------------------------------------------------------------------
diff --git a/c/tests/message.c b/c/tests/message.c
deleted file mode 100644
index 7a6dc4f..0000000
--- a/c/tests/message.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- *
- * 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 "test_tools.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <proton/error.h>
-#include <proton/message.h>
-
-#define assert(E) ((E) ? 0 : (abort(), 0))
-
-static void test_overflow_error(test_t *t)
-{
- pn_message_t *message = pn_message();
- char buf[6];
- size_t size = 6;
-
- int err = pn_message_encode(message, buf, &size);
- TEST_INT_EQUAL(t,PN_OVERFLOW, err);
- TEST_INT_EQUAL(t, 0, pn_message_errno(message));
- pn_message_free(message);
-}
-
-static void recode(pn_message_t *dst, pn_message_t *src) {
- pn_rwbytes_t buf = { 0 };
- int size = pn_message_encode2(src, &buf);
- assert(size > 0);
- pn_message_decode(dst, buf.start, size);
- free(buf.start);
-}
-
-static void test_inferred(test_t *t) {
- pn_message_t *src = pn_message();
- pn_message_t *dst = pn_message();
-
- TEST_CHECK(t, !pn_message_is_inferred(src));
- pn_data_put_binary(pn_message_body(src), PN_BYTES_LITERAL("hello"));
- recode(dst, src);
- TEST_CHECK(t, !pn_message_is_inferred(dst));
- pn_message_set_inferred(src, true);
- recode(dst, src);
- TEST_CHECK(t, pn_message_is_inferred(dst));
-
- pn_message_clear(src);
- TEST_CHECK(t, !pn_message_is_inferred(src));
- pn_data_put_list(pn_message_body(src));
- pn_data_enter(pn_message_body(src));
- pn_data_put_binary(pn_message_body(src), PN_BYTES_LITERAL("hello"));
- recode(dst, src);
- TEST_CHECK(t, !pn_message_is_inferred(dst));
- pn_message_set_inferred(src, true);
- recode(dst, src);
- TEST_CHECK(t, pn_message_is_inferred(dst));
-
- pn_message_clear(src);
- TEST_CHECK(t, !pn_message_is_inferred(src));
- pn_data_put_string(pn_message_body(src), PN_BYTES_LITERAL("hello"));
- recode(dst, src);
- TEST_CHECK(t, !pn_message_is_inferred(dst));
- pn_message_set_inferred(src, true);
- recode(dst, src);
- /* A value section is never considered to be inferred */
- TEST_CHECK(t, !pn_message_is_inferred(dst));
-
- pn_message_free(src);
- pn_message_free(dst);
-}
-
-int main(int argc, char **argv)
-{
- int failed = 0;
- RUN_ARGV_TEST(failed, t, test_overflow_error(&t));
- RUN_ARGV_TEST(failed, t, test_inferred(&t));
- return 0;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0bdba37d/c/tests/message_test.cpp
----------------------------------------------------------------------
diff --git a/c/tests/message_test.cpp b/c/tests/message_test.cpp
new file mode 100644
index 0000000..5d76abe
--- /dev/null
+++ b/c/tests/message_test.cpp
@@ -0,0 +1,84 @@
+/*
+ *
+ * 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 "./pn_test.hpp"
+
+#include <proton/error.h>
+#include <proton/message.h>
+#include <stdarg.h>
+
+using namespace pn_test;
+
+TEST_CASE("message_overflow_error") {
+ pn_message_t *message = pn_message();
+ char buf[6];
+ size_t size = 6;
+
+ int err = pn_message_encode(message, buf, &size);
+ CHECK(PN_OVERFLOW == err);
+ CHECK(0 == pn_message_errno(message));
+ pn_message_free(message);
+}
+
+static void recode(pn_message_t *dst, pn_message_t *src) {
+ pn_rwbytes_t buf = {0};
+ int size = pn_message_encode2(src, &buf);
+ REQUIRE(size > 0);
+ pn_message_decode(dst, buf.start, size);
+ free(buf.start);
+}
+
+TEST_CASE("message_inferred") {
+ pn_message_t *src = pn_message();
+ pn_message_t *dst = pn_message();
+
+ CHECK(!pn_message_is_inferred(src));
+ pn_data_put_binary(pn_message_body(src), pn_bytes("hello"));
+ recode(dst, src);
+ CHECK(!pn_message_is_inferred(dst));
+ pn_message_set_inferred(src, true);
+ recode(dst, src);
+ CHECK(pn_message_is_inferred(dst));
+
+ pn_message_clear(src);
+ CHECK(!pn_message_is_inferred(src));
+ pn_data_put_list(pn_message_body(src));
+ pn_data_enter(pn_message_body(src));
+ pn_data_put_binary(pn_message_body(src), pn_bytes("hello"));
+ recode(dst, src);
+ CHECK(!pn_message_is_inferred(dst));
+ pn_message_set_inferred(src, true);
+ recode(dst, src);
+ CHECK(pn_message_is_inferred(dst));
+
+ pn_message_clear(src);
+ CHECK(!pn_message_is_inferred(src));
+ pn_data_put_string(pn_message_body(src), pn_bytes("hello"));
+ recode(dst, src);
+ CHECK(!pn_message_is_inferred(dst));
+ pn_message_set_inferred(src, true);
+ recode(dst, src);
+ /* A value section is never considered to be inferred */
+ CHECK(!pn_message_is_inferred(dst));
+
+ pn_message_free(src);
+ pn_message_free(dst);
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0bdba37d/c/tests/object.c
----------------------------------------------------------------------
diff --git a/c/tests/object.c b/c/tests/object.c
deleted file mode 100644
index 8a1d00e..0000000
--- a/c/tests/object.c
+++ /dev/null
@@ -1,1115 +0,0 @@
-/*
- *
- * 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;
-}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0bdba37d/c/tests/object_test.cpp
----------------------------------------------------------------------
diff --git a/c/tests/object_test.cpp b/c/tests/object_test.cpp
new file mode 100644
index 0000000..8588955
--- /dev/null
+++ b/c/tests/object_test.cpp
@@ -0,0 +1,969 @@
+/*
+ *
+ * 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 "./pn_test.hpp"
+
+#include <proton/object.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+using Catch::Matchers::Equals;
+
+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) {
+ INFO("class=" << pn_class_name(clazz) << " size=" << size);
+ void *a = pn_class_new(clazz, size);
+ void *b = pn_class_new(clazz, size);
+
+ CHECK(!pn_class_equals(clazz, a, b));
+ CHECK(pn_class_equals(clazz, a, a));
+ CHECK(pn_class_equals(clazz, b, b));
+ CHECK(!pn_class_equals(clazz, a, NULL));
+ CHECK(!pn_class_equals(clazz, NULL, a));
+
+ int rca = pn_class_refcount(clazz, a);
+ int rcb = pn_class_refcount(clazz, b);
+
+ CHECK((rca == -1 || rca == 1));
+ CHECK((rcb == -1 || rcb == 1));
+
+ pn_class_incref(clazz, a);
+
+ rca = pn_class_refcount(clazz, a);
+ CHECK((rca == -1 || rca == 2));
+
+ pn_class_decref(clazz, a);
+
+ rca = pn_class_refcount(clazz, a);
+ CHECK((rca == -1 || rca == 1));
+
+ pn_class_free(clazz, a);
+ pn_class_free(clazz, b);
+}
+
+TEST_CASE("object_class") {
+ test_class(PN_OBJECT, 0);
+ test_class(PN_VOID, 5);
+ test_class(&noop_class, 128);
+}
+
+static void test_new(size_t size, const pn_class_t *clazz) {
+ INFO("class=" << pn_class_name(clazz) << " size=" << size);
+ void *obj = pn_class_new(clazz, size);
+ REQUIRE(obj);
+ CHECK(pn_class_refcount(PN_OBJECT, obj) == 1);
+ CHECK(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);
+}
+
+TEST_CASE("object_class new") {
+ test_new(0, PN_OBJECT);
+ test_new(5, PN_OBJECT);
+ test_new(128, &noop_class);
+}
+
+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
+
+TEST_CASE("object_finalize") {
+ static pn_class_t clazz = PN_CLASS(finalizer);
+
+ int **obj = (int **)pn_class_new(&clazz, sizeof(int *));
+ REQUIRE(obj);
+
+ int called = 0;
+ *obj = &called;
+ pn_free(obj);
+
+ CHECK(called == 1);
+}
+
+TEST_CASE("object_free") {
+ // 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
+
+TEST_CASE("object_hashcode") {
+ static pn_class_t clazz = PN_CLASS(hashcode);
+ void *obj = pn_class_new(&clazz, 0);
+ REQUIRE(obj);
+ CHECK(pn_hashcode(obj) == (uintptr_t)obj);
+ CHECK(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
+
+TEST_CASE("object_compare") {
+ static pn_class_t clazz = PN_CLASS(compare);
+
+ void *a = pn_class_new(&clazz, 0);
+ REQUIRE(a);
+ void *b = pn_class_new(&clazz, 0);
+ REQUIRE(b);
+
+ CHECK(pn_compare(a, b));
+ CHECK(!pn_equals(a, b));
+ CHECK(!pn_compare(a, a));
+ CHECK(pn_equals(a, a));
+ CHECK(!pn_compare(b, b));
+ CHECK(pn_equals(b, b));
+ CHECK(pn_compare(a, b) == (intptr_t)((uintptr_t)b - (uintptr_t)a));
+
+ CHECK(pn_compare(NULL, b));
+ CHECK(!pn_equals(NULL, b));
+
+ CHECK(pn_compare(a, NULL));
+ CHECK(!pn_equals(a, NULL));
+
+ CHECK(!pn_compare(NULL, NULL));
+ CHECK(pn_equals(NULL, NULL));
+
+ pn_free(a);
+ pn_free(b);
+}
+
+TEST_CASE("object_refcounting") {
+ int refs = 3;
+ void *obj = pn_class_new(PN_OBJECT, 0);
+
+ CHECK(pn_refcount(obj) == 1);
+
+ for (int i = 0; i < refs; i++) {
+ pn_incref(obj);
+ CHECK(pn_refcount(obj) == i + 2);
+ }
+
+ CHECK(pn_refcount(obj) == refs + 1);
+
+ for (int i = 0; i < refs; i++) {
+ pn_decref(obj);
+ CHECK(pn_refcount(obj) == refs - i);
+ }
+
+ CHECK(pn_refcount(obj) == 1);
+
+ pn_free(obj);
+}
+
+TEST_CASE("list") {
+ pn_list_t *list = pn_list(PN_WEAKREF, 0);
+ CHECK(pn_list_size(list) == 0);
+ CHECK(!pn_list_add(list, (void *)0));
+ CHECK(!pn_list_add(list, (void *)1));
+ CHECK(!pn_list_add(list, (void *)2));
+ CHECK(!pn_list_add(list, (void *)3));
+ CHECK(pn_list_get(list, 0) == (void *)0);
+ CHECK(pn_list_get(list, 1) == (void *)1);
+ CHECK(pn_list_get(list, 2) == (void *)2);
+ CHECK(pn_list_get(list, 3) == (void *)3);
+ CHECK(pn_list_size(list) == 4);
+ pn_list_del(list, 1, 2);
+ CHECK(pn_list_size(list) == 2);
+ CHECK(pn_list_get(list, 0) == (void *)0);
+ CHECK(pn_list_get(list, 1) == (void *)3);
+ pn_decref(list);
+}
+
+TEST_CASE("list_refcount") {
+ 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);
+ CHECK(!pn_list_add(list, one));
+ CHECK(!pn_list_add(list, two));
+ CHECK(!pn_list_add(list, three));
+ CHECK(!pn_list_add(list, four));
+ CHECK(pn_list_get(list, 0) == one);
+ CHECK(pn_list_get(list, 1) == two);
+ CHECK(pn_list_get(list, 2) == three);
+ CHECK(pn_list_get(list, 3) == four);
+ CHECK(pn_list_size(list) == 4);
+
+ CHECK(pn_refcount(one) == 2);
+ CHECK(pn_refcount(two) == 2);
+ CHECK(pn_refcount(three) == 2);
+ CHECK(pn_refcount(four) == 2);
+
+ pn_list_del(list, 1, 2);
+ CHECK(pn_list_size(list) == 2);
+
+ CHECK(pn_refcount(one) == 2);
+ CHECK(pn_refcount(two) == 1);
+ CHECK(pn_refcount(three) == 1);
+ CHECK(pn_refcount(four) == 2);
+
+ CHECK(pn_list_get(list, 0) == one);
+ CHECK(pn_list_get(list, 1) == four);
+
+ CHECK(!pn_list_add(list, one));
+
+ CHECK(pn_list_size(list) == 3);
+ CHECK(pn_refcount(one) == 3);
+
+ pn_decref(list);
+
+ CHECK(pn_refcount(one) == 1);
+ CHECK(pn_refcount(two) == 1);
+ CHECK(pn_refcount(three) == 1);
+ CHECK(pn_refcount(four) == 1);
+
+ pn_decref(one);
+ pn_decref(two);
+ pn_decref(three);
+ pn_decref(four);
+}
+
+#define check_list_index(list, value, idx) \
+ CHECK(pn_list_index(list, value) == idx)
+
+TEST_CASE("list_index") {
+ 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);
+}
+
+TEST_CASE("list_build") {
+ pn_list_t *l = build_list(0, pn_string("one"), pn_string("two"),
+ pn_string("three"), END);
+
+ REQUIRE(pn_list_size(l) == 3);
+
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_list_get(l, 0)), Equals("one"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_list_get(l, 1)), Equals("two"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_list_get(l, 2)), Equals("three"));
+ pn_free(l);
+}
+
+TEST_CASE("map_build") {
+ pn_map_t *m = build_map(0.75, 0, pn_string("key"), pn_string("value"),
+ pn_string("key2"), pn_string("value2"), END);
+
+ CHECK(pn_map_size(m) == 2);
+
+ pn_string_t *key = pn_string(NULL);
+
+ pn_string_set(key, "key");
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_map_get(m, key)), Equals("value"));
+ pn_string_set(key, "key2");
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_map_get(m, key)),
+ Equals("value2"));
+
+ pn_free(m);
+ pn_free(key);
+}
+
+TEST_CASE("map_build_odd") {
+ 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);
+
+ CHECK(pn_map_size(m) == 3);
+
+ pn_string_t *key = pn_string(NULL);
+
+ pn_string_set(key, "key");
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_map_get(m, key)), Equals("value"));
+ pn_string_set(key, "key2");
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_map_get(m, key)),
+ Equals("value2"));
+ pn_string_set(key, "key3");
+ CHECK(pn_map_get(m, key) == NULL);
+
+ pn_free(m);
+ pn_free(key);
+}
+
+TEST_CASE("map") {
+ 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);
+ CHECK(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");
+
+ CHECK(!pn_map_put(map, key, one));
+ CHECK(pn_map_size(map) == 1);
+ CHECK(!pn_map_put(map, key1, two));
+ CHECK(pn_map_size(map) == 2);
+ CHECK(!pn_map_put(map, key2, three));
+ CHECK(pn_map_size(map) == 3);
+
+ CHECK(pn_map_get(map, dup) == one);
+
+ CHECK(!pn_map_put(map, dup, one));
+ CHECK(pn_map_size(map) == 3);
+
+ CHECK(!pn_map_put(map, dup, two));
+ CHECK(pn_map_size(map) == 3);
+ CHECK(pn_map_get(map, dup) == two);
+
+ CHECK(pn_refcount(key) == 2);
+ CHECK(pn_refcount(dup) == 1);
+ CHECK(pn_refcount(key1) == 2);
+ CHECK(pn_refcount(key2) == 2);
+
+ CHECK(pn_refcount(one) == 1);
+ CHECK(pn_refcount(two) == 3);
+ CHECK(pn_refcount(three) == 2);
+
+ pn_map_del(map, key1);
+ CHECK(pn_map_size(map) == 2);
+
+ CHECK(pn_refcount(key) == 2);
+ CHECK(pn_refcount(dup) == 1);
+ CHECK(pn_refcount(key1) == 1);
+ CHECK(pn_refcount(key2) == 2);
+
+ CHECK(pn_refcount(one) == 1);
+ CHECK(pn_refcount(two) == 2);
+ CHECK(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);
+}
+
+TEST_CASE("hash") {
+ 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);
+
+ CHECK(pn_hash_get(hash, 2) == two);
+ CHECK(pn_hash_get(hash, 5) == two);
+ CHECK(pn_hash_get(hash, 18) == one);
+ CHECK(pn_hash_get(hash, 0) == NULL);
+
+ CHECK(pn_hash_size(hash) == 14);
+
+ pn_hash_del(hash, 5);
+ CHECK(pn_hash_get(hash, 5) == NULL);
+ CHECK(pn_hash_size(hash) == 13);
+ pn_hash_del(hash, 18);
+ CHECK(pn_hash_get(hash, 18) == NULL);
+ CHECK(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
+
+TEST_CASE("map_links") {
+ 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];
+ CHECK(pn_map_get(map, keys[i]) == value);
+ }
+ pn_free(map);
+ }
+ for (int i = 0; i < 3; i++) pn_free(keys[i]);
+}
+
+static void test_string(const char *value) {
+ size_t size = value ? strlen(value) : 0;
+
+ pn_string_t *str = pn_string(value);
+ CHECK_THAT(value, Equals(pn_string_get(str)));
+ CHECK(size == pn_string_size(str));
+
+ pn_string_t *strn = pn_stringn(value, size);
+ CHECK_THAT(value, Equals(pn_string_get(strn)));
+ CHECK(size == pn_string_size(strn));
+
+ pn_string_t *strset = pn_string(NULL);
+ pn_string_set(strset, value);
+ CHECK_THAT(value, Equals(pn_string_get(strset)));
+ CHECK(size == pn_string_size(strset));
+
+ pn_string_t *strsetn = pn_string(NULL);
+ pn_string_setn(strsetn, value, size);
+ CHECK_THAT(value, Equals(pn_string_get(strsetn)));
+ CHECK(size == pn_string_size(strsetn));
+
+ CHECK(pn_hashcode(str) == pn_hashcode(strn));
+ CHECK(pn_hashcode(str) == pn_hashcode(strset));
+ CHECK(pn_hashcode(str) == pn_hashcode(strsetn));
+
+ CHECK(!pn_compare(str, str));
+ CHECK(!pn_compare(str, strn));
+ CHECK(!pn_compare(str, strset));
+ CHECK(!pn_compare(str, strsetn));
+
+ pn_free(str);
+ pn_free(strn);
+ pn_free(strset);
+ pn_free(strsetn);
+}
+
+TEST_CASE("string_null") { test_string(NULL); }
+TEST_CASE("string_empty") { test_string(""); }
+TEST_CASE("string_simple") { test_string("this is a test"); }
+TEST_CASE("string_long") {
+ test_string(
+ "012345678910111213151617181920212223242526272829303132333435363"
+ "738394041424344454647484950515253545556575859606162636465666768");
+}
+
+TEST_CASE("string embedded null") {
+ const char value[] = "this has an embedded \000 in it";
+ size_t size = sizeof(value);
+
+ pn_string_t *strn = pn_stringn(value, size);
+ CHECK_THAT(value, Equals(pn_string_get(strn)));
+ CHECK(pn_string_size(strn) == size);
+
+ pn_string_t *strsetn = pn_string(NULL);
+ pn_string_setn(strsetn, value, size);
+ CHECK_THAT(value, Equals(pn_string_get(strsetn)));
+ CHECK(pn_string_size(strsetn) == size);
+
+ CHECK(pn_hashcode(strn) == pn_hashcode(strsetn));
+ CHECK(!pn_compare(strn, strsetn));
+
+ pn_free(strn);
+ pn_free(strsetn);
+}
+
+TEST_CASE("string_format") {
+ pn_string_t *str = pn_string("");
+ CHECK(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");
+ CHECK(err == 0);
+ pn_free(str);
+}
+
+TEST_CASE("string_addf") {
+ pn_string_t *str = pn_string("hello ");
+ CHECK(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");
+ CHECK(err == 0);
+ pn_free(str);
+}
+
+TEST_CASE("map_iteration") {
+ int n = 5;
+ 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);
+
+ CHECK(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);
+ CHECK(idx >= 0);
+
+ CHECK(pn_list_get(pairs, idx) == key);
+ CHECK(pn_list_get(pairs, idx + 1) == value);
+
+ pn_list_del(pairs, idx, 2);
+ }
+
+ CHECK(pn_list_size(pairs) == 0);
+
+ pn_decref(map);
+ pn_decref(pairs);
+}
+
+#define test_inspect(o, expected) \
+ do { \
+ pn_string_t *dst = pn_string(NULL); \
+ pn_inspect(o, dst); \
+ CHECK_THAT(expected, Equals(pn_string_get(dst))); \
+ pn_free(dst); \
+ } while (0)
+
+TEST_CASE("list_inspect") {
+ 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);
+}
+
+TEST_CASE("map_inspect") {
+ // 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);
+}
+
+TEST_CASE("map_coalesced_chain") {
+ 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]);
+ CHECK(pn_hash_size(map) == 8);
+
+ // free up one non-addressable entry:
+ pn_hash_del(map, 16);
+ CHECK(pn_hash_get(map, 16) == NULL);
+ CHECK(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);
+ CHECK(pn_hash_get(map, 4) == NULL);
+
+ // test lookup of all entries:
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 1)), Equals("a"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 2)), Equals("b"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 3)), Equals("c"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 14)), Equals("d"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 15)), Equals("e"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 17)), Equals("h"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 12)), Equals("i"));
+ CHECK(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));
+ }
+ CHECK(pn_hash_size(map) == 0);
+
+ for (size_t i = 0; i < 9; ++i) {
+ pn_free(values[i]);
+ }
+ pn_free(map);
+}
+
+TEST_CASE("map_coalesced_chain2") {
+ 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);
+ CHECK(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
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 12)), Equals("h"));
+ // delete from tail of coalesced chain:
+ pn_hash_del(map, 12);
+ CHECK(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:
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 29)), Equals("g"));
+ pn_hash_del(map, 29);
+
+ // test lookup of all entries:
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 1)), Equals("a"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 2)), Equals("b"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 3)), Equals("c"));
+ // d was deleted
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 15)), Equals("e"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 16)), Equals("f"));
+ // g was deleted, h was deleted
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 42)), Equals("i"));
+ CHECK_THAT(pn_string_get((pn_string_t *)pn_hash_get(map, 25)), Equals("j"));
+ CHECK(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));
+ }
+ CHECK(pn_hash_size(map) == 0);
+
+ for (size_t i = 0; i < 10; ++i) {
+ pn_free(values[i]);
+ }
+ pn_free(map);
+}
+
+TEST_CASE("list_compare") {
+ pn_list_t *a = pn_list(PN_OBJECT, 0);
+ pn_list_t *b = pn_list(PN_OBJECT, 0);
+
+ CHECK(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);
+ CHECK(!pn_equals(a, b));
+ pn_list_add(b, one);
+ CHECK(pn_equals(a, b));
+
+ pn_list_add(b, two);
+ CHECK(!pn_equals(a, b));
+ pn_list_add(a, two);
+ CHECK(pn_equals(a, b));
+
+ pn_list_add(a, three);
+ CHECK(!pn_equals(a, b));
+ pn_list_add(b, three);
+ CHECK(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;
+ }
+}
+
+TEST_CASE("list_iterator") {
+ 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))) {
+ CHECK(obj == pn_list_get(list, index));
+ ++index;
+ }
+ CHECK(index == 4);
+
+ pn_free(list);
+ pn_free(it);
+}
+
+TEST_CASE("list_heap") {
+ int size = 64;
+ 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);
+ CHECK(prev == min);
+ CHECK(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);
+ CHECK(r >= prev);
+ prev = r;
+ count++;
+ }
+ CHECK(count == size - 1);
+ CHECK(prev == max);
+
+ pn_free(list);
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0bdba37d/c/tests/parse-url.c
----------------------------------------------------------------------
diff --git a/c/tests/parse-url.c b/c/tests/parse-url.c
deleted file mode 100644
index ea5abc3..0000000
--- a/c/tests/parse-url.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-#define PN_USE_DEPRECATED_API 1
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "proton/type_compat.h"
-#include "proton/error.h"
-#include "proton/url.h"
-
-static bool verify(const char* what, const char* want, const char* got) {
- bool eq = (want == got || (want && got && strcmp(want, got) == 0));
- if (!eq) printf(" %s: '%s' != '%s'\n", what, want, got);
- return eq;
-}
-
-static bool test(const char* url, const char* scheme, const char* user, const char* pass, const char* host, const char* port, const char*path)
-{
- pn_url_t *purl = pn_url_parse(url);
- bool ok =
- verify("scheme", scheme, pn_url_get_scheme(purl)) &&
- verify("user", user, pn_url_get_username(purl)) &&
- verify("pass", pass, pn_url_get_password(purl)) &&
- verify("host", host, pn_url_get_host(purl)) &&
- verify("port", port, pn_url_get_port(purl)) &&
- verify("path", path, pn_url_get_path(purl));
- pn_url_free(purl);
- return ok;
-}
-
-// Run test and additionally verify the round trip of parse and stringify
-// matches original string.
-static bool testrt(const char* url, const char* scheme, const char* user, const char* pass, const char* host, const char* port, const char*path)
-{
- bool ok = test(url, scheme, user, pass, host, port, path);
- pn_url_t *purl = pn_url_parse(url);
- ok = ok && verify("url", url, pn_url_str(purl));
- pn_url_free(purl);
- return ok;
-}
-
-#define TEST(EXPR) \
- do { if (!(EXPR)) { printf("%s:%d: %s\n\n", __FILE__, __LINE__, #EXPR); failed++; } } while(0)
-
-int main(int argc, char **argv)
-{
- int failed = 0;
- TEST(testrt("/Foo.bar:90087@somewhere", 0, 0, 0, 0, 0, "Foo.bar:90087@somewhere"));
- TEST(testrt("host", 0, 0, 0, "host", 0, 0));
- TEST(testrt("host:423", 0, 0, 0, "host", "423", 0));
- TEST(testrt("user@host", 0, "user", 0, "host", 0, 0));
-
- // Can't round-trip passwords with ':', not strictly legal but the parser allows it.
- TEST(test("user:1243^&^:pw@host:423", 0, "user", "1243^&^:pw", "host", "423", 0));
- TEST(test("user:1243^&^:pw@host:423/Foo.bar:90087", 0, "user", "1243^&^:pw", "host", "423", "Foo.bar:90087"));
- TEST(test("user:1243^&^:pw@host:423/Foo.bar:90087@somewhere", 0, "user", "1243^&^:pw", "host", "423", "Foo.bar:90087@somewhere"));
-
- TEST(testrt("[::1]", 0, 0, 0, "::1", 0, 0));
- TEST(testrt("[::1]:amqp", 0, 0, 0, "::1", "amqp", 0));
- TEST(testrt("user@[::1]", 0, "user", 0, "::1", 0, 0));
- TEST(testrt("user@[::1]:amqp", 0, "user", 0, "::1", "amqp", 0));
-
- // Can't round-trip passwords with ':', not strictly legal but the parser allows it.
- TEST(test("user:1243^&^:pw@[::1]:amqp", 0, "user", "1243^&^:pw", "::1", "amqp", 0));
- TEST(test("user:1243^&^:pw@[::1]:amqp/Foo.bar:90087", 0, "user", "1243^&^:pw", "::1", "amqp", "Foo.bar:90087"));
- TEST(test("user:1243^&^:pw@[::1:amqp/Foo.bar:90087", 0, "user", "1243^&^:pw", "[::1", "amqp", "Foo.bar:90087"));
- TEST(test("user:1243^&^:pw@::1]:amqp/Foo.bar:90087", 0, "user", "1243^&^:pw", "::1]", "amqp", "Foo.bar:90087"));
-
- TEST(testrt("amqp://user@[::1]", "amqp", "user", 0, "::1", 0, 0));
- TEST(testrt("amqp://user@[::1]:amqp", "amqp", "user", 0, "::1", "amqp", 0));
- TEST(testrt("amqp://user@[1234:52:0:1260:f2de:f1ff:fe59:8f87]:amqp", "amqp", "user", 0, "1234:52:0:1260:f2de:f1ff:fe59:8f87", "amqp", 0));
-
- // Can't round-trip passwords with ':', not strictly legal but the parser allows it.
- TEST(test("amqp://user:1243^&^:pw@[::1]:amqp", "amqp", "user", "1243^&^:pw", "::1", "amqp", 0));
- TEST(test("amqp://user:1243^&^:pw@[::1]:amqp/Foo.bar:90087", "amqp", "user", "1243^&^:pw", "::1", "amqp", "Foo.bar:90087"));
-
- TEST(testrt("amqp://host", "amqp", 0, 0, "host", 0, 0));
- TEST(testrt("amqp://user@host", "amqp", "user", 0, "host", 0, 0));
- TEST(testrt("amqp://user@host/path:%", "amqp", "user", 0, "host", 0, "path:%"));
- TEST(testrt("amqp://user@host:5674/path:%", "amqp", "user", 0, "host", "5674", "path:%"));
- TEST(testrt("amqp://user@host/path:%", "amqp", "user", 0, "host", 0, "path:%"));
- TEST(testrt("amqp://bigbird@host/queue@host", "amqp", "bigbird", 0, "host", 0, "queue@host"));
- TEST(testrt("amqp://host/queue@host", "amqp", 0, 0, "host", 0, "queue@host"));
- TEST(testrt("amqp://host:9765/queue@host", "amqp", 0, 0, "host", "9765", "queue@host"));
- TEST(test("user:pass%2fword@host", 0, "user", "pass/word", "host", 0, 0));
- TEST(testrt("user:pass%2Fword@host", 0, "user", "pass/word", "host", 0, 0));
- // Can't round-trip passwords with lowercase hex encoding
- TEST(test("us%2fer:password@host", 0, "us/er", "password", "host", 0, 0));
- TEST(testrt("us%2Fer:password@host", 0, "us/er", "password", "host", 0, 0));
- // Can't round-trip passwords with lowercase hex encoding
- TEST(test("user:pass%2fword%@host", 0, "user", "pass/word%", "host", 0, 0));
- TEST(testrt("localhost/temp-queue://ID:ganymede-36663-1408448359876-2:123:0", 0, 0, 0, "localhost", 0, "temp-queue://ID:ganymede-36663-1408448359876-2:123:0"));
- TEST(testrt("/temp-queue://ID:ganymede-36663-1408448359876-2:123:0", 0, 0, 0, 0, 0, "temp-queue://ID:ganymede-36663-1408448359876-2:123:0"));
- TEST(testrt("amqp://localhost/temp-queue://ID:ganymede-36663-1408448359876-2:123:0", "amqp", 0, 0, "localhost", 0, "temp-queue://ID:ganymede-36663-1408448359876-2:123:0"));
- // PROTON-995
- TEST(testrt("amqps://%40user%2F%3A:%40pass%2F%3A@example.net/some_topic",
- "amqps", "@user/:", "@pass/:", "example.net", 0, "some_topic"));
- TEST(testrt("amqps://user%2F%3A=:pass%2F%3A=@example.net/some_topic",
- "amqps", "user/:=", "pass/:=", "example.net", 0, "some_topic"));
- // Really perverse url
- TEST(testrt("://:@://:", "", "", "", 0, "", "/:"));
- return failed;
-}
-
-#undef PN_USE_DEPRECATED_API
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0bdba37d/c/tests/pn_test.cpp
----------------------------------------------------------------------
diff --git a/c/tests/pn_test.cpp b/c/tests/pn_test.cpp
new file mode 100644
index 0000000..e683898
--- /dev/null
+++ b/c/tests/pn_test.cpp
@@ -0,0 +1,217 @@
+/*
+ * 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 "./pn_test.hpp"
+
+#include <proton/condition.h>
+#include <proton/connection.h>
+#include <proton/delivery.h>
+#include <proton/event.h>
+#include <proton/link.h>
+#include <proton/message.h>
+#include <proton/netaddr.h>
+#include <proton/object.h>
+#include <proton/transport.h>
+
+std::ostream &operator<<(std::ostream &o, pn_event_type_t et) {
+ return o << pn_event_type_name(et);
+}
+
+inline std::ostream "e(std::ostream &o, const char *s) {
+ return s ? (o << '"' << s << '"') : (o << "null");
+}
+
+std::ostream &operator<<(std::ostream &o, const pn_condition_t &const_cond) {
+ pn_condition_t *cond = const_cast<pn_condition_t *>(&const_cond);
+ o << "pn_condition{";
+ if (pn_condition_is_set(cond)) {
+ quote(o, pn_condition_get_name(cond)) << ", ";
+ quote(o, pn_condition_get_description(cond));
+ }
+ o << "}";
+ return o;
+}
+
+std::ostream &operator<<(std::ostream &o, const pn_error_t &const_err) {
+ pn_error_t *err = const_cast<pn_error_t *>(&const_err);
+ o << "pn_error{" << pn_code(pn_error_code(err)) << ", ";
+ return quote(o, pn_error_text(err)) << "}";
+}
+
+namespace pn_test {
+
+std::string inspect(void *obj) {
+ auto_free<pn_string_t, pn_string_free> s(pn_string(NULL));
+ pn_inspect(obj, s);
+ return pn_string_get(s);
+}
+
+etypes make_etypes_(int first, ...) {
+ etypes v;
+ va_list ap;
+ va_start(ap, first);
+ for (int i = first; i >= 0; i = va_arg(ap, int)) {
+ v.push_back(static_cast<pn_event_type_t>(i));
+ }
+ va_end(ap);
+ return v;
+}
+
+std::ostream &operator<<(std::ostream &o, const etypes &et) {
+ return o << Catch::toString(static_cast<std::vector<pn_event_type_t> >(et));
+}
+
+pn_bytes_t pn_bytes(const std::string &s) {
+ return ::pn_bytes(s.size(), s.data());
+}
+
+void rwbytes_ensure(pn_rwbytes_t *buf, size_t size) {
+ if (buf->start == NULL || buf->size < size) {
+ buf->start = (char *)realloc(buf->start, size);
+ buf->size = size;
+ }
+}
+
+void message_decode(pn_message_t *m, pn_delivery_t *d, pn_rwbytes_t *buf) {
+ ssize_t size = pn_delivery_pending(d);
+ rwbytes_ensure(buf, size);
+ ssize_t result = pn_link_recv(pn_delivery_link(d), buf->start, size);
+ REQUIRE(size == result);
+ pn_message_clear(m);
+ if (pn_message_decode(m, buf->start, size)) FAIL(pn_message_error(m));
+}
+
+handler::handler()
+ : last_condition(pn_condition()), connection(), session(), link(), sender(),
+ receiver(), delivery(), message() {}
+
+bool handler::dispatch(pn_event_t *e) {
+ log.push_back(pn_event_type(e));
+ if (pn_event_condition(e)) {
+ pn_condition_copy(last_condition, pn_event_condition(e));
+ } else {
+ pn_condition_clear(last_condition);
+ }
+ return handle(e);
+}
+
+etypes handler::log_clear() {
+ etypes ret;
+ std::swap(ret, log);
+ return ret;
+}
+
+pn_event_type_t handler::log_last() {
+ pn_event_type_t et = log.empty() ? PN_EVENT_NONE : log.back();
+ log.clear();
+ return et;
+}
+
+driver::driver(struct handler &h) : handler(h) {
+ pn_connection_driver_init(this, NULL, NULL);
+}
+driver::~driver() { pn_connection_driver_destroy(this); }
+
+pn_event_type_t driver::run(pn_event_type_t stop) {
+ pn_event_t *e = NULL;
+ while ((e = pn_connection_driver_next_event(this))) {
+ pn_event_type_t et = pn_event_type(e);
+ if (handler.dispatch(e) || et == stop) return et;
+ }
+ return PN_EVENT_NONE;
+}
+
+driver_pair::driver_pair(handler &ch, handler &sh) : client(ch), server(sh) {
+ pn_transport_set_server(server.transport);
+}
+
+size_t driver::read(pn_connection_driver_t &src) {
+ pn_bytes_t wb = pn_connection_driver_write_buffer(&src);
+ pn_rwbytes_t rb = pn_connection_driver_read_buffer(this);
+ size_t size = rb.size < wb.size ? rb.size : wb.size;
+ if (size) {
+ std::copy(wb.start, wb.start + size, rb.start);
+ pn_connection_driver_write_done(&src, size);
+ pn_connection_driver_read_done(this, size);
+ }
+ return size;
+}
+
+pn_event_type_t driver_pair::run() {
+ pn_connection_open(client.connection); // Make sure it is open
+ size_t n = 0;
+ do {
+ pn_event_type_t et = PN_EVENT_NONE;
+ if ((et = client.run())) return et;
+ if ((et = server.run())) return et;
+ n = client.read(server) + server.read(client);
+ } while (n || pn_connection_driver_has_event(&client) ||
+ pn_connection_driver_has_event(&server));
+ return PN_EVENT_NONE;
+}
+
+std::string cond_empty::describe() const { return "is empty"; }
+
+bool cond_empty::match(const pn_condition_t &cond) const {
+ return !pn_condition_is_set(const_cast<pn_condition_t *>(&cond));
+}
+
+cond_matches::cond_matches(const std::string &name, const std::string &desc)
+ : name_(name), desc_(desc) {}
+
+std::string cond_matches::describe() const {
+ std::ostringstream o;
+ o << "matches " << Catch::toString(name_);
+ if (!desc_.empty()) o << ", " + Catch::toString(desc_);
+ return o.str();
+}
+
+bool cond_matches::match(const pn_condition_t &const_cond) const {
+ pn_condition_t *cond = const_cast<pn_condition_t *>(&const_cond);
+ const char *name = pn_condition_get_name(cond);
+ const char *desc = pn_condition_get_description(cond);
+ return pn_condition_is_set(cond) && name && name_ == name &&
+ (desc_.empty() || (desc && Catch::contains(desc, desc_)));
+}
+
+std::string error_empty::describe() const { return "is empty"; }
+
+bool error_empty::match(const pn_error_t &err) const {
+ return !pn_error_code(const_cast<pn_error_t *>(&err));
+}
+
+error_matches::error_matches(int code, const std::string &desc)
+ : code_(code), desc_(desc) {}
+
+std::string error_matches::describe() const {
+ std::ostringstream o;
+ o << "matches " << pn_code(code_);
+ if (!desc_.empty()) o << ", " + Catch::toString(desc_);
+ return o.str();
+}
+
+bool error_matches::match(const pn_error_t &const_err) const {
+ pn_error_t *err = const_cast<pn_error_t *>(&const_err);
+ int code = pn_error_code(err);
+ const char *desc = pn_error_text(err);
+ return code_ == code &&
+ (desc_.empty() || (desc && Catch::contains(desc, desc_)));
+}
+
+} // namespace pn_test
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0bdba37d/c/tests/pn_test.hpp
----------------------------------------------------------------------
diff --git a/c/tests/pn_test.hpp b/c/tests/pn_test.hpp
new file mode 100644
index 0000000..bbfa3d5
--- /dev/null
+++ b/c/tests/pn_test.hpp
@@ -0,0 +1,193 @@
+#ifndef TESTS_PN_TEST_HPP
+#define TESTS_PN_TEST_HPP
+/*
+ * 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.
+ */
+
+/// @file
+///
+/// Wrappers and Catch2 extensions to simplify testing the proton-C library.
+
+#include <catch_extra.hpp>
+
+#include <proton/condition.h>
+#include <proton/connection_driver.h>
+#include <proton/event.h>
+#include <proton/message.h>
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+// String form of C pn_ types used in tests, must be in global C namespace
+// Note objects are passed by reference, not pointer.
+std::ostream &operator<<(std::ostream &, pn_event_type_t);
+std::ostream &operator<<(std::ostream &, const pn_condition_t &);
+std::ostream &operator<<(std::ostream &, const pn_error_t &);
+
+namespace pn_test {
+
+// Holder for T*, calls function Free() in dtor. Not copyable.
+template <class T, void (*Free)(T *)> class auto_free {
+ T *ptr_;
+ auto_free &operator=(auto_free &x);
+ auto_free(auto_free &x);
+
+public:
+ auto_free(T *p = 0) : ptr_(p) {}
+ ~auto_free() { Free(ptr_); }
+ T *get() const { return ptr_; }
+ operator T *() const { return ptr_; }
+};
+
+// pn_free() works for some, but not all pn_xxx_t* types.
+// Add typed pn_string_free() so we can be consistent and safe.
+inline void pn_string_free(pn_string_t *s) { pn_free(s); }
+
+// Call pn_inspect(), return std::string
+std::string inspect(void *);
+
+// List of pn_event_type_t
+typedef std::vector<pn_event_type_t> etypes;
+std::ostream &operator<<(std::ostream &o, const etypes &et);
+
+// Workaround for lack of list initializers in C++03.
+// Use ETYPES macro, don't call make_etypes_ directly
+etypes make_etypes_(int first, ...);
+#define ETYPES(...) (make_etypes_(__VA_ARGS__, -1))
+
+/// Make a pn_bytes_t from a std::string
+pn_bytes_t pn_bytes(const std::string &s);
+
+/// Ensure buf has at least size bytes, use realloc if need be
+void rwbytes_ensure(pn_rwbytes_t *buf, size_t size);
+
+/// Decode message from delivery into buf, expand buf as needed.
+void message_decode(pn_message_t *m, pn_delivery_t *d, pn_rwbytes_t *buf);
+
+// A test handler that logs the type of each event handled, and has
+// slots to store all of the basic proton types for ad-hoc use in
+// tests. Subclass and override the handle() method.
+struct handler {
+ etypes log; // Log of events
+ auto_free<pn_condition_t, pn_condition_free>
+ last_condition; // Condition of last event
+
+ // Slots to save proton objects for use outside the handler.
+ pn_listener_t *listener;
+ pn_connection_t *connection;
+ pn_session_t *session;
+ pn_link_t *link;
+ pn_link_t *sender;
+ pn_link_t *receiver;
+ pn_delivery_t *delivery;
+ pn_message_t *message;
+
+ handler();
+
+ /// dispatch an event: log its type then call handle()
+ /// Returns the value of handle()
+ bool dispatch(pn_event_t *e);
+
+ // Return the current log contents, clear the log.
+ etypes log_clear();
+
+ // Return the last event in the log, clear the log.
+ pn_event_type_t log_last();
+
+protected:
+ // Override this function to handle events.
+ //
+ // Return true to stop dispatching and return control to the test function,
+ // false to continue processing.
+ virtual bool handle(pn_event_t *e) { return false; }
+};
+
+// A pn_connection_driver_t that dispatches to a pn_test::handler
+//
+// driver::run() dispatches events to the handler, but returns if the handler
+// returns true, or if a specific event type is handled. Test functions can
+// alternate between letting the handler run and checking state or calling
+// functions on proton objects in the test function directly. Handlers can
+// automate uninteresting work, the test function can make checks that are
+// clearly located in the flow of the test logic.
+struct driver : public ::pn_connection_driver_t {
+ struct handler &handler;
+
+ driver(struct handler &h);
+ ~driver();
+
+ // Dispatch events till a handler returns true, the `stop` event is handled,
+ // or there are no more events
+ // Returns the last event handled or PN_EVENT_NONE if none were.
+ pn_event_type_t run(pn_event_type_t stop = PN_EVENT_NONE);
+
+ // Transfer available data from src write buffer to this read-buffer and
+ // update both drivers. Return size of data transferred.
+ size_t read(pn_connection_driver_t &src);
+};
+
+// A client/server pair drivers. run() simulates a connection in memory.
+struct driver_pair {
+ driver client, server;
+
+ // Associate handlers with drivers. Sets server.transport to server mode
+ driver_pair(handler &ch, handler &sh);
+
+ // Run the drivers until a handle returns true or there is nothing left to
+ // do. Opens the client.connection() if not already open.
+ // Return the last event handled or PN_EVENT_NONE
+ pn_event_type_t run();
+};
+
+// Matches for use with Catch macros CHECK_THAT and REQUIRE_THAT.
+// Check pn_condition_t and pn_error_t, failed checks report code, name,
+// description etc.
+
+struct cond_empty : public Catch::MatcherBase<pn_condition_t> {
+ std::string describe() const CATCH_OVERRIDE;
+ bool match(const pn_condition_t &cond) const CATCH_OVERRIDE;
+};
+
+class cond_matches : public Catch::MatcherBase<pn_condition_t> {
+ std::string name_, desc_;
+
+public:
+ cond_matches(const std::string &name, const std::string &desc_contains = "");
+ std::string describe() const CATCH_OVERRIDE;
+ bool match(const pn_condition_t &cond) const CATCH_OVERRIDE;
+};
+
+struct error_empty : public Catch::MatcherBase<pn_error_t> {
+ std::string describe() const CATCH_OVERRIDE;
+ bool match(const pn_error_t &) const CATCH_OVERRIDE;
+};
+
+class error_matches : public Catch::MatcherBase<pn_error_t> {
+ int code_;
+ std::string desc_;
+
+public:
+ error_matches(int code, const std::string &desc_contains = "");
+ std::string describe() const CATCH_OVERRIDE;
+ bool match(const pn_error_t &) const CATCH_OVERRIDE;
+};
+
+} // namespace pn_test
+
+#endif // TESTS_PN_TEST_HPP
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org