fdd7a10466f2b5f4cbd410f1723cfe5fba5b0dc0
[mono.git] / mono / mini / TestDriver.cs
1 using System;
2 using System.Reflection;
3 using System.Collections.Generic;
4
5 [AttributeUsageAttribute(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
6 public class CategoryAttribute : Attribute
7 {
8         public CategoryAttribute (string category) {
9                 Category = category;
10         }
11
12         public string Category {
13                 get; set;
14         }
15 }
16
17 public class TestDriver {
18
19         static public int RunTests (Type type, string[] args) {
20                 int failed = 0, ran = 0;
21                 int result, expected;
22                 int i, j, iterations;
23                 string name;
24                 MethodInfo[] methods;
25                 bool do_timings = false;
26                 bool verbose = false;
27                 bool quiet = false;
28                 int tms = 0;
29                 DateTime start, end = DateTime.Now;
30
31                 iterations = 1;
32
33                 var exclude = new Dictionary<string, string> ();
34                 List<string> run_only = new List<string> ();
35                 List<string> exclude_test = new List<string> ();
36                 if (args != null && args.Length > 0) {
37                         for (j = 0; j < args.Length;) {
38                                 if (args [j] == "--time") {
39                                         do_timings = !quiet;
40                                         j ++;
41                                 } else if (args [j] == "--iter") {
42                                         iterations = Int32.Parse (args [j + 1]);
43                                         j += 2;
44                                 } else if ((args [j] == "-v") || (args [j] == "--verbose")) {
45                                         verbose = !quiet;
46                                         j += 1;
47                                 } else if ((args [j] == "-q") || (args [j] == "--quiet")) {
48                                         quiet = true;
49                                         verbose = false;
50                                         do_timings = false;
51                                         j += 1;
52                                 } else if (args [j] == "--exclude") {
53                                         exclude [args [j + 1]] = args [j + 1];
54                                         j += 2;
55                                 } else if (args [j] == "--exclude-test") {
56                                         exclude_test.Add (args [j + 1]);
57                                         j += 2;
58                                 } else if (args [j] == "--run-only") {
59                                         run_only.Add (args [j + 1]);
60                                         j += 2;
61                                 } else {
62                                         Console.WriteLine ("Unknown argument: " + args [j]);
63                                         return 1;
64                                 }
65                         }
66                 }
67                 int nskipped = 0;
68                 methods = type.GetMethods (BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static);
69                 for (int iter = 0; iter < iterations; ++iter) {
70                         for (i = 0; i < methods.Length; ++i) {
71                                 name = methods [i].Name;
72                                 if (!name.StartsWith ("test_", StringComparison.Ordinal))
73                                         continue;
74                                 if (run_only.Count > 0) {
75                                         bool found = false;
76                                         for (j = 0; j < run_only.Count; j++) {
77                                                 if (name.EndsWith (run_only [j])) {
78                                                         found = true;
79                                                         break;
80                                                 }
81                                         }
82                                         if (!found)
83                                                 continue;
84                                 }
85                                 if (exclude.Count > 0 || exclude_test.Count > 0) {
86                                         var attrs = methods [i].GetCustomAttributes (typeof (CategoryAttribute), false);
87                                         bool skip = false;
88                                         for (j = 0; j < exclude_test.Count; j++) {
89                                                 if (name.EndsWith (exclude_test [j])) {
90                                                         skip = true;
91                                                         break;
92                                                 }
93                                         }
94                                         foreach (CategoryAttribute attr in attrs) {
95                                                 if (exclude.ContainsKey (attr.Category))
96                                                         skip = true;
97                                         }
98                                         if (skip) {
99                                                 if (verbose)
100                                                         Console.WriteLine ("Skipping '{0}'.", name);
101                                                 nskipped ++;
102                                                 continue;
103                                         }
104                                 }
105                                 for (j = 5; j < name.Length; ++j)
106                                         if (!Char.IsDigit (name [j]))
107                                                 break;
108                                 if (verbose)
109                                         Console.WriteLine ("Running '{0}' ...", name);
110                                 expected = Int32.Parse (name.Substring (5, j - 5));
111                                 start = DateTime.Now;
112                                 result = (int)methods [i].Invoke (null, null);
113                                 if (do_timings) {
114                                         end = DateTime.Now;
115                                         long tdiff = end.Ticks - start.Ticks;
116                                         int mdiff = (int)tdiff/10000;
117                                         tms += mdiff;
118                                         Console.WriteLine ("{0} took {1} ms", name, mdiff);
119                                 }
120                                 ran++;
121                                 if (result != expected) {
122                                         failed++;
123                                         Console.WriteLine ("{0} failed: got {1}, expected {2}", name, result, expected);
124                                 }
125                         }
126                 
127                         if (!quiet) {
128                                 if (do_timings) {
129                                         Console.WriteLine ("Total ms: {0}", tms);
130                                 }
131                                 if (nskipped > 0)
132                                         Console.WriteLine ("Regression tests: {0} ran, {1} skipped, {2} failed in {3}", ran, nskipped, failed, type);
133                                 else
134                                         Console.WriteLine ("Regression tests: {0} ran, {1} failed in {2}", ran, failed, type);
135                         }
136                 }
137
138                 //Console.WriteLine ("Regression tests: {0} ran, {1} failed in [{2}]{3}", ran, failed, type.Assembly.GetName().Name, type);
139                 return failed;
140         }
141         static public int RunTests (Type type) {
142                 return RunTests (type, null);
143         }
144 }
145
146 /// Provide tests with the ability to find out how much time they have to run before being timed out.
147 public class TestTimeout {
148         const string ENV_TIMEOUT = "TEST_DRIVER_TIMEOUT_SEC";
149         private readonly TimeSpan availableTime;
150         private TimeSpan slack;
151         private DateTime startTime;
152
153         /// <summary>
154         ///   How much time the test runner provided for us or TimeSpan.Zero if there is no bound.
155         /// </summary>
156         public TimeSpan AvailableTime { get { return availableTime; } }
157
158         public DateTime StartTime { get { return startTime; } }
159
160         /// <summary> Extra time to add when deciding if there
161         ///   is still time to run.  Bigger slack means less
162         ///   time left.
163         /// </summary>
164         public TimeSpan Slack {
165                 get { return slack; }
166                 set { slack = value; }
167         }
168
169         public TestTimeout () {
170                 availableTime = initializeAvailableTime ();
171                 slack = defaultSlack ();
172         }
173
174         /// <summary>
175         ///    Consider the test started.
176         /// </summary>
177         public void Start ()
178         {
179                 startTime = DateTime.UtcNow;
180         }
181
182         public bool HaveTimeLeft ()
183         {
184                 if (availableTime == TimeSpan.Zero)
185                         return true;
186                 var t = DateTime.UtcNow;
187                 var finishTime = startTime + availableTime - slack;
188                 return (t < finishTime);
189         }
190
191         private TimeSpan defaultSlack ()
192         {
193                 return TimeSpan.FromSeconds (5);
194         }
195
196         private TimeSpan initializeAvailableTime ()
197         {
198                 var e = System.Environment.GetEnvironmentVariable(ENV_TIMEOUT);
199                 double d;
200                 if (Double.TryParse(e, out d)) {
201                         return TimeSpan.FromSeconds(d);
202                 } else {
203                         return TimeSpan.Zero;
204                 }
205         }
206
207 }