aboutsummaryrefslogtreecommitdiffstats
path: root/libparc/parc/testing
diff options
context:
space:
mode:
Diffstat (limited to 'libparc/parc/testing')
-rwxr-xr-xlibparc/parc/testing/parc_MemoryTesting.c44
-rwxr-xr-xlibparc/parc/testing/parc_MemoryTesting.h47
-rw-r--r--libparc/parc/testing/parc_ObjectTesting.c266
-rw-r--r--libparc/parc/testing/parc_ObjectTesting.h253
-rw-r--r--libparc/parc/testing/test/.gitignore2
-rw-r--r--libparc/parc/testing/test/CMakeLists.txt12
-rwxr-xr-xlibparc/parc/testing/test/test_parc_MemoryTesting.c86
-rwxr-xr-xlibparc/parc/testing/test/test_parc_ObjectTesting.c543
8 files changed, 1253 insertions, 0 deletions
diff --git a/libparc/parc/testing/parc_MemoryTesting.c b/libparc/parc/testing/parc_MemoryTesting.c
new file mode 100755
index 00000000..9a7b49fa
--- /dev/null
+++ b/libparc/parc/testing/parc_MemoryTesting.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed 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 <config.h>
+
+#include <stdio.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/algol/parc_Memory.h>
+
+bool
+parcMemoryTesting_ExpectedOutstanding(const uint32_t expected, const char *format, ...)
+{
+ bool result = true;
+
+ int allocationsLeaked = parcMemory_Outstanding() - expected;
+ if (allocationsLeaked != 0) {
+ va_list ap;
+ va_start(ap, format);
+ vprintf(format, ap);
+ va_end(ap);
+ if (allocationsLeaked < 0) {
+ printf(" (%d more allocations deallocated than allocated)\n", -allocationsLeaked);
+ } else {
+ printf(" (%d allocations not deallocated)\n", allocationsLeaked);
+ }
+ result = false;
+ }
+
+ return result;
+}
diff --git a/libparc/parc/testing/parc_MemoryTesting.h b/libparc/parc/testing/parc_MemoryTesting.h
new file mode 100755
index 00000000..32b139db
--- /dev/null
+++ b/libparc/parc/testing/parc_MemoryTesting.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed 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 parc_TestingMemory.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef PARC_Library_parc_TestingMemory_h
+#define PARC_Library_parc_TestingMemory_h
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+/**
+ * Determine if the current number of memory allocations is equal to the specified number.
+ *
+ * @param [in] expected The expected number of outstanding allocations.
+ *
+ * @return true The expected number of outstanding allocations is equal to the actual outstanding allocations.
+ *
+ * Example:
+ * @code
+ * {
+ * parcMemoryTesting_ExpectedOutstanding(0, "%s memory leak", __func__);
+ * }
+ * @endcode
+ */
+bool parcMemoryTesting_ExpectedOutstanding(const uint32_t expected, const char *format, ...);
+#endif
diff --git a/libparc/parc/testing/parc_ObjectTesting.c b/libparc/parc/testing/parc_ObjectTesting.c
new file mode 100644
index 00000000..03fe2222
--- /dev/null
+++ b/libparc/parc/testing/parc_ObjectTesting.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed 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 <config.h>
+#include <LongBow/runtime.h>
+#include <inttypes.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Memory.h>
+
+void
+parcObjectTesting_AssertAcquireReleaseContractImpl(void *(acquireFunction)(const PARCObject *), const PARCObject *instance)
+{
+ void *reference = acquireFunction(instance);
+ assertTrue(reference == instance, "Expected the acquire function to return the same instance pointer.");
+ parcObject_Release(&reference);
+ parcObjectTesting_AssertAcquireReleaseImpl(instance);
+}
+
+void
+parcObjectTesting_AssertAcquireReleaseImpl(const PARCObject *instance)
+{
+ PARCReferenceCount originalReferences = parcObject_GetReferenceCount(instance);
+
+ PARCObject *newReference = parcObject_Acquire(instance);
+
+ assertTrue(newReference == instance, "Expected the acquire function to return the same instance pointer.");
+
+ PARCReferenceCount currentReferences = parcObject_GetReferenceCount(instance);
+ assertTrue(currentReferences == (originalReferences + 1),
+ "Expected references to be %" PRIu64 ", actual %" PRIu64, (originalReferences + 1), currentReferences);
+
+ parcObject_Release(&newReference);
+ currentReferences = parcObject_GetReferenceCount(instance);
+ assertTrue(currentReferences == originalReferences,
+ "Expected references to be %" PRIu64 ", actual %" PRIu64, originalReferences, currentReferences);
+}
+
+static void
+_parcObjectTesting_AssertEquals(bool (*equalsFunction)(const void *a, const void *b), const void *x, const void *y, const void *z, va_list ap)
+{
+ assertNotNull(x, "The value of x cannot be NULL.");
+ assertNotNull(y, "The value of y cannot be NULL.");
+ assertNotNull(z, "The value of z cannot be NULL.");
+
+ assertFalse(x == y, "The value x cannot be the same as y");
+ assertFalse(x == z, "The value x cannot be the same as z");
+ assertFalse(y == z, "The value y cannot be the same as z");
+
+ assertTrue(equalsFunction(NULL, NULL), "Equality failed: Equals(NULL, NULL) must be true");
+
+ assertFalse(equalsFunction(x, NULL), "Equality failed: The value of x must not be Equal to NULL.");
+ assertFalse(equalsFunction(NULL, x), "Equality failed: NULL must not be equal to the value of x.");
+
+ assertTrue(equalsFunction(x, x), "Reflexive failed: for any non-null reference value x, equals(x, x) must return true.");
+
+ assertTrue(equalsFunction(x, y), "Equality failed: The values of x and y must be Equal.");
+ assertTrue(equalsFunction(x, z), "Equality failed: The values of x and z must be Equal.");
+
+ assertTrue(equalsFunction(x, y) == equalsFunction(y, x), "Symmetric equality failed: equals(x, y) == equals(y, x) must true.");
+
+ assertTrue((equalsFunction(x, y) == equalsFunction(y, z)) == equalsFunction(z, x),
+ "Transitive equality failed: equals(x, y) == equals(y, z) == equals(z, x) must true.");
+
+ int index = 0;
+ for (void *value = va_arg(ap, void *); value != 0; value = va_arg(ap, void *)) {
+ assertFalse(equalsFunction(x, value), "Value %d (@%p) must not be equal to x", index, value);
+ assertTrue(equalsFunction(x, value) == equalsFunction(value, x),
+ "Symmetric equality failed: equals(x, value) == equals(value, x) must true.");
+ index++;
+ }
+}
+
+void
+parcObjectTesting_AssertEquals(const PARCObject *x, const void *y, const void *z, ...)
+{
+ va_list ap;
+ va_start(ap, z);
+
+ _parcObjectTesting_AssertEquals((bool (*)(const void *, const void *))parcObject_Equals, x, y, z, ap);
+
+ assertTrue(parcObject_HashCode(x) == parcObject_HashCode(y),
+ "HashCode of x and y must be equal");
+ assertTrue(parcObject_HashCode(x) == parcObject_HashCode(z),
+ "HashCode of x and z must be equal");
+
+ va_end(ap);
+}
+
+void
+parcObjectTesting_AssertEqualsFunctionImpl(bool (*equalsFunction)(const void *a, const void *b), const void *x, const void *y, const void *z, ...)
+{
+ va_list ap;
+ va_start(ap, z);
+ _parcObjectTesting_AssertEquals(equalsFunction, x, y, z, ap);
+
+ va_end(ap);
+}
+
+bool
+parcObjectTesting_AssertCompareToImpl(int (*compareTo)(const void *a, const void *b),
+ const void *exemplar,
+ const void **equivalent,
+ const void **lesser,
+ const void **greater)
+{
+ assertNotNull(exemplar, "Parameter exemplar must not be NULL");
+ assertNotNull(equivalent, "Parameter equivalent must not be NULL");
+ assertNotNull(lesser, "Parameter less must not be NULL");
+ assertNotNull(greater, "Parameter greater must not be NULL");
+
+ assertTrue(compareTo(NULL, NULL) == 0, "Comparison of null values must be 0.");
+
+ assertTrue(compareTo(exemplar, NULL) > 0, "Comparison of a non-null value to a null value must be > 0.");
+
+ assertTrue(compareTo(NULL, exemplar) < 0, "Comparison of null value to a non-null value must be < 0.");
+
+ assertTrue(compareTo(exemplar, exemplar) == 0, "Comparison of a value to itself must == 0");
+
+ for (int i = 0; equivalent[i] != NULL; i++) {
+ assertTrue(compareTo(exemplar, equivalent[i]) == 0,
+ "Comparison of the value to equivalent[%d] must == 0", i);
+ assertTrue(compareTo(exemplar, equivalent[i]) == -compareTo(equivalent[i], exemplar),
+ "Requires sgn(compareTo(value, equivalent[%d])) == -sgn(equivalent[%d], value)", i, i);
+ }
+ for (int i = 0; lesser[i] != NULL; i++) {
+ assertTrue(compareTo(exemplar, lesser[i]) > 0,
+ "Compare of value to lesser[%d] must be > 0", i);
+ assertTrue(compareTo(exemplar, lesser[i]) == -compareTo(lesser[i], exemplar),
+ "Requires signum(compareTo(value, lesser[%d])) == -signum(lesser[%d], value)", i, i);
+ }
+ for (int i = 0; greater[i] != NULL; i++) {
+ assertTrue(compareTo(exemplar, greater[i]) < 0, "Compare to greater[%d] must be > 0", i);
+ assertTrue(compareTo(exemplar, greater[i]) == -compareTo(greater[i], exemplar),
+ "Requires compareTo(value, greater[%d]) == -compareTo(greater[%d], value)", i, i);
+ }
+
+ return true;
+}
+
+void
+parcObjectTesting_AssertHashCode(const PARCObject *x, const void *y)
+{
+ assertFalse(x == y, "The parameters x and y cannot be the same value.");
+ assertTrue(parcObject_Equals(x, y), "The parameters x and y must be equal");
+
+ PARCHashCode xCode = parcObject_HashCode(x);
+ PARCHashCode yCode = parcObject_HashCode(y);
+
+ assertTrue(xCode == yCode, "Expected the HashCode of two equal objects to be equal.");
+}
+
+void
+parcObjectTesting_AssertHashCodeImpl(PARCHashCode (*hashCode)(const void *a), void *a)
+{
+ PARCHashCode code1 = hashCode(a);
+ PARCHashCode code2 = hashCode(a);
+ assertTrue(code1 == code2, "HashCode function does not consistently return the same value.");
+}
+
+static void
+_parcObjectTesting_AssertCopy(const PARCObject *instance)
+{
+ PARCObject *copy = parcObject_Copy(instance);
+ if (copy == instance) {
+ parcObject_Release(&copy);
+ assertFalse(true, "Copy should not be the same object");
+ }
+ if (!parcObject_Equals(instance, copy)) {
+ parcObject_Release(&copy);
+ assertTrue(false, "Object fails Copy Test");
+ }
+
+ parcObject_Release(&copy);
+}
+
+static void
+_parcObjectTesting_AssertEqualsWrapper(const PARCObject *a,
+ const PARCObject *b,
+ const PARCObject *c,
+ ...)
+{
+ va_list ap;
+ va_start(ap, c);
+
+ _parcObjectTesting_AssertEquals((bool (*)(const void *, const void *))parcObject_Equals, a, b, c, ap);
+
+ va_end(ap);
+}
+
+static void
+_parcObjectTesting_AssertToJSON(const PARCObject *instance)
+{
+ PARCJSON *json = parcObject_ToJSON(instance);
+ char *result = parcJSON_ToString(json);
+ assertNotNull(result, "Something should be returned");
+ parcMemory_Deallocate(&result);
+ parcJSON_Release(&json);
+}
+
+static void
+_parcObjectTesting_AssertToString(const PARCObject *instance)
+{
+ char *result = parcObject_ToString(instance);
+ assertNotNull(result, "Something should be returned");
+ parcMemory_Deallocate(&result);
+}
+
+void
+parcObjectTesting_AssertObjectConformance(const PARCObject *inst1,
+ const PARCObject *inst2,
+ const PARCObject *inst3,
+ const PARCObject *lesser,
+ const PARCObject *greater)
+{
+ assertNotNull(inst1, "The value of x cannot be NULL.");
+ assertNotNull(inst2, "The value of y cannot be NULL.");
+ assertNotNull(inst3, "The value of z cannot be NULL.");
+ assertNotNull(lesser, "The value of z cannot be NULL.");
+ assertNotNull(greater, "The value of z cannot be NULL.");
+
+ parcObject_AssertValid(inst1);
+ parcObject_AssertValid(inst2);
+ parcObject_AssertValid(inst3);
+ parcObject_AssertValid(lesser);
+ parcObject_AssertValid(greater);
+
+ // Acquire/Release
+ parcObjectTesting_AssertAcquireReleaseImpl(inst1);
+
+ // Equals
+ _parcObjectTesting_AssertEqualsWrapper(inst1, inst2, inst3, lesser, greater, NULL);
+
+ // Copy
+ _parcObjectTesting_AssertCopy(inst1);
+
+ // Compare
+ const void *equals[] = { inst1, inst2, NULL };
+ const void *lessThan[] = { lesser, NULL };
+ const void *greaterThan[] = { greater, NULL };
+ parcObjectTesting_AssertCompareToImpl(parcObject_Compare, inst1, equals, lessThan, greaterThan);
+
+ // HashCode
+ parcObjectTesting_AssertHashCode(inst1, inst2);
+
+ // ToJSON
+ _parcObjectTesting_AssertToJSON(inst1);
+
+ // ToString
+ _parcObjectTesting_AssertToString(inst1);
+}
diff --git a/libparc/parc/testing/parc_ObjectTesting.h b/libparc/parc/testing/parc_ObjectTesting.h
new file mode 100644
index 00000000..557fee10
--- /dev/null
+++ b/libparc/parc/testing/parc_ObjectTesting.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed 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 parc_ObjectTesting.h
+ * @brief Support for LongBow runtime and unit testing of PARCObject implementations.
+ *
+ */
+#ifndef PARC_Library_parc_ObjectTest_h
+#define PARC_Library_parc_ObjectTest_h
+
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_HashCode.h>
+
+/**
+ * Test if a PARCObject subclass behaves well as a PARCObject when passed to the various PARCObject functions.
+ *
+ * @param [in] inst1 A pointer to an instance that will be used as the base comparison for remaining parameters.
+ * @param [in] inst2 A pointer to an instance that is known to be equal to @p inst1, but is not @p inst1.
+ * @param [in] inst3 A pointer to an instance that is known to be equal to @p inst1 & @p inst2, but is not @p inst1 or @p inst2.
+ * @param [in] lesser A pointer to and instance that are known to be lesser than @p inst1.
+ * @param [in] greater A pointer to and instance that are known to be greater than @p inst1.
+ *
+ * @see parcObjectTesting_AssertEqualsFunction
+ * @see parcObjectTesting_AssertCompareTo
+ * @see parcObjectTesting_AssertAcquire
+ * @see parcObjectTesting_AssertHashCode
+ */
+
+void parcObjectTesting_AssertObjectConformance(const PARCObject *inst1,
+ const PARCObject *inst2,
+ const PARCObject *inst3,
+ const PARCObject *lesser,
+ const PARCObject *greater);
+
+/**
+ * Ensure that a function implements the Equals contract.
+ *
+ * The equality function must implement the following equivalence relations on non-null instances:
+ *
+ * * It is reflexive: for any non-null reference value x, equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, equals(x, y) must return true if and only if
+ * equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * equals(x, y) returns true and
+ * equals(y, z) returns true,
+ * then equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, equals(x, NULL)) must return false.
+ *
+ * @param [in] _function_ A pointer to a function that will be called to determine if it conforms to the Equals contract.
+ * @param [in] _x_ A pointer to a value that will be used as the base comparison for remaining parameters.
+ * @param [in] _y_ A pointer to a value that is known to be equal to @p x, but is not @p x.
+ * @param [in] _z_ A pointer to a value that is known to be equal to @p x and to @p y, but is neither @p x nor @p y.
+ * @param [in] ... A list of pointers to values that are known to be not equal to @p x, @p y, or @p z.
+ * @see parcObjectTesting_AssertEqualsImpl
+ */
+#define parcObjectTesting_AssertEqualsFunction(_function_, _x_, _y_, _z_, ...) \
+ parcObjectTesting_AssertEqualsFunctionImpl((bool (*)(const void *, const void *))_function_, _x_, _y_, _z_, __VA_ARGS__, NULL)
+
+/**
+ * Compares instance a known set of other instances for order.
+ *
+ * The comparison function that this evaluates <i>sgn(a - b)</i> required to return a negative integer,
+ * zero, or a positive integer as <code>a</code> is less than,
+ * equal to, or greater than <code>b</code>.
+ *
+ * The function must ensure that:
+ * <ul>
+ * <li>sgn(compareTo(a, b)) == -sgn(b, a) for all values of a and b.</li>
+ * <li>the relation is transitive: (compareTo(x, y)>0 && compareTo(y, z)>0) implies compareTo(x, z)>0.</li>
+ * <li>compareTo(x, y)== 0 implies that sgn(compareTo(x, z)) == sgn(compareTo(y, z)), for all values of z.</li>
+ * </ul>
+ *
+ * This also stipulates that
+ * <code>compareTo(NULL, NULL)) == 0</code>,
+ * <code>compareTo(not-NULL, NULL)) > 0</code>,
+ * <code>compareTo(NULL, not-NULL)) < 0</code>.
+ *
+ * It is strongly recommended, but not strictly required that relation(compareTo(x, y)==0) == equals(x, y)) is true.
+ * Any module that implements the compareTo function and violates this condition
+ * should clearly indicate this fact.
+ * For example, "Note: this implementation has a natural ordering that is inconsistent with equals."
+ *
+ * @param [in] compareTo A pointer to a function implementing the CompareTo function signature.
+ * @param [in] exemplar The pivotal value under test.
+ * @param [in] equivalent A NULL terminated array of values that are all equivalent to <code>value</code>.
+ * @param [in] lesser A NULL terminated array of values that are all less than <code>value</code>.
+ * @param [in] greater A NULL terminated array of values that are all greater than <code>value</code>.
+ * @see parcObjectTesting_AssertCompareTo
+ */
+#define parcObjectTesting_AssertCompareTo(function, value, equality, lesser, greater) \
+ parcObjectTesting_AssertCompareToImpl((int (*)(const void *, const void *))function, (void *) value, (void *) equality, (void *) lesser, (void *) greater)
+
+#define parcObjectTesting_AssertAcquireReleaseContract(_function_, _instance_) \
+ parcObjectTesting_AssertAcquireReleaseContractImpl((void *(*)(const PARCObject *))_function_, _instance_)
+/**
+ * Assert the acquire/release contract given the Acquire function of a PARCObject implementation.
+ *
+ * Paragraphs Of Explanation
+ *
+ * @param [in] acquireFunction A pointer to the acquireFunction to invoke.
+ * @param [in] instance A pointer to a PARCObject implementation that will be used to acquire and release references.
+ */
+void parcObjectTesting_AssertAcquireReleaseContractImpl(void *(acquireFunction)(const PARCObject *),
+ const PARCObject *instance);
+
+
+#define parcObjectTesting_AssertAcquire(_instance_) \
+ parcObjectTesting_AssertAcquireReleaseImpl((const PARCObject *) _instance_)
+
+/**
+ * Assert that the given PARCObject's Acquire/Release contract is correct.
+ *
+ * @param [in] instance A pointer to a PARCObject instance.
+ */
+void parcObjectTesting_AssertAcquireReleaseImpl(const PARCObject *instance);
+
+/**
+ * Ensure that a function implements the Equals contract.
+ *
+ * The equality function must implement the following equivalence relations on non-null instances:
+ *
+ * * It is reflexive: for any non-null reference value x, equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, equals(x, y) must return true if and only if
+ * equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * equals(x, y) returns true and
+ * equals(y, z) returns true,
+ * then equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, equals(x, NULL)) must return false.
+ *
+ * @param [in] equalsFunction A pointer to a function that will be called to determine if it conforms to the Equals contract.
+ * @param [in] x A pointer to a value that will be used as the base comparison for remaining parameters.
+ * @param [in] y A pointer to a value that is known to be equal to @p x, but is not @p x.
+ * @param [in] z A pointer to a value that is known to be equal to @p x and to @p y, but is neither @p x nor @p y.
+ * @param [in] ... A NULL terminated variable number of parameters consisting of pointers to values that are known to be not equal to @p x, @p y, or @p z.
+ * @see parcObjectTesting_AssertEquals
+ */
+void parcObjectTesting_AssertEqualsFunctionImpl(bool (*equalsFunction)(const void *a, const void *b), const void *x, const void *y, const void *z, ...);
+
+/**
+ * Ensure that a PARCObject implements the Equals contract.
+ *
+ * The PARCObject's `Equals()` function must implement the following equivalence relations on non-null instances:
+ *
+ * * It is reflexive: for any non-null reference value x, equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, equals(x, y) must return true if and only if
+ * equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * equals(x, y) returns true and
+ * equals(y, z) returns true,
+ * then equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, equals(x, NULL)) must return false.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ * @param [in] y A pointer to a value that is known to be equal to @p object, but is not the same as @p object.
+ * @param [in] z A pointer to a value that is known to be equal to @p object and to @p y, but is neither the same as @p object nor @p y.
+ * @param [in] ... A NULL terminated variable number of parameters consisting of pointers to values that are known to be not equal to @p object, @p y, or @p z.
+ */
+void parcObjectTesting_AssertEquals(const PARCObject *object, const void *y, const void *z, ...);
+
+/**
+ * Compares instance <code>a</code> with instance <code>b</code> for order.
+ *
+ * The comparison function that this evaluates <i>sgn(a - b)</i> required to return a negative integer,
+ * zero, or a positive integer as <code>a</code> is less than,
+ * equal to, or greater than <code>b</code>.
+ *
+ * The function must ensure that:
+ * <ul>
+ * <li>sgn(compareTo(a, b)) == -sgn(b, a) for all values of a and b.</li>
+ * <li>the relation is transitive: (compareTo(x, y)>0 && compareTo(y, z)>0) implies compareTo(x, z)>0.</li>
+ * <li>compareTo(x, y)== 0 implies that sgn(compareTo(x, z)) == sgn(compareTo(y, z)), for all values of z.</li>
+ * </ul>
+ *
+ * This also stipulates that
+ * <code>compareTo(NULL, NULL)) == 0</code>,
+ * <code>compareTo(not-NULL, NULL)) > 0</code>,
+ * <code>compareTo(NULL, not-NULL)) < 0</code>.
+ *
+ * It is strongly recommended, but not strictly required that relation(compareTo(x, y)==0) == equals(x, y)) is true.
+ * Any module that implements the compareTo function and violates this condition
+ * should clearly indicate this fact.
+ * For example, "Note: this implementation has a natural ordering that is inconsistent with equals."
+ *
+ * @param [in] compareTo A pointer to a function implementing the CompareTo function signature.
+ * @param [in] exemplar The pivotal value under test.
+ * @param [in] equivalent A NULL terminated array of values that are all equivalent to <code>value</code>.
+ * @param [in] lesser A NULL terminated array of values that are all less than <code>value</code>.
+ * @param [in] greater A NULL terminated array of values that are all greater than <code>value</code>.
+ * @see parcObjectTesting_AssertCompareTo
+ */
+bool parcObjectTesting_AssertCompareToImpl(int (*compareTo)(const void *a, const void *b),
+ const void *exemplar,
+ const void **equivalent,
+ const void **lesser,
+ const void **greater);
+
+/**
+ * Assert the HashCode contract on a PARCObject.
+ *
+ * @param [in] x A pointer to a valid PARCObject.
+ * @param [in] y A pointer to a valid PARCObject, that must be equal to @p x, but not the same.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcObjectTesting_AssertHashCode(const PARCObject *x, const void *y);
+
+/**
+ * Assert the HashCode function contract.
+ *
+ * @param [in] hashCode A pointer to a function implementing the hash code function.
+ */
+void parcObjectTesting_AssertHashCodeImpl(PARCHashCode (*hashCode)(const void *a), void *a);
+#endif
diff --git a/libparc/parc/testing/test/.gitignore b/libparc/parc/testing/test/.gitignore
new file mode 100644
index 00000000..3b3dc64d
--- /dev/null
+++ b/libparc/parc/testing/test/.gitignore
@@ -0,0 +1,2 @@
+test_parc_MemoryTesting
+test_parc_ObjectTesting
diff --git a/libparc/parc/testing/test/CMakeLists.txt b/libparc/parc/testing/test/CMakeLists.txt
new file mode 100644
index 00000000..1de2e89d
--- /dev/null
+++ b/libparc/parc/testing/test/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(TestsExpectedToPass
+ test_parc_MemoryTesting
+ test_parc_ObjectTesting
+ )
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
diff --git a/libparc/parc/testing/test/test_parc_MemoryTesting.c b/libparc/parc/testing/test/test_parc_MemoryTesting.c
new file mode 100755
index 00000000..d24e79d4
--- /dev/null
+++ b/libparc/parc/testing/test/test_parc_MemoryTesting.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_MemoryTesting.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Memory.h>
+
+LONGBOW_TEST_RUNNER(test_parc_MemoryTest)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_MemoryTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_MemoryTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcMemoryTesting_ExpectedOutstanding);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcMemoryTesting_ExpectedOutstanding)
+{
+ void *memory = parcMemory_Allocate(4);
+
+ assertTrue(parcMemoryTesting_ExpectedOutstanding(1, "Expected 1 outstanding allocation"),
+ "Failed 1 expected allocation");
+
+ parcMemory_Deallocate(&memory);
+ assertTrue(parcMemoryTesting_ExpectedOutstanding(0, "Expected 0 outstanding allocations"),
+ "Failed 0 expected allocations");
+
+ assertFalse(parcMemoryTesting_ExpectedOutstanding(1, "Expected 1 outstanding allocations"),
+ "Failed 1 expected llocations");
+ assertFalse(parcMemoryTesting_ExpectedOutstanding(-1, "Expected -1 outstanding allocations"),
+ "Failed -1 expected allocations");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_MemoryTest);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/testing/test/test_parc_ObjectTesting.c b/libparc/parc/testing/test/test_parc_ObjectTesting.c
new file mode 100755
index 00000000..9d70b68c
--- /dev/null
+++ b/libparc/parc/testing/test/test_parc_ObjectTesting.c
@@ -0,0 +1,543 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_ObjectTesting.c"
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+LONGBOW_TEST_RUNNER(test_parc_ObjectTesting)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(CompareTo);
+ LONGBOW_RUN_TEST_FIXTURE(Equals);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Conformance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_ObjectTesting)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_ObjectTesting)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static bool
+_equalsFunction(const void *x, const void *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ return (strcmp(x, y) == 0);
+}
+
+static bool
+_equalsFunction_NotReflexive(const void *x, const void *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+ if (x < y) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+LONGBOW_TEST_FIXTURE(Equals)
+{
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEquals);
+
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl);
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXYsame);
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXZsame);
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXnotequalZ);
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXnotequalY);
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailNotSymmetric);
+}
+
+static uint32_t _longBowGlobal_Global_outstanding;
+
+LONGBOW_TEST_FIXTURE_SETUP(Equals)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Equals)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ if (parcMemoryTesting_ExpectedOutstanding(_longBowGlobal_Global_outstanding, longBowTestCase_GetName(testCase)) == false) {
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return result;
+}
+
+LONGBOW_TEST_CASE(Equals, parcObjectTesting_AssertEquals)
+{
+ PARCBuffer *x = parcBuffer_Allocate(sizeof(uint64_t));
+ PARCBuffer *y = parcBuffer_Allocate(sizeof(uint64_t));
+ PARCBuffer *z = parcBuffer_Allocate(sizeof(uint64_t));
+ PARCBuffer *u1 = parcBuffer_Allocate(sizeof(uint64_t));
+ PARCBuffer *u2 = parcBuffer_Allocate(sizeof(uint64_t));
+ parcBuffer_Flip(parcBuffer_PutUint64(x, 1));
+ parcBuffer_Flip(parcBuffer_PutUint64(y, 1));
+ parcBuffer_Flip(parcBuffer_PutUint64(z, 1));
+ parcBuffer_Flip(parcBuffer_PutUint64(u1, 2));
+ parcBuffer_Flip(parcBuffer_PutUint64(u2, 3));
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, u2, NULL);
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+ parcBuffer_Release(&z);
+ parcBuffer_Release(&u1);
+ parcBuffer_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl)
+{
+ void *x = strdup("1");
+ void *y = strdup("1");
+ void *z = strdup("1");
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXYsame, .event = &LongBowAssertEvent)
+{
+ void *x = strdup("1");
+ void *y = x;
+ void *z = strdup("1");
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXZsame, .event = &LongBowAssertEvent)
+{
+ void *x = strdup("1");
+ void *y = strdup("1");
+ void *z = x;
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXnotequalY, .event = &LongBowAssertEvent)
+{
+ void *x = strdup("1");
+ void *y = strdup("xyzzy");
+ void *z = strdup("1");
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXnotequalZ, .event = &LongBowAssertEvent)
+{
+ void *x = strdup("1");
+ void *y = strdup("1");
+ void *z = strdup("xyzzy");
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailNotSymmetric, .event = &LongBowAssertEvent)
+{
+ void *x = strdup("1");
+ void *y = strdup("1");
+ void *z = strdup("1");
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction_NotReflexive, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcObjectTesting_AssertAcquire);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ if (parcMemoryTesting_ExpectedOutstanding(_longBowGlobal_Global_outstanding, longBowTestCase_GetName(testCase)) == false) {
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return result;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcObjectTesting_AssertAcquire)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcObjectTesting_AssertAcquireReleaseImpl(buffer);
+ parcBuffer_Release(&buffer);
+}
+
+
+LONGBOW_TEST_FIXTURE(CompareTo)
+{
+ LONGBOW_RUN_TEST_CASE(CompareTo, parcObjectTesting_AssertCompareTo);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CompareTo)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CompareTo)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ if (parcMemoryTesting_ExpectedOutstanding(_longBowGlobal_Global_outstanding, longBowTestCase_GetName(testCase)) == false) {
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return result;
+}
+
+LONGBOW_TEST_CASE(CompareTo, parcObjectTesting_AssertCompareTo)
+{
+ PARCBuffer *x = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCBuffer *y = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+
+ PARCBuffer *equivalent[] = {
+ x,
+ y,
+ NULL
+ };
+ PARCBuffer *lesser[] = {
+ parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8 }, 10, 0, 10),
+ parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 5, 7, 8, }, 9, 0, 9),
+ NULL
+ };
+ PARCBuffer *greater[] = {
+ parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10),
+ parcBuffer_Wrap((uint8_t [11]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 11, 0, 11),
+ NULL
+ };
+
+ parcObjectTesting_AssertCompareTo(parcBuffer_Compare, x, equivalent, lesser, greater);
+
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+
+ for (int i = 0; lesser[i] != NULL; i++) {
+ parcBuffer_Release(&lesser[i]);
+ }
+ for (int i = 0; greater[i] != NULL; i++) {
+ parcBuffer_Release(&greater[i]);
+ }
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ size_t allocationsLeaked = parcMemory_Outstanding() - _longBowGlobal_Global_outstanding;
+
+ if (allocationsLeaked) {
+ printf("%s leaks memory by %zd allocations\n", longBowTestCase_GetName(testCase), allocationsLeaked);
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return result;
+}
+
+LONGBOW_TEST_FIXTURE(Conformance)
+{
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_succeed);
+
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_non_object);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_equals);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_compare);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_copy_junk);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_copy_same);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_hash);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_toString);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_toJSON);
+}
+
+
+typedef struct {
+ PARCBuffer *inst1;
+ PARCBuffer *inst2;
+ PARCBuffer *inst3;
+ PARCBuffer *lesser;
+ PARCBuffer *greater;
+ PARCObjectDescriptor *descriptor;
+} TestData_t;
+
+static const PARCObjectDescriptor *
+_copyDescriptor(const PARCObjectDescriptor *orig)
+{
+ return parcObjectDescriptor_Create("Name",
+ orig->objectSize,
+ orig->objectAlignment,
+ orig->isLockable,
+ orig->destructor,
+ orig->release, orig->copy,
+ orig->toString, orig->equals,
+ orig->compare, orig->hashCode,
+ orig->toJSON, orig->display,
+ orig->super, orig->typeState);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Conformance)
+{
+ TestData_t *data = parcMemory_AllocateAndClear(sizeof(TestData_t));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData_t));
+
+ data->inst1 = parcBuffer_Flip(parcBuffer_CreateFromArray((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10));
+ data->inst2 = parcBuffer_Flip(parcBuffer_CreateFromArray((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10));
+ data->inst3 = parcBuffer_Flip(parcBuffer_CreateFromArray((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10));
+ data->lesser = parcBuffer_Flip(parcBuffer_CreateFromArray((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8 }, 10));
+ data->greater = parcBuffer_Flip(parcBuffer_CreateFromArray((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10));
+
+ PARCObjectDescriptor *d = (PARCObjectDescriptor *) parcObject_GetDescriptor(data->inst1);
+ data->descriptor = (PARCObjectDescriptor *) _copyDescriptor(d);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Conformance)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcBuffer_Release(&data->inst1);
+ parcBuffer_Release(&data->inst2);
+ parcBuffer_Release(&data->inst3);
+ parcBuffer_Release(&data->lesser);
+ parcBuffer_Release(&data->greater);
+
+ parcObjectDescriptor_Destroy(&data->descriptor);
+
+ parcMemory_Deallocate(&data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_succeed)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->lesser, data->greater);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_non_object, .event = &LongBowAssertEvent)
+{
+ char *inst1 = "not an object";
+ char *inst2 = "not an object";
+ char *inst3 = "not an object";
+
+ parcObjectTesting_AssertObjectConformance(inst1, inst2, inst3, NULL, NULL);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_equals, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *inst1 = data->inst1;
+ PARCBuffer *inst2 = inst1;
+ PARCBuffer *inst3 = inst1;
+
+ parcObjectTesting_AssertObjectConformance(inst1, inst2, inst3, data->lesser, data->greater);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_compare, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+__attribute__ ((noinline))
+static PARCObject *
+badCopyJunk(const PARCObject *instance)
+{
+ return parcBuffer_Allocate(10);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_copy_junk, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ data->descriptor->copy = badCopyJunk;
+ parcObject_SetDescriptor(data->inst1, data->descriptor);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+static PARCObject *
+badCopySame(const PARCObject *instance)
+{
+ return parcObject_Acquire(instance);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_copy_same, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ data->descriptor->copy = badCopySame;
+ parcObject_SetDescriptor(data->inst1, data->descriptor);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+static PARCHashCode
+badHash(const PARCObject *instance)
+{
+ return (PARCHashCode) instance;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_hash, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ data->descriptor->hashCode = badHash;
+ parcObject_SetDescriptor(data->inst1, data->descriptor);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+static PARCJSON *
+badToJSON(const PARCObject *instance)
+{
+ return NULL;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_toJSON, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ data->descriptor->toJSON = badToJSON;
+ parcObject_SetDescriptor(data->inst1, data->descriptor);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+static char *
+badToString(const PARCObject *instance)
+{
+ return NULL;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_toString, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ data->descriptor->toString = badToString;
+ parcObject_SetDescriptor(data->inst1, data->descriptor);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_ObjectTesting);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}