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/28 19:47:35 UTC

[lucy-commits] [02/19] Rework Clownfish test harness

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestFolder.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestFolder.c b/core/Lucy/Test/Store/TestFolder.c
index ce7d417..2c2662e 100644
--- a/core/Lucy/Test/Store/TestFolder.c
+++ b/core/Lucy/Test/Store/TestFolder.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/TestFolder.h"
 #include "Lucy/Store/DirHandle.h"
@@ -40,14 +40,8 @@ static CharBuf *foo_foo           = NULL;
 static CharBuf *nope              = NULL;
 
 TestFolder*
-TestFolder_new(TestFormatter *formatter) {
-    TestFolder *self = (TestFolder*)VTable_Make_Obj(TESTFOLDER);
-    return TestFolder_init(self, formatter);
-}
-
-TestFolder*
-TestFolder_init(TestFolder *self, TestFormatter *formatter) {
-    return (TestFolder*)TestBatch_init((TestBatch*)self, 79, formatter);
+TestFolder_new() {
+    return (TestFolder*)VTable_Make_Obj(TESTFOLDER);
 }
 
 static void
@@ -81,7 +75,7 @@ S_destroy_strings(void) {
 }
 
 static void
-test_Exists(TestBatch *batch) {
+test_Exists(TestBatchRunner *runner) {
     Folder *folder = (Folder*)RAMFolder_new(NULL);
     FileHandle *fh;
 
@@ -93,80 +87,80 @@ test_Exists(TestBatch *batch) {
                                 FH_CREATE | FH_WRITE_ONLY);
     DECREF(fh);
 
-    TEST_TRUE(batch, Folder_Exists(folder, foo), "Dir exists");
-    TEST_TRUE(batch, Folder_Exists(folder, boffo), "File exists");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_bar),
+    TEST_TRUE(runner, Folder_Exists(folder, foo), "Dir exists");
+    TEST_TRUE(runner, Folder_Exists(folder, boffo), "File exists");
+    TEST_TRUE(runner, Folder_Exists(folder, foo_bar),
               "Nested dir exists");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
               "Nested file exists");
 
-    TEST_FALSE(batch, Folder_Exists(folder, banana),
+    TEST_FALSE(runner, Folder_Exists(folder, banana),
                "Non-existent entry");
-    TEST_FALSE(batch, Folder_Exists(folder, foo_foo),
+    TEST_FALSE(runner, Folder_Exists(folder, foo_foo),
                "Non-existent nested entry");
 
     DECREF(folder);
 }
 
 static void
-test_Set_Path_and_Get_Path(TestBatch *batch) {
+test_Set_Path_and_Get_Path(TestBatchRunner *runner) {
     Folder *folder = (Folder*)RAMFolder_new(foo);
-    TEST_TRUE(batch, CB_Equals(Folder_Get_Path(folder), (Obj*)foo),
+    TEST_TRUE(runner, CB_Equals(Folder_Get_Path(folder), (Obj*)foo),
               "Get_Path");
     Folder_Set_Path(folder, bar);
-    TEST_TRUE(batch, CB_Equals(Folder_Get_Path(folder), (Obj*)bar),
+    TEST_TRUE(runner, CB_Equals(Folder_Get_Path(folder), (Obj*)bar),
               "Set_Path");
     DECREF(folder);
 }
 
 static void
-test_MkDir_and_Is_Directory(TestBatch *batch) {
+test_MkDir_and_Is_Directory(TestBatchRunner *runner) {
     Folder *folder = (Folder*)RAMFolder_new(NULL);
     FileHandle *fh;
 
-    TEST_FALSE(batch, Folder_Is_Directory(folder, foo),
+    TEST_FALSE(runner, Folder_Is_Directory(folder, foo),
                "Is_Directory() false for non-existent entry");
 
-    TEST_TRUE(batch, Folder_MkDir(folder, foo),
+    TEST_TRUE(runner, Folder_MkDir(folder, foo),
               "MkDir returns true on success");
-    TEST_TRUE(batch, Folder_Is_Directory(folder, foo),
+    TEST_TRUE(runner, Folder_Is_Directory(folder, foo),
               "Is_Directory() true for local folder");
 
-    TEST_FALSE(batch, Folder_Is_Directory(folder, foo_bar_baz),
+    TEST_FALSE(runner, Folder_Is_Directory(folder, foo_bar_baz),
                "Is_Directory() false for non-existent deeply nested dir");
     Err_set_error(NULL);
-    TEST_FALSE(batch, Folder_MkDir(folder, foo_bar_baz),
+    TEST_FALSE(runner, Folder_MkDir(folder, foo_bar_baz),
                "MkDir for deeply nested dir fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "MkDir for deeply nested dir sets Err_error");
 
-    TEST_TRUE(batch, Folder_MkDir(folder, foo_bar),
+    TEST_TRUE(runner, Folder_MkDir(folder, foo_bar),
               "MkDir for nested dir");
-    TEST_TRUE(batch, Folder_Is_Directory(folder, foo_bar),
+    TEST_TRUE(runner, Folder_Is_Directory(folder, foo_bar),
               "Is_Directory() true for nested dir");
 
     Err_set_error(NULL);
-    TEST_FALSE(batch, Folder_MkDir(folder, foo_bar),
+    TEST_FALSE(runner, Folder_MkDir(folder, foo_bar),
                "Overwrite dir with MkDir fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Overwrite dir with MkDir sets Err_error");
 
     fh = Folder_Open_FileHandle(folder, foo_boffo,
                                 FH_CREATE | FH_WRITE_ONLY);
     DECREF(fh);
     Err_set_error(NULL);
-    TEST_FALSE(batch, Folder_MkDir(folder, foo_boffo),
+    TEST_FALSE(runner, Folder_MkDir(folder, foo_boffo),
                "Overwrite file with MkDir fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Overwrite file with MkDir sets Err_error");
-    TEST_FALSE(batch, Folder_Is_Directory(folder, foo_boffo),
+    TEST_FALSE(runner, Folder_Is_Directory(folder, foo_boffo),
                "Is_Directory() false for nested file");
 
     DECREF(folder);
 }
 
 static void
-test_Enclosing_Folder_and_Find_Folder(TestBatch *batch) {
+test_Enclosing_Folder_and_Find_Folder(TestBatchRunner *runner) {
     Folder *folder = (Folder*)RAMFolder_new(NULL);
     FileHandle *fh;
 
@@ -179,21 +173,21 @@ test_Enclosing_Folder_and_Find_Folder(TestBatch *batch) {
     {
         Folder *encloser = Folder_Enclosing_Folder(folder, (CharBuf*)nope);
         Folder *found = Folder_Find_Folder(folder, (CharBuf*)nope);
-        TEST_TRUE(batch, encloser == folder,
+        TEST_TRUE(runner, encloser == folder,
                   "Enclosing_Folder() - non-existent entry yields parent");
-        TEST_TRUE(batch, found == NULL,
+        TEST_TRUE(runner, found == NULL,
                   "Find_Folder() - non-existent entry yields NULL");
     }
 
     {
         Folder *encloser = Folder_Enclosing_Folder(folder, foo_bar);
         Folder *found = Folder_Find_Folder(folder, foo_bar);
-        TEST_TRUE(batch,
+        TEST_TRUE(runner,
                   encloser
                   && Folder_Is_A(encloser, FOLDER)
                   && CB_Ends_With(Folder_Get_Path(encloser), foo),
                   "Enclosing_Folder() - find one directory down");
-        TEST_TRUE(batch,
+        TEST_TRUE(runner,
                   found
                   && Folder_Is_A(found, FOLDER)
                   && CB_Ends_With(Folder_Get_Path(found), bar),
@@ -203,12 +197,12 @@ test_Enclosing_Folder_and_Find_Folder(TestBatch *batch) {
     {
         Folder *encloser = Folder_Enclosing_Folder(folder, foo_bar_baz);
         Folder *found = Folder_Find_Folder(folder, foo_bar_baz);
-        TEST_TRUE(batch,
+        TEST_TRUE(runner,
                   encloser
                   && Folder_Is_A(encloser, FOLDER)
                   && CB_Ends_With(Folder_Get_Path(encloser), bar),
                   "Find two directories down");
-        TEST_TRUE(batch,
+        TEST_TRUE(runner,
                   found
                   && Folder_Is_A(found, FOLDER)
                   && CB_Ends_With(Folder_Get_Path(found), baz),
@@ -219,12 +213,12 @@ test_Enclosing_Folder_and_Find_Folder(TestBatch *batch) {
         Folder *encloser
             = Folder_Enclosing_Folder(folder, foo_bar_baz_boffo);
         Folder *found = Folder_Find_Folder(folder, foo_bar_baz_boffo);
-        TEST_TRUE(batch,
+        TEST_TRUE(runner,
                   encloser
                   && Folder_Is_A(encloser, FOLDER)
                   && CB_Ends_With(Folder_Get_Path(encloser), baz),
                   "Recurse to find a directory containing a real file");
-        TEST_TRUE(batch, found == NULL,
+        TEST_TRUE(runner, found == NULL,
                   "Find_Folder() - file instead of folder yields NULL");
     }
 
@@ -233,7 +227,7 @@ test_Enclosing_Folder_and_Find_Folder(TestBatch *batch) {
 }
 
 static void
-test_List(TestBatch *batch) {
+test_List(TestBatchRunner *runner) {
     Folder     *folder = (Folder*)RAMFolder_new(NULL);
     FileHandle *fh;
     VArray     *list;
@@ -249,21 +243,21 @@ test_List(TestBatch *batch) {
 
     list = Folder_List(folder, NULL);
     VA_Sort(list, NULL, NULL);
-    TEST_INT_EQ(batch, VA_Get_Size(list), 3, "List");
+    TEST_INT_EQ(runner, VA_Get_Size(list), 3, "List");
     elem = (CharBuf*)DOWNCAST(VA_Fetch(list, 0), CHARBUF);
-    TEST_TRUE(batch, elem && CB_Equals(elem, (Obj*)banana),
+    TEST_TRUE(runner, elem && CB_Equals(elem, (Obj*)banana),
               "List first file");
     elem = (CharBuf*)DOWNCAST(VA_Fetch(list, 1), CHARBUF);
-    TEST_TRUE(batch, elem && CB_Equals(elem, (Obj*)boffo),
+    TEST_TRUE(runner, elem && CB_Equals(elem, (Obj*)boffo),
               "List second file");
     elem = (CharBuf*)DOWNCAST(VA_Fetch(list, 2), CHARBUF);
-    TEST_TRUE(batch, elem && CB_Equals(elem, (Obj*)foo), "List dir");
+    TEST_TRUE(runner, elem && CB_Equals(elem, (Obj*)foo), "List dir");
     DECREF(list);
 
     list = Folder_List(folder, foo_bar);
-    TEST_INT_EQ(batch, VA_Get_Size(list), 1, "List subdirectory contents");
+    TEST_INT_EQ(runner, VA_Get_Size(list), 1, "List subdirectory contents");
     elem = (CharBuf*)DOWNCAST(VA_Fetch(list, 0), CHARBUF);
-    TEST_TRUE(batch, elem && CB_Equals(elem, (Obj*)baz),
+    TEST_TRUE(runner, elem && CB_Equals(elem, (Obj*)baz),
               "Just the filename");
     DECREF(list);
 
@@ -271,7 +265,7 @@ test_List(TestBatch *batch) {
 }
 
 static void
-test_Open_Dir(TestBatch *batch) {
+test_Open_Dir(TestBatchRunner *runner) {
     Folder     *folder = (Folder*)RAMFolder_new(NULL);
     DirHandle  *dh;
 
@@ -279,107 +273,107 @@ test_Open_Dir(TestBatch *batch) {
     Folder_MkDir(folder, foo_bar);
 
     dh = Folder_Open_Dir(folder, foo);
-    TEST_TRUE(batch, dh && DH_Is_A(dh, DIRHANDLE), "Open_Dir");
+    TEST_TRUE(runner, dh && DH_Is_A(dh, DIRHANDLE), "Open_Dir");
     DECREF(dh);
     dh = Folder_Open_Dir(folder, foo_bar);
-    TEST_TRUE(batch, dh && DH_Is_A(dh, DIRHANDLE), "Open_Dir nested dir");
+    TEST_TRUE(runner, dh && DH_Is_A(dh, DIRHANDLE), "Open_Dir nested dir");
     DECREF(dh);
 
     Err_set_error(NULL);
     dh = Folder_Open_Dir(folder, bar);
-    TEST_TRUE(batch, dh == NULL,
+    TEST_TRUE(runner, dh == NULL,
               "Open_Dir on non-existent entry fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Open_Dir on non-existent entry sets Err_error");
 
     Err_set_error(NULL);
     dh = Folder_Open_Dir(folder, foo_foo);
-    TEST_TRUE(batch, dh == NULL,
+    TEST_TRUE(runner, dh == NULL,
               "Open_Dir on non-existent nested entry fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Open_Dir on non-existent nested entry sets Err_error");
 
     DECREF(folder);
 }
 
 static void
-test_Open_FileHandle(TestBatch *batch) {
+test_Open_FileHandle(TestBatchRunner *runner) {
     Folder     *folder = (Folder*)RAMFolder_new(NULL);
     FileHandle *fh;
 
     Folder_MkDir(folder, foo);
 
     fh = Folder_Open_FileHandle(folder, boffo, FH_CREATE | FH_WRITE_ONLY);
-    TEST_TRUE(batch, fh && FH_Is_A(fh, FILEHANDLE), "Open_FileHandle");
+    TEST_TRUE(runner, fh && FH_Is_A(fh, FILEHANDLE), "Open_FileHandle");
     DECREF(fh);
 
     fh = Folder_Open_FileHandle(folder, foo_boffo,
                                 FH_CREATE | FH_WRITE_ONLY);
-    TEST_TRUE(batch, fh && FH_Is_A(fh, FILEHANDLE),
+    TEST_TRUE(runner, fh && FH_Is_A(fh, FILEHANDLE),
               "Open_FileHandle for nested file");
     DECREF(fh);
 
     Err_set_error(NULL);
     fh = Folder_Open_FileHandle(folder, foo, FH_CREATE | FH_WRITE_ONLY);
-    TEST_TRUE(batch, fh == NULL,
+    TEST_TRUE(runner, fh == NULL,
               "Open_FileHandle on existing dir path fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Open_FileHandle on existing dir name sets Err_error");
 
     Err_set_error(NULL);
     fh = Folder_Open_FileHandle(folder, foo_bar_baz_boffo,
                                 FH_CREATE | FH_WRITE_ONLY);
-    TEST_TRUE(batch, fh == NULL,
+    TEST_TRUE(runner, fh == NULL,
               "Open_FileHandle for entry within non-existent dir fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Open_FileHandle for entry within non-existent dir sets Err_error");
 
     DECREF(folder);
 }
 
 static void
-test_Open_Out(TestBatch *batch) {
+test_Open_Out(TestBatchRunner *runner) {
     Folder    *folder = (Folder*)RAMFolder_new(NULL);
     OutStream *outstream;
 
     Folder_MkDir(folder, foo);
 
     outstream = Folder_Open_Out(folder, boffo);
-    TEST_TRUE(batch, outstream && OutStream_Is_A(outstream, OUTSTREAM),
+    TEST_TRUE(runner, outstream && OutStream_Is_A(outstream, OUTSTREAM),
               "Open_Out");
     DECREF(outstream);
 
     outstream = Folder_Open_Out(folder, foo_boffo);
-    TEST_TRUE(batch, outstream && OutStream_Is_A(outstream, OUTSTREAM),
+    TEST_TRUE(runner, outstream && OutStream_Is_A(outstream, OUTSTREAM),
               "Open_Out for nested file");
     DECREF(outstream);
 
     Err_set_error(NULL);
     outstream = Folder_Open_Out(folder, boffo);
-    TEST_TRUE(batch, outstream == NULL,
+    TEST_TRUE(runner, outstream == NULL,
               "Open_OutStream on existing file fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Open_Out on existing file sets Err_error");
 
     Err_set_error(NULL);
     outstream = Folder_Open_Out(folder, foo);
-    TEST_TRUE(batch, outstream == NULL,
+    TEST_TRUE(runner, outstream == NULL,
               "Open_OutStream on existing dir path fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Open_Out on existing dir name sets Err_error");
 
     Err_set_error(NULL);
     outstream = Folder_Open_Out(folder, foo_bar_baz_boffo);
-    TEST_TRUE(batch, outstream == NULL,
+    TEST_TRUE(runner, outstream == NULL,
               "Open_Out for entry within non-existent dir fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Open_Out for entry within non-existent dir sets Err_error");
 
     DECREF(folder);
 }
 
 static void
-test_Open_In(TestBatch *batch) {
+test_Open_In(TestBatchRunner *runner) {
     Folder     *folder = (Folder*)RAMFolder_new(NULL);
     FileHandle *fh;
     InStream   *instream;
@@ -392,34 +386,34 @@ test_Open_In(TestBatch *batch) {
     DECREF(fh);
 
     instream = Folder_Open_In(folder, boffo);
-    TEST_TRUE(batch, instream && InStream_Is_A(instream, INSTREAM),
+    TEST_TRUE(runner, instream && InStream_Is_A(instream, INSTREAM),
               "Open_In");
     DECREF(instream);
 
     instream = Folder_Open_In(folder, foo_boffo);
-    TEST_TRUE(batch, instream && InStream_Is_A(instream, INSTREAM),
+    TEST_TRUE(runner, instream && InStream_Is_A(instream, INSTREAM),
               "Open_In for nested file");
     DECREF(instream);
 
     Err_set_error(NULL);
     instream = Folder_Open_In(folder, foo);
-    TEST_TRUE(batch, instream == NULL,
+    TEST_TRUE(runner, instream == NULL,
               "Open_InStream on existing dir path fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Open_In on existing dir name sets Err_error");
 
     Err_set_error(NULL);
     instream = Folder_Open_In(folder, foo_bar_baz_boffo);
-    TEST_TRUE(batch, instream == NULL,
+    TEST_TRUE(runner, instream == NULL,
               "Open_In for entry within non-existent dir fails");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Open_In for entry within non-existent dir sets Err_error");
 
     DECREF(folder);
 }
 
 static void
-test_Delete(TestBatch *batch) {
+test_Delete(TestBatchRunner *runner) {
     Folder *folder = (Folder*)RAMFolder_new(NULL);
     FileHandle *fh;
     bool result;
@@ -434,28 +428,28 @@ test_Delete(TestBatch *batch) {
 
     Err_set_error(NULL);
     result = Folder_Delete(folder, banana);
-    TEST_FALSE(batch, result, "Delete on non-existent entry returns false");
+    TEST_FALSE(runner, result, "Delete on non-existent entry returns false");
 
     Err_set_error(NULL);
     result = Folder_Delete(folder, foo);
-    TEST_FALSE(batch, result, "Delete on non-empty dir returns false");
+    TEST_FALSE(runner, result, "Delete on non-empty dir returns false");
 
-    TEST_TRUE(batch, Folder_Delete(folder, foo_boffo),
+    TEST_TRUE(runner, Folder_Delete(folder, foo_boffo),
               "Delete nested file");
-    TEST_FALSE(batch, Folder_Exists(folder, foo_boffo),
+    TEST_FALSE(runner, Folder_Exists(folder, foo_boffo),
                "File is really gone");
-    TEST_TRUE(batch, Folder_Delete(folder, foo_bar),
+    TEST_TRUE(runner, Folder_Delete(folder, foo_bar),
               "Delete nested dir");
-    TEST_FALSE(batch, Folder_Exists(folder, foo_bar),
+    TEST_FALSE(runner, Folder_Exists(folder, foo_bar),
                "Dir is really gone");
-    TEST_TRUE(batch, Folder_Delete(folder, foo), "Delete empty dir");
-    TEST_FALSE(batch, Folder_Exists(folder, foo), "Dir is really gone");
+    TEST_TRUE(runner, Folder_Delete(folder, foo), "Delete empty dir");
+    TEST_FALSE(runner, Folder_Exists(folder, foo), "Dir is really gone");
 
     DECREF(folder);
 }
 
 static void
-test_Delete_Tree(TestBatch *batch) {
+test_Delete_Tree(TestBatchRunner *runner) {
     Folder *folder = (Folder*)RAMFolder_new(NULL);
     FileHandle *fh;
     bool result;
@@ -474,19 +468,19 @@ test_Delete_Tree(TestBatch *batch) {
     DECREF(fh);
 
     result = Folder_Delete_Tree(folder, foo);
-    TEST_TRUE(batch, result, "Delete_Tree() succeeded");
-    TEST_FALSE(batch, Folder_Exists(folder, foo), "Tree really gone");
+    TEST_TRUE(runner, result, "Delete_Tree() succeeded");
+    TEST_FALSE(runner, Folder_Exists(folder, foo), "Tree really gone");
 
-    TEST_TRUE(batch, Folder_Exists(folder, bar),
+    TEST_TRUE(runner, Folder_Exists(folder, bar),
               "local dir with same name as nested dir left intact");
-    TEST_TRUE(batch, Folder_Exists(folder, baz),
+    TEST_TRUE(runner, Folder_Exists(folder, baz),
               "local file with same name as nested dir left intact");
 
     // Kill off the bystanders.
     result = Folder_Delete_Tree(folder, bar);
-    TEST_TRUE(batch, result, "Delete_Tree() on empty dir");
+    TEST_TRUE(runner, result, "Delete_Tree() on empty dir");
     result = Folder_Delete_Tree(folder, baz);
-    TEST_TRUE(batch, result, "Delete_Tree() on file");
+    TEST_TRUE(runner, result, "Delete_Tree() on file");
 
     // Create new tree to be deleted.
     Folder_MkDir(folder, foo);
@@ -498,17 +492,17 @@ test_Delete_Tree(TestBatch *batch) {
 
     // Remove tree in subdir.
     result = Folder_Delete_Tree(folder, foo_bar);
-    TEST_TRUE(batch, result, "Delete_Tree() of subdir succeeded");
-    TEST_FALSE(batch, Folder_Exists(folder, foo_bar),
+    TEST_TRUE(runner, result, "Delete_Tree() of subdir succeeded");
+    TEST_FALSE(runner, Folder_Exists(folder, foo_bar),
                "subdir really gone");
-    TEST_TRUE(batch, Folder_Exists(folder, foo),
+    TEST_TRUE(runner, Folder_Exists(folder, foo),
               "enclosing dir left intact");
 
     DECREF(folder);
 }
 
 static void
-test_Slurp_File(TestBatch *batch) {
+test_Slurp_File(TestBatchRunner *runner) {
     Folder *folder = (Folder*)RAMFolder_new(NULL);
     FileHandle *fh = Folder_Open_FileHandle(folder, foo,
                                             FH_CREATE | FH_WRITE_ONLY);
@@ -518,28 +512,28 @@ test_Slurp_File(TestBatch *batch) {
     FH_Close(fh);
     DECREF(fh);
     contents = Folder_Slurp_File(folder, foo);
-    TEST_TRUE(batch, BB_Equals_Bytes(contents, "stuff", 5), "Slurp_File");
+    TEST_TRUE(runner, BB_Equals_Bytes(contents, "stuff", 5), "Slurp_File");
 
     DECREF(contents);
     DECREF(folder);
 }
 
 void
-TestFolder_run_tests(TestFolder *self) {
-    TestBatch *batch = (TestBatch*)self;
+TestFolder_run(TestFolder *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 79);
     S_init_strings();
-    test_Exists(batch);
-    test_Set_Path_and_Get_Path(batch);
-    test_MkDir_and_Is_Directory(batch);
-    test_Enclosing_Folder_and_Find_Folder(batch);
-    test_List(batch);
-    test_Open_Dir(batch);
-    test_Open_FileHandle(batch);
-    test_Open_Out(batch);
-    test_Open_In(batch);
-    test_Delete(batch);
-    test_Delete_Tree(batch);
-    test_Slurp_File(batch);
+    test_Exists(runner);
+    test_Set_Path_and_Get_Path(runner);
+    test_MkDir_and_Is_Directory(runner);
+    test_Enclosing_Folder_and_Find_Folder(runner);
+    test_List(runner);
+    test_Open_Dir(runner);
+    test_Open_FileHandle(runner);
+    test_Open_Out(runner);
+    test_Open_In(runner);
+    test_Delete(runner);
+    test_Delete_Tree(runner);
+    test_Slurp_File(runner);
     S_destroy_strings();
 }
 

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

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestFolderCommon.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestFolderCommon.c b/core/Lucy/Test/Store/TestFolderCommon.c
index c2ba9a4..d902bb6 100644
--- a/core/Lucy/Test/Store/TestFolderCommon.c
+++ b/core/Lucy/Test/Store/TestFolderCommon.c
@@ -19,7 +19,7 @@
 
 #include "Lucy/Test.h"
 #include "Lucy/Test/Store/TestFolderCommon.h"
-#include "Clownfish/TestHarness/TestBatch.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
 #include "Lucy/Store/Folder.h"
 #include "Lucy/Store/DirHandle.h"
 #include "Lucy/Store/FileHandle.h"
@@ -75,7 +75,7 @@ S_destroy_strings(void) {
 }
 
 static void
-test_Local_Exists(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
+test_Local_Exists(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
     Folder *folder = set_up();
     OutStream *outstream = Folder_Open_Out(folder, boffo);
     DECREF(outstream);
@@ -83,13 +83,13 @@ test_Local_Exists(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
     outstream = Folder_Open_Out(folder, foo_boffo);
     DECREF(outstream);
 
-    TEST_TRUE(batch, Folder_Local_Exists(folder, boffo),
+    TEST_TRUE(runner, Folder_Local_Exists(folder, boffo),
               "Local_Exists() returns true for file");
-    TEST_TRUE(batch, Folder_Local_Exists(folder, foo),
+    TEST_TRUE(runner, Folder_Local_Exists(folder, foo),
               "Local_Exists() returns true for dir");
-    TEST_FALSE(batch, Folder_Local_Exists(folder, foo_boffo),
+    TEST_FALSE(runner, Folder_Local_Exists(folder, foo_boffo),
                "Local_Exists() returns false for nested entry");
-    TEST_FALSE(batch, Folder_Local_Exists(folder, bar),
+    TEST_FALSE(runner, Folder_Local_Exists(folder, bar),
                "Local_Exists() returns false for non-existent entry");
 
     Folder_Delete(folder, foo_boffo);
@@ -100,18 +100,18 @@ test_Local_Exists(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
 }
 
 static void
-test_Local_Is_Directory(TestBatch *batch, set_up_t set_up,
+test_Local_Is_Directory(TestBatchRunner *runner, set_up_t set_up,
                         tear_down_t tear_down) {
     Folder *folder = set_up();
     OutStream *outstream = Folder_Open_Out(folder, boffo);
     DECREF(outstream);
     Folder_Local_MkDir(folder, foo);
 
-    TEST_FALSE(batch, Folder_Local_Is_Directory(folder, boffo),
+    TEST_FALSE(runner, Folder_Local_Is_Directory(folder, boffo),
                "Local_Is_Directory() returns false for file");
-    TEST_TRUE(batch, Folder_Local_Is_Directory(folder, foo),
+    TEST_TRUE(runner, Folder_Local_Is_Directory(folder, foo),
               "Local_Is_Directory() returns true for dir");
-    TEST_FALSE(batch, Folder_Local_Is_Directory(folder, bar),
+    TEST_FALSE(runner, Folder_Local_Is_Directory(folder, bar),
                "Local_Is_Directory() returns false for non-existent entry");
 
     Folder_Delete(folder, boffo);
@@ -121,7 +121,7 @@ test_Local_Is_Directory(TestBatch *batch, set_up_t set_up,
 }
 
 static void
-test_Local_Find_Folder(TestBatch *batch, set_up_t set_up,
+test_Local_Find_Folder(TestBatchRunner *runner, set_up_t set_up,
                        tear_down_t tear_down) {
     Folder    *folder = set_up();
     Folder    *local;
@@ -135,26 +135,26 @@ test_Local_Find_Folder(TestBatch *batch, set_up_t set_up,
     DECREF(outstream);
 
     local = Folder_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 = Folder_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 = Folder_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 = Folder_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 = Folder_Local_Find_Folder(folder, boffo);
-    TEST_TRUE(batch, local == NULL, "local file yields NULL");
+    TEST_TRUE(runner, local == NULL, "local file yields NULL");
 
     local = Folder_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 = Folder_Local_Find_Folder(folder, foo);
-    TEST_TRUE(batch,
+    TEST_TRUE(runner,
               local
               && Folder_Is_A(local, FOLDER)
               && CB_Ends_With(Folder_Get_Path(local), foo),
@@ -169,31 +169,31 @@ test_Local_Find_Folder(TestBatch *batch, set_up_t set_up,
 }
 
 static void
-test_Local_MkDir(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
+test_Local_MkDir(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
     Folder *folder = set_up();
     bool result;
 
     result = Folder_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 = Folder_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, Folder_Exists(folder, foo),
+    TEST_TRUE(runner, Folder_Exists(folder, foo),
               "Existing dir untouched after failed Local_MkDir");
 
     OutStream *outstream = Folder_Open_Out(folder, boffo);
     DECREF(outstream);
     Err_set_error(NULL);
     result = Folder_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, Folder_Exists(folder, boffo) &&
+    TEST_TRUE(runner, Folder_Exists(folder, boffo) &&
               !Folder_Local_Is_Directory(folder, boffo),
               "Existing file untouched after failed Local_MkDir");
 
@@ -204,10 +204,10 @@ test_Local_MkDir(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
 }
 
 static void
-test_Local_Open_Dir(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
+test_Local_Open_Dir(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
     Folder *folder = set_up();
     DirHandle *dh = Folder_Local_Open_Dir(folder);
-    TEST_TRUE(batch, dh && DH_Is_A(dh, DIRHANDLE),
+    TEST_TRUE(runner, dh && DH_Is_A(dh, DIRHANDLE),
               "Local_Open_Dir returns an DirHandle");
     DECREF(dh);
     DECREF(folder);
@@ -215,40 +215,40 @@ test_Local_Open_Dir(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
 }
 
 static void
-test_Local_Open_FileHandle(TestBatch *batch, set_up_t set_up,
+test_Local_Open_FileHandle(TestBatchRunner *runner, set_up_t set_up,
                            tear_down_t tear_down) {
     Folder *folder = set_up();
     FileHandle *fh;
 
     fh = Folder_Local_Open_FileHandle(folder, boffo,
                                       FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE);
-    TEST_TRUE(batch, fh && FH_Is_A(fh, FILEHANDLE),
+    TEST_TRUE(runner, fh && FH_Is_A(fh, FILEHANDLE),
               "opened FileHandle");
     DECREF(fh);
 
     fh = Folder_Local_Open_FileHandle(folder, boffo,
                                       FH_CREATE | FH_WRITE_ONLY);
-    TEST_TRUE(batch, fh && FH_Is_A(fh, FILEHANDLE),
+    TEST_TRUE(runner, fh && FH_Is_A(fh, FILEHANDLE),
               "opened FileHandle for append");
     DECREF(fh);
 
     Err_set_error(NULL);
     fh = Folder_Local_Open_FileHandle(folder, boffo,
                                       FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE);
-    TEST_TRUE(batch, fh == NULL, "FH_EXLUSIVE flag prevents clobber");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, fh == NULL, "FH_EXLUSIVE flag prevents clobber");
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "failure due to FH_EXLUSIVE flag sets Err_error");
 
     fh = Folder_Local_Open_FileHandle(folder, boffo, FH_READ_ONLY);
-    TEST_TRUE(batch, fh && FH_Is_A(fh, FILEHANDLE),
+    TEST_TRUE(runner, fh && FH_Is_A(fh, FILEHANDLE),
               "opened FileHandle for reading");
     DECREF(fh);
 
     Err_set_error(NULL);
     fh = Folder_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");
 
     Folder_Delete(folder, boffo);
@@ -257,15 +257,15 @@ test_Local_Open_FileHandle(TestBatch *batch, set_up_t set_up,
 }
 
 static void
-test_Local_Delete(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
+test_Local_Delete(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
     Folder *folder = set_up();
     OutStream *outstream;
 
     outstream = Folder_Open_Out(folder, boffo);
     DECREF(outstream);
-    TEST_TRUE(batch, Folder_Local_Delete(folder, boffo),
+    TEST_TRUE(runner, Folder_Local_Delete(folder, boffo),
               "Local_Delete on file succeeds");
-    TEST_FALSE(batch, Folder_Exists(folder, boffo),
+    TEST_FALSE(runner, Folder_Exists(folder, boffo),
                "File is really gone");
 
     Folder_Local_MkDir(folder, foo);
@@ -273,13 +273,13 @@ test_Local_Delete(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
     DECREF(outstream);
 
     Err_set_error(NULL);
-    TEST_FALSE(batch, Folder_Local_Delete(folder, foo),
+    TEST_FALSE(runner, Folder_Local_Delete(folder, foo),
                "Local_Delete on non-empty dir fails");
 
     Folder_Delete(folder, foo_boffo);
-    TEST_TRUE(batch, Folder_Local_Delete(folder, foo),
+    TEST_TRUE(runner, Folder_Local_Delete(folder, foo),
               "Local_Delete on empty dir succeeds");
-    TEST_FALSE(batch, Folder_Exists(folder, foo),
+    TEST_FALSE(runner, Folder_Exists(folder, foo),
                "Dir is really gone");
 
     DECREF(folder);
@@ -287,7 +287,7 @@ test_Local_Delete(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
 }
 
 static void
-test_Rename(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
+test_Rename(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
     Folder *folder = set_up();
     OutStream *outstream;
     bool result;
@@ -301,24 +301,24 @@ test_Rename(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
     // Move files.
 
     result = Folder_Rename(folder, boffo, banana);
-    TEST_TRUE(batch, result, "Rename succeeds and returns true");
-    TEST_TRUE(batch, Folder_Exists(folder, banana),
+    TEST_TRUE(runner, result, "Rename succeeds and returns true");
+    TEST_TRUE(runner, Folder_Exists(folder, banana),
               "File exists at new path");
-    TEST_FALSE(batch, Folder_Exists(folder, boffo),
+    TEST_FALSE(runner, Folder_Exists(folder, boffo),
                "File no longer exists at old path");
 
     result = Folder_Rename(folder, banana, foo_bar_boffo);
-    TEST_TRUE(batch, result, "Rename to file in nested dir");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_bar_boffo),
+    TEST_TRUE(runner, result, "Rename to file in nested dir");
+    TEST_TRUE(runner, Folder_Exists(folder, foo_bar_boffo),
               "File exists at new path");
-    TEST_FALSE(batch, Folder_Exists(folder, banana),
+    TEST_FALSE(runner, Folder_Exists(folder, banana),
                "File no longer exists at old path");
 
     result = Folder_Rename(folder, foo_bar_boffo, boffo);
-    TEST_TRUE(batch, result, "Rename from file in nested dir");
-    TEST_TRUE(batch, Folder_Exists(folder, boffo),
+    TEST_TRUE(runner, result, "Rename from file in nested dir");
+    TEST_TRUE(runner, Folder_Exists(folder, boffo),
               "File exists at new path");
-    TEST_FALSE(batch, Folder_Exists(folder, foo_bar_boffo),
+    TEST_FALSE(runner, Folder_Exists(folder, foo_bar_boffo),
                "File no longer exists at old path");
 
     outstream = Folder_Open_Out(folder, foo_boffo);
@@ -326,17 +326,17 @@ test_Rename(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
     DECREF(outstream);
     result = Folder_Rename(folder, boffo, foo_boffo);
     if (result) {
-        PASS(batch, "Rename clobbers on this system");
-        TEST_TRUE(batch, Folder_Exists(folder, foo_boffo),
+        PASS(runner, "Rename clobbers on this system");
+        TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
                   "File exists at new path");
-        TEST_FALSE(batch, Folder_Exists(folder, boffo),
+        TEST_FALSE(runner, Folder_Exists(folder, boffo),
                    "File no longer exists at old path");
     }
     else {
-        PASS(batch, "Rename does not clobber on this system");
-        TEST_TRUE(batch, Folder_Exists(folder, foo_boffo),
+        PASS(runner, "Rename does not clobber on this system");
+        TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
                   "File exists at new path");
-        TEST_TRUE(batch, Folder_Exists(folder, boffo),
+        TEST_TRUE(runner, Folder_Exists(folder, boffo),
                   "File still exists at old path");
         Folder_Delete(folder, boffo);
     }
@@ -345,74 +345,74 @@ test_Rename(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
 
     Folder_MkDir(folder, baz);
     result = Folder_Rename(folder, baz, boffo);
-    TEST_TRUE(batch, result, "Rename dir");
-    TEST_TRUE(batch, Folder_Exists(folder, boffo),
+    TEST_TRUE(runner, result, "Rename dir");
+    TEST_TRUE(runner, Folder_Exists(folder, boffo),
               "Folder exists at new path");
-    TEST_FALSE(batch, Folder_Exists(folder, baz),
+    TEST_FALSE(runner, Folder_Exists(folder, baz),
                "Folder no longer exists at old path");
 
     result = Folder_Rename(folder, boffo, foo_foo);
-    TEST_TRUE(batch, result, "Rename dir into nested subdir");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_foo),
+    TEST_TRUE(runner, result, "Rename dir into nested subdir");
+    TEST_TRUE(runner, Folder_Exists(folder, foo_foo),
               "Folder exists at new path");
-    TEST_FALSE(batch, Folder_Exists(folder, boffo),
+    TEST_FALSE(runner, Folder_Exists(folder, boffo),
                "Folder no longer exists at old path");
 
     result = Folder_Rename(folder, foo_foo, foo_bar_baz);
-    TEST_TRUE(batch, result, "Rename dir from nested subdir");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_bar_baz),
+    TEST_TRUE(runner, result, "Rename dir from nested subdir");
+    TEST_TRUE(runner, Folder_Exists(folder, foo_bar_baz),
               "Folder exists at new path");
-    TEST_FALSE(batch, Folder_Exists(folder, foo_foo),
+    TEST_FALSE(runner, Folder_Exists(folder, foo_foo),
                "Folder no longer exists at old path");
 
     // Test failed clobbers.
 
     Err_set_error(NULL);
     result = Folder_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, Folder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
               "File still exists at old path");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_bar),
+    TEST_TRUE(runner, Folder_Exists(folder, foo_bar),
               "Dir still exists after failed clobber");
 
     Err_set_error(NULL);
     result = Folder_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, Folder_Exists(folder, foo_bar),
+    TEST_TRUE(runner, Folder_Exists(folder, foo_bar),
               "Dir still exists at old path");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
               "File still exists after failed clobber");
 
     // Test that "renaming" succeeds where to and from are the same.
 
     result = Folder_Rename(folder, foo_boffo, foo_boffo);
-    TEST_TRUE(batch, result, "Renaming file to itself succeeds");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, result, "Renaming file to itself succeeds");
+    TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
               "File still exists");
 
     result = Folder_Rename(folder, foo_bar, foo_bar);
-    TEST_TRUE(batch, result, "Renaming dir to itself succeeds");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_bar),
+    TEST_TRUE(runner, result, "Renaming dir to itself succeeds");
+    TEST_TRUE(runner, Folder_Exists(folder, foo_bar),
               "Dir still exists");
 
     // Invalid filepaths.
 
     Err_set_error(NULL);
     result = Folder_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, Folder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
               "Entry still exists at old path");
 
     Err_set_error(NULL);
     result = Folder_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");
 
     Folder_Delete(folder, foo_bar_baz);
@@ -424,7 +424,7 @@ test_Rename(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
 }
 
 static void
-test_Hard_Link(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
+test_Hard_Link(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
     Folder *folder = set_up();
     OutStream *outstream;
     bool result;
@@ -437,26 +437,26 @@ test_Hard_Link(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
     // Link files.
 
     result = Folder_Hard_Link(folder, boffo, banana);
-    TEST_TRUE(batch, result, "Hard_Link succeeds and returns true");
-    TEST_TRUE(batch, Folder_Exists(folder, banana),
+    TEST_TRUE(runner, result, "Hard_Link succeeds and returns true");
+    TEST_TRUE(runner, Folder_Exists(folder, banana),
               "File exists at new path");
-    TEST_TRUE(batch, Folder_Exists(folder, boffo),
+    TEST_TRUE(runner, Folder_Exists(folder, boffo),
               "File still exists at old path");
     Folder_Delete(folder, boffo);
 
     result = Folder_Hard_Link(folder, banana, foo_bar_boffo);
-    TEST_TRUE(batch, result, "Hard_Link to target within nested dir");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_bar_boffo),
+    TEST_TRUE(runner, result, "Hard_Link to target within nested dir");
+    TEST_TRUE(runner, Folder_Exists(folder, foo_bar_boffo),
               "File exists at new path");
-    TEST_TRUE(batch, Folder_Exists(folder, banana),
+    TEST_TRUE(runner, Folder_Exists(folder, banana),
               "File still exists at old path");
     Folder_Delete(folder, banana);
 
     result = Folder_Hard_Link(folder, foo_bar_boffo, foo_boffo);
-    TEST_TRUE(batch, result, "Hard_Link from file in nested dir");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, result, "Hard_Link from file in nested dir");
+    TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
               "File exists at new path");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_bar_boffo),
+    TEST_TRUE(runner, Folder_Exists(folder, foo_bar_boffo),
               "File still exists at old path");
     Folder_Delete(folder, foo_bar_boffo);
 
@@ -465,19 +465,19 @@ test_Hard_Link(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
     outstream = Folder_Open_Out(folder, boffo);
     DECREF(outstream);
     result = Folder_Hard_Link(folder, foo_boffo, boffo);
-    TEST_FALSE(batch, result, "Clobber of file fails");
-    TEST_TRUE(batch, Folder_Exists(folder, boffo),
+    TEST_FALSE(runner, result, "Clobber of file fails");
+    TEST_TRUE(runner, Folder_Exists(folder, boffo),
               "File still exists at new path");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
               "File still exists at old path");
     Folder_Delete(folder, boffo);
 
     Folder_MkDir(folder, baz);
     result = Folder_Hard_Link(folder, foo_boffo, baz);
-    TEST_FALSE(batch, result, "Clobber of dir fails");
-    TEST_TRUE(batch, Folder_Exists(folder, baz),
+    TEST_FALSE(runner, result, "Clobber of dir fails");
+    TEST_TRUE(runner, Folder_Exists(folder, baz),
               "Dir still exists at new path");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
               "File still exists at old path");
     Folder_Delete(folder, baz);
 
@@ -485,34 +485,34 @@ test_Hard_Link(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
 
     Folder_MkDir(folder, baz);
     result = Folder_Hard_Link(folder, baz, banana);
-    TEST_FALSE(batch, result, "Hard_Link dir fails");
-    TEST_FALSE(batch, Folder_Exists(folder, banana),
+    TEST_FALSE(runner, result, "Hard_Link dir fails");
+    TEST_FALSE(runner, Folder_Exists(folder, banana),
                "Nothing at new path");
-    TEST_TRUE(batch, Folder_Exists(folder, baz),
+    TEST_TRUE(runner, Folder_Exists(folder, baz),
               "Folder still exists at old path");
     Folder_Delete(folder, baz);
 
     // Test that linking to yourself fails.
 
     result = Folder_Hard_Link(folder, foo_boffo, foo_boffo);
-    TEST_FALSE(batch, result, "Hard_Link file to itself fails");
-    TEST_TRUE(batch, Folder_Exists(folder, foo_boffo),
+    TEST_FALSE(runner, result, "Hard_Link file to itself fails");
+    TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
               "File still exists");
 
     // Invalid filepaths.
 
     Err_set_error(NULL);
     result = Folder_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, Folder_Exists(folder, foo_boffo),
+    TEST_TRUE(runner, Folder_Exists(folder, foo_boffo),
               "Entry still exists at old path");
 
     Err_set_error(NULL);
     result = Folder_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");
 
     Folder_Delete(folder, foo_bar);
@@ -523,13 +523,13 @@ test_Hard_Link(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
 }
 
 static void
-test_Close(TestBatch *batch, set_up_t set_up, tear_down_t tear_down) {
+test_Close(TestBatchRunner *runner, set_up_t set_up, tear_down_t tear_down) {
     Folder *folder = set_up();
     Folder_Close(folder);
-    PASS(batch, "Close() concludes without incident");
+    PASS(runner, "Close() concludes without incident");
     Folder_Close(folder);
     Folder_Close(folder);
-    PASS(batch, "Calling Close() multiple times is safe");
+    PASS(runner, "Calling Close() multiple times is safe");
     DECREF(folder);
     tear_down();
 }
@@ -540,21 +540,19 @@ TestFolderCommon_num_tests() {
 }
 
 void
-TestFolderCommon_run_tests(void *test_batch, set_up_t set_up,
+TestFolderCommon_run_tests(TestBatchRunner *runner, set_up_t set_up,
                            tear_down_t tear_down) {
-    TestBatch *batch = (TestBatch*)test_batch;
-
     S_init_strings();
-    test_Local_Exists(batch, set_up, tear_down);
-    test_Local_Is_Directory(batch, set_up, tear_down);
-    test_Local_Find_Folder(batch, set_up, tear_down);
-    test_Local_MkDir(batch, set_up, tear_down);
-    test_Local_Open_Dir(batch, set_up, tear_down);
-    test_Local_Open_FileHandle(batch, set_up, tear_down);
-    test_Local_Delete(batch, set_up, tear_down);
-    test_Rename(batch, set_up, tear_down);
-    test_Hard_Link(batch, set_up, tear_down);
-    test_Close(batch, set_up, tear_down);
+    test_Local_Exists(runner, set_up, tear_down);
+    test_Local_Is_Directory(runner, set_up, tear_down);
+    test_Local_Find_Folder(runner, set_up, tear_down);
+    test_Local_MkDir(runner, set_up, tear_down);
+    test_Local_Open_Dir(runner, set_up, tear_down);
+    test_Local_Open_FileHandle(runner, set_up, tear_down);
+    test_Local_Delete(runner, set_up, tear_down);
+    test_Rename(runner, set_up, tear_down);
+    test_Hard_Link(runner, set_up, tear_down);
+    test_Close(runner, set_up, tear_down);
     S_destroy_strings();
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestFolderCommon.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestFolderCommon.cfh b/core/Lucy/Test/Store/TestFolderCommon.cfh
index f072ce9..e75dce4 100644
--- a/core/Lucy/Test/Store/TestFolderCommon.cfh
+++ b/core/Lucy/Test/Store/TestFolderCommon.cfh
@@ -32,7 +32,7 @@ inert class Lucy::Test::Store::TestFolderCommon {
     num_tests();
 
     inert void
-    run_tests(void *test_batch,
+    run_tests(TestBatchRunner *runner,
               Lucy_TestFolderCommon_Set_Up_t set_up,
               Lucy_TestFolderCommon_Tear_Down_t tear_down);
 }

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestIOChunks.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestIOChunks.c b/core/Lucy/Test/Store/TestIOChunks.c
index cbf4f10..fe2fc61 100644
--- a/core/Lucy/Test/Store/TestIOChunks.c
+++ b/core/Lucy/Test/Store/TestIOChunks.c
@@ -22,7 +22,7 @@
 
 #define TESTLUCY_USE_SHORT_NAMES
 #include "Lucy/Util/ToolSet.h"
-#include "Clownfish/TestHarness/TestFormatter.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
 #include "Clownfish/TestHarness/TestUtils.h"
 #include "Lucy/Test.h"
 #include "Lucy/Test/TestUtils.h"
@@ -34,25 +34,19 @@
 #include "Clownfish/Util/NumberUtils.h"
 
 TestIOChunks*
-TestIOChunks_new(TestFormatter *formatter) {
-    TestIOChunks *self = (TestIOChunks*)VTable_Make_Obj(TESTIOCHUNKS);
-    return TestIOChunks_init(self, formatter);
-}
-
-TestIOChunks*
-TestIOChunks_init(TestIOChunks *self, TestFormatter *formatter) {
-    return (TestIOChunks*)TestBatch_init((TestBatch*)self, 36, formatter);
+TestIOChunks_new() {
+    return (TestIOChunks*)VTable_Make_Obj(TESTIOCHUNKS);
 }
 
 static void
-test_Align(TestBatch *batch) {
+test_Align(TestBatchRunner *runner) {
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
 
     for (int32_t i = 1; i < 32; i++) {
         int64_t random_bytes = TestUtils_random_u64() % 32;
         while (random_bytes--) { OutStream_Write_U8(outstream, 0); }
-        TEST_TRUE(batch, (OutStream_Align(outstream, i) % i) == 0,
+        TEST_TRUE(runner, (OutStream_Align(outstream, i) % i) == 0,
                   "Align to %ld", (long)i);
     }
     DECREF(file);
@@ -60,7 +54,7 @@ test_Align(TestBatch *batch) {
 }
 
 static void
-test_Read_Write_Bytes(TestBatch *batch) {
+test_Read_Write_Bytes(TestBatchRunner *runner) {
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
     InStream   *instream;
@@ -71,7 +65,7 @@ test_Read_Write_Bytes(TestBatch *batch) {
 
     instream = InStream_open((Obj*)file);
     InStream_Read_Bytes(instream, buf, 4);
-    TEST_TRUE(batch, strcmp(buf, "foo") == 0, "Read_Bytes Write_Bytes");
+    TEST_TRUE(runner, strcmp(buf, "foo") == 0, "Read_Bytes Write_Bytes");
 
     DECREF(instream);
     DECREF(outstream);
@@ -79,7 +73,7 @@ test_Read_Write_Bytes(TestBatch *batch) {
 }
 
 static void
-test_Buf(TestBatch *batch) {
+test_Buf(TestBatchRunner *runner) {
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
     size_t      size      = IO_STREAM_BUF_SIZE * 2 + 5;
@@ -93,24 +87,24 @@ test_Buf(TestBatch *batch) {
 
     instream = InStream_open((Obj*)file);
     buf = InStream_Buf(instream, 5);
-    TEST_INT_EQ(batch, instream->limit - buf, IO_STREAM_BUF_SIZE,
+    TEST_INT_EQ(runner, instream->limit - buf, IO_STREAM_BUF_SIZE,
                 "Small request bumped up");
 
     buf += IO_STREAM_BUF_SIZE - 10; // 10 bytes left in buffer.
     InStream_Advance_Buf(instream, buf);
 
     buf = InStream_Buf(instream, 10);
-    TEST_INT_EQ(batch, instream->limit - buf, 10,
+    TEST_INT_EQ(runner, instream->limit - buf, 10,
                 "Exact request doesn't trigger refill");
 
     buf = InStream_Buf(instream, 11);
-    TEST_INT_EQ(batch, instream->limit - buf, IO_STREAM_BUF_SIZE,
+    TEST_INT_EQ(runner, instream->limit - buf, IO_STREAM_BUF_SIZE,
                 "Requesting over limit triggers refill");
 
     int64_t  expected = InStream_Length(instream) - InStream_Tell(instream);
     char    *buff     = InStream_Buf(instream, 100000);
     int64_t  got      = PTR_TO_I64(instream->limit) - PTR_TO_I64(buff);
-    TEST_TRUE(batch, got == expected,
+    TEST_TRUE(runner, got == expected,
               "Requests greater than file size get pared down");
 
     DECREF(instream);
@@ -119,12 +113,12 @@ test_Buf(TestBatch *batch) {
 }
 
 void
-TestIOChunks_run_tests(TestIOChunks *self) {
-    TestBatch *batch = (TestBatch*)self;
+TestIOChunks_run(TestIOChunks *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 36);
     srand((unsigned int)time((time_t*)NULL));
-    test_Align(batch);
-    test_Read_Write_Bytes(batch);
-    test_Buf(batch);
+    test_Align(runner);
+    test_Read_Write_Bytes(runner);
+    test_Buf(runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestIOChunks.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestIOChunks.cfh b/core/Lucy/Test/Store/TestIOChunks.cfh
index 1cae6a9..68c459a 100644
--- a/core/Lucy/Test/Store/TestIOChunks.cfh
+++ b/core/Lucy/Test/Store/TestIOChunks.cfh
@@ -22,13 +22,10 @@ class Lucy::Test::Store::TestIOChunks
     inherits Clownfish::TestHarness::TestBatch {
 
     inert incremented TestIOChunks*
-    new(TestFormatter *formatter);
-
-    inert TestIOChunks*
-    init(TestIOChunks *self, TestFormatter *formatter);
+    new();
 
     void
-    Run_Tests(TestIOChunks *self);
+    Run(TestIOChunks *self, TestBatchRunner *runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestIOPrimitives.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestIOPrimitives.c b/core/Lucy/Test/Store/TestIOPrimitives.c
index 38635d8..95565f5 100644
--- a/core/Lucy/Test/Store/TestIOPrimitives.c
+++ b/core/Lucy/Test/Store/TestIOPrimitives.c
@@ -22,7 +22,7 @@
 
 #define TESTLUCY_USE_SHORT_NAMES
 #include "Lucy/Util/ToolSet.h"
-#include "Clownfish/TestHarness/TestFormatter.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
 #include "Clownfish/TestHarness/TestUtils.h"
 #include "Lucy/Test.h"
 #include "Lucy/Test/TestUtils.h"
@@ -34,18 +34,12 @@
 #include "Clownfish/Util/NumberUtils.h"
 
 TestIOPrimitives*
-TestIOPrimitives_new(TestFormatter *formatter) {
-    TestIOPrimitives *self = (TestIOPrimitives*)VTable_Make_Obj(TESTIOPRIMITIVES);
-    return TestIOPrimitives_init(self, formatter);
-}
-
-TestIOPrimitives*
-TestIOPrimitives_init(TestIOPrimitives *self, TestFormatter *formatter) {
-    return (TestIOPrimitives*)TestBatch_init((TestBatch*)self, 11, formatter);
+TestIOPrimitives_new() {
+    return (TestIOPrimitives*)VTable_Make_Obj(TESTIOPRIMITIVES);
 }
 
 static void
-test_i8(TestBatch *batch) {
+test_i8(TestBatchRunner *runner) {
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
     InStream   *instream;
@@ -60,7 +54,7 @@ test_i8(TestBatch *batch) {
     for (i = -128; i < 128; i++) {
         if (InStream_Read_I8(instream) != i) { break; }
     }
-    TEST_INT_EQ(batch, i, 128, "round trip i8 successful for %d out of 256",
+    TEST_INT_EQ(runner, i, 128, "round trip i8 successful for %d out of 256",
                 i + 128);
 
     DECREF(instream);
@@ -69,7 +63,7 @@ test_i8(TestBatch *batch) {
 }
 
 static void
-test_u8(TestBatch *batch) {
+test_u8(TestBatchRunner *runner) {
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
     InStream   *instream;
@@ -84,7 +78,7 @@ test_u8(TestBatch *batch) {
     for (i = 0; i < 256; i++) {
         if (InStream_Read_U8(instream) != i) { break; }
     }
-    TEST_INT_EQ(batch, i, 256,
+    TEST_INT_EQ(runner, i, 256,
                 "round trip u8 successful for %d out of 256", i);
 
     DECREF(instream);
@@ -93,7 +87,7 @@ test_u8(TestBatch *batch) {
 }
 
 static void
-test_i32(TestBatch *batch) {
+test_i32(TestBatchRunner *runner) {
     int64_t    *ints = TestUtils_random_i64s(NULL, 1000, INT32_MIN, INT32_MAX);
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
@@ -115,13 +109,13 @@ test_i32(TestBatch *batch) {
     for (i = 0; i < 1000; i++) {
         int32_t got = InStream_Read_I32(instream);
         if (got != ints[i]) {
-            FAIL(batch, "i32 round trip failed: %ld, %ld", (long)got,
+            FAIL(runner, "i32 round trip failed: %ld, %ld", (long)got,
                  (long)ints[i]);
             break;
         }
     }
     if (i == 1000) {
-        PASS(batch, "i32 round trip");
+        PASS(runner, "i32 round trip");
     }
 
     DECREF(instream);
@@ -131,7 +125,7 @@ test_i32(TestBatch *batch) {
 }
 
 static void
-test_u32(TestBatch *batch) {
+test_u32(TestBatchRunner *runner) {
     uint64_t   *ints = TestUtils_random_u64s(NULL, 1000, 0, UINT32_MAX);
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
@@ -153,13 +147,13 @@ test_u32(TestBatch *batch) {
     for (i = 0; i < 1000; i++) {
         uint32_t got = InStream_Read_U32(instream);
         if (got != ints[i]) {
-            FAIL(batch, "u32 round trip failed: %lu, %lu", (unsigned long)got,
+            FAIL(runner, "u32 round trip failed: %lu, %lu", (unsigned long)got,
                  (unsigned long)ints[i]);
             break;
         }
     }
     if (i == 1000) {
-        PASS(batch, "u32 round trip");
+        PASS(runner, "u32 round trip");
     }
 
     DECREF(instream);
@@ -169,7 +163,7 @@ test_u32(TestBatch *batch) {
 }
 
 static void
-test_i64(TestBatch *batch) {
+test_i64(TestBatchRunner *runner) {
     int64_t    *ints = TestUtils_random_i64s(NULL, 1000, INT64_MIN, INT64_MAX);
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
@@ -191,13 +185,13 @@ test_i64(TestBatch *batch) {
     for (i = 0; i < 1000; i++) {
         int64_t got = InStream_Read_I64(instream);
         if (got != ints[i]) {
-            FAIL(batch, "i64 round trip failed: %" PRId64 ", %" PRId64,
+            FAIL(runner, "i64 round trip failed: %" PRId64 ", %" PRId64,
                  got, ints[i]);
             break;
         }
     }
     if (i == 1000) {
-        PASS(batch, "i64 round trip");
+        PASS(runner, "i64 round trip");
     }
 
     DECREF(instream);
@@ -208,7 +202,7 @@ test_i64(TestBatch *batch) {
 
 
 static void
-test_u64(TestBatch *batch) {
+test_u64(TestBatchRunner *runner) {
     uint64_t   *ints = TestUtils_random_u64s(NULL, 1000, 0, UINT64_MAX);
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
@@ -230,13 +224,13 @@ test_u64(TestBatch *batch) {
     for (i = 0; i < 1000; i++) {
         uint64_t got = InStream_Read_U64(instream);
         if (got != ints[i]) {
-            FAIL(batch, "u64 round trip failed: %" PRIu64 ", %" PRIu64,
+            FAIL(runner, "u64 round trip failed: %" PRIu64 ", %" PRIu64,
                  got, ints[i]);
             break;
         }
     }
     if (i == 1000) {
-        PASS(batch, "u64 round trip");
+        PASS(runner, "u64 round trip");
     }
 
     DECREF(instream);
@@ -246,7 +240,7 @@ test_u64(TestBatch *batch) {
 }
 
 static void
-test_c32(TestBatch *batch) {
+test_c32(TestBatchRunner *runner) {
     uint64_t   *ints = TestUtils_random_u64s(NULL, 1000, 0, UINT32_MAX);
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
@@ -268,13 +262,13 @@ test_c32(TestBatch *batch) {
     for (i = 0; i < 1000; i++) {
         uint32_t got = InStream_Read_C32(instream);
         if (got != ints[i]) {
-            FAIL(batch, "c32 round trip failed: %lu, %lu", (unsigned long)got,
+            FAIL(runner, "c32 round trip failed: %lu, %lu", (unsigned long)got,
                  (unsigned long)ints[i]);
             break;
         }
     }
     if (i == 1000) {
-        PASS(batch, "c32 round trip");
+        PASS(runner, "c32 round trip");
     }
 
     DECREF(instream);
@@ -284,7 +278,7 @@ test_c32(TestBatch *batch) {
 }
 
 static void
-test_c64(TestBatch *batch) {
+test_c64(TestBatchRunner *runner) {
     uint64_t   *ints   = TestUtils_random_u64s(NULL, 1000, 0, UINT64_MAX);
     RAMFile    *file     = RAMFile_new(NULL, false);
     RAMFile    *raw_file = RAMFile_new(NULL, false);
@@ -311,13 +305,13 @@ test_c64(TestBatch *batch) {
     for (i = 0; i < 1000; i++) {
         uint64_t got = InStream_Read_C64(instream);
         if (got != ints[i]) {
-            FAIL(batch, "c64 round trip failed: %" PRIu64 ", %" PRIu64,
+            FAIL(runner, "c64 round trip failed: %" PRIu64 ", %" PRIu64,
                  got, ints[i]);
             break;
         }
     }
     if (i == 1000) {
-        PASS(batch, "c64 round trip");
+        PASS(runner, "c64 round trip");
     }
 
     raw_instream = InStream_open((Obj*)raw_file);
@@ -328,13 +322,13 @@ test_c64(TestBatch *batch) {
         uint64_t got = NumUtil_decode_c64(&buf);
         UNUSED_VAR(size);
         if (got != ints[i]) {
-            FAIL(batch, "Read_Raw_C64 failed: %" PRIu64 ", %" PRIu64,
+            FAIL(runner, "Read_Raw_C64 failed: %" PRIu64 ", %" PRIu64,
                  got, ints[i]);
             break;
         }
     }
     if (i == 1000) {
-        PASS(batch, "Read_Raw_C64");
+        PASS(runner, "Read_Raw_C64");
     }
 
     DECREF(raw_instream);
@@ -347,7 +341,7 @@ test_c64(TestBatch *batch) {
 }
 
 static void
-test_f32(TestBatch *batch) {
+test_f32(TestBatchRunner *runner) {
     double     *f64s   = TestUtils_random_f64s(NULL, 1000);
     float      *values = (float*)MALLOCATE(1000 * sizeof(float));
     RAMFile    *file      = RAMFile_new(NULL, false);
@@ -373,12 +367,12 @@ test_f32(TestBatch *batch) {
     for (i = 0; i < 1000; i++) {
         float got = InStream_Read_F32(instream);
         if (got != values[i]) {
-            FAIL(batch, "f32 round trip failed: %f, %f", got, values[i]);
+            FAIL(runner, "f32 round trip failed: %f, %f", got, values[i]);
             break;
         }
     }
     if (i == 1000) {
-        PASS(batch, "f32 round trip");
+        PASS(runner, "f32 round trip");
     }
 
     DECREF(instream);
@@ -389,7 +383,7 @@ test_f32(TestBatch *batch) {
 }
 
 static void
-test_f64(TestBatch *batch) {
+test_f64(TestBatchRunner *runner) {
     double     *values = TestUtils_random_f64s(NULL, 1000);
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
@@ -409,12 +403,12 @@ test_f64(TestBatch *batch) {
     for (i = 0; i < 1000; i++) {
         double got = InStream_Read_F64(instream);
         if (got != values[i]) {
-            FAIL(batch, "f64 round trip failed: %f, %f", got, values[i]);
+            FAIL(runner, "f64 round trip failed: %f, %f", got, values[i]);
             break;
         }
     }
     if (i == 1000) {
-        PASS(batch, "f64 round trip");
+        PASS(runner, "f64 round trip");
     }
 
     DECREF(instream);
@@ -424,19 +418,19 @@ test_f64(TestBatch *batch) {
 }
 
 void
-TestIOPrimitives_run_tests(TestIOPrimitives *self) {
-    TestBatch *batch = (TestBatch*)self;
+TestIOPrimitives_run(TestIOPrimitives *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 11);
     srand((unsigned int)time((time_t*)NULL));
-    test_i8(batch);
-    test_u8(batch);
-    test_i32(batch);
-    test_u32(batch);
-    test_i64(batch);
-    test_u64(batch);
-    test_c32(batch);
-    test_c64(batch);
-    test_f32(batch);
-    test_f64(batch);
+    test_i8(runner);
+    test_u8(runner);
+    test_i32(runner);
+    test_u32(runner);
+    test_i64(runner);
+    test_u64(runner);
+    test_c32(runner);
+    test_c64(runner);
+    test_f32(runner);
+    test_f64(runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestIOPrimitives.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestIOPrimitives.cfh b/core/Lucy/Test/Store/TestIOPrimitives.cfh
index ddf7852..c75419a 100644
--- a/core/Lucy/Test/Store/TestIOPrimitives.cfh
+++ b/core/Lucy/Test/Store/TestIOPrimitives.cfh
@@ -22,13 +22,10 @@ class Lucy::Test::Store::TestIOPrimitives
     inherits Clownfish::TestHarness::TestBatch {
 
     inert incremented TestIOPrimitives*
-    new(TestFormatter *formatter);
-
-    inert TestIOPrimitives*
-    init(TestIOPrimitives *self, TestFormatter *formatter);
+    new();
 
     void
-    Run_Tests(TestIOPrimitives *self);
+    Run(TestIOPrimitives *self, TestBatchRunner *runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestInStream.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestInStream.c b/core/Lucy/Test/Store/TestInStream.c
index 9a29002..a09df9f 100644
--- a/core/Lucy/Test/Store/TestInStream.c
+++ b/core/Lucy/Test/Store/TestInStream.c
@@ -20,7 +20,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/TestUtils.h"
 #include "Lucy/Test/Store/TestInStream.h"
@@ -33,18 +33,12 @@
 #include "Clownfish/Util/NumberUtils.h"
 
 TestInStream*
-TestInStream_new(TestFormatter *formatter) {
-    TestInStream *self = (TestInStream*)VTable_Make_Obj(TESTINSTREAM);
-    return TestInStream_init(self, formatter);
-}
-
-TestInStream*
-TestInStream_init(TestInStream *self, TestFormatter *formatter) {
-    return (TestInStream*)TestBatch_init((TestBatch*)self, 37, formatter);
+TestInStream_new() {
+    return (TestInStream*)VTable_Make_Obj(TESTINSTREAM);
 }
 
 static void
-test_refill(TestBatch *batch) {
+test_refill(TestBatchRunner *runner) {
     RAMFile    *file      = RAMFile_new(NULL, false);
     OutStream  *outstream = OutStream_open((Obj*)file);
     InStream   *instream;
@@ -59,35 +53,35 @@ test_refill(TestBatch *batch) {
 
     instream = InStream_open((Obj*)file);
     InStream_Refill(instream);
-    TEST_INT_EQ(batch, instream->limit - instream->buf, IO_STREAM_BUF_SIZE,
+    TEST_INT_EQ(runner, instream->limit - instream->buf, IO_STREAM_BUF_SIZE,
                 "Refill");
-    TEST_INT_EQ(batch, (long)InStream_Tell(instream), 0,
+    TEST_INT_EQ(runner, (long)InStream_Tell(instream), 0,
                 "Correct file pos after standing-start Refill()");
     DECREF(instream);
 
     instream = InStream_open((Obj*)file);
     InStream_Fill(instream, 30);
-    TEST_INT_EQ(batch, instream->limit - instream->buf, 30, "Fill()");
-    TEST_INT_EQ(batch, (long)InStream_Tell(instream), 0,
+    TEST_INT_EQ(runner, instream->limit - instream->buf, 30, "Fill()");
+    TEST_INT_EQ(runner, (long)InStream_Tell(instream), 0,
                 "Correct file pos after standing-start Fill()");
     DECREF(instream);
 
     instream = InStream_open((Obj*)file);
     InStream_Read_Bytes(instream, scratch, 5);
-    TEST_INT_EQ(batch, instream->limit - instream->buf,
+    TEST_INT_EQ(runner, instream->limit - instream->buf,
                 IO_STREAM_BUF_SIZE - 5, "small read triggers refill");
     DECREF(instream);
 
     instream = InStream_open((Obj*)file);
-    TEST_INT_EQ(batch, InStream_Read_U8(instream), 'x', "Read_U8");
+    TEST_INT_EQ(runner, InStream_Read_U8(instream), 'x', "Read_U8");
     InStream_Seek(instream, 1023);
-    TEST_INT_EQ(batch, (long)instream->window->offset, 0,
+    TEST_INT_EQ(runner, (long)instream->window->offset, 0,
                 "no unnecessary refill on Seek");
-    TEST_INT_EQ(batch, (long)InStream_Tell(instream), 1023, "Seek/Tell");
-    TEST_INT_EQ(batch, InStream_Read_U8(instream), 'y',
+    TEST_INT_EQ(runner, (long)InStream_Tell(instream), 1023, "Seek/Tell");
+    TEST_INT_EQ(runner, InStream_Read_U8(instream), 'y',
                 "correct data after in-buffer Seek()");
-    TEST_INT_EQ(batch, InStream_Read_U8(instream), 'z', "automatic Refill");
-    TEST_TRUE(batch, (instream->window->offset != 0), "refilled");
+    TEST_INT_EQ(runner, InStream_Read_U8(instream), 'z', "automatic Refill");
+    TEST_TRUE(runner, (instream->window->offset != 0), "refilled");
 
     DECREF(instream);
     DECREF(outstream);
@@ -95,7 +89,7 @@ test_refill(TestBatch *batch) {
 }
 
 static void
-test_Clone_and_Reopen(TestBatch *batch) {
+test_Clone_and_Reopen(TestBatchRunner *runner) {
     ZombieCharBuf *foo       = ZCB_WRAP_STR("foo", 3);
     ZombieCharBuf *bar       = ZCB_WRAP_STR("bar", 3);
     RAMFile       *file      = RAMFile_new(NULL, false);
@@ -113,28 +107,28 @@ test_Clone_and_Reopen(TestBatch *batch) {
     fh = RAMFH_open((CharBuf*)foo, FH_READ_ONLY, file);
     instream = InStream_open((Obj*)fh);
     InStream_Seek(instream, 1);
-    TEST_TRUE(batch, CB_Equals(InStream_Get_Filename(instream), (Obj*)foo),
+    TEST_TRUE(runner, CB_Equals(InStream_Get_Filename(instream), (Obj*)foo),
               "Get_Filename");
 
     clone    = InStream_Clone(instream);
-    TEST_TRUE(batch, CB_Equals(InStream_Get_Filename(clone), (Obj*)foo),
+    TEST_TRUE(runner, CB_Equals(InStream_Get_Filename(clone), (Obj*)foo),
               "Clones have same filename");
-    TEST_TRUE(batch, InStream_Length(instream) == InStream_Length(clone),
+    TEST_TRUE(runner, InStream_Length(instream) == InStream_Length(clone),
               "Clones have same length");
-    TEST_TRUE(batch, InStream_Read_U8(instream) == InStream_Read_U8(clone),
+    TEST_TRUE(runner, InStream_Read_U8(instream) == InStream_Read_U8(clone),
               "Clones start at same file position");
 
     reopened = InStream_Reopen(instream, (CharBuf*)bar, 25, 1);
-    TEST_TRUE(batch, CB_Equals(InStream_Get_Filename(reopened), (Obj*)bar),
+    TEST_TRUE(runner, CB_Equals(InStream_Get_Filename(reopened), (Obj*)bar),
               "Reopened InStreams take new filename");
-    TEST_TRUE(batch, InStream_Read_U8(reopened) == 'z',
+    TEST_TRUE(runner, InStream_Read_U8(reopened) == 'z',
               "Reopened stream starts at supplied offset");
-    TEST_TRUE(batch, InStream_Length(reopened) == 1,
+    TEST_TRUE(runner, InStream_Length(reopened) == 1,
               "Reopened stream uses supplied length");
-    TEST_TRUE(batch, InStream_Tell(reopened) == 1,
+    TEST_TRUE(runner, InStream_Tell(reopened) == 1,
               "Tell() uses supplied offset for reopened stream");
     InStream_Seek(reopened, 0);
-    TEST_TRUE(batch, InStream_Read_U8(reopened) == 'z',
+    TEST_TRUE(runner, InStream_Read_U8(reopened) == 'z',
               "Seek() uses supplied offset for reopened stream");
 
     DECREF(reopened);
@@ -146,18 +140,18 @@ test_Clone_and_Reopen(TestBatch *batch) {
 }
 
 static void
-test_Close(TestBatch *batch) {
+test_Close(TestBatchRunner *runner) {
     RAMFile  *file     = RAMFile_new(NULL, false);
     InStream *instream = InStream_open((Obj*)file);
     InStream_Close(instream);
-    TEST_TRUE(batch, instream->file_handle == NULL,
+    TEST_TRUE(runner, instream->file_handle == NULL,
               "Close decrements FileHandle's refcount");
     DECREF(instream);
     DECREF(file);
 }
 
 static void
-test_Seek_and_Tell(TestBatch *batch) {
+test_Seek_and_Tell(TestBatchRunner *runner) {
     int64_t     gb1      = INT64_C(0x40000000);
     int64_t     gb3      = gb1 * 3;
     int64_t     gb6      = gb1 * 6;
@@ -166,47 +160,47 @@ test_Seek_and_Tell(TestBatch *batch) {
     InStream   *instream = InStream_open((Obj*)fh);
 
     InStream_Buf(instream, 10000);
-    TEST_TRUE(batch, instream->limit == ((char*)NULL) + 10000,
+    TEST_TRUE(runner, instream->limit == ((char*)NULL) + 10000,
               "InStream_Buf sets limit");
 
     InStream_Seek(instream, gb6);
-    TEST_TRUE(batch, InStream_Tell(instream) == gb6,
+    TEST_TRUE(runner, InStream_Tell(instream) == gb6,
               "Tell after seek forwards outside buffer");
-    TEST_TRUE(batch, instream->buf == NULL,
+    TEST_TRUE(runner, instream->buf == NULL,
               "Seek forwards outside buffer sets buf to NULL");
-    TEST_TRUE(batch, instream->limit == NULL,
+    TEST_TRUE(runner, instream->limit == NULL,
               "Seek forwards outside buffer sets limit to NULL");
-    TEST_TRUE(batch, instream->window->offset == gb6,
+    TEST_TRUE(runner, instream->window->offset == gb6,
               "Seek forwards outside buffer tracks pos in window offset");
 
     InStream_Buf(instream, (size_t)gb1);
-    TEST_TRUE(batch, instream->limit == ((char*)NULL) + gb1,
+    TEST_TRUE(runner, instream->limit == ((char*)NULL) + gb1,
               "InStream_Buf sets limit");
 
     InStream_Seek(instream, gb6 + 10);
-    TEST_TRUE(batch, InStream_Tell(instream) == gb6 + 10,
+    TEST_TRUE(runner, InStream_Tell(instream) == gb6 + 10,
               "Tell after seek forwards within buffer");
-    TEST_TRUE(batch, instream->buf == ((char*)NULL) + 10,
+    TEST_TRUE(runner, instream->buf == ((char*)NULL) + 10,
               "Seek within buffer sets buf");
-    TEST_TRUE(batch, instream->limit == ((char*)NULL) + gb1,
+    TEST_TRUE(runner, instream->limit == ((char*)NULL) + gb1,
               "Seek within buffer leaves limit alone");
 
     InStream_Seek(instream, gb6 + 1);
-    TEST_TRUE(batch, InStream_Tell(instream) == gb6 + 1,
+    TEST_TRUE(runner, InStream_Tell(instream) == gb6 + 1,
               "Tell after seek backwards within buffer");
-    TEST_TRUE(batch, instream->buf == ((char*)NULL) + 1,
+    TEST_TRUE(runner, instream->buf == ((char*)NULL) + 1,
               "Seek backwards within buffer sets buf");
-    TEST_TRUE(batch, instream->limit == ((char*)NULL) + gb1,
+    TEST_TRUE(runner, instream->limit == ((char*)NULL) + gb1,
               "Seek backwards within buffer leaves limit alone");
 
     InStream_Seek(instream, gb3);
-    TEST_TRUE(batch, InStream_Tell(instream) == gb3,
+    TEST_TRUE(runner, InStream_Tell(instream) == gb3,
               "Tell after seek backwards outside buffer");
-    TEST_TRUE(batch, instream->buf == NULL,
+    TEST_TRUE(runner, instream->buf == NULL,
               "Seek backwards outside buffer sets buf to NULL");
-    TEST_TRUE(batch, instream->limit == NULL,
+    TEST_TRUE(runner, instream->limit == NULL,
               "Seek backwards outside buffer sets limit to NULL");
-    TEST_TRUE(batch, instream->window->offset == gb3,
+    TEST_TRUE(runner, instream->window->offset == gb3,
               "Seek backwards outside buffer tracks pos in window offset");
 
     DECREF(instream);
@@ -214,12 +208,12 @@ test_Seek_and_Tell(TestBatch *batch) {
 }
 
 void
-TestInStream_run_tests(TestInStream *self) {
-    TestBatch *batch = (TestBatch*)self;
-    test_refill(batch);
-    test_Clone_and_Reopen(batch);
-    test_Close(batch);
-    test_Seek_and_Tell(batch);
+TestInStream_run(TestInStream *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 37);
+    test_refill(runner);
+    test_Clone_and_Reopen(runner);
+    test_Close(runner);
+    test_Seek_and_Tell(runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestInStream.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestInStream.cfh b/core/Lucy/Test/Store/TestInStream.cfh
index 7b97094..b216fcd 100644
--- a/core/Lucy/Test/Store/TestInStream.cfh
+++ b/core/Lucy/Test/Store/TestInStream.cfh
@@ -24,13 +24,10 @@ class Lucy::Test::Store::TestInStream
     inherits Clownfish::TestHarness::TestBatch {
 
     inert incremented TestInStream*
-    new(TestFormatter *formatter);
-
-    inert TestInStream*
-    init(TestInStream *self, TestFormatter *formatter);
+    new();
 
     void
-    Run_Tests(TestInStream *self);
+    Run(TestInStream *self, TestBatchRunner *runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestRAMDirHandle.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestRAMDirHandle.c b/core/Lucy/Test/Store/TestRAMDirHandle.c
index 7997aa2..fd5cc00 100644
--- a/core/Lucy/Test/Store/TestRAMDirHandle.c
+++ b/core/Lucy/Test/Store/TestRAMDirHandle.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/TestRAMDirHandle.h"
 #include "Lucy/Store/FileHandle.h"
@@ -26,18 +26,12 @@
 #include "Lucy/Store/RAMDirHandle.h"
 
 TestRAMDirHandle*
-TestRAMDH_new(TestFormatter *formatter) {
-    TestRAMDirHandle *self = (TestRAMDirHandle*)VTable_Make_Obj(TESTRAMDIRHANDLE);
-    return TestRAMDH_init(self, formatter);
-}
-
-TestRAMDirHandle*
-TestRAMDH_init(TestRAMDirHandle *self, TestFormatter *formatter) {
-    return (TestRAMDirHandle*)TestBatch_init((TestBatch*)self, 6, formatter);
+TestRAMDH_new() {
+    return (TestRAMDirHandle*)VTable_Make_Obj(TESTRAMDIRHANDLE);
 }
 
 static void
-test_all(TestBatch *batch) {
+test_all(TestBatchRunner *runner) {
     RAMFolder *folder        = RAMFolder_new(NULL);
     CharBuf   *foo           = (CharBuf*)ZCB_WRAP_STR("foo", 3);
     CharBuf   *boffo         = (CharBuf*)ZCB_WRAP_STR("boffo", 5);
@@ -70,17 +64,17 @@ test_all(TestBatch *batch) {
             boffo_was_dir = RAMDH_Entry_Is_Dir(dh);
         }
     }
-    TEST_INT_EQ(batch, 2, count, "correct number of entries");
-    TEST_TRUE(batch, saw_foo, "Directory was iterated over");
-    TEST_TRUE(batch, foo_was_dir,
+    TEST_INT_EQ(runner, 2, count, "correct number of entries");
+    TEST_TRUE(runner, saw_foo, "Directory was iterated over");
+    TEST_TRUE(runner, foo_was_dir,
               "Dir correctly identified by Entry_Is_Dir");
-    TEST_TRUE(batch, saw_boffo, "File was iterated over");
-    TEST_FALSE(batch, boffo_was_dir,
+    TEST_TRUE(runner, saw_boffo, "File was iterated over");
+    TEST_FALSE(runner, boffo_was_dir,
                "File correctly identified by Entry_Is_Dir");
 
     uint32_t refcount = RAMFolder_Get_RefCount(folder);
     RAMDH_Close(dh);
-    TEST_INT_EQ(batch, RAMFolder_Get_RefCount(folder), refcount - 1,
+    TEST_INT_EQ(runner, RAMFolder_Get_RefCount(folder), refcount - 1,
                 "Folder reference released by Close()");
 
     DECREF(dh);
@@ -88,9 +82,9 @@ test_all(TestBatch *batch) {
 }
 
 void
-TestRAMDH_run_tests(TestRAMDirHandle *self) {
-    TestBatch *batch = (TestBatch*)self;
-    test_all(batch);
+TestRAMDH_run(TestRAMDirHandle *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 6);
+    test_all(runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestRAMDirHandle.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestRAMDirHandle.cfh b/core/Lucy/Test/Store/TestRAMDirHandle.cfh
index ac80e4d..31e242a 100644
--- a/core/Lucy/Test/Store/TestRAMDirHandle.cfh
+++ b/core/Lucy/Test/Store/TestRAMDirHandle.cfh
@@ -20,13 +20,10 @@ class Lucy::Test::Store::TestRAMDirHandle cnick TestRAMDH
     inherits Clownfish::TestHarness::TestBatch {
 
     inert incremented TestRAMDirHandle*
-    new(TestFormatter *formatter);
-
-    inert TestRAMDirHandle*
-    init(TestRAMDirHandle *self, TestFormatter *formatter);
+    new();
 
     void
-    Run_Tests(TestRAMDirHandle *self);
+    Run(TestRAMDirHandle *self, TestBatchRunner *runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestRAMFileHandle.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestRAMFileHandle.c b/core/Lucy/Test/Store/TestRAMFileHandle.c
index 0289c79..4a4bfb5 100644
--- a/core/Lucy/Test/Store/TestRAMFileHandle.c
+++ b/core/Lucy/Test/Store/TestRAMFileHandle.c
@@ -22,7 +22,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/TestRAMFileHandle.h"
 #include "Lucy/Store/RAMFileHandle.h"
@@ -30,30 +30,24 @@
 #include "Lucy/Store/RAMFile.h"
 
 TestRAMFileHandle*
-TestRAMFH_new(TestFormatter *formatter) {
-    TestRAMFileHandle *self = (TestRAMFileHandle*)VTable_Make_Obj(TESTRAMFILEHANDLE);
-    return TestRAMFH_init(self, formatter);
-}
-
-TestRAMFileHandle*
-TestRAMFH_init(TestRAMFileHandle *self, TestFormatter *formatter) {
-    return (TestRAMFileHandle*)TestBatch_init((TestBatch*)self, 32, formatter);
+TestRAMFH_new() {
+    return (TestRAMFileHandle*)VTable_Make_Obj(TESTRAMFILEHANDLE);
 }
 
 static void
-test_open(TestBatch *batch) {
+test_open(TestBatchRunner *runner) {
     RAMFileHandle *fh;
 
     Err_set_error(NULL);
     fh = RAMFH_open(NULL, FH_WRITE_ONLY, NULL);
-    TEST_TRUE(batch, fh == NULL,
+    TEST_TRUE(runner, fh == NULL,
               "open() without a RAMFile or FH_CREATE returns NULL");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "open() without a RAMFile or FH_CREATE sets error");
 }
 
 static void
-test_Read_Write(TestBatch *batch) {
+test_Read_Write(TestBatchRunner *runner) {
     RAMFile *file = RAMFile_new(NULL, false);
     RAMFileHandle *fh = RAMFH_open(NULL, FH_WRITE_ONLY, file);
     const char *foo = "foo";
@@ -61,47 +55,47 @@ test_Read_Write(TestBatch *batch) {
     char buffer[12];
     char *buf = buffer;
 
-    TEST_TRUE(batch, CB_Equals_Str(RAMFH_Get_Path(fh), "", 0),
+    TEST_TRUE(runner, CB_Equals_Str(RAMFH_Get_Path(fh), "", 0),
               "NULL arg as filepath yields empty string");
 
-    TEST_TRUE(batch, RAMFH_Write(fh, foo, 3), "Write returns success");
-    TEST_TRUE(batch, RAMFH_Length(fh) == 3, "Length after one Write");
-    TEST_TRUE(batch, RAMFH_Write(fh, bar, 3), "Write returns success");
-    TEST_TRUE(batch, RAMFH_Length(fh) == 6, "Length after two Writes");
+    TEST_TRUE(runner, RAMFH_Write(fh, foo, 3), "Write returns success");
+    TEST_TRUE(runner, RAMFH_Length(fh) == 3, "Length after one Write");
+    TEST_TRUE(runner, RAMFH_Write(fh, bar, 3), "Write returns success");
+    TEST_TRUE(runner, RAMFH_Length(fh) == 6, "Length after two Writes");
 
     Err_set_error(NULL);
-    TEST_FALSE(batch, RAMFH_Read(fh, buf, 0, 2),
+    TEST_FALSE(runner, RAMFH_Read(fh, buf, 0, 2),
                "Reading from a write-only handle returns false");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Reading from a write-only handle sets error");
 
     // Reopen for reading.
     DECREF(fh);
     fh = RAMFH_open(NULL, FH_READ_ONLY, file);
-    TEST_TRUE(batch, RAMFile_Read_Only(file),
+    TEST_TRUE(runner, RAMFile_Read_Only(file),
               "FH_READ_ONLY propagates to RAMFile's read_only property");
 
-    TEST_TRUE(batch, RAMFH_Read(fh, buf, 0, 6), "Read returns success");
-    TEST_TRUE(batch, strncmp(buf, "foobar", 6) == 0, "Read/Write");
-    TEST_TRUE(batch, RAMFH_Read(fh, buf, 2, 3), "Read returns success");
-    TEST_TRUE(batch, strncmp(buf, "oba", 3) == 0, "Read with offset");
+    TEST_TRUE(runner, RAMFH_Read(fh, buf, 0, 6), "Read returns success");
+    TEST_TRUE(runner, strncmp(buf, "foobar", 6) == 0, "Read/Write");
+    TEST_TRUE(runner, RAMFH_Read(fh, buf, 2, 3), "Read returns success");
+    TEST_TRUE(runner, strncmp(buf, "oba", 3) == 0, "Read with offset");
 
     Err_set_error(NULL);
-    TEST_FALSE(batch, RAMFH_Read(fh, buf, -1, 4),
+    TEST_FALSE(runner, RAMFH_Read(fh, buf, -1, 4),
                "Read() with a negative offset returns false");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Read() with a negative offset sets error");
 
     Err_set_error(NULL);
-    TEST_FALSE(batch, RAMFH_Read(fh, buf, 6, 1),
+    TEST_FALSE(runner, RAMFH_Read(fh, buf, 6, 1),
                "Read() past EOF returns false");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Read() past EOF sets error");
 
     Err_set_error(NULL);
-    TEST_FALSE(batch, RAMFH_Write(fh, foo, 3),
+    TEST_FALSE(runner, RAMFH_Write(fh, foo, 3),
                "Writing to a read-only handle returns false");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Writing to a read-only handle sets error");
 
     DECREF(fh);
@@ -109,26 +103,26 @@ test_Read_Write(TestBatch *batch) {
 }
 
 static void
-test_Grow_and_Get_File(TestBatch *batch) {
+test_Grow_and_Get_File(TestBatchRunner *runner) {
     RAMFileHandle *fh = RAMFH_open(NULL, FH_WRITE_ONLY | FH_CREATE, NULL);
     RAMFile *ram_file = RAMFH_Get_File(fh);
     ByteBuf *contents = RAMFile_Get_Contents(ram_file);
 
     RAMFH_Grow(fh, 100);
-    TEST_TRUE(batch, BB_Get_Capacity(contents) >= 100, "Grow");
+    TEST_TRUE(runner, BB_Get_Capacity(contents) >= 100, "Grow");
 
     DECREF(fh);
 }
 
 static void
-test_Close(TestBatch *batch) {
+test_Close(TestBatchRunner *runner) {
     RAMFileHandle *fh = RAMFH_open(NULL, FH_WRITE_ONLY | FH_CREATE, NULL);
-    TEST_TRUE(batch, RAMFH_Close(fh), "Close returns true");
+    TEST_TRUE(runner, RAMFH_Close(fh), "Close returns true");
     DECREF(fh);
 }
 
 static void
-test_Window(TestBatch *batch) {
+test_Window(TestBatchRunner *runner) {
     RAMFile *file = RAMFile_new(NULL, false);
     RAMFileHandle *fh = RAMFH_open(NULL, FH_WRITE_ONLY, file);
     FileWindow *window = FileWindow_new();
@@ -143,26 +137,26 @@ test_Window(TestBatch *batch) {
     fh = RAMFH_open(NULL, FH_READ_ONLY, file);
 
     Err_set_error(NULL);
-    TEST_FALSE(batch, RAMFH_Window(fh, window, -1, 4),
+    TEST_FALSE(runner, RAMFH_Window(fh, window, -1, 4),
                "Window() with a negative offset returns false");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Window() with a negative offset sets error");
 
     Err_set_error(NULL);
-    TEST_FALSE(batch, RAMFH_Window(fh, window, 4000, 1000),
+    TEST_FALSE(runner, RAMFH_Window(fh, window, 4000, 1000),
                "Window() past EOF returns false");
-    TEST_TRUE(batch, Err_get_error() != NULL,
+    TEST_TRUE(runner, Err_get_error() != NULL,
               "Window() past EOF sets error");
 
-    TEST_TRUE(batch, RAMFH_Window(fh, window, 1021, 2),
+    TEST_TRUE(runner, RAMFH_Window(fh, window, 1021, 2),
               "Window() returns true");
-    TEST_TRUE(batch, strncmp(window->buf, "oo", 2) == 0, "Window()");
+    TEST_TRUE(runner, strncmp(window->buf, "oo", 2) == 0, "Window()");
 
-    TEST_TRUE(batch, RAMFH_Release_Window(fh, window),
+    TEST_TRUE(runner, RAMFH_Release_Window(fh, window),
               "Release_Window() returns true");
-    TEST_TRUE(batch, window->buf == NULL, "Release_Window() resets buf");
-    TEST_TRUE(batch, window->offset == 0, "Release_Window() resets offset");
-    TEST_TRUE(batch, window->len == 0, "Release_Window() resets len");
+    TEST_TRUE(runner, window->buf == NULL, "Release_Window() resets buf");
+    TEST_TRUE(runner, window->offset == 0, "Release_Window() resets offset");
+    TEST_TRUE(runner, window->len == 0, "Release_Window() resets len");
 
     DECREF(window);
     DECREF(fh);
@@ -170,13 +164,13 @@ test_Window(TestBatch *batch) {
 }
 
 void
-TestRAMFH_run_tests(TestRAMFileHandle *self) {
-    TestBatch *batch = (TestBatch*)self;
-    test_open(batch);
-    test_Read_Write(batch);
-    test_Grow_and_Get_File(batch);
-    test_Close(batch);
-    test_Window(batch);
+TestRAMFH_run(TestRAMFileHandle *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 32);
+    test_open(runner);
+    test_Read_Write(runner);
+    test_Grow_and_Get_File(runner);
+    test_Close(runner);
+    test_Window(runner);
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/40220b9e/core/Lucy/Test/Store/TestRAMFileHandle.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Store/TestRAMFileHandle.cfh b/core/Lucy/Test/Store/TestRAMFileHandle.cfh
index 2b64af1..a795d23 100644
--- a/core/Lucy/Test/Store/TestRAMFileHandle.cfh
+++ b/core/Lucy/Test/Store/TestRAMFileHandle.cfh
@@ -20,13 +20,10 @@ class Lucy::Test::Store::TestRAMFileHandle cnick TestRAMFH
     inherits Clownfish::TestHarness::TestBatch {
 
     inert incremented TestRAMFileHandle*
-    new(TestFormatter *formatter);
-
-    inert TestRAMFileHandle*
-    init(TestRAMFileHandle *self, TestFormatter *formatter);
+    new();
 
     void
-    Run_Tests(TestRAMFileHandle *self);
+    Run(TestRAMFileHandle *self, TestBatchRunner *runner);
 }