http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestNumberUtils.c
----------------------------------------------------------------------
diff --git a/test/Lucy/Test/Util/TestNumberUtils.c 
b/test/Lucy/Test/Util/TestNumberUtils.c
new file mode 100644
index 0000000..f9cf3a1
--- /dev/null
+++ b/test/Lucy/Test/Util/TestNumberUtils.c
@@ -0,0 +1,473 @@
+/* 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 <stdlib.h>
+#include <time.h>
+
+#define TESTLUCY_USE_SHORT_NAMES
+#include "Lucy/Util/ToolSet.h"
+
+#include "charmony.h"
+
+#include "Lucy/Test/Util/TestNumberUtils.h"
+
+#include "Clownfish/TestHarness/TestBatchRunner.h"
+#include "Clownfish/TestHarness/TestUtils.h"
+#include "Lucy/Util/NumberUtils.h"
+
+TestNumberUtils*
+TestNumUtil_new() {
+    return (TestNumberUtils*)Class_Make_Obj(TESTNUMBERUTILS);
+}
+
+static void
+test_u1(TestBatchRunner *runner) {
+    size_t    count   = 64;
+    uint64_t *ints    = TestUtils_random_u64s(NULL, count, 0, 2);
+    size_t    amount  = count / 8;
+    uint8_t  *bits    = (uint8_t*)CALLOCATE(amount, sizeof(uint8_t));
+
+    for (size_t i = 0; i < count; i++) {
+        if (ints[i]) { NumUtil_u1set(bits, i); }
+    }
+    for (size_t i = 0; i < count; i++) {
+        TEST_UINT_EQ(runner, NumUtil_u1get(bits, i), ints[i], "u1 set/get");
+    }
+
+    for (size_t i = 0; i < count; i++) {
+        NumUtil_u1flip(bits, i);
+    }
+    for (size_t i = 0; i < count; i++) {
+        TEST_UINT_EQ(runner, NumUtil_u1get(bits, i), !ints[i], "u1 flip");
+    }
+
+    FREEMEM(bits);
+    FREEMEM(ints);
+}
+
+static void
+test_u2(TestBatchRunner *runner) {
+    size_t    count = 32;
+    uint64_t *ints = TestUtils_random_u64s(NULL, count, 0, 4);
+    uint8_t  *bits = (uint8_t*)CALLOCATE((count / 4), sizeof(uint8_t));
+
+    for (size_t i = 0; i < count; i++) {
+        NumUtil_u2set(bits, i, (uint8_t)ints[i]);
+    }
+    for (size_t i = 0; i < count; i++) {
+        TEST_UINT_EQ(runner, NumUtil_u2get(bits, i), ints[i], "u2");
+    }
+
+    FREEMEM(bits);
+    FREEMEM(ints);
+}
+
+static void
+test_u4(TestBatchRunner *runner) {
+    size_t    count = 128;
+    uint64_t *ints  = TestUtils_random_u64s(NULL, count, 0, 16);
+    uint8_t  *bits  = (uint8_t*)CALLOCATE((count / 2), sizeof(uint8_t));
+
+    for (size_t i = 0; i < count; i++) {
+        NumUtil_u4set(bits, i, (uint8_t)ints[i]);
+    }
+    for (size_t i = 0; i < count; i++) {
+        TEST_UINT_EQ(runner, NumUtil_u4get(bits, i), ints[i], "u4");
+    }
+
+    FREEMEM(bits);
+    FREEMEM(ints);
+}
+
+static void
+test_ci32(TestBatchRunner *runner) {
+    int64_t   mins[]   = { -500, -0x4000 - 100, INT32_MIN };
+    int64_t   limits[] = { 500,  -0x4000 + 100, INT32_MIN + 10 };
+    int32_t   set_num;
+    int32_t   num_sets  = sizeof(mins) / sizeof(int64_t);
+    size_t    count     = 64;
+    int64_t  *ints      = NULL;
+    size_t    amount    = count * CI32_MAX_BYTES;
+    char     *encoded   = (char*)CALLOCATE(amount, sizeof(char));
+    char     *target    = encoded;
+    char     *limit     = target + amount;
+    const char *decode;
+
+    for (set_num = 0; set_num < num_sets; set_num++) {
+        const char *skip;
+        ints = TestUtils_random_i64s(ints, count,
+                                     mins[set_num], limits[set_num]);
+        target = encoded;
+        for (size_t i = 0; i < count; i++) {
+            NumUtil_encode_ci32((int32_t)ints[i], &target);
+        }
+        decode = encoded;
+        skip   = encoded;
+        for (size_t i = 0; i < count; i++) {
+            TEST_INT_EQ(runner, NumUtil_decode_ci32(&decode), ints[i],
+                        "ci32 %" PRId64, ints[i]);
+            NumUtil_skip_cint(&skip);
+            if (decode > limit) { THROW(ERR, "overrun"); }
+        }
+        TEST_TRUE(runner, skip == decode, "skip %p == %p", skip, decode);
+    }
+
+    target = encoded;
+    NumUtil_encode_ci32(INT32_MAX, &target);
+    decode = encoded;
+    TEST_INT_EQ(runner, NumUtil_decode_ci32(&decode), INT32_MAX,
+                "ci32 INT32_MAX");
+    target = encoded;
+    NumUtil_encode_ci32(INT32_MIN, &target);
+    decode = encoded;
+    TEST_INT_EQ(runner, NumUtil_decode_ci32(&decode), INT32_MIN,
+                "ci32 INT32_MIN");
+
+    FREEMEM(encoded);
+    FREEMEM(ints);
+}
+
+static void
+test_cu32(TestBatchRunner *runner) {
+    uint64_t  mins[]   = { 0,   0x4000 - 100, (uint32_t)INT32_MAX - 100, 
UINT32_MAX - 10 };
+    uint64_t  limits[] = { 500, 0x4000 + 100, (uint32_t)INT32_MAX + 100, 
UINT32_MAX      };
+    uint32_t  set_num;
+    uint32_t  num_sets  = sizeof(mins) / sizeof(uint64_t);
+    size_t    count     = 64;
+    uint64_t *ints      = NULL;
+    size_t    amount    = count * CU32_MAX_BYTES;
+    char     *encoded   = (char*)CALLOCATE(amount, sizeof(char));
+    char     *target    = encoded;
+    char     *limit     = target + amount;
+    const char *decode;
+
+    for (set_num = 0; set_num < num_sets; set_num++) {
+        const char *skip;
+        ints = TestUtils_random_u64s(ints, count,
+                                     mins[set_num], limits[set_num]);
+        target = encoded;
+        for (size_t i = 0; i < count; i++) {
+            ints[i] = (uint32_t)ints[i];
+            NumUtil_encode_cu32((uint32_t)ints[i], &target);
+        }
+        decode = encoded;
+        skip   = encoded;
+        for (size_t i = 0; i < count; i++) {
+            TEST_UINT_EQ(runner, NumUtil_decode_cu32(&decode), ints[i],
+                         "cu32 %lu", (unsigned long)ints[i]);
+            NumUtil_skip_cint(&skip);
+            if (decode > limit) { THROW(ERR, "overrun"); }
+        }
+        TEST_TRUE(runner, skip == decode, "skip %p == %p", skip, decode);
+
+        target = encoded;
+        for (size_t i = 0; i < count; i++) {
+            NumUtil_encode_padded_cu32((uint32_t)ints[i], &target);
+        }
+        TEST_TRUE(runner, target == limit,
+                  "padded cu32 uses 5 bytes (%p == %p)", target, limit);
+        decode = encoded;
+        skip   = encoded;
+        for (size_t i = 0; i < count; i++) {
+            TEST_UINT_EQ(runner, NumUtil_decode_cu32(&decode), ints[i],
+                         "padded cu32 %lu", (unsigned long)ints[i]);
+            NumUtil_skip_cint(&skip);
+            if (decode > limit) { THROW(ERR, "overrun"); }
+        }
+        TEST_TRUE(runner, skip == decode, "skip padded %p == %p", skip,
+                  decode);
+    }
+
+    target = encoded;
+    NumUtil_encode_cu32(UINT32_MAX, &target);
+    decode = encoded;
+    TEST_UINT_EQ(runner, NumUtil_decode_cu32(&decode), UINT32_MAX, "cu32 
UINT32_MAX");
+
+    FREEMEM(encoded);
+    FREEMEM(ints);
+}
+
+static void
+test_ci64(TestBatchRunner *runner) {
+    int64_t   mins[]    = { -500, -0x4000 - 100, (int64_t)INT32_MIN - 100,  
INT64_MIN };
+    int64_t   limits[]  = { 500,  -0x4000 + 100, (int64_t)INT32_MIN + 1000, 
INT64_MIN + 10 };
+    int32_t   set_num;
+    int32_t   num_sets  = sizeof(mins) / sizeof(int64_t);
+    size_t    count     = 64;
+    int64_t  *ints      = NULL;
+    size_t    amount    = count * CI64_MAX_BYTES;
+    char     *encoded   = (char*)CALLOCATE(amount, sizeof(char));
+    char     *target    = encoded;
+    char     *limit     = target + amount;
+    const char *decode;
+
+    for (set_num = 0; set_num < num_sets; set_num++) {
+        const char *skip;
+        ints = TestUtils_random_i64s(ints, count,
+                                     mins[set_num], limits[set_num]);
+        target = encoded;
+        for (size_t i = 0; i < count; i++) {
+            NumUtil_encode_ci64(ints[i], &target);
+        }
+        decode = encoded;
+        skip   = encoded;
+        for (size_t i = 0; i < count; i++) {
+            int64_t got = NumUtil_decode_ci64(&decode);
+            TEST_INT_EQ(runner, got, ints[i],
+                        "ci64 %" PRId64 " == %" PRId64, got, ints[i]);
+            if (decode > limit) { THROW(ERR, "overrun"); }
+            NumUtil_skip_cint(&skip);
+        }
+        TEST_TRUE(runner, skip == decode, "skip %p == %p", skip, decode);
+    }
+
+    target = encoded;
+    NumUtil_encode_ci64(INT64_MAX, &target);
+    decode = encoded;
+    int64_t got = NumUtil_decode_ci64(&decode);
+    TEST_INT_EQ(runner, got, INT64_MAX, "ci64 INT64_MAX");
+
+    target = encoded;
+    NumUtil_encode_ci64(INT64_MIN, &target);
+    decode = encoded;
+    got = NumUtil_decode_ci64(&decode);
+    TEST_INT_EQ(runner, got, INT64_MIN, "ci64 INT64_MIN");
+
+    FREEMEM(encoded);
+    FREEMEM(ints);
+}
+
+static void
+test_cu64(TestBatchRunner *runner) {
+    uint64_t  mins[]    = { 0,   0x4000 - 100, (uint64_t)UINT32_MAX - 100,  
UINT64_MAX - 10 };
+    uint64_t  limits[]  = { 500, 0x4000 + 100, (uint64_t)UINT32_MAX + 1000, 
UINT64_MAX      };
+    uint32_t  set_num;
+    uint32_t  num_sets  = sizeof(mins) / sizeof(uint64_t);
+    size_t    count     = 64;
+    uint64_t *ints      = NULL;
+    size_t    amount    = count * CU64_MAX_BYTES;
+    char     *encoded   = (char*)CALLOCATE(amount, sizeof(char));
+    char     *target    = encoded;
+    char     *limit     = target + amount;
+    const char *decode;
+
+    for (set_num = 0; set_num < num_sets; set_num++) {
+        const char *skip;
+        ints = TestUtils_random_u64s(ints, count,
+                                     mins[set_num], limits[set_num]);
+        target = encoded;
+        for (size_t i = 0; i < count; i++) {
+            NumUtil_encode_cu64(ints[i], &target);
+        }
+        decode = encoded;
+        skip   = encoded;
+        for (size_t i = 0; i < count; i++) {
+            uint64_t got = NumUtil_decode_cu64(&decode);
+            TEST_TRUE(runner, got == ints[i],
+                      "cu64 %" PRIu64 " == %" PRIu64, got, ints[i]);
+            if (decode > limit) { THROW(ERR, "overrun"); }
+            NumUtil_skip_cint(&skip);
+        }
+        TEST_TRUE(runner, skip == decode, "skip %p == %p", skip, decode);
+    }
+
+    target = encoded;
+    NumUtil_encode_cu64(UINT64_MAX, &target);
+
+    decode = encoded;
+    uint64_t got = NumUtil_decode_cu64(&decode);
+    TEST_TRUE(runner, got == UINT64_MAX, "cu64 UINT64_MAX");
+
+    FREEMEM(encoded);
+    FREEMEM(ints);
+}
+
+static void
+test_bigend_u16(TestBatchRunner *runner) {
+    size_t    count     = 32;
+    uint64_t *ints      = TestUtils_random_u64s(NULL, count, 0, UINT16_MAX + 
1);
+    size_t    amount    = (count + 1) * sizeof(uint16_t);
+    char     *allocated = (char*)CALLOCATE(amount, sizeof(char));
+    char     *encoded   = allocated + 1; // Intentionally misaligned.
+    char     *target    = encoded;
+
+    for (size_t i = 0; i < count; i++) {
+        NumUtil_encode_bigend_u16((uint16_t)ints[i], &target);
+        target += sizeof(uint16_t);
+    }
+    target = encoded;
+    for (size_t i = 0; i < count; i++) {
+        uint16_t got = NumUtil_decode_bigend_u16(target);
+        TEST_INT_EQ(runner, got, (long)ints[i], "bigend u16");
+        target += sizeof(uint16_t);
+    }
+
+    target = encoded;
+    NumUtil_encode_bigend_u16(1, &target);
+    TEST_INT_EQ(runner, encoded[0], 0, "Truly big-endian u16");
+    TEST_INT_EQ(runner, encoded[1], 1, "Truly big-endian u16");
+
+    FREEMEM(allocated);
+    FREEMEM(ints);
+}
+
+static void
+test_bigend_u32(TestBatchRunner *runner) {
+    size_t    count     = 32;
+    uint64_t *ints      = TestUtils_random_u64s(NULL, count, 0, UINT64_C(1) + 
UINT32_MAX);
+    size_t    amount    = (count + 1) * sizeof(uint32_t);
+    char     *allocated = (char*)CALLOCATE(amount, sizeof(char));
+    char     *encoded   = allocated + 1; // Intentionally misaligned.
+    char     *target    = encoded;
+
+    for (size_t i = 0; i < count; i++) {
+        ints[i] = (uint32_t)ints[i];
+        NumUtil_encode_bigend_u32((uint32_t)ints[i], &target);
+        target += sizeof(uint32_t);
+    }
+    target = encoded;
+    for (size_t i = 0; i < count; i++) {
+        uint32_t got = NumUtil_decode_bigend_u32(target);
+        TEST_UINT_EQ(runner, got, ints[i], "bigend u32");
+        target += sizeof(uint32_t);
+    }
+
+    target = encoded;
+    NumUtil_encode_bigend_u32(1, &target);
+    TEST_INT_EQ(runner, encoded[0], 0, "Truly big-endian u32");
+    TEST_INT_EQ(runner, encoded[3], 1, "Truly big-endian u32");
+
+    FREEMEM(allocated);
+    FREEMEM(ints);
+}
+
+static void
+test_bigend_u64(TestBatchRunner *runner) {
+    size_t    count     = 32;
+    uint64_t *ints      = TestUtils_random_u64s(NULL, count, 0, UINT64_MAX);
+    size_t    amount    = (count + 1) * sizeof(uint64_t);
+    char     *allocated = (char*)CALLOCATE(amount, sizeof(char));
+    char     *encoded   = allocated + 1; // Intentionally misaligned.
+    char     *target    = encoded;
+
+    for (size_t i = 0; i < count; i++) {
+        NumUtil_encode_bigend_u64(ints[i], &target);
+        target += sizeof(uint64_t);
+    }
+    target = encoded;
+    for (size_t i = 0; i < count; i++) {
+        uint64_t got = NumUtil_decode_bigend_u64(target);
+        TEST_TRUE(runner, got == ints[i], "bigend u64");
+        target += sizeof(uint64_t);
+    }
+
+    target = encoded;
+    NumUtil_encode_bigend_u64(1, &target);
+    TEST_INT_EQ(runner, encoded[0], 0, "Truly big-endian");
+    TEST_INT_EQ(runner, encoded[7], 1, "Truly big-endian");
+
+    FREEMEM(allocated);
+    FREEMEM(ints);
+}
+
+static void
+test_bigend_f32(TestBatchRunner *runner) {
+    float    source[]  = { -1.3f, 0.0f, 100.2f };
+    size_t   count     = 3;
+    size_t   amount    = (count + 1) * sizeof(float);
+    uint8_t *allocated = (uint8_t*)CALLOCATE(amount, sizeof(uint8_t));
+    uint8_t *encoded   = allocated + 1; // Intentionally misaligned.
+    uint8_t *target    = encoded;
+
+    for (size_t i = 0; i < count; i++) {
+        NumUtil_encode_bigend_f32(source[i], &target);
+        target += sizeof(float);
+    }
+    target = encoded;
+    for (size_t i = 0; i < count; i++) {
+        float got = NumUtil_decode_bigend_f32(target);
+        TEST_TRUE(runner, got == source[i], "bigend f32");
+        target += sizeof(float);
+    }
+
+    target = encoded;
+    NumUtil_encode_bigend_f32(-2.0f, &target);
+    TEST_INT_EQ(runner, (encoded[0] & 0x80), 0x80,
+                "Truly big-endian (IEEE 754 sign bit set for negative 
number)");
+    TEST_INT_EQ(runner, encoded[0], 0xC0,
+                "IEEE 754 representation of -2.0f, byte 0");
+    for (size_t i = 1; i < sizeof(float); i++) {
+        TEST_INT_EQ(runner, encoded[i], 0,
+                    "IEEE 754 representation of -2.0f, byte %d", (int)i);
+    }
+
+    FREEMEM(allocated);
+}
+
+static void
+test_bigend_f64(TestBatchRunner *runner) {
+    double   source[]  = { -1.3, 0.0, 100.2 };
+    size_t   count     = 3;
+    size_t   amount    = (count + 1) * sizeof(double);
+    uint8_t *allocated = (uint8_t*)CALLOCATE(amount, sizeof(uint8_t));
+    uint8_t *encoded   = allocated + 1; // Intentionally misaligned.
+    uint8_t *target    = encoded;
+
+    for (size_t i = 0; i < count; i++) {
+        NumUtil_encode_bigend_f64(source[i], &target);
+        target += sizeof(double);
+    }
+    target = encoded;
+    for (size_t i = 0; i < count; i++) {
+        double got = NumUtil_decode_bigend_f64(target);
+        TEST_TRUE(runner, got == source[i], "bigend f64");
+        target += sizeof(double);
+    }
+
+    target = encoded;
+    NumUtil_encode_bigend_f64(-2.0, &target);
+    TEST_INT_EQ(runner, (encoded[0] & 0x80), 0x80,
+                "Truly big-endian (IEEE 754 sign bit set for negative 
number)");
+    TEST_INT_EQ(runner, encoded[0], 0xC0,
+                "IEEE 754 representation of -2.0, byte 0");
+    for (size_t i = 1; i < sizeof(double); i++) {
+        TEST_INT_EQ(runner, encoded[i], 0,
+                    "IEEE 754 representation of -2.0, byte %d", (int)i);
+    }
+
+    FREEMEM(allocated);
+}
+
+void
+TestNumUtil_Run_IMP(TestNumberUtils *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 1655);
+    srand((unsigned int)time((time_t*)NULL));
+    test_u1(runner);
+    test_u2(runner);
+    test_u4(runner);
+    test_ci32(runner);
+    test_cu32(runner);
+    test_ci64(runner);
+    test_cu64(runner);
+    test_bigend_u16(runner);
+    test_bigend_u32(runner);
+    test_bigend_u64(runner);
+    test_bigend_f32(runner);
+    test_bigend_f64(runner);
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestNumberUtils.cfh
----------------------------------------------------------------------
diff --git a/test/Lucy/Test/Util/TestNumberUtils.cfh 
b/test/Lucy/Test/Util/TestNumberUtils.cfh
new file mode 100644
index 0000000..fcb20a9
--- /dev/null
+++ b/test/Lucy/Test/Util/TestNumberUtils.cfh
@@ -0,0 +1,29 @@
+/* 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.
+ */
+
+parcel TestLucy;
+
+class Lucy::Test::Util::TestNumberUtils nickname TestNumUtil
+    inherits Clownfish::TestHarness::TestBatch {
+
+    inert incremented TestNumberUtils*
+    new();
+
+    void
+    Run(TestNumberUtils *self, TestBatchRunner *runner);
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestPriorityQueue.c
----------------------------------------------------------------------
diff --git a/test/Lucy/Test/Util/TestPriorityQueue.c 
b/test/Lucy/Test/Util/TestPriorityQueue.c
new file mode 100644
index 0000000..7265170
--- /dev/null
+++ b/test/Lucy/Test/Util/TestPriorityQueue.c
@@ -0,0 +1,165 @@
+/* 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 C_TESTLUCY_TESTPRIORITYQUEUE
+#define TESTLUCY_USE_SHORT_NAMES
+#include "Lucy/Util/ToolSet.h"
+
+#include "Clownfish/Num.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
+#include "Lucy/Test.h"
+#include "Lucy/Test/Util/TestPriorityQueue.h"
+#include "Lucy/Util/PriorityQueue.h"
+
+TestPriorityQueue*
+TestPriQ_new() {
+    return (TestPriorityQueue*)Class_Make_Obj(TESTPRIORITYQUEUE);
+}
+
+NumPriorityQueue*
+NumPriQ_new(uint32_t max_size) {
+    NumPriorityQueue *self
+        = (NumPriorityQueue*)Class_Make_Obj(NUMPRIORITYQUEUE);
+    return (NumPriorityQueue*)PriQ_init((PriorityQueue*)self, max_size);
+}
+
+bool
+NumPriQ_Less_Than_IMP(NumPriorityQueue *self, Obj *a, Obj *b) {
+    Float *num_a = (Float*)a;
+    Float *num_b = (Float*)b;
+    UNUSED_VAR(self);
+    return Float_Get_Value(num_a) < Float_Get_Value(num_b) ? true : false;
+}
+
+static void
+S_insert_num(NumPriorityQueue *pq, int32_t value) {
+    NumPriQ_Insert(pq, (Obj*)Float_new((double)value));
+}
+
+static int32_t
+S_pop_num(NumPriorityQueue *pq) {
+    Float *num = (Float*)NumPriQ_Pop(pq);
+    int32_t retval;
+    if (!num) { THROW(ERR, "Queue is empty"); }
+    retval = (int32_t)Float_Get_Value(num);
+    DECREF(num);
+    return retval;
+}
+
+static void
+test_Peek_and_Pop_All(TestBatchRunner *runner) {
+    NumPriorityQueue *pq = NumPriQ_new(5);
+    Float *val;
+
+    S_insert_num(pq, 3);
+    S_insert_num(pq, 1);
+    S_insert_num(pq, 2);
+    S_insert_num(pq, 20);
+    S_insert_num(pq, 10);
+    val = (Float*)CERTIFY(NumPriQ_Peek(pq), FLOAT);
+    TEST_INT_EQ(runner, (long)Float_Get_Value(val), 1,
+                "peek at the least item in the queue");
+
+    Vector  *got = NumPriQ_Pop_All(pq);
+    val = (Float*)CERTIFY(Vec_Fetch(got, 0), FLOAT);
+    TEST_INT_EQ(runner, (long)Float_Get_Value(val), 20, "pop_all");
+    val = (Float*)CERTIFY(Vec_Fetch(got, 1), FLOAT);
+    TEST_INT_EQ(runner, (long)Float_Get_Value(val), 10, "pop_all");
+    val = (Float*)CERTIFY(Vec_Fetch(got, 2), FLOAT);
+    TEST_INT_EQ(runner, (long)Float_Get_Value(val),  3, "pop_all");
+    val = (Float*)CERTIFY(Vec_Fetch(got, 3), FLOAT);
+    TEST_INT_EQ(runner, (long)Float_Get_Value(val),  2, "pop_all");
+    val = (Float*)CERTIFY(Vec_Fetch(got, 4), FLOAT);
+    TEST_INT_EQ(runner, (long)Float_Get_Value(val),  1, "pop_all");
+
+    DECREF(got);
+    DECREF(pq);
+}
+
+static void
+test_Insert_and_Pop(TestBatchRunner *runner) {
+    NumPriorityQueue *pq = NumPriQ_new(5);
+
+    S_insert_num(pq, 3);
+    S_insert_num(pq, 1);
+    S_insert_num(pq, 2);
+    S_insert_num(pq, 20);
+    S_insert_num(pq, 10);
+
+    TEST_INT_EQ(runner, S_pop_num(pq), 1, "Pop");
+    TEST_INT_EQ(runner, S_pop_num(pq), 2, "Pop");
+    TEST_INT_EQ(runner, S_pop_num(pq), 3, "Pop");
+    TEST_INT_EQ(runner, S_pop_num(pq), 10, "Pop");
+
+    S_insert_num(pq, 7);
+    TEST_INT_EQ(runner, S_pop_num(pq), 7,
+                "Insert after Pop still sorts correctly");
+
+    DECREF(pq);
+}
+
+static void
+test_discard(TestBatchRunner *runner) {
+    int32_t i;
+    NumPriorityQueue *pq = NumPriQ_new(5);
+
+    for (i = 1; i <= 10; i++) { S_insert_num(pq, i); }
+    S_insert_num(pq, -3);
+    for (i = 1590; i <= 1600; i++) { S_insert_num(pq, i); }
+    S_insert_num(pq, 5);
+
+    TEST_INT_EQ(runner, S_pop_num(pq), 1596, "discard waste");
+    TEST_INT_EQ(runner, S_pop_num(pq), 1597, "discard waste");
+    TEST_INT_EQ(runner, S_pop_num(pq), 1598, "discard waste");
+    TEST_INT_EQ(runner, S_pop_num(pq), 1599, "discard waste");
+    TEST_INT_EQ(runner, S_pop_num(pq), 1600, "discard waste");
+
+    DECREF(pq);
+}
+
+static void
+test_random_insertion(TestBatchRunner *runner) {
+    int i;
+    int shuffled[64];
+    NumPriorityQueue *pq = NumPriQ_new(64);
+
+    for (i = 0; i < 64; i++) { shuffled[i] = i; }
+    for (i = 0; i < 64; i++) {
+        int shuffle_pos = rand() % 64;
+        int temp = shuffled[shuffle_pos];
+        shuffled[shuffle_pos] = shuffled[i];
+        shuffled[i] = temp;
+    }
+    for (i = 0; i < 64; i++) { S_insert_num(pq, shuffled[i]); }
+    for (i = 0; i < 64; i++) {
+        if (S_pop_num(pq) != i) { break; }
+    }
+    TEST_INT_EQ(runner, i, 64, "random insertion");
+
+    DECREF(pq);
+}
+
+void
+TestPriQ_Run_IMP(TestPriorityQueue *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 17);
+    test_Peek_and_Pop_All(runner);
+    test_Insert_and_Pop(runner);
+    test_discard(runner);
+    test_random_insertion(runner);
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestPriorityQueue.cfh
----------------------------------------------------------------------
diff --git a/test/Lucy/Test/Util/TestPriorityQueue.cfh 
b/test/Lucy/Test/Util/TestPriorityQueue.cfh
new file mode 100644
index 0000000..4f434f1
--- /dev/null
+++ b/test/Lucy/Test/Util/TestPriorityQueue.cfh
@@ -0,0 +1,39 @@
+/* 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.
+ */
+
+parcel TestLucy;
+
+class Lucy::Test::Util::NumPriorityQueue nickname NumPriQ
+    inherits Lucy::Util::PriorityQueue {
+
+    inert incremented NumPriorityQueue*
+    new(uint32_t max_size);
+
+    bool
+    Less_Than(NumPriorityQueue *self, Obj *a, Obj *b);
+}
+
+class Lucy::Test::Util::TestPriorityQueue nickname TestPriQ
+    inherits Clownfish::TestHarness::TestBatch {
+
+    inert incremented TestPriorityQueue*
+    new();
+
+    void
+    Run(TestPriorityQueue *self, TestBatchRunner *runner);
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestSortExternal.c
----------------------------------------------------------------------
diff --git a/test/Lucy/Test/Util/TestSortExternal.c 
b/test/Lucy/Test/Util/TestSortExternal.c
new file mode 100644
index 0000000..b55dcc2
--- /dev/null
+++ b/test/Lucy/Test/Util/TestSortExternal.c
@@ -0,0 +1,324 @@
+/* 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 <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#define TESTLUCY_USE_SHORT_NAMES
+#include "Lucy/Util/ToolSet.h"
+#include "Lucy/Test/Util/TestSortExternal.h"
+
+#include "Clownfish/Blob.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
+#include "Lucy/Util/BlobSortEx.h"
+#include "Lucy/Util/SortExternal.h"
+
+static Blob *a_blob;
+static Blob *b_blob;
+static Blob *c_blob;
+static Blob *d_blob;
+static Blob *x_blob;
+static Blob *y_blob;
+static Blob *z_blob;
+
+TestSortExternal*
+TestSortExternal_new() {
+    return (TestSortExternal*)Class_Make_Obj(TESTSORTEXTERNAL);
+}
+
+static void
+S_init_blobs() {
+    a_blob = Blob_new("a", 1);
+    b_blob = Blob_new("b", 1);
+    c_blob = Blob_new("c", 1);
+    d_blob = Blob_new("d", 1);
+    x_blob = Blob_new("x", 1);
+    y_blob = Blob_new("y", 1);
+    z_blob = Blob_new("z", 1);
+}
+
+static void
+S_destroy_blobs() {
+    DECREF(a_blob);
+    DECREF(b_blob);
+    DECREF(c_blob);
+    DECREF(d_blob);
+    DECREF(x_blob);
+    DECREF(y_blob);
+    DECREF(z_blob);
+}
+
+static void
+test_bbsortex(TestBatchRunner *runner) {
+    BlobSortEx *sortex = BlobSortEx_new(4, NULL);
+
+    BlobSortEx_Feed(sortex, INCREF(c_blob));
+    TEST_INT_EQ(runner, BlobSortEx_Buffer_Count(sortex), 1,
+                "feed elem into cache");
+
+    BlobSortEx_Feed(sortex, INCREF(b_blob));
+    BlobSortEx_Feed(sortex, INCREF(d_blob));
+    BlobSortEx_Sort_Buffer(sortex);
+
+    {
+        Vector *cache  = BlobSortEx_Peek_Cache(sortex);
+        Vector *wanted = Vec_new(3);
+        Vec_Push(wanted, INCREF(b_blob));
+        Vec_Push(wanted, INCREF(c_blob));
+        Vec_Push(wanted, INCREF(d_blob));
+        TEST_TRUE(runner, Vec_Equals(cache, (Obj*)wanted), "sort cache");
+        DECREF(wanted);
+        DECREF(cache);
+    }
+
+    BlobSortEx_Feed(sortex, INCREF(a_blob));
+    TEST_INT_EQ(runner, BlobSortEx_Buffer_Count(sortex), 0,
+                "cache flushed automatically when mem_thresh crossed");
+    TEST_INT_EQ(runner, BlobSortEx_Get_Num_Runs(sortex), 1, "run added");
+
+    Vector *external = Vec_new(3);
+    Vec_Push(external, INCREF(x_blob));
+    Vec_Push(external, INCREF(y_blob));
+    Vec_Push(external, INCREF(z_blob));
+    BlobSortEx *run = BlobSortEx_new(0x1000000, external);
+    BlobSortEx_Add_Run(sortex, (SortExternal*)run);
+    BlobSortEx_Flip(sortex);
+
+    {
+        Vector *got = Vec_new(7);
+        Obj *object;
+        while (NULL != (object = BlobSortEx_Fetch(sortex))) {
+            Vec_Push(got, object);
+        }
+
+        Vector *wanted = Vec_new(7);
+        Vec_Push(wanted, INCREF(a_blob));
+        Vec_Push(wanted, INCREF(b_blob));
+        Vec_Push(wanted, INCREF(c_blob));
+        Vec_Push(wanted, INCREF(d_blob));
+        Vec_Push(wanted, INCREF(x_blob));
+        Vec_Push(wanted, INCREF(y_blob));
+        Vec_Push(wanted, INCREF(z_blob));
+
+        TEST_TRUE(runner, Vec_Equals(got, (Obj*)wanted), "Add_Run");
+
+        DECREF(wanted);
+        DECREF(got);
+    }
+
+    DECREF(external);
+    DECREF(sortex);
+}
+
+static void
+test_clear_buffer(TestBatchRunner *runner) {
+    BlobSortEx *sortex = BlobSortEx_new(4, NULL);
+
+    BlobSortEx_Feed(sortex, INCREF(c_blob));
+    BlobSortEx_Clear_Buffer(sortex);
+    TEST_INT_EQ(runner, BlobSortEx_Buffer_Count(sortex), 0, "Clear_Buffer");
+
+    BlobSortEx_Feed(sortex, INCREF(b_blob));
+    BlobSortEx_Feed(sortex, INCREF(a_blob));
+    BlobSortEx_Flush(sortex);
+    BlobSortEx_Flip(sortex);
+    Obj *object = BlobSortEx_Peek(sortex);
+    TEST_TRUE(runner, Blob_Equals(a_blob, object), "Peek");
+
+    Vector *got = Vec_new(2);
+    while (NULL != (object = BlobSortEx_Fetch(sortex))) {
+        Vec_Push(got, object);
+    }
+    Vector *wanted = Vec_new(2);
+    Vec_Push(wanted, INCREF(a_blob));
+    Vec_Push(wanted, INCREF(b_blob));
+    TEST_TRUE(runner, Vec_Equals(got, (Obj*)wanted),
+              "elements cleared via Clear_Buffer truly cleared");
+
+    DECREF(wanted);
+    DECREF(got);
+    DECREF(sortex);
+}
+
+static void
+S_test_sort(TestBatchRunner *runner, Vector *blobs, uint32_t mem_thresh,
+            const char *test_name) {
+    size_t       size     = Vec_Get_Size(blobs);
+    BlobSortEx  *sortex   = BlobSortEx_new(mem_thresh, NULL);
+    Blob       **shuffled = (Blob**)MALLOCATE(size * sizeof(Blob*));
+
+    for (size_t i = 0; i < size; ++i) {
+        shuffled[i] = (Blob*)CERTIFY(Vec_Fetch(blobs, i), BLOB);
+    }
+    for (int i = (int)size - 1; i > 0; --i) {
+        int shuffle_pos = rand() % (i + 1);
+        Blob *temp = shuffled[shuffle_pos];
+        shuffled[shuffle_pos] = shuffled[i];
+        shuffled[i] = temp;
+    }
+    for (size_t i = 0; i < size; ++i) {
+        BlobSortEx_Feed(sortex, INCREF(shuffled[i]));
+    }
+
+    BlobSortEx_Flip(sortex);
+    Vector *got = Vec_new(size);
+    Obj *object;
+    while (NULL != (object = BlobSortEx_Fetch(sortex))) {
+        Vec_Push(got, object);
+    }
+    TEST_TRUE(runner, Vec_Equals(got, (Obj*)blobs), test_name);
+
+    FREEMEM(shuffled);
+    DECREF(got);
+    DECREF(sortex);
+}
+
+static void
+S_test_sort_letters(TestBatchRunner *runner, const char *letters,
+                    uint32_t mem_thresh, const char *test_name) {
+    size_t  num_letters = strlen(letters);
+    Vector *blobs       = Vec_new(num_letters);
+
+    for (size_t i = 0; i < num_letters; ++i) {
+        char ch = letters[i];
+        size_t size = ch == '_' ? 0 : 1;
+        Blob *blob = Blob_new(&ch, size);
+        Vec_Push(blobs, (Obj*)blob);
+    }
+
+    S_test_sort(runner, blobs, mem_thresh, test_name);
+
+    DECREF(blobs);
+}
+
+static void
+test_sort_letters(TestBatchRunner *runner) {
+    S_test_sort_letters(runner, "abcdefghijklmnopqrstuvwxyz", 0x1000000,
+                        "sort letters");
+    S_test_sort_letters(runner, "aaabcdxxxxxxyy", 0x1000000,
+                        "sort repeated letters");
+    S_test_sort_letters(runner, "__abcdefghijklmnopqrstuvwxyz", 0x1000000,
+                        "sort letters and empty strings");
+    S_test_sort_letters(runner, "abcdefghijklmnopqrstuvwxyz", 30,
+                        "... with an absurdly low mem_thresh");
+    S_test_sort_letters(runner, "abcdefghijklmnopqrstuvwxyz", 1,
+                        "... with an even lower mem_thresh");
+}
+
+static void
+test_sort_nothing(TestBatchRunner *runner) {
+    BlobSortEx *sortex = BlobSortEx_new(0x1000000, NULL);
+    BlobSortEx_Flip(sortex);
+    TEST_TRUE(runner, BlobSortEx_Fetch(sortex) == NULL,
+              "Sorting nothing returns undef");
+    DECREF(sortex);
+}
+
+static void
+test_sort_packed_ints(TestBatchRunner *runner) {
+    size_t  num_ints = 11001;
+    Vector *blobs    = Vec_new(num_ints);
+
+    for (uint32_t i = 0; i < num_ints; ++i) {
+        uint8_t buf[4];
+        buf[0] = (uint8_t)((i >> 24) & 0xFF);
+        buf[1] = (uint8_t)((i >> 16) & 0xFF);
+        buf[2] = (uint8_t)((i >> 8)  & 0xFF);
+        buf[3] = (uint8_t)(i & 0xFF);
+        Blob *blob = Blob_new((char*)buf, 4);
+        Vec_Push(blobs, (Obj*)blob);
+    }
+
+    S_test_sort(runner, blobs, 5000, "Sorting packed integers...");
+
+    DECREF(blobs);
+}
+
+static void
+test_sort_random_strings(TestBatchRunner *runner) {
+    size_t  num_strings = 1001;
+    Vector *blobs       = Vec_new(num_strings);
+
+    for (uint32_t i = 0; i < num_strings; ++i) {
+        uint8_t buf[1201];
+        int size = rand() % 1200 + 1;
+        for (int i = 0; i < size; ++i) {
+            buf[i] = (uint8_t)(rand() % 256);
+        }
+        Blob *blob = Blob_new((char*)buf, (size_t)size);
+        Vec_Push(blobs, (Obj*)blob);
+    }
+
+    Vec_Sort(blobs);
+    S_test_sort(runner, blobs, 15000,
+                "Random binary strings of random length");
+
+    DECREF(blobs);
+}
+
+static void
+test_run(TestBatchRunner *runner) {
+    Vector *letters = Vec_new(26);
+    for (char i = 0; i < 26; ++i) {
+        char ch = 'a' + i;
+        Blob *blob = Blob_new(&ch, 1);
+        Vec_Push(letters, (Obj*)blob);
+    }
+    BlobSortEx *run = BlobSortEx_new(0x1000000, letters);
+    BlobSortEx_Set_Mem_Thresh(run, 5);
+
+    BlobSortEx_Refill(run);
+    TEST_INT_EQ(runner, BlobSortEx_Buffer_Count(run), 5,
+                "Refill doesn't exceed memory threshold");
+
+    Obj *endpost = BlobSortEx_Peek_Last(run);
+    Blob *wanted = Blob_new("e", 1);
+    TEST_TRUE(runner, Blob_Equals(wanted, endpost), "Peek_Last");
+
+    Vector *elems = Vec_new(26);
+    do {
+        while (BlobSortEx_Buffer_Count(run) > 0) {
+            Obj *object = BlobSortEx_Fetch(run);
+            Vec_Push(elems, object);
+        }
+    } while (BlobSortEx_Refill(run) > 0);
+    TEST_TRUE(runner, Vec_Equals(elems, (Obj*)letters), "retrieve all elems");
+
+    DECREF(elems);
+    DECREF(wanted);
+    DECREF(endpost);
+    DECREF(letters);
+    DECREF(run);
+}
+
+void
+TestSortExternal_Run_IMP(TestSortExternal *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 19);
+
+    srand((unsigned int)time((time_t*)NULL));
+    S_init_blobs();
+    test_bbsortex(runner);
+    test_clear_buffer(runner);
+    test_sort_letters(runner);
+    test_sort_nothing(runner);
+    test_sort_packed_ints(runner);
+    test_sort_random_strings(runner);
+    test_run(runner);
+    S_destroy_blobs();
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/Lucy/Test/Util/TestSortExternal.cfh
----------------------------------------------------------------------
diff --git a/test/Lucy/Test/Util/TestSortExternal.cfh 
b/test/Lucy/Test/Util/TestSortExternal.cfh
new file mode 100644
index 0000000..028b322
--- /dev/null
+++ b/test/Lucy/Test/Util/TestSortExternal.cfh
@@ -0,0 +1,29 @@
+/* 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.
+ */
+
+parcel TestLucy;
+
+class Lucy::Test::Util::TestSortExternal
+    inherits Clownfish::TestHarness::TestBatch {
+
+    inert incremented TestSortExternal*
+    new();
+
+    void
+    Run(TestSortExternal *self, TestBatchRunner *runner);
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/TestLucy.c
----------------------------------------------------------------------
diff --git a/test/TestLucy.c b/test/TestLucy.c
new file mode 100644
index 0000000..f499da5
--- /dev/null
+++ b/test/TestLucy.c
@@ -0,0 +1,22 @@
+/* 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 "testlucy_parcel.h"
+
+void
+testlucy_init_parcel() {
+}
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/572d3564/test/TestLucy.cfp
----------------------------------------------------------------------
diff --git a/test/TestLucy.cfp b/test/TestLucy.cfp
new file mode 100644
index 0000000..a3aef6e
--- /dev/null
+++ b/test/TestLucy.cfp
@@ -0,0 +1,8 @@
+{
+    "name": "TestLucy",
+    "version": "v0.5.0",
+    "prerequisites": {
+        "Clownfish": "v0.5.0",
+        "Lucy": "v0.5.0"
+    }
+}

Reply via email to