[vala/wip/valadate: 117/137] major revision of valadate



commit 7b7811d5a78ba8ee50ce37a7146e1c8799a6ec3b
Author: chebizarro gmail com <chebizarro gmail com>
Date:   Fri Jul 15 22:03:12 2016 -0700

    major revision of valadate

 build-aux/tap-test               |    2 +-
 tests/Makefile.am                |   51 +++++-
 tests/asynchronous/testcase.test |   11 +
 tests/genie/genie.gs             |   18 ++
 tests/valadatetests.vala         |   29 +++
 tests/valatests.vala             |  108 +++++++++---
 valadate/.gitignore              |   18 ++
 valadate/Makefile.am             |    7 +
 valadate/assembly.vala           |    2 +-
 valadate/compositetest.vala      |   39 ++++
 valadate/module.vala             |   65 ++++---
 valadate/tap.vala                |  379 ++++++++++++++++++++++++++++++++++++++
 valadate/tapresult.vala          |   39 ++++
 valadate/test.vala               |   27 ++--
 valadate/testcase.vala           |  319 ++++++++++++++++++--------------
 valadate/testconfig.vala         |  191 +++++++++++++++++++
 valadate/testexplorer.vala       |   76 +++++----
 valadate/testfixture.vala        |   11 +-
 valadate/testresult.vala         |   20 +-
 valadate/testresultfactory.vala  |   59 ++++++
 valadate/testrunner.vala         |  134 ++++----------
 valadate/testsuite.vala          |   30 +++
 22 files changed, 1268 insertions(+), 367 deletions(-)
---
diff --git a/build-aux/tap-test b/build-aux/tap-test
index 481e333..b582791 100755
--- a/build-aux/tap-test
+++ b/build-aux/tap-test
@@ -2,4 +2,4 @@
 
 # run a GTest in tap mode. The test binary is passed as $1
 
-$1 -k --tap
+$1 -f tap
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2fc34b1..ab4a6ab 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,43 +1,78 @@
 include $(top_srcdir)/Makefile.common
 include $(top_srcdir)/build-aux/glib-tap.mk
 
-test_programs = valactests-0
+test_programs = valadatetests valactests@PACKAGE_SUFFIX@
 
-valactests_0_VALAFLAGS = \
+# Valadate tests
+valadatetests_VALAFLAGS = \
        --vapidir $(top_srcdir)/valadate \
        --vapidir $(top_srcdir)/vapi \
        --pkg valadate \
        --pkg gio-2.0 \
        --pkg config \
-       --library valactests-0 \
+       --library valadatetests \
        -g
        
-valactests_0_SOURCES = \
+valadatetests_SOURCES = \
+       valadatetests.vala
+
+valadatetests_LDADD = \
+       $(GLIB_LIBS) \
+       $(GMODULE_LIBS) \
+       -lgio-2.0 \
+       -lm \
+       $(top_srcdir)/valadate/libvaladate.la
+       
+valadatetests_CPPFLAGS = \
+       -I$(top_srcdir)/valadate \
+       $(GLIB_CPPFLAGS) \
+       $(GMODULE_CPPFLAGS) \
+       -fPIE
+       
+valadatetests_CFLAGS = \
+       -I$(top_srcdir)/valadate \
+       $(GLIB_CFLAGS) \
+       $(GMODULE_CFLAGS) \
+       -pie \
+       -g
+
+
+valactests@PACKAGE_SUFFIX@_VALAFLAGS = \
+       --vapidir $(top_srcdir)/valadate \
+       --vapidir $(top_srcdir)/vapi \
+       --pkg valadate \
+       --pkg gio-2.0 \
+       --pkg config \
+       --library valactests@PACKAGE_SUFFIX@ \
+       -g
+       
+valactests@PACKAGE_SUFFIX@_SOURCES = \
        valatests.vala
 
-valactests_0_LDADD = \
+valactests@PACKAGE_SUFFIX@_LDADD = \
        $(GLIB_LIBS) \
        $(GMODULE_LIBS) \
        -lgio-2.0 \
        -lm \
        $(top_srcdir)/valadate/libvaladate.la
        
-valactests_0_CPPFLAGS = \
+valactests@PACKAGE_SUFFIX@_CPPFLAGS = \
        -I$(top_srcdir)/valadate \
        $(GLIB_CPPFLAGS) \
        $(GMODULE_CPPFLAGS) \
        -fPIE
        
-valactests_0_CFLAGS = \
+valactests@PACKAGE_SUFFIX@_CFLAGS = \
        -I$(top_srcdir)/valadate \
        $(GLIB_CFLAGS) \
        $(GMODULE_CFLAGS) \
        -pie \
        -g
 
+
 CLEANFILES += \
        *.gir \
        *.stamp \
-       $(valactests_0_SOURCES:.vala=.c) \
+       $(valactests@PACKAGE_SUFFIX@_SOURCES:.vala=.c) \
        *.vapi \
        rm -R .tests
diff --git a/tests/asynchronous/testcase.test b/tests/asynchronous/testcase.test
new file mode 100644
index 0000000..3b72486
--- /dev/null
+++ b/tests/asynchronous/testcase.test
@@ -0,0 +1,11 @@
+Packages: gio-2.0
+TestCase
+
+class TestCase : Valadate.TestCase {
+
+       public void test_test() {
+       
+       
+       }
+
+}
diff --git a/tests/genie/genie.gs b/tests/genie/genie.gs
new file mode 100644
index 0000000..5ffcde2
--- /dev/null
+++ b/tests/genie/genie.gs
@@ -0,0 +1,18 @@
+[indent=4]
+class Test : Object
+    delegate DelegateType (a : int)
+    data : int = 5
+    d : DelegateType
+
+    construct()
+        self.d = method
+
+    def method (b:int)
+        print "%d %d", b, data
+
+    def run (c:int)
+        d(c)
+
+init
+    var t = new Test()
+    t.run(1)
diff --git a/tests/valadatetests.vala b/tests/valadatetests.vala
new file mode 100644
index 0000000..693c54e
--- /dev/null
+++ b/tests/valadatetests.vala
@@ -0,0 +1,29 @@
+/*
+ * Valadate - Unit testing library for GObject-based libraries.
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ * 
+ * Authors:
+ *     Chris Daley <chebizarro gmail com>
+ */
+ 
+public class Valadate.Tests.TestFixture : Valadate.TestCase {
+       
+       public void test_testcase() {
+               
+       }
+       
+}
diff --git a/tests/valatests.vala b/tests/valatests.vala
index 1e9cbae..47edc27 100644
--- a/tests/valatests.vala
+++ b/tests/valatests.vala
@@ -1,7 +1,7 @@
 namespace Vala.Tests {
        
        /**
-        * Vala.TestFixture
+        * Vala.Tests.Fixture
         * 
         * Searchs all of the sub directories in the current directory for
         * *.vala or *.test files, compiles and runs them.
@@ -30,17 +30,20 @@ namespace Vala.Tests {
                private SubprocessLauncher launcher =
                        new SubprocessLauncher(GLib.SubprocessFlags.STDOUT_PIPE | 
GLib.SubprocessFlags.STDERR_PIPE);
                
-               private const string VALAFLAGS = """--pkg gio-2.0 --pkg valadate
-                        --main main --save-temps --disable-warnings 
-                         -X -pie -X -fPIE -X -g -X -O0 -X -pipe -X -lm 
+               private const string VALA_FLAGS =
+                       """--main main --save-temps --disable-warnings --pkg gio-2.0 
+                         -X -lm -X -g -X -O0 -X -pipe
                          -X -Wno-discarded-qualifiers -X -Wno-incompatible-pointer-types
                          -X -Wno-deprecated-declarations -X -Werror=return-type
                          -X -Werror=init-self -X -Werror=implicit -X -Werror=sequence-point
                          -X -Werror=return-type -X -Werror=uninitialized -X -Werror=pointer-arith
                          -X -Werror=int-to-pointer-cast -X -Werror=pointer-to-int-cast""";
                
-               private const string GIRHEADER ="""
-                       <?xml version="1.0"?>
+               private const string TESTCASE_FLAGS =
+                       "--pkg valadate -X -pie -X -fPIE";
+               
+               private const string GIRHEADER =
+                       """<?xml version="1.0"?>
                        <repository version="1.2"
                                                xmlns="http://www.gtk.org/introspection/core/1.0";
                                                xmlns:c="http://www.gtk.org/introspection/c/1.0";
@@ -54,8 +57,9 @@ namespace Vala.Tests {
                                                         c:symbol-prefixes="test">
                                        %s
                                </namespace>
-                               </repository>
-               """;
+                               </repository>""";
+
+               private const string BUGZILLA_URL = "http://bugzilla.gnome.org/";;
 
                private File testdir;
                private File buildir;
@@ -67,7 +71,6 @@ namespace Vala.Tests {
 
                private string vapidirs;
 
-
                public Fixture() {
                        load_tests();
                }
@@ -88,7 +91,7 @@ namespace Vala.Tests {
                                delete_tempdir();
                                tempdir.make_directory();
 
-                               vapidirs = "--vapidir %s --vapidir %s".printf(vapidir.get_path(), 
valadatedir.get_path());
+                               vapidirs = "--vapidir %s".printf(vapidir.get_path());
 
                                launcher.set_cwd(tempdir.get_path());
 
@@ -132,15 +135,23 @@ namespace Vala.Tests {
                                }
 
                                File testfile = directory.get_child(fname);
-                               string testname = 
testfile.get_basename().substring(0,testfile.get_basename().last_index_of("."));
+                               string testname = testfile.get_basename().substring(
+                                       0,testfile.get_basename().last_index_of("."));
 
-                               if(fname.has_suffix(".vala")) {
-                                       string command = "%s %s %s %s".printf(valac.get_path(), vapidirs, 
VALAFLAGS, testfile.get_path());
-                                       string binary = 
testfile.get_basename().substring(0,testfile.get_basename().last_index_of("."));
+                               if(fname.has_suffix(".vala") || fname.has_suffix(".gs")) {
+                                       string binary = testfile.get_basename().substring(
+                                               0,testfile.get_basename().last_index_of("."));
+                                       string command = "%s %s %s --library %s -o %s %s".printf(
+                                               valac.get_path(), vapidirs, VALA_FLAGS, binary,
+                                               binary, testfile.get_path());
 
                                        add_test(testname,
                                         ()=> {
                                                try {
+                                                       if(binary.has_prefix("bug")) {
+                                                               Test.bug_base (BUGZILLA_URL);                 
                          
+                                                               Test.bug(binary.substring(3));
+                                                       }
                                                        run_command(command);
                                                        if(tempdir.get_child(binary).query_exists())
                                                                run_command("./%s".printf(binary));
@@ -157,6 +168,10 @@ namespace Vala.Tests {
                                        add_test(testname,
                                         ()=> {
                                                try {
+                                                       if(fname.has_prefix("bug")) {
+                                                               Test.bug_base (BUGZILLA_URL);                 
                          
+                                                               Test.bug(fname.substring(3,fname.length-8));
+                                                       }
                                                        parse_test(testfile);
                                                } catch (Error e) {
                                                        Test.fail();
@@ -168,8 +183,9 @@ namespace Vala.Tests {
 
                private void default_callback(Subprocess process, size_t err, string buffer) {
                        if (err > 0) {
-                               Test.fail();
+                               //Test.skip(buffer);
                                stdout.printf ("%s", buffer);
+                               Test.fail();
                                process.force_exit();
                        }
                }
@@ -191,7 +207,8 @@ namespace Vala.Tests {
                private void parse_test(File testfile) throws Error {
                        
                        var stream = new DataInputStream(testfile.read());
-                       string testname = 
testfile.get_basename().substring(0,testfile.get_basename().last_index_of("."));
+                       string testname = testfile.get_basename().substring(
+                               0,testfile.get_basename().last_index_of("."));
                        
                        string line = stream.read_line(null);
                        
@@ -212,7 +229,7 @@ namespace Vala.Tests {
                                        var server = serverfile.create(FileCreateFlags.NONE);
                                        var server_stream = new DataOutputStream (server);
                                        
-                                       while ((line = stream.read_line (null)) != "Program: client") { }
+                                       do {} while ((line = stream.read_line (null)) != "Program: client");
                                        
                                        while ((line = stream.read_line (null)) != "Program: server") {
                                                client_stream.put_string(line + "\n");
@@ -222,15 +239,20 @@ namespace Vala.Tests {
                                                server_stream.put_string(line + "\n");
                                        }
 
-                                       string command = "%s %s %s %s %s".printf(valac.get_path(), vapidirs, 
packages, VALAFLAGS, clientfile.get_path());
+                                       string command = "%s %s %s %s %s".printf(
+                                               valac.get_path(), vapidirs, packages, VALA_FLAGS,
+                                               clientfile.get_path());
                                        
                                        run_command(command);
 
-                                       command = "%s %s %s %s %s".printf(valac.get_path(), vapidirs, 
packages, VALAFLAGS, serverfile.get_path());
+                                       command = "%s %s %s %s %s".printf(
+                                               valac.get_path(), vapidirs, packages, VALA_FLAGS,
+                                               serverfile.get_path());
 
                                        run_command(command);
 
-                                       string binary = 
serverfile.get_basename().substring(0,serverfile.get_basename().last_index_of("."));
+                                       string binary = serverfile.get_basename().substring(
+                                               0,serverfile.get_basename().last_index_of("."));
 
                                        command = "./" + binary;
 
@@ -270,7 +292,12 @@ namespace Vala.Tests {
                                        var girstream = girfile.create(FileCreateFlags.NONE);
                                        girstream.write(GIRHEADER.printf(gir).data);
 
-                                       string command = "%s %s %s --library %s 
%s".printf(vapigen.get_path(), vapidirs, girdirs, testname, girfile.get_path());
+                                       string command = "%s %s %s --library %s %s".printf(
+                                               vapigen.get_path(),
+                                               vapidirs,
+                                               girdirs,
+                                               testname,
+                                               girfile.get_path());
                                
                                        run_command(command);
 
@@ -292,7 +319,11 @@ namespace Vala.Tests {
                                                invalid_stream.put_string(line + "\n");
                                        }
 
-                                       string command = "%s %s %s %s %s".printf(valac.get_path(), vapidirs, 
packages, VALAFLAGS, invalidfile.get_path());
+                                       string command = "%s %s %s %s %s".printf(
+                                               valac.get_path(),
+                                               vapidirs, packages,
+                                               VALA_FLAGS,
+                                               invalidfile.get_path());
 
                                        run_command(command, (p,e,b) => {
                                                if (e <= 0)
@@ -300,9 +331,42 @@ namespace Vala.Tests {
                                        });
                                        break;
 
+                               case "TestCase":
+                                       
+                                       var testcasefile = tempdir.get_child(testname + ".vala");
+                                       var testcase = testcasefile.create(FileCreateFlags.NONE);
+                                       var testcase_stream = new DataOutputStream (testcase);
+
+                                       testcase_stream.put_string("namespace Vala.Tests {\n");
+
+                                       while ((line = stream.read_line (null)) != null) {
+                                               testcase_stream.put_string(line + "\n");
+                                       }
+
+                                       testcase_stream.put_string("\n}");
+
+                                       string command = "%s %s %s %s %s".printf(
+                                               valac.get_path(),
+                                               vapidirs,
+                                               packages,
+                                               VALA_FLAGS,
+                                               testcasefile.get_path());
+                                       
+                                       run_command(command);
+
+                                       string binary = testcasefile.get_basename().substring(
+                                               0,testcasefile.get_basename().last_index_of("."));
+
+                                       command = "./" + binary;
+
+                                       run_command(command);
+
+                                       break;
+
                                default :
                                        break;
                        }
                }
        }
+       
 }
diff --git a/valadate/.gitignore b/valadate/.gitignore
new file mode 100644
index 0000000..cf84fea
--- /dev/null
+++ b/valadate/.gitignore
@@ -0,0 +1,18 @@
+Makefile.in
+Makefile
+*.o
+*.lo
+*.la
+*.c
+*.h
+*.stamp
+*.gir
+*.vapi
+.deps
+.libs
+*.pc
+*.gcda
+*.gcno
+coverage
+lcov.info
+*~
diff --git a/valadate/Makefile.am b/valadate/Makefile.am
index 829e268..900b648 100644
--- a/valadate/Makefile.am
+++ b/valadate/Makefile.am
@@ -7,13 +7,19 @@ lib_LTLIBRARIES = \
 
 libvaladate_la_SOURCES = \
        assembly.vala \
+       compositetest.vala \
        module.vala \
+       tap.vala \
+       tapresult.vala \
        test.vala \
        testcase.vala \
+       testconfig.vala \
        testexplorer.vala \
        testfixture.vala \
        testresult.vala \
+       testresultfactory.vala \
        testrunner.vala \
+       testsuite.vala \
        $(NULL)
 
 libvaladate_la_VALAFLAGS = \
@@ -24,6 +30,7 @@ libvaladate_la_VALAFLAGS = \
        --pkg gmodule-2.0 \
        --pkg vala \
        --pkg gee \
+       --pkg config \
        --library valadate \
        --vapi valadate.vapi \
        -H valadate.h \
diff --git a/valadate/assembly.vala b/valadate/assembly.vala
index e68e607..b7f0c3d 100644
--- a/valadate/assembly.vala
+++ b/valadate/assembly.vala
@@ -1,6 +1,6 @@
 /*
  * Valadate - Unit testing library for GObject-based libraries.
- * Copyright (C) 20016  Chris Daley <chebizarro gmail com>
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
diff --git a/valadate/compositetest.vala b/valadate/compositetest.vala
new file mode 100644
index 0000000..46ada0f
--- /dev/null
+++ b/valadate/compositetest.vala
@@ -0,0 +1,39 @@
+/*
+ * Valadate - Unit testing library for GObject-based libraries.
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Authors:
+ *     Chris Daley <chebizarro gmail com>
+ */
+ 
+public abstract class Valadate.CompositeTest : Object, Test {
+
+       public string name {get;set;} 
+
+       public abstract int size {get;}
+
+       public virtual TestResult? run(TestResult? result = null) { }
+
+       public abstract Test get(string testname);
+       
+       public abstract void set(string testname, Test test);
+
+       public abstract bool contains(string testname);
+       
+       public virtual TestResult? run_test(string testname, TestResult? result = null) throws TestError {}
+
+}
diff --git a/valadate/module.vala b/valadate/module.vala
index a4e9421..c364c2f 100644
--- a/valadate/module.vala
+++ b/valadate/module.vala
@@ -1,6 +1,6 @@
 /*
  * Valadate - Unit testing library for GObject-based libraries.
- * Copyright (C) 20016  Chris Daley <chebizarro gmail com>
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,39 +20,42 @@
  *     Chris Daley <chebizarro gmail com>
  */
 
-namespace Valadate {
+public errordomain Valadate.ModuleError {
+       NOT_FOUND,
+       LOAD,
+       METHOD
+}
 
-       public class Module : Object {
-               
-               private string lib_path;
-               private GLib.Module module;
+/**
+ * Represents a loadable module containing {@link Valadate.Test}s
+ */
+public class Valadate.Module : Object {
+       
+       private string lib_path;
+       private GLib.Module module;
 
-               public Module (string libpath) {
-                       lib_path = libpath;
-               } 
-               
-               public void load_module() throws Error
-                       requires(lib_path != null)
-               {
-                       //if (!File.new_for_path(lib_path).query_exists())
-                               //throw new Error.MODULE("Module: %s does not exist", lib_path);
-                       
-                       module = GLib.Module.open (lib_path, ModuleFlags.BIND_LOCAL);
-                       //if (module == null)
-                               //throw new Error.MODULE(GLib.Module.error());
-                       module.make_resident();
-               }
-               
-               internal void* get_method(string method_name) throws Error {
-                       void* function;
-                       if(module.symbol (method_name, out function))
-                               if (function != null)
-                                       return function;
-                       //throw new Error.METHOD(GLib.Module.error());
-                       return null;
-               }
 
+       public Module (string libpath) {
+               lib_path = libpath;
+       } 
+       
+       public void load_module() throws ModuleError
+               requires(lib_path != null)
+       {
+               if (!File.new_for_path(lib_path).query_exists())
+                       throw new ModuleError.NOT_FOUND("Module: %s does not exist", lib_path);
                
+               module = GLib.Module.open (lib_path, ModuleFlags.BIND_LOCAL);
+               if (module == null)
+                       throw new ModuleError.LOAD(GLib.Module.error());
+               module.make_resident();
+       }
+       
+       internal void* get_method(string method_name) throws ModuleError {
+               void* function;
+               if(module.symbol (method_name, out function))
+                       if (function != null)
+                               return function;
+               throw new ModuleError.METHOD(GLib.Module.error());
        }
-
 }
diff --git a/valadate/tap.vala b/valadate/tap.vala
new file mode 100644
index 0000000..30745be
--- /dev/null
+++ b/valadate/tap.vala
@@ -0,0 +1,379 @@
+/*
+ * Valadate - Unit testing library for GObject-based libraries.
+ * Ported from JTap - http://svn.solucorp.qc.ca/repos/solucorp/JTap/trunk/
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ */
+
+public class Valadate.Tap : Object {
+       
+       private const string version = "1.0";
+       
+       private bool plan_set = false;
+       private bool no_plan = false;
+       private bool skip_all = false;
+       private bool test_died = false;
+       private int expected_tests = 0;
+       private int executed_tests = 0;
+       private int failed_tests = 0;
+       private bool _exit = true;
+       private string? todo = null;
+       
+
+       public Tap(bool really_exit = true) {
+               _exit = really_exit;
+               GLib.set_printerr_handler (printerr_func_stack_trace);
+               Log.set_default_handler (log_func_stack_trace);
+       }
+
+       private static void printerr_func_stack_trace (string? text) {
+               if (text == null || str_equal (text, ""))
+                       return;
+
+               stderr.printf (text);
+
+               /* Print a stack trace since we've hit some major issue */
+               GLib.on_error_stack_trace ("libtool --mode=execute gdb");
+       }
+
+       private void log_func_stack_trace (
+               string? log_domain,
+               LogLevelFlags log_levels,
+               string message) {
+               Log.default_handler (log_domain, log_levels, message);
+
+               /* Print a stack trace for any message at the warning level or above */
+               if ((log_levels & (
+                       LogLevelFlags.LEVEL_WARNING |
+                       LogLevelFlags.LEVEL_ERROR |
+                       LogLevelFlags.LEVEL_CRITICAL)) != 0) {
+                       GLib.on_error_stack_trace ("libtool --mode=execute gdb");
+               }
+       }
+
+       public int plan_no_plan() {
+               if (plan_set)
+                       die("You tried to plan twice!");
+
+               plan_set = true;
+               no_plan = true;
+               return 1;
+       }
+
+
+       public int plan_skip_all(string reason) {
+               if (plan_set)
+                       die("You tried to plan twice!");
+
+               print_plan(0, "Skip " + reason);
+
+               skip_all = true;
+               plan_set = true;
+
+               exit(0);
+               return 0;
+       }
+
+
+       public int plan_tests(int tests) {
+               if (plan_set)
+                       die("You tried to plan twice!");
+
+               if (tests == 0)
+                       die("You said to run 0 tests!  You've got to run something.");
+
+               print_plan(tests);
+               expected_tests = tests;
+
+               plan_set = true;
+
+               return tests;
+       }
+
+
+       private void print_plan(int expected_tests, string? directive = null) {
+               stdout.puts("1.." + expected_tests.to_string());
+               if (directive != null)
+                       stdout.puts(" # " + directive);
+
+               stdout.puts("\n");
+               stdout.flush();
+       }
+
+       public bool pass(string name) {
+               return ok(true, name);
+       }
+
+       public bool fail(string name) {
+               return ok(false, name);
+       }
+
+       /*
+               This is the workhorse method that actually
+               prints the tests result.
+       */
+       public bool ok(bool result, string? name= null) {
+               if (!plan_set)
+                       die("You tried to run a test without a plan!  Gotta have a plan.");
+
+               executed_tests++;
+
+               if (!result) {
+                       stdout.puts("not ");
+                       failed_tests++;
+               }
+               stdout.puts("ok " + executed_tests.to_string());
+
+               if (name != null) {
+                       stdout.puts(" - ");
+                       stdout.puts(name.replace("#", "\\\\#"));
+               }
+
+               if (todo != null) {
+                       stdout.puts(" # TODO " + todo);
+                       if (!result)
+                               failed_tests--;
+               }
+
+               stdout.puts("\n");
+               stdout.flush();
+
+               if (!result) {
+                       /*
+                       string file = null;
+                       string clas = null;
+                       string func = null;
+                       int line = 0;
+
+                       try {
+                               for (int i = 0 ; i < stack.length ; i++) {
+                                       Class c = Class.forName(stack[i].getClassName());
+                                       if (! Tap.class.isAssignableFrom(c)) {
+                                               // We are outside a Tap object, so this is probably the 
callpoint
+                                               file = stack[i].getFileName();
+                                               clas = c.getName();
+                                               func = stack[i].getMethodName();
+                                               line = stack[i].getLineNumber();
+                                               break;
+                                       }
+                               }
+                       }
+                       catch (Exception e) {
+                               e.printStackTrace();
+                       }
+       
+                       if (name != null) {             
+                               diag("  Failed " + (todo == null ? "" : "(TODO) ") + "test '" + name + "'");
+                               diag("  in " + file + ":" + func + "() at line " + line + ".");
+                       }
+                       else {
+                               diag("  Failed " + (todo == null ? "" : "(TODO) ") + "test in " + file + ":" 
+ func + "() at line " + line + ".");
+                       }*/
+               }
+
+               return result;
+       }
+
+       private bool equals(Value result, Value expected) {
+               bool r;
+
+               if ((result.peek_pointer() == null)&&(expected.peek_pointer() == null))
+                       r = true;
+               else if ((result.peek_pointer() == null)||(expected.peek_pointer() == null))
+                       r = false;
+               else
+                       r = (result == expected);
+
+               return r;
+       }
+
+
+       private bool matches(Value result, string? pattern) {
+               bool r;
+
+               if ((result.peek_pointer() == null)||(pattern == null))
+                       r = false;
+               else
+                       r = (result.get_string() == pattern);
+
+               return r;
+       }
+
+
+       private void is_diag(Value result, Value expected) {
+               diag("         got: '" + result.get_string() + "'");
+               diag("    expected: '" + expected.get_string() + "'");
+       }
+
+
+       public bool is(Value result, Value expected, string? name = null) {
+               bool r = ok(equals(result, expected), name);
+               if (!r)
+                       is_diag(result, expected);
+               return r;
+       }
+
+
+       public bool isnt(Value result, Value expected, string? name = null) {
+               bool r = ok(!equals(result, expected), name);
+               if (! r)
+                       is_diag(result, expected);
+               return r;
+       }
+
+       public bool like(Value result, string pattern, string? name = null) {
+               bool r = ok(matches(result, pattern), name);
+               if (!r)
+                       diag("    " + result.get_string() + " doesn't match '" + pattern + "'");
+               return r;
+       }
+
+       public bool unlike(Value result, string pattern, string? name = null) {
+               bool r = ok(! matches(result, pattern), name);
+               if (! r)
+                       diag("    " + result.get_string() + " matches '" + pattern + "'");
+               return r;
+       }
+
+       public bool isa_ok(Value o, Type c, string? name = null) {
+
+               bool r = false;
+               if ((o.peek_pointer() == null)||(c == Type.INVALID))
+                       r = false ;
+               else
+                       r = ok(c.is_a(o.type()), name);
+
+               if (!r)
+                       diag("    Value isn't a '" + c.name() + "' it's a '" + o.type().name() + "'");
+
+               return r;
+       }
+
+
+       public void skip(string reason, int n = 1) throws TapError {
+               for (int i = 0 ; i < n ; i++) {
+                       executed_tests++;
+                       stdout.puts("ok " + executed_tests.to_string() + " # skip " + reason + "\n");
+                       stdout.flush();
+               }
+               throw new TapError.SKIP(reason);
+       }
+
+
+       public void todo_start(string reason) {
+               if (reason == "")
+                       reason = null;
+               todo = reason;
+       }
+
+
+       public void todo_end() {
+               todo = null;
+       }
+
+
+       public bool diag(string msg) {
+               if (msg != null) {
+                       string[] lines = msg.split("\n");
+                       StringBuilder buf = new StringBuilder() ; 
+                       for (int i = 0 ; i < lines.length ; i++)
+                               buf.append("# " + lines[i] + "\n");
+                       stdout.puts(buf.str);
+                       stdout.flush();
+               }
+               return false;
+       }
+
+
+       
+       private void die(string reason) {
+               stderr.puts(reason + "\n");
+        test_died = true;
+               exit(255);
+       }
+
+
+       public void BAIL_OUT(string reason) {
+               stdout.puts("Bail out! " + reason + "\n");
+               stdout.flush();
+               exit(255);
+       }
+
+
+       private int cleanup() {
+               int rc = 0;
+
+               if (! plan_set) {
+                       diag("Looks like your test died before it could output anything.");
+                       return rc;
+               }
+
+               if (test_died) {
+                       diag("Looks like your test died just after " + executed_tests.to_string() + ".");
+                       return rc;
+               }
+
+               if ((! skip_all)&&(no_plan)) {
+                       print_plan(executed_tests);
+               }
+
+               if ((! no_plan)&&(expected_tests < executed_tests)) {
+                       diag("Looks like you planned " + expected_tests.to_string() + " test" + 
(expected_tests > 1 ? "s" : "") + " but ran "
+                               + (executed_tests - expected_tests).to_string() + " extra.");
+                       rc = -1;
+               }
+
+               if ((! no_plan)&&(expected_tests > executed_tests)) {
+                       diag("Looks like you planned " + expected_tests.to_string() + " test" + 
(expected_tests > 1 ? "s" : "") + " but only ran "
+                               + executed_tests.to_string() + ".");
+               }
+
+               if (failed_tests > 0) {
+                       diag("Looks like you failed " + failed_tests.to_string() + " test" + (failed_tests > 
1 ? "s" : "") + " of " + executed_tests.to_string() + ".");
+               }
+
+               return rc;
+       }
+
+
+       public int exit_status() {
+               if ((no_plan)||(! plan_set))
+                       return failed_tests;
+
+               if (expected_tests < executed_tests)
+                       return executed_tests - expected_tests;
+
+               return failed_tests + (expected_tests - executed_tests);
+       }
+
+
+       private void exit(int rc = 0) {
+               int alt_rc = cleanup();
+
+               if (alt_rc != 0)
+                       rc = alt_rc;
+
+               //if (_exit)
+                       //System.exit(rc);
+               //else
+                       //throw new TapError.EXIT(rc.to_string());
+       }
+}
+
+public errordomain Valadate.TapError {
+       EXIT,
+       SKIP
+}
diff --git a/valadate/tapresult.vala b/valadate/tapresult.vala
new file mode 100644
index 0000000..6f176e4
--- /dev/null
+++ b/valadate/tapresult.vala
@@ -0,0 +1,39 @@
+/*
+ * Valadate - Unit testing library for GObject-based libraries.
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ * 
+ * Authors:
+ *     Chris Daley <chebizarro gmail com>
+ */
+
+public class Valadate.TAPResult : Object, TestResult {
+
+
+       public int error_count {get;internal set;}
+       public int failure_count {get;internal set;}
+       public int run_count {get;internal set;}
+
+       public void add_test(Test test) {}
+
+       public void add_error(Test test) {}
+
+       public void add_failure(Test test) {}
+
+       public void report() {}
+
+
+}
diff --git a/valadate/test.vala b/valadate/test.vala
index e769737..be5882a 100644
--- a/valadate/test.vala
+++ b/valadate/test.vala
@@ -1,6 +1,6 @@
 /*
  * Valadate - Unit testing library for GObject-based libraries.
- * Copyright (C) 20016  Chris Daley <chebizarro gmail com>
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,23 +19,20 @@
  * Authors:
  *     Chris Daley <chebizarro gmail com>
  */
-namespace Valadate {
-       
+/**
+ * The Test interface is implemented by TestCase and TestSuite.
+ * It is the base interface for all runnable Tests.
+ */
+public interface Valadate.Test : Object {
        /**
-        * The Test interface is implemented by TestCase and TestSuite.
-        * It is the base interface for all runnable Tests.
+        * Runs the Tests and collects the results in a TestResult 
+        *
+        * @param result the TestResult object used to store the results of the Test
         */
-    public interface Test : Object {
-               /**
-                * Runs the Tests and collects the results in a TestResult 
-                *
-                * @param result the TestResult object used to store the results of the Test
-                */
-               public abstract TestResult run (TestResult? result = null);
-
-               public delegate void TestMethod ();
+       public abstract TestResult? run (TestResult? result = null);
 
+       public abstract string name {get;set;} 
 
-    }
+       public delegate void TestMethod ();
 
 }
diff --git a/valadate/testcase.vala b/valadate/testcase.vala
index 5a8f517..76a295d 100644
--- a/valadate/testcase.vala
+++ b/valadate/testcase.vala
@@ -24,181 +24,224 @@
  *     Julien Peeters <contact julienpeeters fr>
  */
 
-namespace Valadate {
-       
-       public delegate void AsyncBegin(AsyncReadyCallback callback);
-       public delegate void AsyncFinish(AsyncResult result) throws GLib.Error;
+public errordomain Valadate.TestError {
+       NOT_FOUND
+}
 
-       
-       public abstract class TestCase : Object, Test, TestFixture {
+public abstract class Valadate.TestCase : CompositeTest, TestFixture {
 
-               public GLib.TestSuite _suite;
+       private HashTable<string, TestAdaptor> _tests =
+               new HashTable<string, TestAdaptor> (str_hash, str_equal);
 
-               public GLib.TestSuite suite {
-                       get {
-                               if (_suite == null)
-                                       _suite = new GLib.TestSuite (this.name);
-                               return _suite;
-                       }
-               }
+       public virtual void set_up() {}
 
-               public string name {get;set;} 
+       public virtual void tear_down() {}
 
-               private Adaptor[] adaptors = new Adaptor[0];
+       private class TestAdaptor : Object, Test {
 
-               private HashTable<string, Adaptor> tests =
-                       new HashTable<string, Adaptor> (str_hash, str_equal);
+               public string name { get; set; }
 
+               private Test.TestMethod test;
                
-               construct {
-                       name = this.get_type().name();
+               public TestAdaptor(string name, owned Test.TestMethod test) {
+                       this.name = name;
+                       this.test = (owned)test;
                }
 
-               public void add_test (string name, owned Test.TestMethod test)
-                       requires (name.contains("/") != true)
-               {
-                       var adaptor = new Adaptor (name, (owned)test, this);
-                       this.adaptors += adaptor;
+               public TestResult? run(TestResult? result = null) {
+                       this.test();
+                       return result;
+               }
 
-                       this.tests.insert(name, adaptor);
+       }
 
-                       this.suite.add (new GLib.TestCase (adaptor.name,
-                                                                                          adaptor.set_up,
-                                                                                          adaptor.run,
-                                                                                          adaptor.tear_down 
));
-               }
+       public void add_test (string name, owned Test.TestMethod test)
+               requires (name.contains("/") != true)
+       {
+               var adaptor = new TestAdaptor (name, (owned)test);
+               _tests.insert(name, adaptor);
+       }
 
 
-               public void add_async_test (
-                       string name,
-                       owned AsyncBegin async_begin,
-                       owned AsyncFinish async_finish,
-                       int timeout = 200)
-               {
-                       var adaptor = new Adaptor (name, () => { }, this);
-                       adaptor.is_async = true;
-                       adaptor.async_begin = (owned)async_begin;
-                       adaptor.async_finish = (owned)async_finish;
-                       adaptor.async_timeout = timeout;
-                       this.adaptors += adaptor;
-
-                       this.tests.insert(name, adaptor);
-
-                       this.suite.add (new GLib.TestCase (
-                               adaptor.name,
-                               adaptor.set_up,
-                               adaptor.run,
-                               adaptor.tear_down,
-                               sizeof(Adaptor)));
 
-               }
+       public virtual TestResult? run_test(string testname, TestResult? result = null) throws TestError {
+               if(!_tests.contains(testname))
+                       throw new TestError.NOT_FOUND("The Test %s was not found", testname);
+               
+               var test = _tests.get(testname);
+               
+               test.run(result);
+               
+               return result;
+       }
 
 
-               /**
-                * Runs the Tests and collects the results in a TestResult 
-                *
-                * @param result the TestResult object used to store the results of the Test
-                */
-               public virtual TestResult run(TestResult? result = null) {
-                       return result;
-               }
 
-               public virtual TestResult run_test(Test test, TestResult? result = null) {
-                       return result;
+
+
+
+
+
+
+
+
+
+       
+
+
+
+       public delegate void AsyncBegin(AsyncReadyCallback callback);
+       public delegate void AsyncFinish(AsyncResult result) throws GLib.Error;
+
+       public GLib.TestSuite _suite;
+
+       public GLib.TestSuite suite {
+               get {
+                       if (_suite == null)
+                               _suite = new GLib.TestSuite (this.name);
+                       return _suite;
                }
+       }
 
-               public virtual void set_up () {}
 
-               public virtual void tear_down () {}
+       private Adaptor[] adaptors = new Adaptor[0];
 
-               private class Adaptor {
-                       [CCode (notify = false)]
-                       public string name { get; private set; }
-                       public int async_timeout { get; set; }
 
-                       private Test.TestMethod test;
-                       private TestCase test_case;
+       
+       construct {
+               name = this.get_type().name();
+       }
+
+       public void add_testb (string name, owned Test.TestMethod test)
+               requires (name.contains("/") != true)
+       {
+               var adaptor = new Adaptor (name, (owned)test, this);
+               this.adaptors += adaptor;
+
+               //this._tests.insert(name, adaptor);
+
+               this.suite.add (new GLib.TestCase (adaptor.name,
+                                                                                  adaptor.set_up,
+                                                                                  adaptor.run,
+                                                                                  adaptor.tear_down ));
+       }
+
+
+       public void add_async_test (
+               string name,
+               owned AsyncBegin async_begin,
+               owned AsyncFinish async_finish,
+               int timeout = 200)
+       {
+               var adaptor = new Adaptor (name, () => { }, this);
+               adaptor.is_async = true;
+               adaptor.async_begin = (owned)async_begin;
+               adaptor.async_finish = (owned)async_finish;
+               adaptor.async_timeout = timeout;
+               this.adaptors += adaptor;
+
+               //this._tests.insert(name, adaptor);
+
+               this.suite.add (new GLib.TestCase (
+                       adaptor.name,
+                       adaptor.set_up,
+                       adaptor.run,
+                       adaptor.tear_down,
+                       sizeof(Adaptor)));
+
+       }
+
 
-                       public bool is_async = false;
-                       public AsyncBegin async_begin;
-                       public AsyncFinish async_finish;
 
-                       public Adaptor (string name,
-                                                       owned Test.TestMethod test,
-                                                       TestCase test_case) {
-                               this.name = name;
-                               this.test = (owned)test;
-                               this.test_case = test_case;
-                       }
 
-                       public void set_up (void* fixture) {
-                               GLib.set_printerr_handler (printerr_func_stack_trace);
-                               Log.set_default_handler (log_func_stack_trace);
-                               this.test_case.set_up ();
-                       }
 
-                       private static void printerr_func_stack_trace (string? text) {
-                               if (text == null || str_equal (text, ""))
-                                       return;
+       private class Adaptor {
+               [CCode (notify = false)]
+               public string name { get; private set; }
+               public int async_timeout { get; set; }
 
-                               stderr.printf (text);
+               private Test.TestMethod test;
+               private TestCase test_case;
 
-                               /* Print a stack trace since we've hit some major issue */
+               public bool is_async = false;
+               public AsyncBegin async_begin;
+               public AsyncFinish async_finish;
+
+               public Adaptor (string name,
+                                               owned Test.TestMethod test,
+                                               TestCase test_case) {
+                       this.name = name;
+                       this.test = (owned)test;
+                       this.test_case = test_case;
+               }
+
+               public void set_up (void* fixture) {
+                       GLib.set_printerr_handler (printerr_func_stack_trace);
+                       Log.set_default_handler (log_func_stack_trace);
+                       this.test_case.set_up ();
+               }
+
+               private static void printerr_func_stack_trace (string? text) {
+                       if (text == null || str_equal (text, ""))
+                               return;
+
+                       stderr.printf (text);
+
+                       /* Print a stack trace since we've hit some major issue */
+                       GLib.on_error_stack_trace ("libtool --mode=execute gdb");
+               }
+
+               private void log_func_stack_trace (
+                       string? log_domain,
+                       LogLevelFlags log_levels,
+                       string message) {
+                       Log.default_handler (log_domain, log_levels, message);
+
+                       /* Print a stack trace for any message at the warning level or above */
+                       if ((log_levels & (
+                               LogLevelFlags.LEVEL_WARNING |
+                               LogLevelFlags.LEVEL_ERROR |
+                               LogLevelFlags.LEVEL_CRITICAL)) != 0) {
                                GLib.on_error_stack_trace ("libtool --mode=execute gdb");
                        }
+               }
 
-                       private void log_func_stack_trace (
-                               string? log_domain,
-                               LogLevelFlags log_levels,
-                               string message) {
-                               Log.default_handler (log_domain, log_levels, message);
-
-                               /* Print a stack trace for any message at the warning level or above */
-                               if ((log_levels & (
-                                       LogLevelFlags.LEVEL_WARNING |
-                                       LogLevelFlags.LEVEL_ERROR |
-                                       LogLevelFlags.LEVEL_CRITICAL)) != 0) {
-                                       GLib.on_error_stack_trace ("libtool --mode=execute gdb");
+               public void run (void* fixture) {
+                       if (this.is_async) {
+                               try     {
+                                       assert( wait_for_async (async_timeout, this.async_begin, 
this.async_finish) );
                                }
-                       }
-
-                       public void run (void* fixture) {
-                               if (this.is_async) {
-                                       try     {
-                                               assert( wait_for_async (async_timeout, this.async_begin, 
this.async_finish) );
-                                       }
-                                       catch (GLib.Error err) {
-                                               message(@"Got exception while excuting asynchronous test: 
$(err.message)");
-                                               GLib.Test.fail();
-                                       }
-                               } else {
-                                       this.test();
+                               catch (GLib.Error err) {
+                                       message(@"Got exception while excuting asynchronous test: 
$(err.message)");
+                                       GLib.Test.fail();
                                }
+                       } else {
+                               this.test();
                        }
+               }
 
 
-                       public void tear_down (void* fixture) {
-                               this.test_case.tear_down ();
-                       }
-                       
-                       public bool wait_for_async(int timeout, AsyncBegin async_function, AsyncFinish 
async_finish) throws GLib.Error {
-                               var loop = new MainLoop(MainContext.default(), true);
-                               AsyncResult? result = null;
-                               // Plan the async function
-                               async_function((o, r) => { result = r; loop.quit(); });
-                               // Plan timeout
-                               var t1 = Timeout.add(timeout, () => { loop.quit(); return false; });
-                               // Run the loop if it was not quit yet.
-                               if(loop.is_running())
-                                       loop.run();
-                               // Cancel timer
-                               Source.remove(t1);
-                               // Check the outcome
-                               if(result == null)
-                                       return false;
-                               async_finish(result);
-                               return true;
-                       }
+               public void tear_down (void* fixture) {
+                       this.test_case.tear_down ();
+               }
+               
+               public bool wait_for_async(int timeout, AsyncBegin async_function, AsyncFinish async_finish) 
throws GLib.Error {
+                       var loop = new MainLoop(MainContext.default(), true);
+                       AsyncResult? result = null;
+                       // Plan the async function
+                       async_function((o, r) => { result = r; loop.quit(); });
+                       // Plan timeout
+                       var t1 = Timeout.add(timeout, () => { loop.quit(); return false; });
+                       // Run the loop if it was not quit yet.
+                       if(loop.is_running())
+                               loop.run();
+                       // Cancel timer
+                       Source.remove(t1);
+                       // Check the outcome
+                       if(result == null)
+                               return false;
+                       async_finish(result);
+                       return true;
                }
        }
 }
diff --git a/valadate/testconfig.vala b/valadate/testconfig.vala
new file mode 100644
index 0000000..ed66d3d
--- /dev/null
+++ b/valadate/testconfig.vala
@@ -0,0 +1,191 @@
+/*
+ * Valadate - Unit testing library for GObject-based libraries.
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Authors:
+ *     Chris Daley <chebizarro gmail com>
+ */
+
+public class Valadate.TestConfig : Object {
+
+       public virtual signal void set_up() {}
+       public virtual signal void tear_up() {}
+
+       public static string seed;
+       public static string testplan;
+       public static string format = "tap";
+       public static bool fatal_warnings;
+       public static bool list;
+       public static bool quiet;
+       public static bool timed;
+       public static bool verbose;
+       public static bool version;
+       public static bool vala_version;
+
+       [CCode (array_length = false, array_null_terminated = true)]
+       public static string[] paths;
+       [CCode (array_length = false, array_null_terminated = true)]
+       public static string[] skip;
+       [CCode (array_length = false, array_null_terminated = true)]
+       public static string[] testplans;
+
+       public string binary {get;set;}
+
+       public TestResult result {get;set;}
+
+       public OptionContext opt_context;
+
+       private Vala.CodeContext context;
+       private Module module;
+
+
+       public const OptionEntry[] options = {
+               { "seed", 0, 0, OptionArg.STRING, ref seed, "Start tests with random seed", "SEEDSTRING" },
+               { "format", 'f', 0, OptionArg.STRING, ref format, "Output test results using format", 
"FORMAT" },
+               { "g-fatal-warnings", 0, 0, OptionArg.NONE, ref fatal_warnings, "Make all warnings fatal", 
null },
+               { "list", 'l', 0, OptionArg.NONE, ref list, "List test cases available in a test executable", 
null },
+               { "skip", 's', 0, OptionArg.STRING_ARRAY, ref skip, "Skip all tests matching", "TESTPATH..." 
},
+               { "quiet", 'q', 0, OptionArg.NONE, ref quiet, "Run tests quietly", null },
+               { "timed", 't', 0, OptionArg.NONE, ref timed, "Run timed tests", null },
+               { "testplan", 0, 0, OptionArg.STRING, ref testplan, "Run the specified TestPlan", "FILE" },
+               { "verbose", 0, 0, OptionArg.NONE, ref verbose, "Run tests verbosely", null },
+               { "version", 0, 0, OptionArg.NONE, ref version, "Display version number", null },
+               { "vala-version", 0, 0, OptionArg.NONE, ref vala_version, "Display Vala version number", null 
},
+               { "", 0, 0, OptionArg.STRING_ARRAY, ref paths, "Only start test cases matching", 
"TESTPATH..." },
+               { null }
+       };
+
+
+       public TestConfig() {
+               opt_context = new OptionContext ("- Valadate Testing Framework");
+               opt_context.set_help_enabled (true);
+               opt_context.add_main_entries (options, null);
+               setup_context();
+       }
+
+       private void setup_context() {
+               File currdir = File.new_for_path(GLib.Environment.get_current_dir());
+               File valadatedir = currdir.get_parent().get_child("valadate");
+               File vapidir = currdir.get_parent().get_child("vapi");
+
+
+               context = new Vala.CodeContext ();
+               Vala.CodeContext.push (context);
+               context.report.enable_warnings = false;
+               context.report.set_verbose_errors (false);
+               context.verbose_mode = false;
+               
+               context.vapi_directories = {valadatedir.get_path(), vapidir.get_path()};
+               
+               context.add_external_package ("glib-2.0");
+               context.add_external_package ("gobject-2.0");
+               context.add_external_package ("gio-2.0");
+               context.add_external_package ("gmodule-2.0");
+               context.add_external_package ("valadate");
+               
+       }
+
+       public int parse(string[] args) {
+               binary = args[0];
+               GLib.Environment.set_prgname(binary);
+
+               try {
+                       opt_context.parse (ref args);
+               } catch (OptionError e) {
+                       stdout.printf ("%s\n", e.message);
+                       stdout.printf ("Run '%s --help' to see a full list of available command line 
options.\n", args[0]);
+                       return 1;
+               }
+
+               if (version) {
+                       stdout.printf ("Valadate %s\n", "1.0");
+                       return 0;
+               } else if (vala_version) {
+                       stdout.printf ("Vala %s\n", Config.PACKAGE_SUFFIX.substring (1));
+                       return 0;
+               }
+               
+               if(seed == null)
+                       seed = "R02S%08x%08x%08x%08x".printf(
+                               GLib.Random.next_int(),
+                               GLib.Random.next_int(),
+                               GLib.Random.next_int(),
+                               GLib.Random.next_int());
+               
+               result = TestResultFactory.get_instance().new_for_type(format);
+               
+               try {
+                       load();
+               } catch (ConfigError e) {
+                       stdout.printf ("%s\n", e.message);
+                       return 1;
+               }
+
+               // We are just listing the tests in the binary
+               if(paths == null && TestConfig.list) {
+                       result.report();
+                       return 0;
+               }
+               
+               return -1;
+       }
+
+       private void load() throws ConfigError {
+               string testdir = Path.get_dirname(binary).replace(".libs", "");
+               
+               string testplan = Path.get_basename(binary);
+               if(testplan.has_prefix("lt-"))
+                       testplan = testplan.substring(3);
+               
+               string testplanfile = testdir + GLib.Path.DIR_SEPARATOR_S + testplan + ".vapi";
+               
+               if (!FileUtils.test (testplanfile, FileTest.EXISTS))
+                       throw new ConfigError.TESTPLAN("Test Plan %s Not Found!", testplanfile);
+               
+               try {
+                       module = new Module(binary);
+                       module.load_module();
+                       load_test_plan(testplanfile);
+               } catch (ModuleError e) {
+                       throw new ConfigError.MODULE(e.message);
+               }
+       }
+
+
+       internal void load_test_plan(string path) throws ConfigError {
+               
+               context.add_source_file (new Vala.SourceFile (context, Vala.SourceFileType.PACKAGE, path));
+               
+               var parser = new Vala.Parser ();
+               parser.parse (context);
+               
+               context.check ();
+               
+               if (context.report.get_errors () > 0)
+                       throw new ConfigError.TESTPLAN("Error parsing testplan %s", path);
+       
+               var testexplorer = new TestExplorer(module, result);
+               context.accept(testexplorer);
+               //_tests = testexplorer.get_tests();
+       }
+
+}
+
+public errordomain Valadate.ConfigError {
+       MODULE,
+       TESTPLAN
+}
diff --git a/valadate/testexplorer.vala b/valadate/testexplorer.vala
index 97e76a9..bb9bedd 100644
--- a/valadate/testexplorer.vala
+++ b/valadate/testexplorer.vala
@@ -1,6 +1,6 @@
 /*
  * Valadate - Unit testing library for GObject-based libraries.
- * Copyright (C) 20016  Chris Daley <chebizarro gmail com>
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,40 +20,49 @@
  *     Chris Daley <chebizarro gmail com>
  */
  
-namespace Valadate {
-       
-       internal class TestExplorer : Vala.CodeVisitor {
+internal class Valadate.TestExplorer : Vala.CodeVisitor {
                
-               private Vala.Class testcase;
-               private Test[] tests;
-               private TestCase current_test;
-               private weak Module module;
+       private Vala.Class testcase;
+       private Vala.Class testsuite;
+
+
+       private Test[] tests;
+       private TestCase current_test;
+       private weak Module module;
+       private weak TestResult result;
 
-               internal delegate void* Constructor(); 
-               internal delegate void TestMethod(TestCase self);
+       internal delegate void* Constructor(); 
+       internal delegate void TestMethod(TestCase self);
+       
+       public TestExplorer(Module module, TestResult result) {
+               this.module = module;
+               this.result = result;
+       }
+       
+       public Test[] get_tests() {
+               return tests;
+       }
+       
+       public override void visit_class(Vala.Class class) {
                
-               public TestExplorer(Module module) {
-                       this.module = module;
+               if (class.get_full_name() == "Valadate.TestCase") {
+                       testcase = class;
+                       return;
                }
-               
-               public Test[] get_tests() {
-                       return tests;
+
+               if (class.get_full_name() == "Valadate.TestSuite") {
+                       testsuite = class;
+                       return;
                }
-               
-               public override void visit_class(Vala.Class class) {
-                       
-                       if (class.get_full_name() == "Valadate.TestCase") {
-                               testcase = class;
-                               return;
-                       }
 
-                       if (testcase != null &&
-                               class.is_subtype_of(testcase) &&
-                               class.is_abstract != true ) {
+               if (testcase != null &&
+                       class.is_subtype_of(testcase) &&
+                       class.is_abstract != true ) {
 
-                               string cname = Vala.Symbol.camel_case_to_lower_case(
-                                       class.default_construction_method.get_full_name().replace(".","_"));
+                       string cname = Vala.Symbol.camel_case_to_lower_case(
+                               class.default_construction_method.get_full_name().replace(".","_"));
 
+                       try {
                                unowned Constructor meth = (Constructor)module.get_method(cname);
                                current_test = meth() as TestCase;
                                current_test.name = class.get_full_name().replace("."," ");
@@ -77,19 +86,18 @@ namespace Valadate {
                                                
                                        }
                                }
-
                                tests += current_test;
 
                                class.accept_children(this);
-
+                       } catch (ModuleError e) {
+                               stderr.puts(e.message);
                        }
                }
+       }
 
-               public override void visit_namespace(Vala.Namespace ns) {
-                       ns.accept_children(this);
-               }
-               
-               
+       public override void visit_namespace(Vala.Namespace ns) {
+               ns.accept_children(this);
        }
        
+       
 }
diff --git a/valadate/testfixture.vala b/valadate/testfixture.vala
index 6bcebd1..29b75ae 100644
--- a/valadate/testfixture.vala
+++ b/valadate/testfixture.vala
@@ -1,6 +1,6 @@
 /*
  * Valadate - Unit testing library for GObject-based libraries.
- * Copyright (C) 20016  Chris Daley <chebizarro gmail com>
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,14 +19,11 @@
  * Authors:
  *     Chris Daley <chebizarro gmail com>
  */
-namespace Valadate {
 
-    public interface TestFixture : Object {
+public interface Valadate.TestFixture : Object {
 
-               public abstract void set_up ();
+       public abstract void set_up ();
 
-               public abstract void tear_down ();
-
-    }
+       public abstract void tear_down ();
 
 }
diff --git a/valadate/testresult.vala b/valadate/testresult.vala
index e43c9fc..af377b2 100644
--- a/valadate/testresult.vala
+++ b/valadate/testresult.vala
@@ -1,6 +1,6 @@
 /*
  * Valadate - Unit testing library for GObject-based libraries.
- * Copyright (C) 20016  Chris Daley <chebizarro gmail com>
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,20 +19,18 @@
  * Authors:
  *     Chris Daley <chebizarro gmail com>
  */
-namespace Valadate {
+public interface Valadate.TestResult : Object {
 
-    public interface TestResult : Object {
+       public abstract int error_count {get;internal set;}
+       public abstract int failure_count {get;internal set;}
+       public abstract int run_count {get;internal set;}
 
-               public abstract int error_count {get;internal set;}
-               public abstract int failure_count {get;internal set;}
-               public abstract int run_count {get;internal set;}
+       public abstract void add_test(Test test);
 
-               public abstract void add_error(Test test);
+       public abstract void add_error(Test test);
 
-               public abstract void add_failure(Test test);
+       public abstract void add_failure(Test test);
 
-               public abstract void report();
-
-    }
+       public abstract void report();
 
 }
diff --git a/valadate/testresultfactory.vala b/valadate/testresultfactory.vala
new file mode 100644
index 0000000..9eaed52
--- /dev/null
+++ b/valadate/testresultfactory.vala
@@ -0,0 +1,59 @@
+/*
+ * Valadate - Unit testing library for GObject-based libraries.
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Authors:
+ *     Chris Daley <chebizarro gmail com>
+ */
+ 
+/**
+ * The TestResultFactory is a singleton Factory class
+ * for registered TestResult classes
+ */
+public class Valadate.TestResultFactory : Object {
+
+       private static TestResultFactory instance;
+
+       private HashTable<string, Type> result_types =
+               new HashTable<string, Type> (str_hash, str_equal);
+
+
+       private TestResultFactory() {
+               result_types.set("tap",typeof(TAPResult));
+       }
+       
+       public static TestResultFactory get_instance() {
+               if(instance == null)
+                       instance = new TestResultFactory();
+               return instance;
+       }
+
+       public void add_result_type(string type, Type class)
+               requires(class.is_a(typeof(TestResult)))
+       {
+               result_types.set(type, class);
+       }
+
+       public TestResult? new_for_type(string type) {
+               if(result_types.contains(type)) {
+                       Type t = result_types.get(type);
+                       return Object.new(t) as TestResult;
+               }
+               return null;
+       }
+
+}
diff --git a/valadate/testrunner.vala b/valadate/testrunner.vala
index 53f064c..63b1acc 100644
--- a/valadate/testrunner.vala
+++ b/valadate/testrunner.vala
@@ -1,6 +1,6 @@
 /*
  * Valadate - Unit testing library for GObject-based libraries.
- * Copyright (C) 20016  Chris Daley <chebizarro gmail com>
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,117 +20,53 @@
  *     Chris Daley <chebizarro gmail com>
  */
 
-namespace Valadate {
-
-       public errordomain RunError {
-               MODULE,
-               GIR,
-               TESTS,
-               METHOD
-       }
+public class Valadate.TestRunner : Object {
 
+       private TestConfig config;
 
-       public class TestRunner : Object {
-
-               private Vala.CodeContext context;
-               private Module module;
-               private string path;
-               private Test[] _tests;
-               
-               public Test[] tests {
-                       get {
-                               return _tests;
-                       }
-               }
-
-               public TestRunner(string path) {
-                       this.path = path;
-               }
-
-               public void load() throws RunError {
-                       string girdir = Path.get_dirname(path).replace(".libs", "");
-                       
-                       string girname = Path.get_basename(path);
-                       if(girname.has_prefix("lt-"))
-                               girname = girname.substring(3);
-                       
-                       string girfile = girdir + GLib.Path.DIR_SEPARATOR_S + girname + ".vapi";
-                       
-                       try {
-                               module = new Module(path);
-                               module.load_module();
-                               load_test_plan(girfile);
-
-                       } catch (Error e) {
-                               throw new RunError.MODULE(e.message);
-                       }
+       private string path;
+       private Test[] _tests;
+       
+       private TestResult result;
+       
+       public Test[] tests {
+               get {
+                       return _tests;
                }
+       }
 
-               internal void load_test_plan(string girpath) {
-                       if (!FileUtils.test (girpath, FileTest.EXISTS))
-                               return;
-                       
-                       context = new Vala.CodeContext ();
-                       Vala.CodeContext.push (context);
+       public TestRunner(TestConfig config) {
+               this.config = config;
+               this.path = config.binary;
+       }
 
-                       context.report.enable_warnings = false;
-                       context.report.set_verbose_errors (false);
-                       context.verbose_mode = false;
-                       
-                       File currdir = File.new_for_path(GLib.Environment.get_current_dir());
-                       File valadatedir = currdir.get_parent().get_child("valadate");
-                       File vapidir = currdir.get_parent().get_child("vapi");
-                       
-                       context.vapi_directories = {valadatedir.get_path(), vapidir.get_path()};
-                       
-                       context.add_external_package ("glib-2.0");
-                       context.add_external_package ("gobject-2.0");
-                       context.add_external_package ("gio-2.0");
-                       context.add_external_package ("gmodule-2.0");
-                       context.add_external_package ("valadate");
-                       
-                       context.add_source_file (new Vala.SourceFile (context, Vala.SourceFileType.PACKAGE, 
girpath));
-                       
-                       var parser = new Vala.Parser ();
-                       parser.parse (context);
-                       
-                       context.check ();
+       public TestResult? run(TestResult? result = null) throws ConfigError {
                
-                       var testexplorer = new TestExplorer(module);
-                       context.accept(testexplorer);
-                       _tests = testexplorer.get_tests();
-                       
-               }
-
-
-
-               public static int main (string[] args) {
-
-                       var runner = new TestRunner(args[0]);
+               
+               return result;
+       }
 
-                       GLib.Test.init(ref args);
 
-                       try {
-                               runner.load();
-                       } catch (RunError err) {
-                               message(err.message);
-                               return -1;
-                       }
+       public static int main (string[] args) {
 
-                       foreach (Test test in runner.tests)
-                               GLib.TestSuite.get_root().add_suite(((TestCase)test).suite);
+               var config = new TestConfig();
+               
+               int result = config.parse(args);
+               if(result >= 0)
+                       return result;
 
-                       GLib.Test.run ();
-                       
-                       runner = null;
-                       
-                       return 0;
-                       
+               var runner = new TestRunner(config);
+               
+               try {
+                       runner.run();
+               } catch (ConfigError err) {
+                       stderr.puts(err.message);
+                       return 1;
                }
+               
 
-       
+               return 0;
        }
 
 
-
 }
diff --git a/valadate/testsuite.vala b/valadate/testsuite.vala
new file mode 100644
index 0000000..ed4c684
--- /dev/null
+++ b/valadate/testsuite.vala
@@ -0,0 +1,30 @@
+/*
+ * Valadate - Unit testing library for GObject-based libraries.
+ * Copyright (C) 2016  Chris Daley <chebizarro gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Authors:
+ *     Chris Daley <chebizarro gmail com>
+ */
+
+public abstract class Valadate.TestSuite : CompositeTest {
+
+       public abstract void add_test (Test test);
+
+       public virtual Test[] tests {get;set;}
+
+
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]