You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by nw...@apache.org on 2013/05/30 22:36:38 UTC

[lucy-commits] [20/26] Rework Clownfish test harness

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/Store/TestRAMFolder.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestRAMFolder.c b/core/Lucy/Test/Store/TestRAMFolder.c
index 47a69b5..0f01127 100644
--- a/core/Lucy/Test/Store/TestRAMFolder.c
+++ b/core/Lucy/Test/Store/TestRAMFolder.c
@@ -18,7 +18,7 @@
 #define TESTLUCY_USE_SHORT_NAMES
 #include "Lucy/Util/ToolSet.h"
 
-#include "Clownfish/TestHarness/TestFormatter.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
 #include "Lucy/Test.h"
 #include "Lucy/Test/Store/TestRAMFolder.h"
 #include "Lucy/Store/RAMFolder.h"
@@ -40,14 +40,8 @@ static CharBuf *nope          = NULL;
 static CharBuf *nope_nyet     = NULL;
 
 TestRAMFolder*
-TestRAMFolder_new(TestFormatter *formatter) {
-    TestRAMFolder *self = (TestRAMFolder*)VTable_Make_Obj(TESTRAMFOLDER);
-    return TestRAMFolder_init(self, formatter);
-}
-
-TestRAMFolder*
-TestRAMFolder_init(TestRAMFolder *self, TestFormatter *formatter) {
-    return (TestRAMFolder*)TestBatch_init((TestBatch*)self, 98, formatter);
+TestRAMFolder_new() {
+    return (TestRAMFolder*)VTable_Make_Obj(TESTRAMFOLDER);
 }
 
 static void
@@ -83,52 +77,52 @@ S_destroy_strings(void) {
 }
 
 static void
-test_Initialize_and_Check(TestBatch *batch) {
+test_Initialize_and_Check(TestBatchRunner *runner) {
     RAMFolder *folder = RAMFolder_new(NULL);
     RAMFolder_Initialize(folder);
-    PASS(batch, "Initialized concludes without incident");
-    TEST_TRUE(batch, RAMFolder_Check(folder), "Check succeeds");
+    PASS(runner, "Initialized concludes without incident");
+    TEST_TRUE(runner, RAMFolder_Check(folder), "Check succeeds");
     DECREF(folder);
 }
 
 static void
-test_Local_Exists(TestBatch *batch) {
+test_Local_Exists(TestBatchRunner *runner) {
     RAMFolder *folder = RAMFolder_new(NULL);
     FileHandle *fh = RAMFolder_Open_FileHandle(folder, boffo,
                                                FH_CREATE | FH_WRITE_ONLY);
     DECREF(fh);
     RAMFolder_Local_MkDir(folder, foo);
 
-    TEST_TRUE(batch, RAMFolder_Local_Exists(folder, boffo),
+    TEST_TRUE(runner, RAMFolder_Local_Exists(folder, boffo),
               "Local_Exists() returns true for file");
-    TEST_TRUE(batch, RAMFolder_Local_Exists(folder, foo),
+    TEST_TRUE(runner, RAMFolder_Local_Exists(folder, foo),
               "Local_Exists() returns true for dir");
-    TEST_FALSE(batch, RAMFolder_Local_Exists(folder, bar),
+    TEST_FALSE(runner, RAMFolder_Local_Exists(folder, bar),
                "Local_Exists() returns false for non-existent entry");
 
     DECREF(folder);
 }
 
 static void
-test_Local_Is_Directory(TestBatch *batch) {
+test_Local_Is_Directory(TestBatchRunner *runner) {
     RAMFolder *folder = RAMFolder_new(NULL);
     FileHandle *fh = RAMFolder_Open_FileHandle(folder, boffo,
                                                FH_CREATE | FH_WRITE_ONLY);
     DECREF(fh);
     RAMFolder_Local_MkDir(folder, foo);
 
-    TEST_FALSE(batch, RAMFolder_Local_Is_Directory(folder, boffo),
+    TEST_FALSE(runner, RAMFolder_Local_Is_Directory(folder, boffo),
                "Local_Is_Directory() returns false for file");
-    TEST_TRUE(batch, RAMFolder_Local_Is_Directory(folder, foo),
+    TEST_TRUE(runner, RAMFolder_Local_Is_Directory(folder, foo),
               "Local_Is_Directory() returns true for dir");
-    TEST_FALSE(batch, RAMFolder_Local_Is_Directory(folder, bar),
+    TEST_FALSE(runner, RAMFolder_Local_Is_Directory(folder, bar),
                "Local_Is_Directory() returns false for non-existent entry");
 
     DECREF(folder);
 }
 
 static void
-test_Local_Find_Folder(TestBatch *batch) {
+test_Local_Find_Folder(TestBatchRunner *runner) {
     RAMFolder *folder = RAMFolder_new(NULL);
     RAMFolder *local;
     FileHandle *fh;
@@ -143,26 +137,26 @@ test_Local_Find_Folder(TestBatch *batch) {
     DECREF(fh);
 
     local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, nope);
-    TEST_TRUE(batch, local == NULL, "Non-existent entry yields NULL");
+    TEST_TRUE(runner, local == NULL, "Non-existent entry yields NULL");
 
     ZombieCharBuf *empty = ZCB_BLANK();
     local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, (CharBuf*)empty);
-    TEST_TRUE(batch, local == NULL, "Empty string yields NULL");
+    TEST_TRUE(runner, local == NULL, "Empty string yields NULL");
 
     local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, foo_bar);
-    TEST_TRUE(batch, local == NULL, "nested folder yields NULL");
+    TEST_TRUE(runner, local == NULL, "nested folder yields NULL");
 
     local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, foo_boffo);
-    TEST_TRUE(batch, local == NULL, "nested file yields NULL");
+    TEST_TRUE(runner, local == NULL, "nested file yields NULL");
 
     local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, boffo);
-    TEST_TRUE(batch, local == NULL, "local file yields NULL");
+    TEST_TRUE(runner, local == NULL, "local file yields NULL");
 
     local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, bar);
-    TEST_TRUE(batch, local == NULL, "name of nested folder yields NULL");
+    TEST_TRUE(runner, local == NULL, "name of nested folder yields NULL");
 
     local = (RAMFolder*)RAMFolder_Local_Find_Folder(folder, foo);
-    TEST_TRUE(batch,
+    TEST_TRUE(runner,
               local
               && RAMFolder_Is_A(local, RAMFOLDER)
               && CB_Equals_Str(RAMFolder_Get_Path(local), "foo", 3),
@@ -172,20 +166,20 @@ test_Local_Find_Folder(TestBatch *batch) {
 }
 
 static void
-test_Local_MkDir(TestBatch *batch) {
+test_Local_MkDir(TestBatchRunner *runner) {
     RAMFolder *folder = RAMFolder_new(NULL);
     bool result;
 
     result = RAMFolder_Local_MkDir(folder, foo);
-    TEST_TRUE(batch, result, "Local_MkDir succeeds and returns true");
+    TEST_TRUE(runner, result, "Local_MkDir succeeds and returns true");
 
     Err_set_error(NULL);
     result = RAMFolder_Local_MkDir(folder, foo);
-    TEST_FALSE(batch, result,
+    TEST_FALSE(runner, result,
                "Local_MkDir returns false when a dir already exists");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Local_MkDir sets Err_error when a dir already exists");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo),
               "Existing dir untouched after failed Local_MkDir");
 
     FileHandle *fh = RAMFolder_Open_FileHandle(folder, boffo,
@@ -193,11 +187,11 @@ test_Local_MkDir(TestBatch *batch) {
     DECREF(fh);
     Err_set_error(NULL);
     result = RAMFolder_Local_MkDir(folder, foo);
-    TEST_FALSE(batch, result,
+    TEST_FALSE(runner, result,
                "Local_MkDir returns false when a file already exists");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Local_MkDir sets Err_error when a file already exists");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, boffo) &&
+    TEST_TRUE(runner, RAMFolder_Exists(folder, boffo) &&
               !RAMFolder_Local_Is_Directory(folder, boffo),
               "Existing file untouched after failed Local_MkDir");
 
@@ -205,62 +199,62 @@ test_Local_MkDir(TestBatch *batch) {
 }
 
 static void
-test_Local_Open_Dir(TestBatch *batch) {
+test_Local_Open_Dir(TestBatchRunner *runner) {
     RAMFolder *folder = RAMFolder_new(NULL);
     DirHandle *dh = RAMFolder_Local_Open_Dir(folder);
-    TEST_TRUE(batch, dh && DH_Is_A(dh, RAMDIRHANDLE),
+    TEST_TRUE(runner, dh && DH_Is_A(dh, RAMDIRHANDLE),
               "Local_Open_Dir returns a RAMDirHandle");
     DECREF(dh);
     DECREF(folder);
 }
 
 static void
-test_Local_Open_FileHandle(TestBatch *batch) {
+test_Local_Open_FileHandle(TestBatchRunner *runner) {
     RAMFolder *folder = RAMFolder_new(NULL);
     FileHandle *fh;
 
     fh = RAMFolder_Local_Open_FileHandle(folder, boffo,
                                          FH_CREATE | FH_WRITE_ONLY);
-    TEST_TRUE(batch, fh && FH_Is_A(fh, RAMFILEHANDLE),
+    TEST_TRUE(runner, fh && FH_Is_A(fh, RAMFILEHANDLE),
               "opened FileHandle");
     DECREF(fh);
 
     fh = RAMFolder_Local_Open_FileHandle(folder, boffo,
                                          FH_CREATE | FH_WRITE_ONLY);
-    TEST_TRUE(batch, fh && FH_Is_A(fh, RAMFILEHANDLE),
+    TEST_TRUE(runner, fh && FH_Is_A(fh, RAMFILEHANDLE),
               "opened FileHandle for append");
     DECREF(fh);
 
     Err_set_error(NULL);
     fh = RAMFolder_Local_Open_FileHandle(folder, boffo,
                                          FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE);
-    TEST_TRUE(batch, fh == NULL, "FH_EXLUSIVE flag prevents open");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, fh == NULL, "FH_EXLUSIVE flag prevents open");
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "failure due to FH_EXLUSIVE flag sets Err_error");
 
     fh = RAMFolder_Local_Open_FileHandle(folder, boffo, FH_READ_ONLY);
-    TEST_TRUE(batch, fh && FH_Is_A(fh, RAMFILEHANDLE),
+    TEST_TRUE(runner, fh && FH_Is_A(fh, RAMFILEHANDLE),
               "opened FileHandle for reading");
     DECREF(fh);
 
     Err_set_error(NULL);
     fh = RAMFolder_Local_Open_FileHandle(folder, nope, FH_READ_ONLY);
-    TEST_TRUE(batch, fh == NULL,
+    TEST_TRUE(runner, fh == NULL,
               "Can't open non-existent file for reading");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Opening non-existent file for reading sets Err_error");
 
     DECREF(folder);
 }
 
 static void
-test_Local_Delete(TestBatch *batch) {
+test_Local_Delete(TestBatchRunner *runner) {
     RAMFolder *folder = RAMFolder_new(NULL);
     FileHandle *fh;
 
     fh = RAMFolder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY);
     DECREF(fh);
-    TEST_TRUE(batch, RAMFolder_Local_Delete(folder, boffo),
+    TEST_TRUE(runner, RAMFolder_Local_Delete(folder, boffo),
               "Local_Delete on file succeeds");
 
     RAMFolder_Local_MkDir(folder, foo);
@@ -269,18 +263,18 @@ test_Local_Delete(TestBatch *batch) {
     DECREF(fh);
 
     Err_set_error(NULL);
-    TEST_FALSE(batch, RAMFolder_Local_Delete(folder, foo),
+    TEST_FALSE(runner, RAMFolder_Local_Delete(folder, foo),
                "Local_Delete on non-empty dir fails");
 
     RAMFolder_Delete(folder, foo_boffo);
-    TEST_TRUE(batch, RAMFolder_Local_Delete(folder, foo),
+    TEST_TRUE(runner, RAMFolder_Local_Delete(folder, foo),
               "Local_Delete on empty dir succeeds");
 
     DECREF(folder);
 }
 
 static void
-test_Rename(TestBatch *batch) {
+test_Rename(TestBatchRunner *runner) {
     RAMFolder *folder = RAMFolder_new(NULL);
     FileHandle *fh;
     bool result;
@@ -293,115 +287,115 @@ test_Rename(TestBatch *batch) {
     // Move files.
 
     result = RAMFolder_Rename(folder, boffo, banana);
-    TEST_TRUE(batch, result, "Rename succeeds and returns true");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, banana),
+    TEST_TRUE(runner, result, "Rename succeeds and returns true");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, banana),
               "File exists at new path");
-    TEST_FALSE(batch, RAMFolder_Exists(folder, boffo),
+    TEST_FALSE(runner, RAMFolder_Exists(folder, boffo),
                "File no longer exists at old path");
 
     result = RAMFolder_Rename(folder, banana, foo_bar_boffo);
-    TEST_TRUE(batch, result, "Rename to file in nested dir");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_bar_boffo),
+    TEST_TRUE(runner, result, "Rename to file in nested dir");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar_boffo),
               "File exists at new path");
-    TEST_FALSE(batch, RAMFolder_Exists(folder, banana),
+    TEST_FALSE(runner, RAMFolder_Exists(folder, banana),
                "File no longer exists at old path");
 
     result = RAMFolder_Rename(folder, foo_bar_boffo, boffo);
-    TEST_TRUE(batch, result, "Rename from file in nested dir");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, boffo),
+    TEST_TRUE(runner, result, "Rename from file in nested dir");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, boffo),
               "File exists at new path");
-    TEST_FALSE(batch, RAMFolder_Exists(folder, foo_bar_boffo),
+    TEST_FALSE(runner, RAMFolder_Exists(folder, foo_bar_boffo),
                "File no longer exists at old path");
 
     fh = RAMFolder_Open_FileHandle(folder, foo_boffo,
                                    FH_CREATE | FH_WRITE_ONLY);
     DECREF(fh);
     result = RAMFolder_Rename(folder, boffo, foo_boffo);
-    TEST_TRUE(batch, result, "Clobber");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, result, "Clobber");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo),
               "File exists at new path");
-    TEST_FALSE(batch, RAMFolder_Exists(folder, boffo),
+    TEST_FALSE(runner, RAMFolder_Exists(folder, boffo),
                "File no longer exists at old path");
 
     // Move Dirs.
 
     RAMFolder_MkDir(folder, baz);
     result = RAMFolder_Rename(folder, baz, boffo);
-    TEST_TRUE(batch, result, "Rename dir");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, boffo),
+    TEST_TRUE(runner, result, "Rename dir");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, boffo),
               "Folder exists at new path");
-    TEST_FALSE(batch, RAMFolder_Exists(folder, baz),
+    TEST_FALSE(runner, RAMFolder_Exists(folder, baz),
                "Folder no longer exists at old path");
 
     result = RAMFolder_Rename(folder, boffo, foo_foo);
-    TEST_TRUE(batch, result, "Rename dir into nested subdir");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_foo),
+    TEST_TRUE(runner, result, "Rename dir into nested subdir");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_foo),
               "Folder exists at new path");
-    TEST_FALSE(batch, RAMFolder_Exists(folder, boffo),
+    TEST_FALSE(runner, RAMFolder_Exists(folder, boffo),
                "Folder no longer exists at old path");
 
     result = RAMFolder_Rename(folder, foo_foo, foo_bar_baz);
-    TEST_TRUE(batch, result, "Rename dir from nested subdir");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_bar_baz),
+    TEST_TRUE(runner, result, "Rename dir from nested subdir");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar_baz),
               "Folder exists at new path");
-    TEST_FALSE(batch, RAMFolder_Exists(folder, foo_foo),
+    TEST_FALSE(runner, RAMFolder_Exists(folder, foo_foo),
                "Folder no longer exists at old path");
 
     // Test failed clobbers.
 
     Err_set_error(NULL);
     result = RAMFolder_Rename(folder, foo_boffo, foo_bar);
-    TEST_FALSE(batch, result, "Rename file clobbering dir fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_FALSE(runner, result, "Rename file clobbering dir fails");
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Failed rename sets Err_error");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo),
               "File still exists at old path");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_bar),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar),
               "Dir still exists after failed clobber");
 
     Err_set_error(NULL);
     result = RAMFolder_Rename(folder, foo_bar, foo_boffo);
-    TEST_FALSE(batch, result, "Rename dir clobbering file fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_FALSE(runner, result, "Rename dir clobbering file fails");
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Failed rename sets Err_error");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_bar),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar),
               "Dir still exists at old path");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo),
               "File still exists after failed clobber");
 
     // Test that "renaming" succeeds where to and from are the same.
 
     result = RAMFolder_Rename(folder, foo_boffo, foo_boffo);
-    TEST_TRUE(batch, result, "Renaming file to itself succeeds");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, result, "Renaming file to itself succeeds");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo),
               "File still exists");
 
     result = RAMFolder_Rename(folder, foo_bar, foo_bar);
-    TEST_TRUE(batch, result, "Renaming dir to itself succeeds");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_bar),
+    TEST_TRUE(runner, result, "Renaming dir to itself succeeds");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar),
               "Dir still exists");
 
     // Invalid filepaths.
 
     Err_set_error(NULL);
     result = RAMFolder_Rename(folder, foo_boffo, nope_nyet);
-    TEST_FALSE(batch, result, "Rename into non-existent subdir fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_FALSE(runner, result, "Rename into non-existent subdir fails");
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Renaming into non-existent subdir sets Err_error");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo),
               "Entry still exists at old path");
 
     Err_set_error(NULL);
     result = RAMFolder_Rename(folder, nope_nyet, boffo);
-    TEST_FALSE(batch, result, "Rename non-existent file fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_FALSE(runner, result, "Rename non-existent file fails");
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Renaming non-existent source file sets Err_error");
 
     DECREF(folder);
 }
 
 static void
-test_Hard_Link(TestBatch *batch) {
+test_Hard_Link(TestBatchRunner *runner) {
     RAMFolder *folder = RAMFolder_new(NULL);
     FileHandle *fh;
     bool result;
@@ -414,26 +408,26 @@ test_Hard_Link(TestBatch *batch) {
     // Link files.
 
     result = RAMFolder_Hard_Link(folder, boffo, banana);
-    TEST_TRUE(batch, result, "Hard_Link succeeds and returns true");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, banana),
+    TEST_TRUE(runner, result, "Hard_Link succeeds and returns true");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, banana),
               "File exists at new path");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, boffo),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, boffo),
               "File still exists at old path");
     RAMFolder_Delete(folder, boffo);
 
     result = RAMFolder_Hard_Link(folder, banana, foo_bar_boffo);
-    TEST_TRUE(batch, result, "Hard_Link to target within nested dir");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_bar_boffo),
+    TEST_TRUE(runner, result, "Hard_Link to target within nested dir");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar_boffo),
               "File exists at new path");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, banana),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, banana),
               "File still exists at old path");
     RAMFolder_Delete(folder, banana);
 
     result = RAMFolder_Hard_Link(folder, foo_bar_boffo, foo_boffo);
-    TEST_TRUE(batch, result, "Hard_Link from file in nested dir");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, result, "Hard_Link from file in nested dir");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo),
               "File exists at new path");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_bar_boffo),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_bar_boffo),
               "File still exists at old path");
     RAMFolder_Delete(folder, foo_bar_boffo);
 
@@ -442,19 +436,19 @@ test_Hard_Link(TestBatch *batch) {
     fh = RAMFolder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY);
     DECREF(fh);
     result = RAMFolder_Hard_Link(folder, foo_boffo, boffo);
-    TEST_FALSE(batch, result, "Clobber of file fails");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, boffo),
+    TEST_FALSE(runner, result, "Clobber of file fails");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, boffo),
               "File still exists at new path");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo),
               "File still exists at old path");
     RAMFolder_Delete(folder, boffo);
 
     RAMFolder_MkDir(folder, baz);
     result = RAMFolder_Hard_Link(folder, foo_boffo, baz);
-    TEST_FALSE(batch, result, "Clobber of dir fails");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, baz),
+    TEST_FALSE(runner, result, "Clobber of dir fails");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, baz),
               "Dir still exists at new path");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo),
               "File still exists at old path");
     RAMFolder_Delete(folder, baz);
 
@@ -462,65 +456,65 @@ test_Hard_Link(TestBatch *batch) {
 
     RAMFolder_MkDir(folder, baz);
     result = RAMFolder_Hard_Link(folder, baz, banana);
-    TEST_FALSE(batch, result, "Hard_Link dir fails");
-    TEST_FALSE(batch, RAMFolder_Exists(folder, banana),
+    TEST_FALSE(runner, result, "Hard_Link dir fails");
+    TEST_FALSE(runner, RAMFolder_Exists(folder, banana),
                "Nothing at new path");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, baz),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, baz),
               "Folder still exists at old path");
     RAMFolder_Delete(folder, baz);
 
     // Test that linking to yourself fails.
 
     result = RAMFolder_Hard_Link(folder, foo_boffo, foo_boffo);
-    TEST_FALSE(batch, result, "Hard_Link file to itself fails");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_boffo),
+    TEST_FALSE(runner, result, "Hard_Link file to itself fails");
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo),
               "File still exists");
 
     // Invalid filepaths.
 
     Err_set_error(NULL);
     result = RAMFolder_Rename(folder, foo_boffo, nope_nyet);
-    TEST_FALSE(batch, result, "Hard_Link into non-existent subdir fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_FALSE(runner, result, "Hard_Link into non-existent subdir fails");
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Hard_Link into non-existent subdir sets Err_error");
-    TEST_TRUE(batch, RAMFolder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, RAMFolder_Exists(folder, foo_boffo),
               "Entry still exists at old path");
 
     Err_set_error(NULL);
     result = RAMFolder_Rename(folder, nope_nyet, boffo);
-    TEST_FALSE(batch, result, "Hard_Link non-existent source file fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_FALSE(runner, result, "Hard_Link non-existent source file fails");
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Hard_Link non-existent source file sets Err_error");
 
     DECREF(folder);
 }
 
 static void
-test_Close(TestBatch *batch) {
+test_Close(TestBatchRunner *runner) {
     RAMFolder *folder = RAMFolder_new(NULL);
     RAMFolder_Close(folder);
-    PASS(batch, "Close() concludes without incident");
+    PASS(runner, "Close() concludes without incident");
     RAMFolder_Close(folder);
     RAMFolder_Close(folder);
-    PASS(batch, "Calling Close() multiple times is safe");
+    PASS(runner, "Calling Close() multiple times is safe");
     DECREF(folder);
 }
 
 void
-TestRAMFolder_run_tests(TestRAMFolder *self) {
-    TestBatch *batch = (TestBatch*)self;
+TestRAMFolder_run(TestRAMFolder *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 98);
     S_init_strings();
-    test_Initialize_and_Check(batch);
-    test_Local_Exists(batch);
-    test_Local_Is_Directory(batch);
-    test_Local_Find_Folder(batch);
-    test_Local_MkDir(batch);
-    test_Local_Open_Dir(batch);
-    test_Local_Open_FileHandle(batch);
-    test_Local_Delete(batch);
-    test_Rename(batch);
-    test_Hard_Link(batch);
-    test_Close(batch);
+    test_Initialize_and_Check(runner);
+    test_Local_Exists(runner);
+    test_Local_Is_Directory(runner);
+    test_Local_Find_Folder(runner);
+    test_Local_MkDir(runner);
+    test_Local_Open_Dir(runner);
+    test_Local_Open_FileHandle(runner);
+    test_Local_Delete(runner);
+    test_Rename(runner);
+    test_Hard_Link(runner);
+    test_Close(runner);
     S_destroy_strings();
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/Store/TestRAMFolder.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestRAMFolder.cfh b/core/Lucy/Test/Store/TestRAMFolder.cfh
index 231e579..6fc392c 100644
--- a/core/Lucy/Test/Store/TestRAMFolder.cfh
+++ b/core/Lucy/Test/Store/TestRAMFolder.cfh
@@ -20,13 +20,10 @@ class Lucy::Test::Store::TestRAMFolder
     inherits Clownfish::TestHarness::TestBatch {
 
     inert incremented TestRAMFolder*
-    new(TestFormatter *formatter);
-
-    inert TestRAMFolder*
-    init(TestRAMFolder *self, TestFormatter *formatter);
+    new();
 
     void
-    Run_Tests(TestRAMFolder *self);
+    Run(TestRAMFolder *self, TestBatchRunner *runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/TestSchema.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/TestSchema.c b/core/Lucy/Test/TestSchema.c
index 847fa74..6dcb80e 100644
--- a/core/Lucy/Test/TestSchema.c
+++ b/core/Lucy/Test/TestSchema.c
@@ -18,7 +18,7 @@
 #define TESTLUCY_USE_SHORT_NAMES
 #include "Lucy/Util/ToolSet.h"
 
-#include "Clownfish/TestHarness/TestFormatter.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
 #include "Lucy/Test.h"
 #include "Lucy/Test/Plan/TestArchitecture.h"
 #include "Lucy/Test/TestSchema.h"
@@ -54,18 +54,12 @@ TestSchema_architecture(TestSchema *self) {
 }
 
 TestBatchSchema*
-TestBatchSchema_new(TestFormatter *formatter) {
-    TestBatchSchema *self = (TestBatchSchema*)VTable_Make_Obj(TESTBATCHSCHEMA);
-    return TestBatchSchema_init(self, formatter);
-}
-
-TestBatchSchema*
-TestBatchSchema_init(TestBatchSchema *self, TestFormatter *formatter) {
-    return (TestBatchSchema*)TestBatch_init((TestBatch*)self, 4, formatter);
+TestBatchSchema_new() {
+    return (TestBatchSchema*)VTable_Make_Obj(TESTBATCHSCHEMA);
 }
 
 static void
-test_Equals(TestBatch *batch) {
+test_Equals(TestBatchRunner *runner) {
     TestSchema *schema = TestSchema_new();
     TestSchema *arch_differs = TestSchema_new();
     TestSchema *spec_differs = TestSchema_new();
@@ -73,15 +67,15 @@ test_Equals(TestBatch *batch) {
     FullTextType *type = (FullTextType*)TestSchema_Fetch_Type(spec_differs,
                                                               content);
 
-    TEST_TRUE(batch, TestSchema_Equals(schema, (Obj*)schema), "Equals");
+    TEST_TRUE(runner, TestSchema_Equals(schema, (Obj*)schema), "Equals");
 
     FullTextType_Set_Boost(type, 2.0f);
-    TEST_FALSE(batch, TestSchema_Equals(schema, (Obj*)spec_differs),
+    TEST_FALSE(runner, TestSchema_Equals(schema, (Obj*)spec_differs),
                "Equals spoiled by differing FieldType");
 
     DECREF(arch_differs->arch);
     arch_differs->arch = Arch_new();
-    TEST_FALSE(batch, TestSchema_Equals(schema, (Obj*)arch_differs),
+    TEST_FALSE(runner, TestSchema_Equals(schema, (Obj*)arch_differs),
                "Equals spoiled by differing Architecture");
 
     DECREF(schema);
@@ -90,12 +84,12 @@ test_Equals(TestBatch *batch) {
 }
 
 static void
-test_Dump_and_Load(TestBatch *batch) {
+test_Dump_and_Load(TestBatchRunner *runner) {
     TestSchema *schema = TestSchema_new();
     Obj        *dump   = (Obj*)TestSchema_Dump(schema);
     TestSchema *loaded = (TestSchema*)Obj_Load(dump, dump);
 
-    TEST_FALSE(batch, TestSchema_Equals(schema, (Obj*)loaded),
+    TEST_FALSE(runner, TestSchema_Equals(schema, (Obj*)loaded),
                "Dump => Load round trip");
 
     DECREF(schema);
@@ -104,10 +98,10 @@ test_Dump_and_Load(TestBatch *batch) {
 }
 
 void
-TestBatchSchema_run_tests(TestBatchSchema *self) {
-    TestBatch *batch = (TestBatch*)self;
-    test_Equals(batch);
-    test_Dump_and_Load(batch);
+TestBatchSchema_run(TestBatchSchema *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 4);
+    test_Equals(runner);
+    test_Dump_and_Load(runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/TestSchema.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/TestSchema.cfh b/core/Lucy/Test/TestSchema.cfh
index 758c707..c422435 100644
--- a/core/Lucy/Test/TestSchema.cfh
+++ b/core/Lucy/Test/TestSchema.cfh
@@ -37,13 +37,10 @@ class Lucy::Test::TestBatchSchema
     inherits Clownfish::TestHarness::TestBatch {
 
     inert incremented TestBatchSchema*
-    new(TestFormatter *formatter);
-
-    inert TestBatchSchema*
-    init(TestBatchSchema *self, TestFormatter *formatter);
+    new();
 
     void
-    Run_Tests(TestBatchSchema *self);
+    Run(TestBatchSchema *self, TestBatchRunner *runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/TestUtils.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/TestUtils.c b/core/Lucy/Test/TestUtils.c
index e345338..6624389 100644
--- a/core/Lucy/Test/TestUtils.c
+++ b/core/Lucy/Test/TestUtils.c
@@ -21,7 +21,7 @@
 
 #include "Lucy/Test/TestUtils.h"
 #include "Lucy/Test.h"
-#include "Clownfish/TestHarness/TestBatch.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
 #include "Clownfish/TestHarness/TestUtils.h"
 #include "Lucy/Analysis/Analyzer.h"
 #include "Lucy/Analysis/Inversion.h"
@@ -127,8 +127,9 @@ TestUtils_make_range_query(const char *field, const char *lower_term,
 }
 
 void
-TestUtils_test_analyzer(TestBatch *batch, Analyzer *analyzer, CharBuf *source,
-                        VArray *expected, const char *message) {
+TestUtils_test_analyzer(TestBatchRunner *runner, Analyzer *analyzer,
+                        CharBuf *source, VArray *expected,
+                        const char *message) {
     Token *seed = Token_new((char*)CB_Get_Ptr8(source), CB_Get_Size(source),
                             0, 0, 1.0f, 1);
     Inversion *starter = Inversion_new(seed);
@@ -140,7 +141,7 @@ TestUtils_test_analyzer(TestBatch *batch, Analyzer *analyzer, CharBuf *source,
             = CB_new_from_utf8(Token_Get_Text(token), Token_Get_Len(token));
         VA_Push(got, (Obj*)token_text);
     }
-    TEST_TRUE(batch, VA_Equals(expected, (Obj*)got),
+    TEST_TRUE(runner, VA_Equals(expected, (Obj*)got),
               "Transform(): %s", message);
     DECREF(transformed);
 
@@ -151,13 +152,13 @@ TestUtils_test_analyzer(TestBatch *batch, Analyzer *analyzer, CharBuf *source,
             = CB_new_from_utf8(Token_Get_Text(token), Token_Get_Len(token));
         VA_Push(got, (Obj*)token_text);
     }
-    TEST_TRUE(batch, VA_Equals(expected, (Obj*)got),
+    TEST_TRUE(runner, VA_Equals(expected, (Obj*)got),
               "Transform_Text(): %s", message);
     DECREF(transformed);
 
     DECREF(got);
     got = Analyzer_Split(analyzer, source);
-    TEST_TRUE(batch, VA_Equals(expected, (Obj*)got), "Split(): %s", message);
+    TEST_TRUE(runner, VA_Equals(expected, (Obj*)got), "Split(): %s", message);
 
     DECREF(got);
     DECREF(starter);

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/TestUtils.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/TestUtils.cfh b/core/Lucy/Test/TestUtils.cfh
index 189ad0a..9dc07ad 100644
--- a/core/Lucy/Test/TestUtils.cfh
+++ b/core/Lucy/Test/TestUtils.cfh
@@ -62,7 +62,7 @@ inert class Lucy::Test::TestUtils  {
     /** Verify an Analyzer's transform, transform_text, and split methods.
      */
     inert void
-    test_analyzer(TestBatch *batch, Analyzer *analyzer, CharBuf *source,
+    test_analyzer(TestBatchRunner *runner, Analyzer *analyzer, CharBuf *source,
                   VArray *expected, const char *message);
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/Util/TestIndexFileNames.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Util/TestIndexFileNames.c b/core/Lucy/Test/Util/TestIndexFileNames.c
index 5f7e41a..b3f89ed 100644
--- a/core/Lucy/Test/Util/TestIndexFileNames.c
+++ b/core/Lucy/Test/Util/TestIndexFileNames.c
@@ -17,78 +17,72 @@
 #define TESTLUCY_USE_SHORT_NAMES
 #include "Lucy/Util/ToolSet.h"
 
-#include "Clownfish/TestHarness/TestFormatter.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
 #include "Lucy/Test.h"
 #include "Lucy/Test/Util/TestIndexFileNames.h"
 #include "Lucy/Util/IndexFileNames.h"
 
 TestIndexFileNames*
-TestIxFileNames_new(TestFormatter *formatter) {
-    TestIndexFileNames *self = (TestIndexFileNames*)VTable_Make_Obj(TESTINDEXFILENAMES);
-    return TestIxFileNames_init(self, formatter);
-}
-
-TestIndexFileNames*
-TestIxFileNames_init(TestIndexFileNames *self, TestFormatter *formatter) {
-    return (TestIndexFileNames*)TestBatch_init((TestBatch*)self, 10, formatter);
+TestIxFileNames_new() {
+    return (TestIndexFileNames*)VTable_Make_Obj(TESTINDEXFILENAMES);
 }
 
 static void
-test_local_part(TestBatch *batch) {
+test_local_part(TestBatchRunner *runner) {
     ZombieCharBuf *source = ZCB_BLANK();
     ZombieCharBuf *got    = ZCB_BLANK();
 
     got = IxFileNames_local_part((CharBuf*)source, got);
-    TEST_TRUE(batch, ZCB_Equals(got, (Obj*)source), "simple name");
+    TEST_TRUE(runner, ZCB_Equals(got, (Obj*)source), "simple name");
 
     ZCB_Assign_Str(source, "foo.txt", 7);
     got = IxFileNames_local_part((CharBuf*)source, got);
-    TEST_TRUE(batch, ZCB_Equals(got, (Obj*)source), "name with extension");
+    TEST_TRUE(runner, ZCB_Equals(got, (Obj*)source), "name with extension");
 
     ZCB_Assign_Str(source, "/foo", 4);
     got = IxFileNames_local_part((CharBuf*)source, got);
-    TEST_TRUE(batch, ZCB_Equals_Str(got, "foo", 3), "strip leading slash");
+    TEST_TRUE(runner, ZCB_Equals_Str(got, "foo", 3), "strip leading slash");
 
     ZCB_Assign_Str(source, "/foo/", 5);
     got = IxFileNames_local_part((CharBuf*)source, got);
-    TEST_TRUE(batch, ZCB_Equals_Str(got, "foo", 3), "strip trailing slash");
+    TEST_TRUE(runner, ZCB_Equals_Str(got, "foo", 3), "strip trailing slash");
 
     ZCB_Assign_Str(source, "foo/bar\\ ", 9);
     got = IxFileNames_local_part((CharBuf*)source, got);
-    TEST_TRUE(batch, ZCB_Equals_Str(got, "bar\\ ", 5),
+    TEST_TRUE(runner, ZCB_Equals_Str(got, "bar\\ ", 5),
               "Include garbage like backslashes and spaces");
 
     ZCB_Assign_Str(source, "foo/bar/baz.txt", 15);
     got = IxFileNames_local_part((CharBuf*)source, got);
-    TEST_TRUE(batch, ZCB_Equals_Str(got, "baz.txt", 7), "find last component");
+    TEST_TRUE(runner, ZCB_Equals_Str(got, "baz.txt", 7), "find last component");
 }
 
 static void
-test_extract_gen(TestBatch *batch) {
+test_extract_gen(TestBatchRunner *runner) {
     ZombieCharBuf *source = ZCB_WRAP_STR("", 0);
 
     ZCB_Assign_Str(source, "seg_9", 5);
-    TEST_TRUE(batch, IxFileNames_extract_gen((CharBuf*)source) == 9,
+    TEST_TRUE(runner, IxFileNames_extract_gen((CharBuf*)source) == 9,
               "extract_gen");
 
     ZCB_Assign_Str(source, "seg_9/", 6);
-    TEST_TRUE(batch, IxFileNames_extract_gen((CharBuf*)source) == 9,
+    TEST_TRUE(runner, IxFileNames_extract_gen((CharBuf*)source) == 9,
               "deal with trailing slash");
 
     ZCB_Assign_Str(source, "seg_9_8", 7);
-    TEST_TRUE(batch, IxFileNames_extract_gen((CharBuf*)source) == 9,
+    TEST_TRUE(runner, IxFileNames_extract_gen((CharBuf*)source) == 9,
               "Only go past first underscore");
 
     ZCB_Assign_Str(source, "snapshot_5.json", 15);
-    TEST_TRUE(batch, IxFileNames_extract_gen((CharBuf*)source) == 5,
+    TEST_TRUE(runner, IxFileNames_extract_gen((CharBuf*)source) == 5,
               "Deal with file suffix");
 }
 
 void
-TestIxFileNames_run_tests(TestIndexFileNames *self) {
-    TestBatch *batch = (TestBatch*)self;
-    test_local_part(batch);
-    test_extract_gen(batch);
+TestIxFileNames_run(TestIndexFileNames *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 10);
+    test_local_part(runner);
+    test_extract_gen(runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/Util/TestIndexFileNames.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Util/TestIndexFileNames.cfh b/core/Lucy/Test/Util/TestIndexFileNames.cfh
index 44323de..e098c72 100644
--- a/core/Lucy/Test/Util/TestIndexFileNames.cfh
+++ b/core/Lucy/Test/Util/TestIndexFileNames.cfh
@@ -20,13 +20,10 @@ class Lucy::Test::Util::TestIndexFileNames cnick TestIxFileNames
     inherits Clownfish::TestHarness::TestBatch {
 
     inert incremented TestIndexFileNames*
-    new(TestFormatter *formatter);
-
-    inert TestIndexFileNames*
-    init(TestIndexFileNames *self, TestFormatter *formatter);
+    new();
 
     void
-    Run_Tests(TestIndexFileNames *self);
+    Run(TestIndexFileNames *self, TestBatchRunner *runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/Util/TestJson.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Util/TestJson.c b/core/Lucy/Test/Util/TestJson.c
index 7be389a..8962c8c 100644
--- a/core/Lucy/Test/Util/TestJson.c
+++ b/core/Lucy/Test/Util/TestJson.c
@@ -18,7 +18,7 @@
 #define TESTLUCY_USE_SHORT_NAMES
 #include "Lucy/Util/ToolSet.h"
 
-#include "Clownfish/TestHarness/TestFormatter.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
 #include "Lucy/Test.h"
 #include "Lucy/Test/Util/TestJson.h"
 #include "Lucy/Util/Json.h"
@@ -26,18 +26,8 @@
 #include "Lucy/Store/RAMFolder.h"
 
 TestJson*
-TestJson_new(TestFormatter *formatter) {
-    TestJson *self = (TestJson*)VTable_Make_Obj(TESTJSON);
-    return TestJson_init(self, formatter);
-}
-
-TestJson*
-TestJson_init(TestJson *self, TestFormatter *formatter) {
-    int num_tests = 107;
-#ifndef LUCY_VALGRIND
-    num_tests += 28; // FIXME: syntax errors leak memory.
-#endif
-    return (TestJson*)TestBatch_init((TestBatch*)self, num_tests, formatter);
+TestJson_new() {
+    return (TestJson*)VTable_Make_Obj(TESTJSON);
 }
 
 // Create a test data structure including at least one each of Hash, VArray,
@@ -51,12 +41,12 @@ S_make_dump() {
 }
 
 static void
-test_tolerance(TestBatch *batch) {
+test_tolerance(TestBatchRunner *runner) {
     CharBuf *foo = CB_newf("foo");
     CharBuf *not_json = Json_to_json((Obj*)foo);
-    TEST_TRUE(batch, not_json == NULL,
+    TEST_TRUE(runner, not_json == NULL,
               "to_json returns NULL when fed invalid data type");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "to_json sets Err_error when fed invalid data type");
     DECREF(foo);
 }
@@ -123,7 +113,7 @@ static const char* quote_escapes_json[] = {
 };
 
 static void
-test_escapes(TestBatch *batch) {
+test_escapes(TestBatchRunner *runner) {
     CharBuf *string      = CB_new(10);
     CharBuf *json_wanted = CB_new(10);
 
@@ -136,10 +126,10 @@ test_escapes(TestBatch *batch) {
 
         CB_setf(json_wanted, "\"%s\"", escaped);
         CB_Trim(json);
-        TEST_TRUE(batch, json != NULL && CB_Equals(json_wanted, (Obj*)json),
+        TEST_TRUE(runner, json != NULL && CB_Equals(json_wanted, (Obj*)json),
                   "encode control escape: %s", escaped);
 
-        TEST_TRUE(batch, decoded != NULL && CB_Equals(string, (Obj*)decoded),
+        TEST_TRUE(runner, decoded != NULL && CB_Equals(string, (Obj*)decoded),
                   "decode control escape: %s", escaped);
 
         DECREF(json);
@@ -155,10 +145,10 @@ test_escapes(TestBatch *batch) {
 
         CB_setf(json_wanted, "\"%s\"", escaped);
         CB_Trim(json);
-        TEST_TRUE(batch, json != NULL && CB_Equals(json_wanted, (Obj*)json),
+        TEST_TRUE(runner, json != NULL && CB_Equals(json_wanted, (Obj*)json),
                   "encode quote/backslash escapes: %s", source);
 
-        TEST_TRUE(batch, decoded != NULL && CB_Equals(string, (Obj*)decoded),
+        TEST_TRUE(runner, decoded != NULL && CB_Equals(string, (Obj*)decoded),
                   "decode quote/backslash escapes: %s", source);
 
         DECREF(json);
@@ -170,11 +160,11 @@ test_escapes(TestBatch *batch) {
 }
 
 static void
-test_numbers(TestBatch *batch) {
+test_numbers(TestBatchRunner *runner) {
     Integer64 *i64  = Int64_new(33);
     CharBuf   *json = Json_to_json((Obj*)i64);
     CB_Trim(json);
-    TEST_TRUE(batch, json && CB_Equals_Str(json, "33", 2), "Integer");
+    TEST_TRUE(runner, json && CB_Equals_Str(json, "33", 2), "Integer");
     DECREF(json);
 
     Float64 *f64 = Float64_new(33.33);
@@ -183,11 +173,11 @@ test_numbers(TestBatch *batch) {
         double value = CB_To_F64(json);
         double diff = 33.33 - value;
         if (diff < 0.0) { diff = 0.0 - diff; }
-        TEST_TRUE(batch, diff < 0.0001, "Float");
+        TEST_TRUE(runner, diff < 0.0001, "Float");
         DECREF(json);
     }
     else {
-        FAIL(batch, "Float conversion to  json  failed.");
+        FAIL(runner, "Float conversion to  json  failed.");
     }
 
     DECREF(i64);
@@ -195,11 +185,11 @@ test_numbers(TestBatch *batch) {
 }
 
 static void
-test_to_and_from(TestBatch *batch) {
+test_to_and_from(TestBatchRunner *runner) {
     Obj *dump = S_make_dump();
     CharBuf *json = Json_to_json(dump);
     Obj *got = Json_from_json(json);
-    TEST_TRUE(batch, got != NULL && Obj_Equals(dump, got),
+    TEST_TRUE(runner, got != NULL && Obj_Equals(dump, got),
               "Round trip through to_json and from_json");
     DECREF(dump);
     DECREF(json);
@@ -207,33 +197,33 @@ test_to_and_from(TestBatch *batch) {
 }
 
 static void
-test_spew_and_slurp(TestBatch *batch) {
+test_spew_and_slurp(TestBatchRunner *runner) {
     Obj *dump = S_make_dump();
     Folder *folder = (Folder*)RAMFolder_new(NULL);
 
     CharBuf *foo = (CharBuf*)ZCB_WRAP_STR("foo", 3);
     bool result = Json_spew_json(dump, folder, foo);
-    TEST_TRUE(batch, result, "spew_json returns true on success");
-    TEST_TRUE(batch, Folder_Exists(folder, foo),
+    TEST_TRUE(runner, result, "spew_json returns true on success");
+    TEST_TRUE(runner, Folder_Exists(folder, foo),
               "spew_json wrote file");
 
     Obj *got = Json_slurp_json(folder, foo);
-    TEST_TRUE(batch, got && Obj_Equals(dump, got),
+    TEST_TRUE(runner, got && Obj_Equals(dump, got),
               "Round trip through spew_json and slurp_json");
     DECREF(got);
 
     Err_set_error(NULL);
     result = Json_spew_json(dump, folder, foo);
-    TEST_FALSE(batch, result, "Can't spew_json when file exists");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_FALSE(runner, result, "Can't spew_json when file exists");
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Failed spew_json sets Err_error");
 
     Err_set_error(NULL);
     CharBuf *bar = (CharBuf*)ZCB_WRAP_STR("bar", 3);
     got = Json_slurp_json(folder, bar);
-    TEST_TRUE(batch, got == NULL,
+    TEST_TRUE(runner, got == NULL,
               "slurp_json returns NULL when file doesn't exist");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Failed slurp_json sets Err_error");
 
     CharBuf *boffo = (CharBuf*)ZCB_WRAP_STR("boffo", 5);
@@ -245,9 +235,9 @@ test_spew_and_slurp(TestBatch *batch) {
 
     Err_set_error(NULL);
     got = Json_slurp_json(folder, boffo);
-    TEST_TRUE(batch, got == NULL,
+    TEST_TRUE(runner, got == NULL,
               "slurp_json returns NULL when file doesn't contain valid JSON");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Failed slurp_json sets Err_error");
     DECREF(got);
 
@@ -256,44 +246,44 @@ test_spew_and_slurp(TestBatch *batch) {
 }
 
 static void
-S_verify_bad_syntax(TestBatch *batch, const char *bad, const char *mess) {
+S_verify_bad_syntax(TestBatchRunner *runner, const char *bad, const char *mess) {
     ZombieCharBuf *has_errors = ZCB_WRAP_STR(bad, strlen(bad));
     Err_set_error(NULL);
     Obj *not_json = Json_from_json((CharBuf*)has_errors);
-    TEST_TRUE(batch, not_json == NULL, "from_json returns NULL: %s", mess);
-    TEST_TRUE(batch, Err_get_error() != NULL, "from_json sets Err_error: %s",
+    TEST_TRUE(runner, not_json == NULL, "from_json returns NULL: %s", mess);
+    TEST_TRUE(runner, Err_get_error() != NULL, "from_json sets Err_error: %s",
               mess);
 }
 
 static void
-test_syntax_errors(TestBatch *batch) {
-    S_verify_bad_syntax(batch, "[", "unclosed left bracket");
-    S_verify_bad_syntax(batch, "]", "unopened right bracket");
-    S_verify_bad_syntax(batch, "{", "unclosed left curly");
-    S_verify_bad_syntax(batch, "}", "unopened right curly");
-    S_verify_bad_syntax(batch, "{}[]", "two top-level objects");
-    S_verify_bad_syntax(batch, "[1 \"foo\"]", "missing comma in array");
-    S_verify_bad_syntax(batch, "[1, \"foo\",]", "extra comma in array");
-    S_verify_bad_syntax(batch, "{\"1\":1 \"2\":2}", "missing comma in hash");
-    S_verify_bad_syntax(batch, "{\"1\":1,\"2\":2,}", "extra comma in hash");
-    S_verify_bad_syntax(batch, "\"1", "unterminated string");
+test_syntax_errors(TestBatchRunner *runner) {
+    S_verify_bad_syntax(runner, "[", "unclosed left bracket");
+    S_verify_bad_syntax(runner, "]", "unopened right bracket");
+    S_verify_bad_syntax(runner, "{", "unclosed left curly");
+    S_verify_bad_syntax(runner, "}", "unopened right curly");
+    S_verify_bad_syntax(runner, "{}[]", "two top-level objects");
+    S_verify_bad_syntax(runner, "[1 \"foo\"]", "missing comma in array");
+    S_verify_bad_syntax(runner, "[1, \"foo\",]", "extra comma in array");
+    S_verify_bad_syntax(runner, "{\"1\":1 \"2\":2}", "missing comma in hash");
+    S_verify_bad_syntax(runner, "{\"1\":1,\"2\":2,}", "extra comma in hash");
+    S_verify_bad_syntax(runner, "\"1", "unterminated string");
     // Tolerated by strtod().
-    // S_verify_bad_syntax(batch, "1. ", "float missing fraction");
-    // S_verify_bad_syntax(batch, "-.3 ", "Number missing integral part");
-    S_verify_bad_syntax(batch, "-. ", "Number missing any digits");
-    S_verify_bad_syntax(batch, "+1.0 ", "float with prepended plus");
-    S_verify_bad_syntax(batch, "\"\\g\"", "invalid char escape");
-    S_verify_bad_syntax(batch, "\"\\uAAAZ\"", "invalid \\u escape");
+    // S_verify_bad_syntax(runner, "1. ", "float missing fraction");
+    // S_verify_bad_syntax(runner, "-.3 ", "Number missing integral part");
+    S_verify_bad_syntax(runner, "-. ", "Number missing any digits");
+    S_verify_bad_syntax(runner, "+1.0 ", "float with prepended plus");
+    S_verify_bad_syntax(runner, "\"\\g\"", "invalid char escape");
+    S_verify_bad_syntax(runner, "\"\\uAAAZ\"", "invalid \\u escape");
 }
 
 static void
-S_round_trip_integer(TestBatch *batch, int64_t value) {
+S_round_trip_integer(TestBatchRunner *runner, int64_t value) {
     Integer64 *num = Int64_new(value);
     VArray *array = VA_new(1);
     VA_Store(array, 0, (Obj*)num);
     CharBuf *json = Json_to_json((Obj*)array);
     Obj *dump = Json_from_json(json);
-    TEST_TRUE(batch, VA_Equals(array, dump), "Round trip integer %ld",
+    TEST_TRUE(runner, VA_Equals(array, dump), "Round trip integer %ld",
               (long)value);
     DECREF(dump);
     DECREF(json);
@@ -301,15 +291,15 @@ S_round_trip_integer(TestBatch *batch, int64_t value) {
 }
 
 static void
-test_integers(TestBatch *batch) {
-    S_round_trip_integer(batch, 0);
-    S_round_trip_integer(batch, -1);
-    S_round_trip_integer(batch, -1000000);
-    S_round_trip_integer(batch, 1000000);
+test_integers(TestBatchRunner *runner) {
+    S_round_trip_integer(runner, 0);
+    S_round_trip_integer(runner, -1);
+    S_round_trip_integer(runner, -1000000);
+    S_round_trip_integer(runner, 1000000);
 }
 
 static void
-S_round_trip_float(TestBatch *batch, double value, double max_diff) {
+S_round_trip_float(TestBatchRunner *runner, double value, double max_diff) {
     Float64 *num = Float64_new(value);
     VArray *array = VA_new(1);
     VA_Store(array, 0, (Obj*)num);
@@ -318,69 +308,73 @@ S_round_trip_float(TestBatch *batch, double value, double max_diff) {
     Float64 *got = (Float64*)CERTIFY(VA_Fetch((VArray*)dump, 0), FLOAT64);
     double diff = Float64_Get_Value(num) - Float64_Get_Value(got);
     if (diff < 0) { diff = 0 - diff; }
-    TEST_TRUE(batch, diff <= max_diff, "Round trip float %f", value);
+    TEST_TRUE(runner, diff <= max_diff, "Round trip float %f", value);
     DECREF(dump);
     DECREF(json);
     DECREF(array);
 }
 
 static void
-test_floats(TestBatch *batch) {
-    S_round_trip_float(batch, 0.0, 0.0);
-    S_round_trip_float(batch, 0.1, 0.00001);
-    S_round_trip_float(batch, -0.1, 0.00001);
-    S_round_trip_float(batch, 1000000.5, 1.0);
-    S_round_trip_float(batch, -1000000.5, 1.0);
+test_floats(TestBatchRunner *runner) {
+    S_round_trip_float(runner, 0.0, 0.0);
+    S_round_trip_float(runner, 0.1, 0.00001);
+    S_round_trip_float(runner, -0.1, 0.00001);
+    S_round_trip_float(runner, 1000000.5, 1.0);
+    S_round_trip_float(runner, -1000000.5, 1.0);
 }
 
 static void
-test_max_depth(TestBatch *batch) {
+test_max_depth(TestBatchRunner *runner) {
     Hash *circular = Hash_new(0);
     Hash_Store_Str(circular, "circular", 8, INCREF(circular));
     Err_set_error(NULL);
     CharBuf *not_json = Json_to_json((Obj*)circular);
-    TEST_TRUE(batch, not_json == NULL,
+    TEST_TRUE(runner, not_json == NULL,
               "to_json returns NULL when fed recursing data");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "to_json sets Err_error when fed recursing data");
     DECREF(Hash_Delete_Str(circular, "circular", 8));
     DECREF(circular);
 }
 
 static void
-test_illegal_keys(TestBatch *batch) {
+test_illegal_keys(TestBatchRunner *runner) {
     Hash *hash = Hash_new(0);
     Float64 *key = Float64_new(1.1);
     Hash_Store(hash, (Obj*)key, (Obj*)CB_newf("blah"));
     Err_set_error(NULL);
     CharBuf *not_json = Json_to_json((Obj*)hash);
-    TEST_TRUE(batch, not_json == NULL,
+    TEST_TRUE(runner, not_json == NULL,
               "to_json returns NULL when fed an illegal key");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "to_json sets Err_error when fed an illegal key");
     DECREF(key);
     DECREF(hash);
 }
 
 void
-TestJson_run_tests(TestJson *self) {
-    TestBatch *batch = (TestBatch*)self;
+TestJson_run(TestJson *self, TestBatchRunner *runner) {
+    uint32_t num_tests = 107;
+#ifndef LUCY_VALGRIND
+    num_tests += 28; // FIXME: syntax errors leak memory.
+#endif
+    TestBatchRunner_Plan(runner, (TestBatch*)self, num_tests);
 
     // Test tolerance, then liberalize for testing.
-    test_tolerance(batch);
+    test_tolerance(runner);
     Json_set_tolerant(true);
 
-    test_to_and_from(batch);
-    test_escapes(batch);
-    test_numbers(batch);
-    test_spew_and_slurp(batch);
-    test_integers(batch);
-    test_floats(batch);
-    test_max_depth(batch);
-    test_illegal_keys(batch);
+    test_to_and_from(runner);
+    test_escapes(runner);
+    test_numbers(runner);
+    test_spew_and_slurp(runner);
+    test_integers(runner);
+    test_floats(runner);
+    test_max_depth(runner);
+    test_illegal_keys(runner);
 
 #ifndef LUCY_VALGRIND
-    test_syntax_errors(batch);
+    test_syntax_errors(runner);
 #endif
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/Util/TestJson.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Util/TestJson.cfh b/core/Lucy/Test/Util/TestJson.cfh
index f077492..ddba309 100644
--- a/core/Lucy/Test/Util/TestJson.cfh
+++ b/core/Lucy/Test/Util/TestJson.cfh
@@ -20,13 +20,10 @@ class Lucy::Test::Util::TestJson
     inherits Clownfish::TestHarness::TestBatch {
 
     inert incremented TestJson*
-    new(TestFormatter *formatter);
-
-    inert TestJson*
-    init(TestJson *self, TestFormatter *formatter);
+    new();
 
     void
-    Run_Tests(TestJson *self);
+    Run(TestJson *self, TestBatchRunner *runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/Util/TestMemoryPool.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Util/TestMemoryPool.c b/core/Lucy/Test/Util/TestMemoryPool.c
index 69b5620..d671467 100644
--- a/core/Lucy/Test/Util/TestMemoryPool.c
+++ b/core/Lucy/Test/Util/TestMemoryPool.c
@@ -19,25 +19,20 @@
 #define TESTLUCY_USE_SHORT_NAMES
 #include "Lucy/Util/ToolSet.h"
 
-#include "Clownfish/TestHarness/TestFormatter.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
 #include "Lucy/Test.h"
 #include "Lucy/Test/Util/TestMemoryPool.h"
 #include "Lucy/Util/MemoryPool.h"
 
 TestMemoryPool*
-TestMemPool_new(TestFormatter *formatter) {
-    TestMemoryPool *self = (TestMemoryPool*)VTable_Make_Obj(TESTMEMORYPOOL);
-    return TestMemPool_init(self, formatter);
-}
-
-TestMemoryPool*
-TestMemPool_init(TestMemoryPool *self, TestFormatter *formatter) {
-    return (TestMemoryPool*)TestBatch_init((TestBatch*)self, 4, formatter);
+TestMemPool_new() {
+    return (TestMemoryPool*)VTable_Make_Obj(TESTMEMORYPOOL);
 }
 
 void
-TestMemPool_run_tests(TestMemoryPool *self) {
-    TestBatch  *batch    = (TestBatch*)self;
+TestMemPool_run(TestMemoryPool *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 4);
+
     MemoryPool *mem_pool = MemPool_new(0);
     MemoryPool *other    = MemPool_new(0);
     char *ptr_a, *ptr_b;
@@ -47,17 +42,17 @@ TestMemPool_run_tests(TestMemoryPool *self) {
     MemPool_Release_All(mem_pool);
 
     ptr_b = (char*)MemPool_Grab(mem_pool, 10);
-    TEST_STR_EQ(batch, ptr_b, "foo", "Recycle RAM on Release_All");
+    TEST_STR_EQ(runner, ptr_b, "foo", "Recycle RAM on Release_All");
 
     ptr_a = mem_pool->buf;
     MemPool_Resize(mem_pool, ptr_b, 6);
-    TEST_TRUE(batch, mem_pool->buf < ptr_a, "Resize");
+    TEST_TRUE(runner, mem_pool->buf < ptr_a, "Resize");
 
     ptr_a = (char*)MemPool_Grab(other, 20);
     MemPool_Release_All(other);
     MemPool_Eat(other, mem_pool);
-    TEST_TRUE(batch, other->buf == mem_pool->buf, "Eat");
-    TEST_TRUE(batch, other->buf != NULL, "Eat");
+    TEST_TRUE(runner, other->buf == mem_pool->buf, "Eat");
+    TEST_TRUE(runner, other->buf != NULL, "Eat");
 
     DECREF(mem_pool);
     DECREF(other);

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/Util/TestMemoryPool.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Util/TestMemoryPool.cfh b/core/Lucy/Test/Util/TestMemoryPool.cfh
index 378567a..f7ba344 100644
--- a/core/Lucy/Test/Util/TestMemoryPool.cfh
+++ b/core/Lucy/Test/Util/TestMemoryPool.cfh
@@ -20,13 +20,10 @@ class Lucy::Test::Util::TestMemoryPool cnick TestMemPool
     inherits Clownfish::TestHarness::TestBatch {
 
     inert incremented TestMemoryPool*
-    new(TestFormatter *formatter);
-
-    inert TestMemoryPool*
-    init(TestMemoryPool *self, TestFormatter *formatter);
+    new();
 
     void
-    Run_Tests(TestMemoryPool *self);
+    Run(TestMemoryPool *self, TestBatchRunner *runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/core/Lucy/Test/Util/TestPriorityQueue.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Util/TestPriorityQueue.c b/core/Lucy/Test/Util/TestPriorityQueue.c
index 56dc58c..67bd20c 100644
--- a/core/Lucy/Test/Util/TestPriorityQueue.c
+++ b/core/Lucy/Test/Util/TestPriorityQueue.c
@@ -18,20 +18,14 @@
 #define TESTLUCY_USE_SHORT_NAMES
 #include "Lucy/Util/ToolSet.h"
 
-#include "Clownfish/TestHarness/TestFormatter.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
 #include "Lucy/Test.h"
 #include "Lucy/Test/Util/TestPriorityQueue.h"
 #include "Lucy/Util/PriorityQueue.h"
 
 TestPriorityQueue*
-TestPriQ_new(TestFormatter *formatter) {
-    TestPriorityQueue *self = (TestPriorityQueue*)VTable_Make_Obj(TESTPRIORITYQUEUE);
-    return TestPriQ_init(self, formatter);
-}
-
-TestPriorityQueue*
-TestPriQ_init(TestPriorityQueue *self, TestFormatter *formatter) {
-    return (TestPriorityQueue*)TestBatch_init((TestBatch*)self, 17, formatter);
+TestPriQ_new() {
+    return (TestPriorityQueue*)VTable_Make_Obj(TESTPRIORITYQUEUE);
 }
 
 NumPriorityQueue*
@@ -65,7 +59,7 @@ S_pop_num(NumPriorityQueue *pq) {
 }
 
 static void
-test_Peek_and_Pop_All(TestBatch *batch) {
+test_Peek_and_Pop_All(TestBatchRunner *runner) {
     NumPriorityQueue *pq = NumPriQ_new(5);
     Float64 *val;
 
@@ -75,27 +69,27 @@ test_Peek_and_Pop_All(TestBatch *batch) {
     S_insert_num(pq, 20);
     S_insert_num(pq, 10);
     val = (Float64*)CERTIFY(NumPriQ_Peek(pq), FLOAT64);
-    TEST_INT_EQ(batch, (long)Float64_Get_Value(val), 1,
+    TEST_INT_EQ(runner, (long)Float64_Get_Value(val), 1,
                 "peek at the least item in the queue");
 
     VArray  *got = NumPriQ_Pop_All(pq);
     val = (Float64*)CERTIFY(VA_Fetch(got, 0), FLOAT64);
-    TEST_INT_EQ(batch, (long)Float64_Get_Value(val), 20, "pop_all");
+    TEST_INT_EQ(runner, (long)Float64_Get_Value(val), 20, "pop_all");
     val = (Float64*)CERTIFY(VA_Fetch(got, 1), FLOAT64);
-    TEST_INT_EQ(batch, (long)Float64_Get_Value(val), 10, "pop_all");
+    TEST_INT_EQ(runner, (long)Float64_Get_Value(val), 10, "pop_all");
     val = (Float64*)CERTIFY(VA_Fetch(got, 2), FLOAT64);
-    TEST_INT_EQ(batch, (long)Float64_Get_Value(val),  3, "pop_all");
+    TEST_INT_EQ(runner, (long)Float64_Get_Value(val),  3, "pop_all");
     val = (Float64*)CERTIFY(VA_Fetch(got, 3), FLOAT64);
-    TEST_INT_EQ(batch, (long)Float64_Get_Value(val),  2, "pop_all");
+    TEST_INT_EQ(runner, (long)Float64_Get_Value(val),  2, "pop_all");
     val = (Float64*)CERTIFY(VA_Fetch(got, 4), FLOAT64);
-    TEST_INT_EQ(batch, (long)Float64_Get_Value(val),  1, "pop_all");
+    TEST_INT_EQ(runner, (long)Float64_Get_Value(val),  1, "pop_all");
 
     DECREF(got);
     DECREF(pq);
 }
 
 static void
-test_Insert_and_Pop(TestBatch *batch) {
+test_Insert_and_Pop(TestBatchRunner *runner) {
     NumPriorityQueue *pq = NumPriQ_new(5);
 
     S_insert_num(pq, 3);
@@ -104,20 +98,20 @@ test_Insert_and_Pop(TestBatch *batch) {
     S_insert_num(pq, 20);
     S_insert_num(pq, 10);
 
-    TEST_INT_EQ(batch, S_pop_num(pq), 1, "Pop");
-    TEST_INT_EQ(batch, S_pop_num(pq), 2, "Pop");
-    TEST_INT_EQ(batch, S_pop_num(pq), 3, "Pop");
-    TEST_INT_EQ(batch, S_pop_num(pq), 10, "Pop");
+    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(batch, S_pop_num(pq), 7,
+    TEST_INT_EQ(runner, S_pop_num(pq), 7,
                 "Insert after Pop still sorts correctly");
 
     DECREF(pq);
 }
 
 static void
-test_discard(TestBatch *batch) {
+test_discard(TestBatchRunner *runner) {
     int32_t i;
     NumPriorityQueue *pq = NumPriQ_new(5);
 
@@ -126,17 +120,17 @@ test_discard(TestBatch *batch) {
     for (i = 1590; i <= 1600; i++) { S_insert_num(pq, i); }
     S_insert_num(pq, 5);
 
-    TEST_INT_EQ(batch, S_pop_num(pq), 1596, "discard waste");
-    TEST_INT_EQ(batch, S_pop_num(pq), 1597, "discard waste");
-    TEST_INT_EQ(batch, S_pop_num(pq), 1598, "discard waste");
-    TEST_INT_EQ(batch, S_pop_num(pq), 1599, "discard waste");
-    TEST_INT_EQ(batch, S_pop_num(pq), 1600, "discard waste");
+    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(TestBatch *batch) {
+test_random_insertion(TestBatchRunner *runner) {
     int i;
     int shuffled[64];
     NumPriorityQueue *pq = NumPriQ_new(64);
@@ -152,18 +146,18 @@ test_random_insertion(TestBatch *batch) {
     for (i = 0; i < 64; i++) {
         if (S_pop_num(pq) != i) { break; }
     }
-    TEST_INT_EQ(batch, i, 64, "random insertion");
+    TEST_INT_EQ(runner, i, 64, "random insertion");
 
     DECREF(pq);
 }
 
 void
-TestPriQ_run_tests(TestPriorityQueue *self) {
-    TestBatch *batch = (TestBatch*)self;
-    test_Peek_and_Pop_All(batch);
-    test_Insert_and_Pop(batch);
-    test_discard(batch);
-    test_random_insertion(batch);
+TestPriQ_run(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/3da6ebd3/core/Lucy/Test/Util/TestPriorityQueue.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Util/TestPriorityQueue.cfh b/core/Lucy/Test/Util/TestPriorityQueue.cfh
index 02f591d..296c2f7 100644
--- a/core/Lucy/Test/Util/TestPriorityQueue.cfh
+++ b/core/Lucy/Test/Util/TestPriorityQueue.cfh
@@ -30,13 +30,10 @@ class Lucy::Test::Util::TestPriorityQueue cnick TestPriQ
     inherits Clownfish::TestHarness::TestBatch {
 
     inert incremented TestPriorityQueue*
-    new(TestFormatter *formatter);
-
-    inert TestPriorityQueue*
-    init(TestPriorityQueue *self, TestFormatter *formatter);
+    new();
 
     void
-    Run_Tests(TestPriorityQueue *self);
+    Run(TestPriorityQueue *self, TestBatchRunner *runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/3da6ebd3/perl/buildlib/Lucy/Build/Binding/Misc.pm
----------------------------------------------------------------------
diff --git a/perl/buildlib/Lucy/Build/Binding/Misc.pm b/perl/buildlib/Lucy/Build/Binding/Misc.pm
index e55382d..f27e83d 100644
--- a/perl/buildlib/Lucy/Build/Binding/Misc.pm
+++ b/perl/buildlib/Lucy/Build/Binding/Misc.pm
@@ -89,9 +89,11 @@ CODE:
     cfish_CharBuf *class_name = cfish_CB_newf("%s", package);
     cfish_TestFormatter *formatter
         = (cfish_TestFormatter*)cfish_TestFormatterTAP_new();
-    bool result = testcfish_Test_run_batch(class_name, formatter);
+    cfish_TestSuite *suite = testcfish_Test_create_test_suite();
+    bool result = Cfish_TestSuite_Run_Batch(suite, class_name, formatter);
     CFISH_DECREF(class_name);
     CFISH_DECREF(formatter);
+    CFISH_DECREF(suite);
 
     RETVAL = result;
 OUTPUT: RETVAL
@@ -117,9 +119,11 @@ CODE:
     cfish_CharBuf *class_name = cfish_CB_newf("%s", package);
     cfish_TestFormatter *formatter
         = (cfish_TestFormatter*)cfish_TestFormatterTAP_new();
-    bool result = testlucy_Test_run_batch(class_name, formatter);
+    cfish_TestSuite *suite = testlucy_Test_create_test_suite();
+    bool result = Cfish_TestSuite_Run_Batch(suite, class_name, formatter);
     CFISH_DECREF(class_name);
     CFISH_DECREF(formatter);
+    CFISH_DECREF(suite);
 
     RETVAL = result;
 OUTPUT: RETVAL