1 /++
2   A module containing the process runner
3 
4   Copyright: © 2018 Szabo Bogdan
5   License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
6   Authors: Szabo Bogdan
7 +/
8 module trial.executor.process;
9 
10 import trial.reporters.visualtrial;
11 import trial.executor.single;
12 public import trial.interfaces;
13 
14 import std.process;
15 import std.path;
16 import std.file;
17 import std.datetime;
18 import std.conv;
19 import std.stdio;
20 
21 void testProcessRuner(string suiteName, string testName, VisualTrialReporterParser parser) {
22   TestResult testResult;
23 
24   auto command = [ thisExePath, 
25     "-s", suiteName,
26     "-t", testName,
27     "-r", "visualtrial",
28     "-e", "default" ];
29 
30   auto pipes = pipeProcess(command, Redirect.stdout | Redirect.stderrToStdout);
31 
32   foreach(line; pipes.stdout.byLine) {
33     parser.add(line.to!string);
34 
35     if(testResult is null && parser.testResult !is null) {
36       testResult = parser.testResult;
37     }
38   }
39 
40   auto code = wait(pipes.pid);
41 
42   if(testResult !is null && testResult.throwable is null && code != 0) {
43     testResult.throwable = new Exception("The process exited with code `" ~ code.to!string ~ "`", testResult.fileName, testResult.line);
44     testResult.status = TestResult.Status.failure;
45   }
46 }
47 
48 /// An executor that will run every test in a separate
49 /// process
50 class ProcessExecutor : DefaultExecutor {
51   alias runTest = DefaultExecutor.runTest;
52 
53   /// A function that should spawn a process that will run the test
54   alias TestProcessRun = void function(string suiteName, string testName, VisualTrialReporterParser parser);
55 
56   private {
57     TestProcessRun testProcessRun;
58     VisualTrialReporterParser parser;
59   }
60 
61   /// Instantiate the executor with a custom process runner
62   this(TestProcessRun testProcessRun) {
63     super();
64 
65     this.parser = new VisualTrialReporterParser();
66     this.parser.onOutput = &this.onOutput;
67     this.testProcessRun = testProcessRun;
68   }
69 
70   /// Instantiate the executor with a custom process runner
71   this() {
72     this(&testProcessRuner);
73   }
74 
75   void onOutput(string line) {
76     writeln(line);
77   }
78 
79   /// Run a test case
80   override
81   void runTest(ref const(TestCase) testCase, TestResult testResult) {
82     this.parser.testResult = testResult;
83     testProcessRun(testCase.suiteName, testCase.name, parser);
84   }
85 }