2 using System.Reflection;
3 using System.Collections.Generic;
5 [AttributeUsageAttribute(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
6 public class CategoryAttribute : Attribute
8 public CategoryAttribute (string category) {
12 public string Category {
17 public class TestDriver {
19 static public int RunTests (Type type, string[] args) {
20 int failed = 0, ran = 0;
25 bool do_timings = false;
29 DateTime start, end = DateTime.Now;
33 var exclude = new Dictionary<string, string> ();
34 List<string> run_only = new List<string> ();
35 if (args != null && args.Length > 0) {
36 for (j = 0; j < args.Length;) {
37 if (args [j] == "--time") {
40 } else if (args [j] == "--iter") {
41 iterations = Int32.Parse (args [j + 1]);
43 } else if ((args [j] == "-v") || (args [j] == "--verbose")) {
46 } else if ((args [j] == "-q") || (args [j] == "--quiet")) {
51 } else if (args [j] == "--exclude") {
52 exclude [args [j + 1]] = args [j + 1];
54 } else if (args [j] == "--run-only") {
55 run_only.Add (args [j + 1]);
58 Console.WriteLine ("Unknown argument: " + args [j]);
64 methods = type.GetMethods (BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static);
65 for (int iter = 0; iter < iterations; ++iter) {
66 for (i = 0; i < methods.Length; ++i) {
67 name = methods [i].Name;
68 if (!name.StartsWith ("test_", StringComparison.Ordinal))
70 if (run_only.Count > 0) {
72 for (j = 0; j < run_only.Count; j++) {
73 if (name.EndsWith (run_only [j])) {
81 if (exclude.Count > 0) {
82 var attrs = methods [i].GetCustomAttributes (typeof (CategoryAttribute), false);
84 foreach (CategoryAttribute attr in attrs) {
85 if (exclude.ContainsKey (attr.Category))
90 Console.WriteLine ("Skipping '{0}'.", name);
95 for (j = 5; j < name.Length; ++j)
96 if (!Char.IsDigit (name [j]))
99 Console.WriteLine ("Running '{0}' ...", name);
100 expected = Int32.Parse (name.Substring (5, j - 5));
101 start = DateTime.Now;
102 result = (int)methods [i].Invoke (null, null);
105 long tdiff = end.Ticks - start.Ticks;
106 int mdiff = (int)tdiff/10000;
108 Console.WriteLine ("{0} took {1} ms", name, mdiff);
111 if (result != expected) {
113 Console.WriteLine ("{0} failed: got {1}, expected {2}", name, result, expected);
119 Console.WriteLine ("Total ms: {0}", tms);
122 Console.WriteLine ("Regression tests: {0} ran, {1} skipped, {2} failed in {3}", ran, nskipped, failed, type);
124 Console.WriteLine ("Regression tests: {0} ran, {1} failed in {2}", ran, failed, type);
128 //Console.WriteLine ("Regression tests: {0} ran, {1} failed in [{2}]{3}", ran, failed, type.Assembly.GetName().Name, type);
131 static public int RunTests (Type type) {
132 return RunTests (type, null);
136 /// Provide tests with the ability to find out how much time they have to run before being timed out.
137 public class TestTimeout {
138 const string ENV_TIMEOUT = "TEST_DRIVER_TIMEOUT_SEC";
139 private readonly TimeSpan availableTime;
140 private TimeSpan slack;
141 private DateTime startTime;
144 /// How much time the test runner provided for us or TimeSpan.Zero if there is no bound.
146 public TimeSpan AvailableTime { get { return availableTime; } }
148 public DateTime StartTime { get { return startTime; } }
150 /// <summary> Extra time to add when deciding if there
151 /// is still time to run. Bigger slack means less
154 public TimeSpan Slack {
155 get { return slack; }
156 set { slack = value; }
159 public TestTimeout () {
160 availableTime = initializeAvailableTime ();
161 slack = defaultSlack ();
165 /// Consider the test started.
169 startTime = DateTime.UtcNow;
172 public bool HaveTimeLeft ()
174 if (availableTime == TimeSpan.Zero)
176 var t = DateTime.UtcNow;
177 var finishTime = startTime + availableTime - slack;
178 return (t < finishTime);
181 private TimeSpan defaultSlack ()
183 return TimeSpan.FromSeconds (5);
186 private TimeSpan initializeAvailableTime ()
188 var e = System.Environment.GetEnvironmentVariable(ENV_TIMEOUT);
190 if (Double.TryParse(e, out d)) {
191 return TimeSpan.FromSeconds(d);
193 return TimeSpan.Zero;