[vala/wip/valadate: 67/101] Now runs tests in separate processes, including DBus



commit a23242ecd03207cf84fa97e587c947a43325030b
Author: chebizarro gmail com <chebizarro gmail com>
Date:   Thu Jul 28 22:19:54 2016 -0700

    Now runs tests in separate processes, including DBus

 tests/Makefile.am               |    2 +-
 tests/valadatetests.vala        |   25 +++-
 tests/valatests.vala            |  348 ++++++++++++++++++++----------------
 valadate/Makefile.am            |    2 -
 valadate/compositetest.vala     |   39 ----
 valadate/tap.vala               |  379 ---------------------------------------
 valadate/tapresult.vala         |   39 ----
 valadate/testcase.vala          |   11 +-
 valadate/testconfig.vala        |    9 +-
 valadate/testexplorer.vala      |   11 +-
 valadate/testfailure.vala       |   33 ----
 valadate/testresult.vala        |  151 +++++++++-------
 valadate/testresultfactory.vala |   59 ------
 valadate/testrunner.vala        |   92 ++++++++--
 valadate/testsuite.vala         |    2 +
 15 files changed, 404 insertions(+), 798 deletions(-)
---
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0015acb..0bb1890 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,7 +1,7 @@
 include $(top_srcdir)/Makefile.common
 include $(top_srcdir)/build-aux/glib-tap.mk
 
-test_programs = valadatetests #valactests@PACKAGE_SUFFIX@
+test_programs = valadatetests valactests@PACKAGE_SUFFIX@
 
 # Valadate tests
 valadatetests_VALAFLAGS = \
diff --git a/tests/valadatetests.vala b/tests/valadatetests.vala
index abaa7bb..d301bdd 100644
--- a/tests/valadatetests.vala
+++ b/tests/valadatetests.vala
@@ -33,10 +33,13 @@ public class Valadate.Tests.TestFixture : Valadate.TestCase {
 
        public void test_testcase_1() {
                message("This is a test of the system");
+               //skip("Because it broke");
+               //fail("No particular reason");
        }
 
        public void test_testcase_2() {
                debug("This is a second test of the system");
+               message(Valadate.get_current_test_path());
                skip("No reason");
        }
 
@@ -44,7 +47,27 @@ public class Valadate.Tests.TestFixture : Valadate.TestCase {
                
                //stdout.puts("Before");
                //assert(false);
-               fail("after");
+               //fail("after");
+               
+               void* nullisland = null;
+               
+               Object nullobj = nullisland as Object;
+               
+               //nullobj.get_type().name();
+               
        }
        
 }
+
+public class Valadate.Tests.TestFixtureTwo : Valadate.TestCase {
+
+       public void test_testcase() {
+               
+               bug_base = "http://bugzilla.gnome.org/";;
+               
+               bug("555999");
+               
+               stdout.puts("This is a test of the system");
+       }
+
+}
diff --git a/tests/valatests.vala b/tests/valatests.vala
index 47edc27..021cfb2 100644
--- a/tests/valatests.vala
+++ b/tests/valatests.vala
@@ -1,34 +1,67 @@
-namespace Vala.Tests {
+/**
+ * Vala.Tests
+ * 
+ * Searchs all of the sub directories in the current directory for
+ * *.vala or *.test files, compiles and runs them.
+ * 
+ * If the test is a self contained application (has its own main entry
+ * point), it will compile and run it. The test is deemed succesful if
+ * it compiles and runs without error.
+ * 
+ * If the test is a collection of {@ref Valadate.TestCase}s then it
+ * compiles the test and runs it. The test results will be appeneded to
+ * the TestFixture's. Not yet implemented.
+ * 
+ * If the test is a .test file it will be parsed, the components
+ * assembled, compiled and run.  The test is deemed succesful if
+ * it compiles and runs without error.
+ * 
+ * The tests can be run against the system compiler or the one in the
+ * source tree. This can be used to verify if a patch or other change
+ * to the compiler either fixes a bug or causes a regression (or both)
+ */
+
+public class Vala.Tests : Valadate.TestSuite {
        
-       /**
-        * Vala.Tests.Fixture
-        * 
-        * Searchs all of the sub directories in the current directory for
-        * *.vala or *.test files, compiles and runs them.
-        * 
-        * If the test is a self contained application (has its own main entry
-        * point), it will compile and run it. The test is deemed succesful if
-        * it compiles and runs without error.
-        * 
-        * If the test is a collection of {@ref Valadate.TestCase}s then it
-        * compiles the test and runs it. The test results will be appeneded to
-        * the TestFixture's. Not yet implemented.
-        * 
-        * If the test is a .test file it will be parsed, the components
-        * assembled, compiled and run.  The test is deemed succesful if
-        * it compiles and runs without error.
-        * 
-        * The tests can be run against the system compiler or the one in the
-        * source tree. This can be used to verify if a patch or other change
-        * to the compiler either fixes a bug or causes a regression (or both)
-        */
-       
-       public class Fixture : Valadate.TestCase {
-               
-               private delegate void CommandCallback(Subprocess process, size_t err, string buffer);
+       public Tests() {
+               load_tests();
+       }
+
+       private void load_tests() {
+               try {
+                       var testdir = File.new_for_path(GLib.Environment.get_current_dir());
+                       var testpath = Valadate.get_current_test_path();
+                       
+                       if (testpath != null) {
+                               var testpaths = testpath.split("/");
+                               if (testpaths.length < 4)
+                                       return;
+                               var runtest = testdir.get_child(testpaths[3]);
+                               if(runtest.query_exists())
+                                       add_test(new ValaTest(runtest));
+                       } else {
+                               var tempdir = testdir.get_child(".tests");
+                               if(!tempdir.query_exists())
+                                       tempdir.make_directory();
+
+                               var enumerator = testdir.enumerate_children (FileAttribute.STANDARD_NAME, 0);
+                               FileInfo file_info;
+                               while ((file_info = enumerator.next_file ()) != null)
+                                       if (file_info.get_file_type() == GLib.FileType.DIRECTORY &&
+                                               !file_info.get_name().has_prefix("."))
+                                               add_test(new 
ValaTest(testdir.get_child(file_info.get_name())));
+                       }
+               } catch (Error e) {
+                       stderr.printf ("Error: %s\n", e.message);
+               }
+       }
+
+
+       private class ValaTest : Valadate.TestCase {
+
+               private delegate void CommandCallback(bool err, string buffer);
                
-               private SubprocessLauncher launcher =
-                       new SubprocessLauncher(GLib.SubprocessFlags.STDOUT_PIPE | 
GLib.SubprocessFlags.STDERR_PIPE);
+               private static SubprocessLauncher launcher;
                
                private const string VALA_FLAGS =
                        """--main main --save-temps --disable-warnings --pkg gio-2.0 
@@ -60,148 +93,139 @@ namespace Vala.Tests {
                                </repository>""";
 
                private const string BUGZILLA_URL = "http://bugzilla.gnome.org/";;
-
-               private File testdir;
-               private File buildir;
-               private File vapidir;
-               private File valadatedir;
-               private File valac;
-               private File vapigen;
-               private File tempdir;
-
-               private string vapidirs;
-
-               public Fixture() {
-                       load_tests();
+               
+               private static File testdir;
+               private static File tempdir;
+               private static File buildir;
+               private static File vapidir;
+               private static File valadatedir;
+               private static File valac;
+               private static File vapigen;
+               private static string vapidirs;
+
+               private File[] testfiles = {};
+
+               class construct {
+                       testdir = File.new_for_path(GLib.Environment.get_current_dir());
+                       tempdir = testdir.get_child(".tests");
+                       buildir = testdir.get_parent();
+                       vapidir = buildir.get_child("vapi");
+                       valadatedir = buildir.get_child("valadate");
+                       valac = buildir.get_child("compiler").get_child("valac");
+                       vapigen = buildir.get_child("vapigen").get_child("vapigen");
+                       vapidirs = "--vapidir %s".printf(vapidir.get_path());
+                       launcher = new SubprocessLauncher(GLib.SubprocessFlags.STDOUT_PIPE | 
GLib.SubprocessFlags.STDERR_MERGE);
+                       launcher.set_cwd(tempdir.get_path());
                }
 
-               ~Fixture() {
-                       delete_tempdir();
+               
+               public override void tear_down() {
+                       foreach(var file in testfiles)
+                               if(file.query_exists())
+                                       file.delete();
                }
-
-               private void load_tests() {
-                       try {
-                               testdir = File.new_for_path(GLib.Environment.get_current_dir());
-                               buildir = testdir.get_parent();
-                               vapidir = buildir.get_child("vapi");
-                               valadatedir = buildir.get_child("valadate");
-                               valac = buildir.get_child("compiler").get_child("valac");
-                               vapigen = buildir.get_child("vapigen").get_child("vapigen");
-                               tempdir = testdir.get_child(".tests");
-                               delete_tempdir();
-                               tempdir.make_directory();
-
-                               vapidirs = "--vapidir %s".printf(vapidir.get_path());
-
-                               launcher.set_cwd(tempdir.get_path());
-
-                               var enumerator = testdir.enumerate_children (FileAttribute.STANDARD_NAME, 0);
+               
+               public ValaTest(File directory) throws Error {
+                       this.name = directory.get_basename();
+                       this.bug_base = BUGZILLA_URL;
+                       
+                       string current_test = Valadate.get_current_test_path();
+
+                       if(current_test != null) {
+                               var basename = Path.get_basename(current_test);
+                               if (directory.get_child(basename + ".vala").query_exists())
+                                       load_test(directory.get_child(basename + ".vala"));
+                               else if (directory.get_child(basename + ".gs").query_exists())
+                                       load_test(directory.get_child(basename + ".gs"));
+                               else if (directory.get_child(basename + ".test").query_exists())
+                                       load_test(directory.get_child(basename + ".test"));
+                       } else {
+                               var enumerator = directory.enumerate_children (FileAttribute.STANDARD_NAME, 
0);
                                FileInfo file_info;
                                while ((file_info = enumerator.next_file ()) != null) {
-                                       if (file_info.get_file_type() == GLib.FileType.DIRECTORY) {
-                                               var subdir = testdir.get_child(file_info.get_name());
-                                               load_tests_from_dir(subdir);
-                                       }
-                               }
-                       } catch (Error e) {
-                               stderr.printf ("Error: %s\n", e.message);
-                       }
-               }
+                                       if (file_info.get_file_type() == GLib.FileType.DIRECTORY)
+                                               continue;
 
-               private void delete_tempdir() throws Error {
-                       if (tempdir == null || !tempdir.query_exists())
-                               return;
-                               
-                       var enumerator = tempdir.enumerate_children (FileAttribute.STANDARD_NAME, 0);
-                       FileInfo file_info;
-                       while ((file_info = enumerator.next_file ()) != null) {
-                               if (file_info.get_file_type() == GLib.FileType.REGULAR) {
-                                       var file = tempdir.get_child(file_info.get_name());
-                                       file.delete();
+                                       string fname = file_info.get_name();
+
+                                       load_test(directory.get_child(fname));
                                }
                        }
-                       tempdir.delete();
                }
 
-               private void load_tests_from_dir(File directory) throws Error {
-                       var enumerator = directory.enumerate_children (FileAttribute.STANDARD_NAME, 0);
-                       FileInfo file_info;
-                       while ((file_info = enumerator.next_file ()) != null) {
-                               string fname = file_info.get_name();
-
-                               if (file_info.get_file_type() == GLib.FileType.DIRECTORY) {
-                                       load_tests_from_dir(directory.get_child(fname));
-                                       continue;
-                               }
+               private void load_test(File testfile) throws Error {
+                       string testname = testfile.get_basename().substring(
+                               0,testfile.get_basename().last_index_of("."));
 
-                               File testfile = directory.get_child(fname);
-                               string testname = testfile.get_basename().substring(
-                                       0,testfile.get_basename().last_index_of("."));
+                       string fname = testfile.get_basename();
 
-                               if(fname.has_suffix(".vala") || fname.has_suffix(".gs")) {
+                       if(fname.has_suffix(".vala") || fname.has_suffix(".gs")) {
+                               
+                               add_test(testname,
+                                ()=> {
                                        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,
+                                       string command = "%s %s %s -o %s %s".printf(
+                                               valac.get_path(), vapidirs, VALA_FLAGS,
                                                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));
-                                                       else
-                                                               Test.fail();
-                                               } catch (Error e) {
-                                                       Test.fail();
-                                                       stdout.printf ("%s", e.message);
-                                               }});
-                                       continue;
-                               }
-                               
-                               if(fname.has_suffix(".test")) {
-                                       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();
-                                                       stdout.printf ("%s", e.message);
-                                               }});
-                               }
+                                       try {
+                                               if(binary.has_prefix("bug")) {
+                                                       bug_base = BUGZILLA_URL;                              
                  
+                                                       bug(binary.substring(3));
+                                               }
+                                               run_command(command);
+                                               
+                                               testfiles += tempdir.get_child(binary);
+                                               testfiles += tempdir.get_child(binary + ".c");
+                                               
+                                               if(tempdir.get_child(binary).query_exists())
+                                                       run_command("./%s".printf(binary));
+                                               else
+                                                       fail("Binary not generated");
+                                       } catch (Error e) {
+                                               fail(e.message);
+                                               stdout.printf ("%s", e.message);
+                                       }});
+                       }
+                       
+                       if(fname.has_suffix(".test")) {
+                               add_test(testname,
+                                ()=> {
+                                       try {
+                                               if(fname.has_prefix("bug")) {
+                                                       bug(fname.substring(3,fname.length-8));
+                                               }
+                                               parse_test(testfile);
+                                       } catch (Error e) {
+                                               fail(e.message);
+                                               stdout.printf ("%s", e.message);
+                                       }});
                        }
                }
 
-               private void default_callback(Subprocess process, size_t err, string buffer) {
-                       if (err > 0) {
-                               //Test.skip(buffer);
+               private void default_callback(bool err, string buffer) {
+                       if (err) {
+                               fail(buffer);
+                       } else {
                                stdout.printf ("%s", buffer);
-                               Test.fail();
-                               process.force_exit();
                        }
                }
 
                private void run_command(string command, CommandCallback callback = default_callback) throws 
Error {
                        string[] args;
                        Shell.parse_argv(command, out args);
-
+                       string buffer = null;
                        var process = launcher.spawnv(args);
-                       var stderr_pipe = process.get_stderr_pipe();
 
-                       uint8 buffer[1028];
-                       var err = stderr_pipe.read(buffer);
-                       
-                       callback(process, err, (string)buffer);
+                       process.communicate_utf8(null, null, out buffer, null);
 
+                       try {
+                               if(process.wait_check())
+                                       callback(false, buffer);
+                       } catch (Error e) {
+                               callback(true, buffer);
+                       }
                }
 
                private void parse_test(File testfile) throws Error {
@@ -223,10 +247,12 @@ namespace Vala.Tests {
                                
                                case "D-Bus":
                                        var clientfile = tempdir.get_child(testname + ".client.vala");
+                                       testfiles += clientfile;
                                        var serverfile = tempdir.get_child(testname + ".server.vala");
-                                       var client = clientfile.create(FileCreateFlags.NONE);
+                                       testfiles += serverfile;
+                                       var client = clientfile.create(FileCreateFlags.REPLACE_DESTINATION);
                                        var client_stream = new DataOutputStream (client);
-                                       var server = serverfile.create(FileCreateFlags.NONE);
+                                       var server = serverfile.create(FileCreateFlags.REPLACE_DESTINATION);
                                        var server_stream = new DataOutputStream (server);
                                        
                                        do {} while ((line = stream.read_line (null)) != "Program: client");
@@ -254,9 +280,21 @@ namespace Vala.Tests {
                                        string binary = serverfile.get_basename().substring(
                                                0,serverfile.get_basename().last_index_of("."));
 
-                                       command = "./" + binary;
+                                       testfiles += tempdir.get_child(binary);
+                                       testfiles += tempdir.get_child(binary + ".c");
+                                       testfiles += tempdir.get_child(testname + ".client");
+                                       testfiles += tempdir.get_child(testname + ".client.c");
 
-                                       run_command(command);
+                                       command = "./" + binary;
+                                       
+                                       Bus.watch_name(
+                                               BusType.SESSION,
+                                               "org.example.Test",
+                                               GLib.BusNameWatcherFlags.NONE,
+                                               null,
+                                               (c,n) => {
+                                                       run_command(command);
+                                               });
 
                                        break;
 
@@ -289,7 +327,8 @@ namespace Vala.Tests {
                                        vapi += "\n}\n";
 
                                        var girfile = tempdir.get_child(testname + ".gir");
-                                       var girstream = girfile.create(FileCreateFlags.NONE);
+                                       testfiles += girfile;
+                                       var girstream = girfile.create(FileCreateFlags.REPLACE_DESTINATION);
                                        girstream.write(GIRHEADER.printf(gir).data);
 
                                        string command = "%s %s %s --library %s %s".printf(
@@ -303,17 +342,19 @@ namespace Vala.Tests {
 
                                        uint8[] contents;
                                        File file = tempdir.get_child(testname+".vapi");
+                                       testfiles += file;
                                        file.load_contents (null, out contents, null);
 
                                        if(strcmp(vapi, (string)contents) != 0)
-                                               Test.fail();
+                                               fail((string)contents);
                                
                                        break;
 
                                case "Invalid Code":
                                        
                                        var invalidfile = tempdir.get_child(testname + ".vala");
-                                       var invalid_stream = new DataOutputStream 
(invalidfile.create(FileCreateFlags.NONE));
+                                       testfiles += invalidfile;
+                                       var invalid_stream = new DataOutputStream 
(invalidfile.create(FileCreateFlags.REPLACE_DESTINATION));
 
                                        while ((line = stream.read_line (null)) != null) {
                                                invalid_stream.put_string(line + "\n");
@@ -325,16 +366,16 @@ namespace Vala.Tests {
                                                VALA_FLAGS,
                                                invalidfile.get_path());
 
-                                       run_command(command, (p,e,b) => {
-                                               if (e <= 0)
-                                                       Test.fail();
+                                       run_command(command, (e,b) => {
+                                               if (!e)
+                                                       fail(b);
                                        });
                                        break;
 
                                case "TestCase":
                                        
                                        var testcasefile = tempdir.get_child(testname + ".vala");
-                                       var testcase = testcasefile.create(FileCreateFlags.NONE);
+                                       var testcase = 
testcasefile.create(FileCreateFlags.REPLACE_DESTINATION);
                                        var testcase_stream = new DataOutputStream (testcase);
 
                                        testcase_stream.put_string("namespace Vala.Tests {\n");
@@ -368,5 +409,4 @@ namespace Vala.Tests {
                        }
                }
        }
-       
 }
diff --git a/valadate/Makefile.am b/valadate/Makefile.am
index 4b084d0..58393ef 100644
--- a/valadate/Makefile.am
+++ b/valadate/Makefile.am
@@ -8,14 +8,12 @@ lib_LTLIBRARIES = \
 libvaladate_la_SOURCES = \
        assembly.vala \
        module.vala \
-       tap.vala \
        test.vala \
        testcase.vala \
        testconfig.vala \
        testexplorer.vala \
        testfixture.vala \
        testresult.vala \
-       testfailure.vala \
        testrunner.vala \
        testsuite.vala \
        $(NULL)
diff --git a/valadate/testcase.vala b/valadate/testcase.vala
index 121f0d7..44286f6 100644
--- a/valadate/testcase.vala
+++ b/valadate/testcase.vala
@@ -84,16 +84,17 @@ public abstract class Valadate.TestCase : Object, Test, TestFixture {
        public void bug(string reference)
                requires(bug_base != null)
        {
-               stdout.printf("MSG: Bug Reference: %s%s\n",bug_base, reference);
-               
+               stdout.printf("MSG: Bug Reference: %s%s",bug_base, reference);
+               stdout.flush();
        }
 
        public void skip(string message) {
-               stdout.printf("SKIP Skipping Test %s\n", message);
+               stderr.printf("SKIP %s", message);
+               stdout.flush();
        }
 
-       public void fail(string message) {
-               error("FAIL Test %s\n", message);
+       public void fail(string? message = null) {
+               error("FAIL %s", message ?? "");
        }
 
        public virtual void set_up() {}
diff --git a/valadate/testconfig.vala b/valadate/testconfig.vala
index 6fcfaab..d61ac7e 100644
--- a/valadate/testconfig.vala
+++ b/valadate/testconfig.vala
@@ -19,15 +19,20 @@
  * Authors:
  *     Chris Daley <chebizarro gmail com>
  */
+namespace Valadate {
+       public static string? get_current_test_path() {
+               return TestConfig._runtest;
+       }
+}
 
 public class Valadate.TestConfig : Object {
 
        private static string _seed;
        private static string testplan;
-       private static string _runtest;
+       internal static string _runtest;
        private static string format = "tap";
        private static bool list;
-       private static bool _keepgoing;
+       private static bool _keepgoing = true;
        private static bool quiet;
        private static bool timed;
        private static bool verbose;
diff --git a/valadate/testexplorer.vala b/valadate/testexplorer.vala
index fd34840..21d6d75 100644
--- a/valadate/testexplorer.vala
+++ b/valadate/testexplorer.vala
@@ -25,7 +25,7 @@ internal class Valadate.TestExplorer : Vala.CodeVisitor {
        private TestConfig config;
        private TestSuite current;
 
-       internal delegate void* Constructor(string? name = null); 
+       internal delegate void* Constructor(); 
        internal delegate void TestMethod(TestCase self);
        
        public TestExplorer(TestConfig config) {
@@ -48,9 +48,7 @@ internal class Valadate.TestExplorer : Vala.CodeVisitor {
                } catch (ModuleError e) {
                        error(e.message);
                }
-
                class.accept_children(this);
-
        }
 
        private bool is_subtype_of(Vala.Class class, string typename) {
@@ -81,7 +79,6 @@ internal class Valadate.TestExplorer : Vala.CodeVisitor {
                                        config.runtest != "/" + method.get_full_name().replace(".","/"))
                                        continue;
 
-
                                unowned TestMethod testmethod = null;
                                var attr = new Vala.CCodeAttribute(method);
                                testmethod = (TestMethod)config.module.get_method(attr.name);
@@ -99,8 +96,10 @@ internal class Valadate.TestExplorer : Vala.CodeVisitor {
 
        public TestSuite visit_testsuite(Vala.Class testclass) throws ModuleError {
                unowned Constructor meth = get_constructor(testclass); 
-               var current_test = meth(testclass.name) as TestSuite;
-               current_test.name = testclass.get_full_name();
+               var current_test = meth() as TestSuite;
+               current_test.name = testclass.name;
+               foreach(var test in current_test)
+                       config.test_count += test.count;
                return current_test;
        }
 
diff --git a/valadate/testresult.vala b/valadate/testresult.vala
index f083816..3e3b62f 100644
--- a/valadate/testresult.vala
+++ b/valadate/testresult.vala
@@ -25,40 +25,33 @@ public class Valadate.TestResult : Object {
                NOT_RUN,
                RUNNING,
                PASSED,
+               SKIPPED,
+               ERROR,
                FAILED
        }
-
-       public signal void test_error(Test test, string error);
-       public signal void test_failure(Test test, string error);
-       public signal void test_complete(Test test);
-       public signal void test_start(Test test);
-       
-       /*internal List<TestFailure> errors = new List<TestFailure>();
-       internal List<TestFailure> failures = new List<TestFailure>();
-
-       public bool should_stop {get;set;default=false;}
        
-       
-       public int error_count {
-               get {
-                       return (int)errors.length();
-               }
-       }
+       private class TestReport {
 
-       public int failure_count {
-               get {
-                       return (int)failures.length();
+               public signal void report(TestStatus status);
+               
+               public Test test {get;set;}
+               
+               public TestStatus status {get;set;}
+               
+               public int index {get;set;}
+               
+               public string message {get;set;}
+               
+               public TestReport(Test test, TestStatus status, int index, string? message = null) {
+                       this.test = test;
+                       this.status = status;
+                       this.index = index;
+                       this.message = message;
                }
        }
 
-       public int run_count {get;private set;default=0;}
-       
-       public bool success {
-               get {
-                       return (failure_count == 0 && error_count == 0);
-               }
-       }
-       */
+       private Queue<TestReport> reports = new Queue<TestReport>();
+       private HashTable<Test, TestReport> tests = new HashTable<Test, TestReport>(direct_hash, 
direct_equal);
        
        public string binary {
                get {
@@ -68,61 +61,81 @@ public class Valadate.TestResult : Object {
        
        private TestConfig config;
        private TestRunner runner;
+       private MainLoop loop;
 
-       /*
-       private HashTable<Test, TestRecord> _tests = new HashTable<Test, TestRecord>(direct_hash, 
direct_equal);
-
-       private class TestRecord : Object {
-               
-               public string path {get;set;}
-               public int index {get;set;}
-               public TestStatus status {get;set;}
-               
-               public TestRecord(string path, int index, TestStatus status) {
-                       this.path = path;
-                       this.index = index;
-                       this.status = status;
-               }
-               
-       }*/
-       
-       
        public TestResult(TestConfig config) {
                this.config = config;
        }
        
+       public void report() {
+               if (reports.is_empty()) {
+                       loop.quit();
+                       return;
+               }
+               var rpt = reports.peek_head();
+
+               if (rpt.status == TestStatus.PASSED ||
+                       rpt.status == TestStatus.SKIPPED ||
+                       rpt.status == TestStatus.FAILED ||
+                       rpt.status == TestStatus.ERROR) {
+                       if (rpt.message != null)
+                               stdout.puts(rpt.message);
+                       stdout.flush();
+                       rpt.report(rpt.status);
+                       reports.pop_head();
+                       report();
+               }
+       }
+       
        public void add_error(Test test, string error) {
-               stdout.printf("%s\n", error);
-               stdout.printf("not ok %d %s\n", testno, test.name);
-               //errors.append(new TestFailure(test, error));
-               //test_error(test, error);
+               update_test(test, TestStatus.ERROR,"# %s\nnot ok %s %s\n".printf(error, "%d", test.name));
        }
 
        public void add_failure(Test test, string failure) {
-               stdout.printf("%s\n", failure);
-               stdout.printf("not ok %d %s\n", testno, test.name);
-               //failures.append(new TestFailure(test, failure));
-               //test_failure(test, failure);
+               update_test(test, TestStatus.FAILED,"# %s\nnot ok %s %s\n".printf(failure, "%d", test.name));
        }
 
        public void add_success(Test test, string message) {
-               stdout.printf("%s\n", message);
-               stdout.printf("ok %d %s\n", testno, test.name);
-               //failures.append(new TestFailure(test, failure));
-               //test_failure(test, failure);
+               update_test(test, TestStatus.PASSED,"# %s\nok %s %s\n".printf(message, "%d", test.name));
+       }
+       
+       public void add_skip(Test test, string reason, string message) {
+               update_test(test, TestStatus.SKIPPED,"# %s\nok %s %s # %s\n".printf(message, "%d", test.name, 
reason));
        }
 
+       private void update_test(Test test, TestStatus status, string message) {
+               var rept = tests.get(test);
+               rept.status = status;
+               rept.message = message.printf(rept.index);
+       }
        
        /**
-        * Runs a {@link Valadate.Test}
+        * Runs a the {@link Valadate.Test}s using the supplied
+        * {@link Valadate.TestRunner}.
+        * 
+        * @param runner
         */
        public void run(TestRunner runner) {
+
                this.runner = runner;
+
                if (!config.list_only && config.runtest == null) {
                        stdout.printf("# random seed: %s\n", config.seed);
                        stdout.printf("1..%d\n", config.test_count);
                }
+
                run_test(config.root, "");
+
+               if (config.runtest == null) {
+                       loop = new MainLoop();
+                       var time = new TimeoutSource (5);
+                       time.set_callback (() => {
+                               report();
+                               return true;
+                       });
+                       time.attach (loop.get_context ());
+                       loop.run();
+               }
        }
 
        private int testno = 0;
@@ -131,13 +144,20 @@ public class Valadate.TestResult : Object {
                foreach(var subtest in test) {
                        string testpath = "%s/%s".printf(path, subtest.name);
                        if(subtest is TestCase) {
-                               if(config.runtest == null)
-                                       stdout.printf("# Start of %s tests\n", testpath);
-                               run_test(subtest, testpath);
-                               if(config.runtest == null)
-                                       stdout.printf("# End of %s tests\n", testpath);
+                               if(config.runtest == null) {
+                                       reports.push_tail(new TestReport(subtest, TestStatus.PASSED,-1,"# 
Start of %s tests\n".printf(testpath)));
+                                       run_test(subtest, testpath);
+                                       reports.push_tail(new TestReport(subtest, TestStatus.PASSED,-1,"# End 
of %s tests\n".printf(testpath)));
+                               } else {
+                                       run_test(subtest, testpath);
+                               }
                        } else if (subtest is TestSuite) {
                                run_test(subtest, testpath);
+                               if(config.runtest == null) {
+                                       var rpt = new TestReport(subtest, TestStatus.PASSED,-1);
+                                       rpt.report.connect((s)=> ((TestSuite)subtest).tear_down());
+                                       reports.push_tail(rpt);
+                               }
                        } else if (config.list_only) {
                                stdout.printf("%s\n", testpath);
                        } else if (config.runtest != null) {
@@ -146,7 +166,10 @@ public class Valadate.TestResult : Object {
                        } else {
                                testno++;
                                subtest.name = testpath;
-                               runner.run(subtest, this);
+                               var rept = new TestReport(subtest, TestStatus.RUNNING, testno);
+                               reports.push_tail(rept);
+                               tests.insert(subtest, rept);
+                               runner.run.begin(subtest, this);
                        }
                }
        }
diff --git a/valadate/testrunner.vala b/valadate/testrunner.vala
index 25b9947..8ff5363 100644
--- a/valadate/testrunner.vala
+++ b/valadate/testrunner.vala
@@ -22,9 +22,19 @@
 
 public class Valadate.TestRunner : Object {
 
+       private uint _n_ongoing_tests = 0;
+       private Queue<DelegateWrapper> _pending_tests = new Queue<DelegateWrapper> ();
+
+       /* Change this to change the cap on the number of concurrent operations. */
+       private const uint _max_n_ongoing_tests = 15;
+
+       private class DelegateWrapper {
+               public SourceFunc cb;
+       }
+
        private SubprocessLauncher launcher =
                new SubprocessLauncher(GLib.SubprocessFlags.STDOUT_PIPE | GLib.SubprocessFlags.STDERR_MERGE);
-       
+
        private string binary;
        
        public TestRunner(string binary) {
@@ -32,39 +42,93 @@ public class Valadate.TestRunner : Object {
                this.launcher.setenv("G_MESSAGES_DEBUG","all", true);
                this.launcher.setenv("G_DEBUG","fatal-criticals fatal-warnings gc-friendly", true);
                this.launcher.setenv("G_SLICE","always-malloc debug-blocks", true);
+               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 void run_test(Test test, TestResult result) {
                test.run(result);
        }
 
-       public void run(Test test, TestResult result) {
+       public async void run(Test test, TestResult result) {
                
                string command = "%s -r %s".printf(binary, test.name);
-
                string[] args;
-
                string buffer = null;
-               
+
+               if (_n_ongoing_tests > _max_n_ongoing_tests) {
+                       var wrapper = new DelegateWrapper();
+                       wrapper.cb = run.callback;
+                       _pending_tests.push_tail((owned)wrapper);
+                       yield;
+               }
+       
                try {
+                       _n_ongoing_tests++;
+                       
                        Shell.parse_argv(command, out args);
-
                        var process = launcher.spawnv(args);
-                       process.communicate_utf8(null, null, out buffer, null);
+                       yield process.communicate_utf8_async(null, null, out buffer, null);
                        
-                       if(process.wait_check()) {
-                               result.add_success(test, buffer);
-                       }
+                       if(process.wait_check())
+                               process_buffer(test, result, buffer);
+
                } catch (Error e) {
-                       result.add_error(test, buffer);
+                       process_buffer(test, result, buffer, true);
+               } finally {
+                       _n_ongoing_tests--;
+                       var wrapper = _pending_tests.pop_head ();
+                       if(wrapper != null)
+                               wrapper.cb();
                }
-               
-
        }
 
+       public void process_buffer(Test test, TestResult result, string buffer, bool failed = false) {
+               string skip = null;
+               string[] message = {};
+               
+               foreach(string line in buffer.split("\n"))
+                       if (line.has_prefix("SKIP "))
+                               skip = line;
+                       else
+                               message += line;
+               
+               if (skip != null)
+                       result.add_skip(test, skip, string.joinv("\n",message));
+               else
+                       if(failed)
+                               result.add_failure(test, string.joinv("\n",message));
+                       else
+                               result.add_success(test, string.joinv("\n",message));
+       }
 
        public static int main (string[] args) {
-
                var config = new TestConfig();
                
                int result = config.parse(args);
diff --git a/valadate/testsuite.vala b/valadate/testsuite.vala
index 37ca8b9..0c47872 100644
--- a/valadate/testsuite.vala
+++ b/valadate/testsuite.vala
@@ -73,5 +73,7 @@ public class Valadate.TestSuite : Object, Test {
                return _tests.nth_data((uint)index);
        }
 
+       public virtual void set_up() {}
+       public virtual void tear_down() {}
        
 }


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