5 // Marek Safar (marek.safar@gmail.com)
9 // Copyright (C) 2008 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Diagnostics;
34 using System.Reflection;
36 using System.Collections;
39 namespace TestRunner {
43 string Output { get; }
44 bool Invoke (string[] args);
45 bool IsWarning (int warningNumber);
48 class ReflectionTester: ITester {
54 public ReflectionTester (Assembly a)
56 Type t = a.GetType ("Mono.CSharp.CompilerCallableEntryPoint");
59 Console.Error.WriteLine ("null, huh?");
61 ep = t.GetMethod ("InvokeCompiler",
62 BindingFlags.Static | BindingFlags.Public);
64 throw new MissingMethodException ("static InvokeCompiler");
65 method_arg = new object [2];
67 PropertyInfo pi = t.GetProperty ("AllWarningNumbers");
68 all_warnings = (int[])pi.GetValue (null, null);
69 Array.Sort (all_warnings);
72 public string Output {
74 return output.GetStringBuilder ().ToString ();
78 public bool Invoke(string[] args)
80 output = new StringWriter ();
81 method_arg [0] = args;
82 method_arg [1] = output;
83 return (bool)ep.Invoke (null, method_arg);
86 public bool IsWarning (int warningNumber)
88 return Array.BinarySearch (all_warnings, warningNumber) >= 0;
93 class ProcessTester: ITester
98 public ProcessTester (string p_path)
100 pi = new ProcessStartInfo ();
101 pi.FileName = p_path;
102 pi.CreateNoWindow = true;
103 pi.WindowStyle = ProcessWindowStyle.Hidden;
104 pi.RedirectStandardOutput = true;
105 pi.RedirectStandardError = true;
106 pi.UseShellExecute = false;
109 public string Output {
115 public bool Invoke(string[] args)
117 StringBuilder sb = new StringBuilder ("/nologo ");
118 foreach (string s in args) {
122 pi.Arguments = sb.ToString ();
123 Process p = Process.Start (pi);
124 output = p.StandardError.ReadToEnd ();
125 if (output.Length == 0)
126 output = p.StandardOutput.ReadToEnd ();
128 return p.ExitCode == 0;
131 public bool IsWarning (int warningNumber)
133 throw new NotImplementedException ();
140 public readonly string FileName;
141 public readonly string[] CompilerOptions;
142 public readonly string[] Dependencies;
144 public TestCase (string filename, string[] options, string[] deps)
146 this.FileName = filename;
147 this.CompilerOptions = options;
148 this.Dependencies = deps;
152 class PositiveTestCase : TestCase
154 public class VerificationData
156 public class MethodData
158 public MethodData (MethodBase mi, int il_size)
160 this.Type = mi.DeclaringType.ToString ();
161 this.MethodName = mi.ToString ();
162 this.ILSize = il_size;
165 public MethodData (string type_name, string method_name, int il_size)
167 this.Type = type_name;
168 this.MethodName = method_name;
169 this.ILSize = il_size;
173 public string MethodName;
179 public bool IsNewSet;
181 public VerificationData (string test_file)
184 this.test_file = test_file;
191 public static VerificationData FromFile (string name, XmlReader r)
193 VerificationData tc = new VerificationData (name);
194 ArrayList methods = new ArrayList ();
196 while (r.ReadToNextSibling ("type")) {
197 string type_name = r ["name"];
199 while (r.ReadToNextSibling ("method")) {
200 string m_name = r ["name"];
202 r.ReadToDescendant ("size");
203 int il_size = r.ReadElementContentAsInt ();
204 methods.Add (new MethodData (type_name, m_name, il_size));
210 tc.methods = methods;
214 public void WriteCodeInfoTo (XmlWriter w)
216 w.WriteStartElement ("test");
217 w.WriteAttributeString ("name", test_file);
220 foreach (MethodData data in methods) {
224 if (type != data.Type) {
226 w.WriteEndElement ();
229 w.WriteStartElement ("type");
230 w.WriteAttributeString ("name", type);
233 w.WriteStartElement ("method");
234 w.WriteAttributeString ("name", data.MethodName);
235 w.WriteStartElement ("size");
236 w.WriteValue (data.ILSize);
237 w.WriteEndElement ();
238 w.WriteEndElement ();
242 w.WriteEndElement ();
244 w.WriteEndElement ();
248 public MethodData FindMethodData (string method_name, string declaring_type)
253 foreach (MethodData md in methods) {
254 if (md.MethodName == method_name && md.Type == declaring_type)
261 public void AddNewMethod (MethodBase mb, int il_size)
264 methods = new ArrayList ();
266 MethodData md = new MethodData (mb, il_size);
272 VerificationData verif_data;
274 public PositiveTestCase (string filename, string [] options, string [] deps)
275 : base (filename, options, deps)
279 public void CreateNewTest ()
281 verif_data = new VerificationData (FileName);
282 verif_data.IsNewSet = true;
285 public VerificationData VerificationProvider {
294 public bool CompareIL (MethodBase mi, PositiveChecker checker)
296 string m_name = mi.ToString ();
297 string decl_type = mi.DeclaringType.ToString ();
298 VerificationData.MethodData md = verif_data.FindMethodData (m_name, decl_type);
300 verif_data.AddNewMethod (mi, GetILSize (mi));
301 if (!verif_data.IsNewSet) {
302 checker.HandleFailure (FileName, PositiveChecker.TestResult.ILError, decl_type + ": " + m_name + " (new method?)");
310 checker.HandleFailure (FileName, PositiveChecker.TestResult.ILError, decl_type + ": " + m_name + " has a duplicate");
316 int il_size = GetILSize (mi);
317 if (md.ILSize == il_size)
320 if (md.ILSize > il_size) {
321 checker.LogFileLine (FileName, "{0} (code size reduction {1} -> {2})", m_name, md.ILSize, il_size);
326 checker.HandleFailure (FileName, PositiveChecker.TestResult.ILError,
327 string.Format ("{0} (code size {1} -> {2})", m_name, md.ILSize, il_size));
334 static int GetILSize (MethodBase mi)
337 MethodBody body = mi.GetMethodBody ();
339 return body.GetILAsByteArray ().Length;
345 class Checker: IDisposable
347 protected ITester tester;
348 protected int success;
350 protected int ignored;
351 protected int syntax_errors;
353 StreamWriter log_file;
354 protected string[] extra_compiler_options;
355 // protected string[] compiler_options;
356 // protected string[] dependencies;
358 protected ArrayList tests = new ArrayList ();
359 protected Hashtable test_hash = new Hashtable ();
360 protected ArrayList regression = new ArrayList ();
361 protected ArrayList know_issues = new ArrayList ();
362 protected ArrayList ignore_list = new ArrayList ();
363 protected ArrayList no_error_list = new ArrayList ();
365 protected bool verbose;
367 int total_known_issues;
369 protected Checker (ITester tester)
371 this.tester = tester;
374 public string IssueFile {
376 this.issue_file = value;
377 ReadWrongErrors (issue_file);
381 public string LogFile {
383 this.log_file = new StreamWriter (value, false);
387 public bool Verbose {
393 public string[] ExtraCompilerOptions {
395 extra_compiler_options = value;
399 protected virtual bool GetExtraOptions (string file, out string[] compiler_options,
400 out string[] dependencies)
403 compiler_options = null;
406 using (StreamReader sr = new StreamReader (file)) {
408 while (row++ < 3 && (line = sr.ReadLine()) != null) {
409 if (!AnalyzeTestFile (file, ref row, line, ref compiler_options,
420 protected virtual bool AnalyzeTestFile (string file, ref int row, string line,
421 ref string[] compiler_options,
422 ref string[] dependencies)
424 const string options = "// Compiler options:";
425 const string depends = "// Dependencies:";
428 compiler_options = null;
432 int index = line.IndexOf (options);
434 compiler_options = line.Substring (index + options.Length).Trim().Split (' ');
435 for (int i = 0; i < compiler_options.Length; i++)
436 compiler_options[i] = compiler_options[i].TrimStart ();
438 index = line.IndexOf (depends);
440 dependencies = line.Substring (index + depends.Length).Trim().Split (' ');
441 for (int i = 0; i < dependencies.Length; i++)
442 dependencies[i] = dependencies[i].TrimStart ();
448 public bool Do (string filename)
450 if (test_hash.Contains (filename))
453 if (ignore_list.Contains (filename)) {
455 LogFileLine (filename, "NOT TESTED");
459 string[] compiler_options, dependencies;
460 if (!GetExtraOptions (filename, out compiler_options, out dependencies)) {
461 LogFileLine (filename, "ERROR");
465 if (extra_compiler_options != null) {
466 if (compiler_options == null)
467 compiler_options = extra_compiler_options;
469 string[] new_options = new string [compiler_options.Length + extra_compiler_options.Length];
470 extra_compiler_options.CopyTo (new_options, 0);
471 compiler_options.CopyTo (new_options, extra_compiler_options.Length);
472 compiler_options = new_options;
476 TestCase test = CreateTestCase (filename, compiler_options, dependencies);
477 test_hash.Add (filename, test);
480 if (dependencies != null) {
481 foreach (string dependency in dependencies) {
482 if (!Do (dependency)) {
483 LogFileLine (filename, "DEPENDENCY FAILED");
494 protected virtual bool Check (TestCase test)
498 if (test.CompilerOptions != null) {
499 test_args = new string [2 + test.CompilerOptions.Length];
500 test.CompilerOptions.CopyTo (test_args, 0);
502 test_args = new string [2];
504 test_args [test_args.Length - 2] = test.FileName;
505 test_args [test_args.Length - 1] = "-debug";
507 return tester.Invoke (test_args);
510 protected virtual TestCase CreateTestCase (string filename, string [] options, string [] deps)
512 return new TestCase (filename, options, deps);
515 void ReadWrongErrors (string file)
517 const string ignored = "IGNORE";
518 const string no_error = "NO ERROR";
520 using (StreamReader sr = new StreamReader (file)) {
522 while ((line = sr.ReadLine()) != null) {
523 if (line.StartsWith ("#"))
526 ArrayList active_cont = know_issues;
528 if (line.IndexOf (ignored) > 0)
529 active_cont = ignore_list;
530 else if (line.IndexOf (no_error) > 0)
531 active_cont = no_error_list;
533 string file_name = line.Split (' ')[0];
534 if (file_name.Length == 0)
537 active_cont.Add (file_name);
540 total_known_issues = know_issues.Count;
543 protected virtual void PrintSummary ()
545 LogLine ("Done" + Environment.NewLine);
548 rate = (float) (success) / (float)total;
549 LogLine ("{0} test cases passed ({1:0.##%})", success, rate);
551 if (syntax_errors > 0)
552 LogLine ("{0} test(s) ignored because of wrong syntax !", syntax_errors);
555 LogLine ("{0} test(s) ignored", ignored);
557 if (total_known_issues - know_issues.Count > 0)
558 LogLine ("{0} known issue(s)", total_known_issues - know_issues.Count);
560 know_issues.AddRange (no_error_list);
561 if (know_issues.Count > 0) {
563 LogLine (issue_file + " contains {0} already fixed issues. Please remove", know_issues.Count);
564 foreach (string s in know_issues)
567 if (regression.Count > 0) {
569 LogLine ("The latest changes caused regression in {0} file(s)", regression.Count);
570 foreach (string s in regression)
575 public int ResultCode
578 return regression.Count == 0 ? 0 : 1;
582 protected void Log (string msg, params object [] rest)
584 Console.Write (msg, rest);
585 if (log_file != null)
586 log_file.Write (msg, rest);
589 protected void LogLine (string msg, params object [] rest)
591 Console.WriteLine (msg, rest);
592 if (log_file != null)
593 log_file.WriteLine (msg, rest);
596 public void LogFileLine (string file, string msg, params object [] args)
598 string s = file + "...\t" + string.Format (msg, args);
599 Console.WriteLine (s);
600 if (log_file != null)
601 log_file.WriteLine (s);
604 #region IDisposable Members
606 public void Dispose()
608 if (log_file != null)
614 public virtual void Initialize ()
618 public virtual void CleanUp ()
624 class PositiveChecker: Checker
626 readonly string files_folder;
627 readonly static object[] default_args = new object[1] { new string[] {} };
630 bool update_verif_file;
631 Hashtable verif_data;
636 readonly string mono;
638 public enum TestResult {
647 public PositiveChecker (ITester tester, string verif_file):
650 files_folder = Directory.GetCurrentDirectory ();
651 this.verif_file = verif_file;
654 pi = new ProcessStartInfo ();
655 pi.CreateNoWindow = true;
656 pi.WindowStyle = ProcessWindowStyle.Hidden;
657 pi.RedirectStandardOutput = true;
658 pi.RedirectStandardError = true;
659 pi.UseShellExecute = false;
661 mono = Environment.GetEnvironmentVariable ("MONO_RUNTIME");
668 public bool UpdateVerificationDataFile {
670 update_verif_file = value;
674 protected override bool GetExtraOptions(string file, out string[] compiler_options,
675 out string[] dependencies) {
676 if (!base.GetExtraOptions (file, out compiler_options, out dependencies))
680 if (compiler_options == null)
683 foreach (string one_opt in compiler_options) {
684 if (one_opt.StartsWith ("-doc:")) {
685 doc_output = one_opt.Split (':', '/')[1];
691 protected override bool Check(TestCase test)
693 string filename = test.FileName;
695 if (!base.Check (test)) {
696 HandleFailure (filename, TestResult.CompileError, tester.Output);
700 catch (Exception e) {
701 if (e.InnerException != null)
702 e = e.InnerException;
704 HandleFailure (filename, TestResult.CompileError, e.ToString ());
709 if (filename.EndsWith ("-lib.cs") || filename.EndsWith ("-mod.cs")) {
711 LogFileLine (filename, "OK");
716 MethodInfo mi = null;
717 string file = Path.Combine (files_folder, Path.GetFileNameWithoutExtension (filename) + ".exe");
719 // Enable .dll only tests (no execution required)
720 if (!File.Exists(file)) {
721 HandleFailure (filename, TestResult.Success, null);
725 Assembly assembly = null;
727 assembly = Assembly.LoadFile (file);
728 mi = assembly.EntryPoint;
730 catch (FileNotFoundException) {
731 if (File.Exists (file)) {
732 Console.WriteLine ("APPDOMAIN LIMIT REACHED");
735 catch (Exception e) {
736 HandleFailure (filename, TestResult.LoadError, e.ToString ());
740 if (!ExecuteFile (mi, file, filename))
743 if (doc_output != null) {
744 string ref_file = filename.Replace (".cs", "-ref.xml");
747 XmlComparer.Compare (ref_file, doc_output);
750 catch (Exception e) {
751 HandleFailure (filename, TestResult.XmlError, e.Message);
755 if (verif_file != null) {
756 PositiveTestCase pt = (PositiveTestCase) test;
757 pt.VerificationProvider = (PositiveTestCase.VerificationData) verif_data [filename];
758 if (!CheckILSize (assembly, pt))
763 HandleFailure (filename, TestResult.Success, null);
767 protected override TestCase CreateTestCase (string filename, string [] options, string [] deps)
769 return new PositiveTestCase (filename, options, deps);
772 bool CheckILSize (Assembly assembly, PositiveTestCase test)
775 Type[] types = assembly.GetTypes ();
776 foreach (Type t in types) {
777 if (!t.IsClass && t.IsValueType)
780 if (test.VerificationProvider == null) {
781 if (!update_verif_file)
782 LogFileLine (test.FileName, "Missing IL verification data");
783 test.CreateNewTest ();
786 foreach (MemberInfo m in t.GetMembers (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly)) {
787 MethodBase mi = m as MethodBase;
791 if ((mi.Attributes & (MethodAttributes.PinvokeImpl)) != 0)
794 success &= test.CompareIL (mi, this);
801 bool ExecuteFile (MethodInfo entry_point, string exe_name, string filename)
803 TextWriter stdout = Console.Out;
804 TextWriter stderr = Console.Error;
805 Console.SetOut (TextWriter.Null);
806 Console.SetError (TextWriter.Null);
807 ParameterInfo[] pi = entry_point.GetParameters ();
808 object[] args = pi.Length == 0 ? null : default_args;
810 object result = null;
813 result = entry_point.Invoke (null, args);
815 Console.SetOut (stdout);
816 Console.SetError (stderr);
819 catch (Exception e) {
820 HandleFailure (filename, TestResult.ExecError, e.ToString ());
824 if (result is int && (int)result != 0) {
825 HandleFailure (filename, TestResult.ExecError, "Wrong return code: " + result.ToString ());
831 public void HandleFailure (string file, TestResult status, string extra)
834 case TestResult.Success:
836 if (know_issues.Contains (file)) {
837 LogFileLine (file, "FIXED ISSUE");
841 LogFileLine (file, "OK");
844 case TestResult.CompileError:
845 if (know_issues.Contains (file)) {
846 LogFileLine (file, "KNOWN ISSUE (Compilation error)");
847 know_issues.Remove (file);
850 LogFileLine (file, "REGRESSION (SUCCESS -> COMPILATION ERROR)");
853 case TestResult.ExecError:
854 if (know_issues.Contains (file)) {
855 LogFileLine (file, "KNOWN ISSUE (Execution error)");
856 know_issues.Remove (file);
859 LogFileLine (file, "REGRESSION (SUCCESS -> EXECUTION ERROR)");
862 case TestResult.XmlError:
863 if (know_issues.Contains (file)) {
864 LogFileLine (file, "KNOWN ISSUE (Xml comparision error)");
865 know_issues.Remove (file);
868 LogFileLine (file, "REGRESSION (SUCCESS -> DOCUMENTATION ERROR)");
871 case TestResult.LoadError:
872 LogFileLine (file, "REGRESSION (SUCCESS -> LOAD ERROR)");
875 case TestResult.ILError:
876 LogFileLine (file, "IL REGRESSION: " + extra);
882 LogLine ("{0}", extra);
884 if (!regression.Contains (file))
885 regression.Add (file);
888 public override void Initialize ()
890 if (verif_file != null) {
892 LoadVerificationData (verif_file);
894 throw new NotSupportedException ();
901 public override void CleanUp ()
905 if (update_verif_file) {
907 UpdateVerificationData (verif_file);
909 throw new NotSupportedException ();
915 void LoadVerificationData (string file)
917 LogLine ("Loading verification data from `{0}' ...", file);
919 using (XmlReader r = XmlReader.Create (file)) {
920 r.ReadStartElement ("tests");
921 verif_data = new Hashtable ();
924 if (r.Name != "test")
927 string name = r.GetAttribute ("name");
928 PositiveTestCase.VerificationData tc = PositiveTestCase.VerificationData.FromFile (name, r);
929 verif_data.Add (name, tc);
934 void UpdateVerificationData (string file)
936 LogLine ("Updating verification data `{0}' ...", file);
938 XmlWriterSettings s = new XmlWriterSettings ();
940 using (XmlWriter w = XmlWriter.Create (new StreamWriter (file, false, Encoding.UTF8), s)) {
941 w.WriteStartDocument ();
942 w.WriteComment ("This file contains expected IL and metadata produced by compiler for each test");
943 w.WriteStartElement ("tests");
944 foreach (PositiveTestCase tc in tests) {
945 if (tc.VerificationProvider != null)
946 tc.VerificationProvider.WriteCodeInfoTo (w);
948 w.WriteEndElement ();
954 class NegativeChecker: Checker
956 string expected_message;
957 string error_message;
959 bool check_error_line;
961 IDictionary wrong_warning;
963 protected enum CompilerError {
972 public NegativeChecker (ITester tester, bool check_msg):
975 this.check_msg = check_msg;
976 wrong_warning = new Hashtable ();
979 protected override bool AnalyzeTestFile (string file, ref int row, string line,
980 ref string[] compiler_options,
981 ref string[] dependencies)
984 expected_message = null;
986 int index = line.IndexOf (':');
987 if (index == -1 || index > 15) {
988 LogFileLine (file, "IGNORING: Wrong test file syntax (missing error mesage text)");
990 base.AnalyzeTestFile (file, ref row, line, ref compiler_options,
995 expected_message = line.Substring (index + 1).Trim ();
999 string filtered = line.Replace(" ", "");
1001 // Some error tests require to have different error text for different runtimes.
1002 if (filtered.StartsWith ("//GMCS")) {
1007 return AnalyzeTestFile(file, ref row, line, ref compiler_options, ref dependencies);
1011 check_error_line = !filtered.StartsWith ("//Line:0");
1013 if (!filtered.StartsWith ("//Line:")) {
1014 LogFileLine (file, "IGNORING: Wrong test syntax (following line after an error messsage must have `// Line: xx' syntax");
1020 if (!base.AnalyzeTestFile (file, ref row, line, ref compiler_options, ref dependencies))
1024 if (compiler_options != null) {
1025 foreach (string s in compiler_options) {
1026 if (s.EndsWith ("warnaserror"))
1034 protected override bool Check (TestCase test)
1036 string filename = test.FileName;
1039 while (Char.IsLetter (filename, start_char))
1042 int end_char = filename.IndexOfAny (new char [] { '-', '.' } );
1043 string expected = filename.Substring (start_char, end_char - start_char);
1046 if (base.Check (test)) {
1047 HandleFailure (filename, CompilerError.Missing);
1051 catch (Exception e) {
1052 HandleFailure (filename, CompilerError.Missing);
1053 if (e.InnerException != null)
1054 e = e.InnerException;
1056 Log (e.ToString ());
1060 int err_id = int.Parse (expected, System.Globalization.CultureInfo.InvariantCulture);
1061 if (tester.IsWarning (err_id)) {
1063 wrong_warning [err_id] = true;
1066 wrong_warning [err_id] = false;
1069 CompilerError result_code = GetCompilerError (expected, tester.Output);
1070 if (HandleFailure (filename, result_code)) {
1075 if (result_code == CompilerError.Wrong)
1076 LogLine (tester.Output);
1081 CompilerError GetCompilerError (string expected, string buffer)
1083 const string error_prefix = "CS";
1084 const string ignored_error = "error CS5001";
1085 string tested_text = "error " + error_prefix + expected;
1086 StringReader sr = new StringReader (buffer);
1087 string line = sr.ReadLine ();
1088 ArrayList ld = new ArrayList ();
1089 CompilerError result = CompilerError.Missing;
1090 while (line != null) {
1091 if (ld.Contains (line)) {
1092 if (line.IndexOf ("Location of the symbol related to previous") == -1)
1093 return CompilerError.Duplicate;
1097 if (result != CompilerError.Expected) {
1098 if (line.IndexOf (tested_text) != -1) {
1100 int first = line.IndexOf (':');
1101 int second = line.IndexOf (':', first + 1);
1102 if (second == -1 || !check_error_line)
1105 string msg = line.Substring (second + 1).TrimEnd ('.').Trim ();
1106 if (msg != expected_message && msg != expected_message.Replace ('`', '\'')) {
1107 error_message = msg;
1108 return CompilerError.WrongMessage;
1111 if (check_error_line && line.IndexOf (".cs(") == -1)
1112 return CompilerError.MissingLocation;
1114 result = CompilerError.Expected;
1115 } else if (line.IndexOf (error_prefix) != -1 &&
1116 line.IndexOf (ignored_error) == -1)
1117 result = CompilerError.Wrong;
1120 line = sr.ReadLine ();
1126 bool HandleFailure (string file, CompilerError status)
1129 case CompilerError.Expected:
1130 if (know_issues.Contains (file) || no_error_list.Contains (file)) {
1131 LogFileLine (file, "FIXED ISSUE");
1136 LogFileLine (file, "OK");
1139 case CompilerError.Wrong:
1140 if (know_issues.Contains (file)) {
1141 LogFileLine (file, "KNOWN ISSUE (Wrong error reported)");
1142 know_issues.Remove (file);
1145 if (no_error_list.Contains (file)) {
1146 LogFileLine (file, "REGRESSION (NO ERROR -> WRONG ERROR CODE)");
1147 no_error_list.Remove (file);
1150 LogFileLine (file, "REGRESSION (CORRECT ERROR -> WRONG ERROR CODE)");
1154 case CompilerError.WrongMessage:
1155 if (know_issues.Contains (file)) {
1156 LogFileLine (file, "KNOWN ISSUE (Wrong error message reported)");
1157 know_issues.Remove (file);
1160 if (no_error_list.Contains (file)) {
1161 LogFileLine (file, "REGRESSION (NO ERROR -> WRONG ERROR MESSAGE)");
1162 no_error_list.Remove (file);
1165 LogFileLine (file, "REGRESSION (CORRECT ERROR -> WRONG ERROR MESSAGE)");
1166 LogLine ("Exp: {0}", expected_message);
1167 LogLine ("Was: {0}", error_message);
1171 case CompilerError.Missing:
1172 if (no_error_list.Contains (file)) {
1173 LogFileLine (file, "KNOWN ISSUE (No error reported)");
1174 no_error_list.Remove (file);
1178 if (know_issues.Contains (file)) {
1179 LogFileLine (file, "REGRESSION (WRONG ERROR -> NO ERROR)");
1180 know_issues.Remove (file);
1183 LogFileLine (file, "REGRESSION (CORRECT ERROR -> NO ERROR)");
1188 case CompilerError.MissingLocation:
1189 if (know_issues.Contains (file)) {
1190 LogFileLine (file, "KNOWN ISSUE (Missing error location)");
1191 know_issues.Remove (file);
1194 if (no_error_list.Contains (file)) {
1195 LogFileLine (file, "REGRESSION (NO ERROR -> MISSING ERROR LOCATION)");
1196 no_error_list.Remove (file);
1199 LogFileLine (file, "REGRESSION (CORRECT ERROR -> MISSING ERROR LOCATION)");
1203 case CompilerError.Duplicate:
1204 // Will become an error soon
1205 LogFileLine (file, "WARNING: EXACTLY SAME ERROR HAS BEEN ISSUED MULTIPLE TIMES");
1209 regression.Add (file);
1213 protected override void PrintSummary()
1215 base.PrintSummary ();
1217 if (wrong_warning.Count > 0) {
1219 LogLine ("List of incorectly defined warnings (they should be either defined in the compiler as a warning or a test-case has redundant `warnaserror' option)");
1221 foreach (DictionaryEntry de in wrong_warning)
1222 LogLine ("CS{0:0000} : {1}", de.Key, (bool)de.Value ? "incorrect warning definition" : "missing warning definition");
1230 static int Main(string[] args)
1234 if (GetOption ("help", args, false, out temp)) {
1240 if (!GetOption ("compiler", args, true, out compiler)) {
1247 Console.WriteLine ("Loading " + compiler + " ...");
1248 tester = new ReflectionTester (Assembly.LoadFile (compiler));
1254 Console.Error.WriteLine ("Switching to command line mode (compiler entry point was not found)");
1255 if (!File.Exists (compiler)) {
1256 Console.Error.WriteLine ("ERROR: Tested compiler was not found");
1259 tester = new ProcessTester (compiler);
1264 if (!GetOption ("mode", args, true, out mode)) {
1272 checker = new NegativeChecker (tester, true);
1276 GetOption ("il", args, false, out iltest);
1277 checker = new PositiveChecker (tester, iltest);
1279 if (iltest != null && GetOption ("update-il", args, false, out temp)) {
1280 ((PositiveChecker) checker).UpdateVerificationDataFile = true;
1285 Console.Error.WriteLine ("Invalid -mode argument");
1290 if (GetOption ("issues", args, true, out temp))
1291 checker.IssueFile = temp;
1292 if (GetOption ("log", args, true, out temp))
1293 checker.LogFile = temp;
1294 if (GetOption ("verbose", args, false, out temp))
1295 checker.Verbose = true;
1296 if (GetOption ("compiler-options", args, true, out temp)) {
1297 string[] extra = temp.Split (' ');
1298 checker.ExtraCompilerOptions = extra;
1301 string test_pattern;
1302 if (!GetOption ("files", args, true, out test_pattern)) {
1307 string [] files = Directory.GetFiles (".", test_pattern);
1308 if (files.Length == 0) {
1309 Console.Error.WriteLine ("No files matching `{0}' found", test_pattern);
1313 checker.Initialize ();
1315 foreach (string s in files) {
1316 string filename = Path.GetFileName (s);
1317 if (Char.IsUpper (filename, 0)) { // Windows hack
1321 if (filename.EndsWith ("-p2.cs"))
1324 checker.Do (filename);
1331 return checker.ResultCode;
1334 static bool GetOption (string opt, string[] args, bool req_arg, out string value)
1337 foreach (string a in args) {
1338 if (a.StartsWith (opt)) {
1339 int sep = a.IndexOf (':');
1341 value = a.Substring (sep + 1);
1345 Console.Error.WriteLine ("Missing argument in option " + opt);
1358 static void Usage ()
1361 "Mono compiler tester, (C) 2008 Novell, Inc.\n" +
1362 "compiler-tester -mode:[pos|neg] -compiler:FILE -files:file-list [options]\n" +
1364 " -compiler:FILE The file which will be used to compiler tests\n" +
1365 " -compiler-options:OPTIONS Add global compiler options\n" +
1366 " -il:IL-FILE XML file with expected IL details for each test\n" +
1367 " -issues:FILE The list of expected failures\n" +
1368 " -log:FILE Writes any output also to the file\n" +
1369 " -help Lists all options\n" +
1370 " -mode:[pos|neg] Specifies compiler test mode\n" +
1371 " -update-il Updates IL-FILE to match compiler output\n" +
1372 " -verbose Prints more details during testing\n"