3 using System.Diagnostics;
4 using System.Collections;
6 using System.Text.RegularExpressions;
8 namespace JSTestRunner {
12 public string preamble;
13 public string test_file;
14 public string fail_file;
16 public string test_dir;
17 public string compile_cmd;
18 public string compile_args;
19 public string run_cmd;
20 public string run_args;
24 static string preamble;
25 static string [] fail_tests;
26 static string [] tests;
28 static void Main (string [] args)
33 // Can specify test to run as first argument
34 if (args.Length == 1) {
35 string arg = args [0];
37 if (arg == "--full-run" || arg == "-f")
38 config.full_run = true;
40 tests = new string [] { args [0] };
43 foreach (string test in tests) {
44 if (File.Exists (test))
47 Console.WriteLine ("WARNING: Test `{0}' doesn't exist.", test);
51 static void LoadConfig ()
53 IDictionary env = Environment.GetEnvironmentVariables ();
54 config = new Config ();
55 config.is_win32 = Environment.OSVersion.ToString ().IndexOf ("Windows") != -1;
57 config.preamble = env ["MJS_TEST_PREAMBLE"] as string;
58 if (config.preamble == null)
59 config.preamble = "mjs.preamble";
61 config.test_file = env ["MJS_TEST_FILE"] as string;
62 if (config.test_file == null)
63 config.test_file = "mjs-most.tests";
65 config.fail_file = env ["MJS_FAIL_FILE"] as string;
66 if (config.fail_file == null)
67 config.fail_file = "mjs-most.fail";
69 config.full_run = false;
70 config.test_dir = env ["MJS_TEST_DIR"] as string;
71 if (config.test_dir == null)
72 config.test_dir = config.is_win32 ? env ["TEMP"] as string : ".";
74 config.compile_cmd = env ["MJS_COMPILE_CMD"] as string;
75 if (config.compile_cmd == null)
76 config.compile_cmd = config.is_win32 ? "bash" : "mjs";
78 string compile_str = env ["MJS_COMPILE_ARGS"] as string;
79 if (compile_str == null)
80 compile_str = config.is_win32 ? "mjs {0}" : "{0}";
81 config.compile_args = String.Format (compile_str, "jstest.js");
83 config.run_cmd = env ["MJS_RUN_CMD"] as string;
84 if (config.run_cmd == null)
85 config.run_cmd = "mono";
87 string run_str = env ["MJS_RUN_ARGS"] as string;
90 config.run_args = String.Format (run_str, "jstest.exe");
93 static void ReadFiles ()
95 StreamReader preamble_io = File.OpenText (config.preamble);
97 preamble = preamble_io.ReadToEnd ();
102 StreamReader fail_io = File.OpenText (config.fail_file);
104 fail_tests = FilterTextToLines (fail_io.ReadToEnd ());
109 StreamReader test_io = File.OpenText (config.test_file);
111 tests = FilterTextToLines (test_io.ReadToEnd ());
117 // Filters whitespace and comment lines
118 static string [] FilterTextToLines (string text)
120 ArrayList result = new ArrayList ();
121 foreach (string line in Regex.Split (text, @"\r?\n")) {
122 string t_line = line.Trim ();
123 if ((t_line != "") && (t_line [0] != '#'))
126 return (string []) result.ToArray (typeof (string));
130 public StringBuilder eval_funs;
131 int eval_fun_count = 0;
133 public ReplaceEval ()
135 eval_funs = new StringBuilder ();
138 public string replace_eval (Match match)
140 string body = ProcessEscapes (match.Groups [2].Value);
142 // Try to insert a return statement before a semicolon or closing curly brace
143 string new_body = Regex.Replace (body, "^(.+)([;}])(.+)$", "$1$2 return $3", RegexOptions.Singleline);
144 // No return inserted yet? Prepend to whole body.
145 if (body == new_body)
146 new_body = "return " + body;
148 string fun_name = String.Format ("eval_fun_{0}", eval_fun_count++);
149 eval_funs.AppendFormat ("function {0}() {{ {1} }}{2}", fun_name, new_body, Environment.NewLine);
151 return fun_name + "()";
155 static void RunTest (string test)
157 string target = Path.Combine (config.test_dir, "jstest.js");
159 ReplaceEval repl_eval = new ReplaceEval ();
160 MatchEvaluator replace_eval = new MatchEvaluator (repl_eval.replace_eval);
162 StreamReader source_io = File.OpenText (test);
165 source = source_io.ReadToEnd ();
170 source = Regex.Replace (source, @"eval\s*\(([""'])(.+?[^\\]?)\1\s*\)", replace_eval).
171 Replace ("new TestCase", "TestCase");
172 string eval_funs = repl_eval.eval_funs.ToString ();
174 StreamWriter target_io = File.CreateText (target);
176 target_io.WriteLine (preamble);
177 target_io.WriteLine (eval_funs);
178 target_io.WriteLine (source);
183 // Luckily, we don't have to deal with multiple threads here...
184 string old_dir = Environment.CurrentDirectory;
185 Environment.CurrentDirectory = config.test_dir;
187 Console.WriteLine ();
188 Console.WriteLine ("Running {0}...", test);
190 ProcessStartInfo compiler_info = new ProcessStartInfo (config.compile_cmd, config.compile_args);
191 compiler_info.CreateNoWindow = true;
192 compiler_info.UseShellExecute = false;
193 compiler_info.RedirectStandardOutput = true;
194 compiler_info.RedirectStandardError = true;
195 Process compiler = Process.Start (compiler_info);
196 compiler.WaitForExit ();
197 Console.Write (compiler.StandardOutput.ReadToEnd ());
198 Console.Write (compiler.StandardError.ReadToEnd ());
199 if (compiler.ExitCode != 0 || !File.Exists ("jstest.exe")) {
200 Failed (test, String.Format ("compiler aborted with exit code {0}", compiler.ExitCode));
204 ProcessStartInfo runtime_info = new ProcessStartInfo (config.run_cmd, config.run_args);
205 runtime_info.CreateNoWindow = true;
206 runtime_info.UseShellExecute = false;
207 runtime_info.RedirectStandardOutput = true;
208 runtime_info.RedirectStandardError = true;
209 Process runtime = Process.Start (runtime_info);
210 // For some reason we need the timeout here even if the runtime does not need longer than it...
211 runtime.WaitForExit (5000);
213 Console.Write (runtime.StandardOutput.ReadToEnd ());
214 Console.Write (runtime.StandardError.ReadToEnd ());
215 if (runtime.ExitCode != 0)
216 Failed (test, String.Format ("runtime aborted with exit code {0}", runtime.ExitCode));
217 File.Delete ("jstest.exe");
221 Environment.CurrentDirectory = old_dir;
224 static string ProcessEscapeMatch (Match match)
226 string escape = match.Groups [1].Value;
240 return "\\" + escape;
244 static string ProcessEscapes (String text)
246 MatchEvaluator process = new MatchEvaluator (ProcessEscapeMatch);
247 return Regex.Replace (text, @"\\(.)", process);
250 static void Failed (string test, string reason)
252 bool fail_expected = Array.IndexOf (fail_tests, test) != -1;
253 Console.WriteLine ("Failed {0}: {1}!", test, reason);
254 Console.WriteLine (); Console.WriteLine (); Console.WriteLine ();
255 if (!fail_expected) {
256 Console.WriteLine ("CRITICAL: Unexpected failure of {0}. Aborting run.", test);
257 if (!config.full_run)
258 Environment.Exit (1);