protected void Test(Delegate d, object knownResult = null, bool knownResultNull = false) { var mi = d.Method; //var stackTrace = new StackTrace(); //var testMethod = stackTrace.GetFrame(1).GetMethod().Name; //Console.WriteLine("Test++ {0}", testMethod); var method = CecilHelper.GetMethod(d); var js = Js.CreateFrom(method, this.Verbose, true).Js; if (this.Verbose) { Console.WriteLine(js); } var testDefaultParamGen = mi.GetCustomAttribute <ParamAttribute>() ?? mi.DeclaringType.GetCustomAttribute <ParamAttribute>() ?? defaultParamGen; var withinAttr = mi.GetCustomAttribute <WithinAttribute>(); var withinUlpsAttr = mi.GetCustomAttribute <WithinUlpsAttribute>(); var withinPercentAttr = mi.GetCustomAttribute <WithinPercentAttribute>(); var icAttr = mi.GetCustomAttribute <IterationCountAttribute>(); var minIterations = mi.GetParameters().Max(x => (x.GetCustomAttribute <ParamAttribute>() ?? testDefaultParamGen).MinIterations); int iterationCount; if (icAttr != null) { iterationCount = icAttr.IterationCount; } else { iterationCount = method.Parameters.Any() ? defaultTestIterations : 1; } if (iterationCount < minIterations) { iterationCount = minIterations.Value; } var range = Enumerable.Range(0, iterationCount); var args = range.Select(i => this.CreateArgs(mi, i, testDefaultParamGen)).ToArray(); var runResults = range.Select(i => { object r = null; Exception e = null; try { r = d.DynamicInvoke(args[i]); } catch (TargetInvocationException ex) { e = ex.InnerException; } if (knownResult != null || knownResultNull) { Assert.That(r, Is.EqualTo(knownResult)); } return(Tuple.Create(r, e)); }).ToArray(); var usingNamespace = NamespaceSetup.Chrome != null; var chrome = usingNamespace ? NamespaceSetup.Chrome : new ChromeDriver(); try { for (int i = 0; i < args.Length; i++) { var arg = args[i]; if (!mi.IsStatic) { arg = arg.Prepend(null).ToArray(); } var jsArgs = string.Join(", ", arg.Select(x => this.ConvertArgToJavascript(x))); //Console.WriteLine("JS args: '{0}'", jsArgs); var jsCall = @" var r; try { r = main(" + jsArgs + @"); console.log(r); } catch (e) { return {exception:[e._.$$TypeNamespace, e._.$$TypeName, e.$$_message]}; } if (typeof r === 'number') { if (isNaN(r)) { return 'NaN'; } if (r === Number.POSITIVE_INFINITY) { return '+Infinity'; } if (r === Number.NEGATIVE_INFINITY) { return '-Infinity'; } return r.toString(); } return r; "; var jsResult = chrome.ExecuteScript(js + jsCall); if (jsResult != null && jsResult is Dictionary <string, object> ) { // Exception Assert.That(runResults[i].Item1, Is.Null, "JS threw exception, but exception not expected"); var jsExInfo = ((ICollection <object>)((Dictionary <string, object>)jsResult)["exception"]).Cast <string>().ToArray(); var jsExType = jsExInfo[0] + "." + jsExInfo[1]; var expectedExType = runResults[i].Item2.GetType().FullName; Assert.That(jsExType, Is.EqualTo(expectedExType)); } else { var returnTypeCode = Type.GetTypeCode(d.Method.ReturnType); if (jsResult != null && jsResult.GetType() != d.Method.ReturnType) { switch (returnTypeCode) { case TypeCode.Int64: { var array = (IList <object>)jsResult; var hi = Convert.ToUInt64(array[0]); var lo = Convert.ToUInt64(array[1]); jsResult = (long)(((ulong)hi) << 32 | (ulong)lo); } break; case TypeCode.UInt64: { var array = (IList <object>)jsResult; var hi = Convert.ToUInt64(array[0]); var lo = Convert.ToUInt64(array[1]); jsResult = ((ulong)hi) << 32 | (ulong)lo; } break; case TypeCode.Single: switch (jsResult as string) { case "NaN": jsResult = Single.NaN; break; case "+Infinity": jsResult = Single.PositiveInfinity; break; case "-Infinity": jsResult = Single.NegativeInfinity; break; default: jsResult = Single.Parse(jsResult as string); break; } break; case TypeCode.Double: switch (jsResult as string) { case "NaN": jsResult = Double.NaN; break; case "+Infinity": jsResult = Double.PositiveInfinity; break; case "-Infinity": jsResult = Double.NegativeInfinity; break; default: jsResult = Double.Parse(jsResult as string); break; } break; case TypeCode.Char: jsResult = (char)int.Parse(jsResult as string); break; default: jsResult = Convert.ChangeType(jsResult, d.Method.ReturnType); break; } } Assert.That(runResults[i].Item2, Is.Null, "Exception expected in JS, but not thrown"); EqualConstraint equalTo = Is.EqualTo(runResults[i].Item1); IResolveConstraint expected = equalTo; if (withinAttr != null) { expected = equalTo.Within(withinAttr.Delta); } else if (withinUlpsAttr != null) { expected = equalTo.Within(withinUlpsAttr.Ulps).Ulps; } else if (withinPercentAttr != null) { expected = equalTo.Within(withinPercentAttr.Percent).Percent; } else { switch (returnTypeCode) { case TypeCode.Single: // Always allow a little inaccuracy with Singles expected = equalTo.Within(0.0001).Percent; break; case TypeCode.Double: expected = equalTo.Within(0.0001).Percent; break; } } Assert.That(jsResult, expected); } } } finally { if (!usingNamespace) { chrome.Quit(); chrome.Dispose(); } } //Console.WriteLine("Test-- {0}", testMethod); }
public static void That(DateTime?result, EqualConstraint constraint) => Assert.That(result, constraint.Within(1).Seconds);