示例#1
0
        protected TryExpectedExceptionResult TryExpectedException(ExecutionContext context, Action action, string contextName, Func <Type, bool> expectedException, string expectedExceptionName, bool isTargetException, bool requireException = true)
        {
            Type caughtType = null;

            Exception caughtException = null;

            try
            {
                action();
            }
            catch (Exception ex)
            {
                if (isTargetException && ex is TargetInvocationException)
                {
                    ex = ((TargetInvocationException)ex).InnerException;
                }
                if (ex is NUnitException)
                {
                    ex = ex.InnerException;
                }
                caughtException = ex;
                if (caughtException != null)
                {
                    caughtType = caughtException.GetType();
                }
            }

            if (caughtException == null && !requireException)
            {
                return(TryExpectedExceptionResult.DidNotThrowException);
            }

            if (caughtType != null && expectedException(caughtType))
            {
                var loggedDiagnosticIds   = GetLoggedDiagnosticIds().OrderBy(x => x);
                var expectedDiagnosticIds = _expectedDiagnosticIds.OrderBy(x => x);
                string GetDiagnosticIds(IEnumerable <DiagnosticId> diagnosticIds) => string.Join(",", diagnosticIds);

                if (!loggedDiagnosticIds.SequenceEqual(expectedDiagnosticIds))
                {
                    context.CurrentResult.SetResult(ResultState.Failure, $"In {contextName} code, expecting diagnostic(s) to be logged with IDs {GetDiagnosticIds(_expectedDiagnosticIds)} but instead the following diagnostic(s) were logged: {GetDiagnosticIds(loggedDiagnosticIds)}");
                    return(TryExpectedExceptionResult.ThrewUnexpectedException);
                }
                else
                {
                    context.CurrentResult.SetResult(ResultState.Success);
                    return(TryExpectedExceptionResult.ThrewExpectedException);
                }
            }
            else if (caughtType != null)
            {
                context.CurrentResult.SetResult(ResultState.Failure, $"In {contextName} code, expected {expectedExceptionName} but got {caughtType.Name}. Exception: {caughtException}");
                return(TryExpectedExceptionResult.ThrewUnexpectedException);
            }
            else
            {
                context.CurrentResult.SetResult(ResultState.Failure, $"In {contextName} code, expected {expectedExceptionName} but no exception was thrown");
                return(TryExpectedExceptionResult.ThrewUnexpectedException);
            }
        }
        public override TestResult Execute(ExecutionContext context)
        {
            TestResult lastResult = null;
            for (int i = 0; i < GetRunCount(); i++)
            {
                lastResult = ExecuteMethod(context);
            }

            return lastResult;
        }
        protected TryExpectedExceptionResult TryExpectedException(ExecutionContext context, Action action, string contextName, Func <Type, bool> expectedException, string expectedExceptionName, bool isTargetException, bool requireException = true)
        {
            Type caughtType = null;

            Exception caughtException = null;

            try
            {
                action();
            }
            catch (Exception ex)
            {
                if (isTargetException && ex is TargetInvocationException)
                {
                    ex = ((TargetInvocationException)ex).InnerException;
                }
                if (ex is NUnitException)
                {
                    ex = ex.InnerException;
                }
                caughtException = ex;
                if (caughtException != null)
                {
                    caughtType = caughtException.GetType();
                }
            }

            if (caughtException == null && !requireException)
            {
                return(TryExpectedExceptionResult.DidNotThrowException);
            }

            if (caughtType != null && expectedException(caughtType))
            {
                if (!CheckExpectedDiagnostics(context, contextName))
                {
                    return(TryExpectedExceptionResult.ThrewUnexpectedException);
                }
                else
                {
                    context.CurrentResult.SetResult(ResultState.Success);
                    return(TryExpectedExceptionResult.ThrewExpectedException);
                }
            }
            else if (caughtType != null)
            {
                context.CurrentResult.SetResult(ResultState.Failure, $"In {contextName} code, expected {expectedExceptionName} but got {caughtType.Name}. Exception: {caughtException}");
                return(TryExpectedExceptionResult.ThrewUnexpectedException);
            }
            else
            {
                context.CurrentResult.SetResult(ResultState.Failure, $"In {contextName} code, expected {expectedExceptionName} but no exception was thrown");
                return(TryExpectedExceptionResult.ThrewUnexpectedException);
            }
        }
示例#4
0
        protected bool CheckExpectedDiagnostics(ExecutionContext context, string contextName)
        {
            var loggedDiagnosticIds   = GetLoggedDiagnosticIds().OrderBy(x => x);
            var expectedDiagnosticIds = _expectedDiagnosticIds.OrderBy(x => x);

            if (!loggedDiagnosticIds.SequenceEqual(expectedDiagnosticIds))
            {
                context.CurrentResult.SetResult(ResultState.Failure, $"In {contextName} code, expecting diagnostic(s) to be logged with IDs {GetDiagnosticIds(_expectedDiagnosticIds)} but instead the following diagnostic(s) were logged: {GetDiagnosticIds(loggedDiagnosticIds)}");
                return(false);
            }
            return(true);
        }
 private bool CheckExpectedDiagnostics(ExecutionContext context, string contextName)
 {
     var loggedDiagnosticIds = GetLoggedDiagnosticIds().OrderBy(x => x);
     var expectedDiagnosticIds = _expectedDiagnosticIds.OrderBy(x => x);
     string GetDiagnosticIds(IEnumerable<DiagnosticId> diagnosticIds) => string.Join(",", diagnosticIds);
     if (!loggedDiagnosticIds.SequenceEqual(expectedDiagnosticIds))
     {
         context.CurrentResult.SetResult(ResultState.Failure, $"In {contextName} code, expecting diagnostic(s) to be logged with IDs {GetDiagnosticIds(_expectedDiagnosticIds)} but instead the following diagnostic(s) were logged: {GetDiagnosticIds(loggedDiagnosticIds)}");
         return false;
     }
     return true;
 }
        public override TestResult Execute(ExecutionContext context)
        {
            // Make sure that we are not running in // the tests
            lock (typeof(TestCompilerCommandBase))
            {
                TestResult lastResult = null;
                for (int i = 0; i < GetRunCount(); i++)
                {
                    lastResult = ExecuteMethod(context);
                }

                return(lastResult);
            }
        }
        protected void TryExpectedException(ExecutionContext context, Action action, string contextName, Func <Type, bool> expectedException, string expectedExceptionName, bool isTargetException)
        {
            Type caughtType = null;

            Exception caughtException = null;

            try
            {
                action();
            }
            catch (Exception ex)
            {
                if (isTargetException && ex is TargetInvocationException)
                {
                    ex = ((TargetInvocationException)ex).InnerException;
                }
                if (ex is NUnitException)
                {
                    ex = ex.InnerException;
                }
                caughtException = ex;
                if (caughtException != null)
                {
                    caughtType = caughtException.GetType();
                }
            }

            if (caughtType != null && expectedException(caughtType))
            {
                context.CurrentResult.SetResult(ResultState.Success);
            }
            else if (caughtType != null)
            {
                context.CurrentResult.SetResult(ResultState.Failure, $"In {contextName} code, expected {expectedExceptionName} but got {caughtType.Name}. Exception: {caughtException}");
            }
            else
            {
                context.CurrentResult.SetResult(ResultState.Failure, $"In {contextName} code, expected {expectedExceptionName} but no exception was thrown");
            }
        }
示例#8
0
 protected abstract TestResult HandleCompilerException(ExecutionContext context, MethodInfo methodInfo);
示例#9
0
 protected abstract Delegate CompileDelegate(ExecutionContext context, MethodInfo methodInfo, Type delegateType);
示例#10
0
 protected abstract void CompleteTest(ExecutionContext context);
示例#11
0
        private TestResult ExecuteMethod(ExecutionContext context)
        {
            Setup();
            var methodInfo = _originalMethod.Method.MethodInfo;

            var arguments = GetArgumentsArray(_originalMethod);

            // Special case for Compiler Exceptions when IL can't be translated
            if (_expectCompilerException)
            {
                // We still need to transform arguments here in case there's a function pointer that we expect to fail compilation.
                var expectedExceptionResult = TryExpectedException(
                    context,
                    () => TransformArguments(_originalMethod.Method.MethodInfo, arguments, out _, out _),
                    "Transforming arguments",
                    type => true,
                    "Any exception",
                    false,
                    false);
                if (expectedExceptionResult != TryExpectedExceptionResult.DidNotThrowException)
                {
                    return(context.CurrentResult);
                }

                return(HandleCompilerException(context, methodInfo));
            }

            object[] nativeArgs;
            Type[]   nativeArgTypes;
            TransformArguments(_originalMethod.Method.MethodInfo, arguments, out nativeArgs, out nativeArgTypes);

            bool isInRegistry = false;
            Func <object, object[], object> nativeDelegateCaller;
            var delegateType = CreateNativeDelegateType(_originalMethod.Method.MethodInfo.ReturnType, nativeArgTypes, out isInRegistry, out nativeDelegateCaller);

            if (!isInRegistry)
            {
                Console.WriteLine($"Warning, the delegate for the method `{_originalMethod.Method}` has not been generated");
            }

            var compiledFunction = CompileDelegate(context, methodInfo, delegateType);

            if (compiledFunction == null)
            {
                return(context.CurrentResult);
            }

            // Special case if we have an expected exception
            if (_expectedException != null)
            {
                if (TryExpectedException(context, () => _originalMethod.Method.Invoke(context.TestObject, arguments), ".NET", type => type == _expectedException, _expectedException.FullName, false) != TryExpectedExceptionResult.ThrewExpectedException)
                {
                    return(context.CurrentResult);
                }

                if (TryExpectedException(context, () => nativeDelegateCaller(compiledFunction, nativeArgs), "Native", type => type == _expectedException, _expectedException.FullName, true) != TryExpectedExceptionResult.ThrewExpectedException)
                {
                    return(context.CurrentResult);
                }
            }
            else
            {
                // We are forced to run native before managed, because on IL2CPP, if a parameter
                // is a ref, it will keep the same memory location for both managed and burst
                // while in .NET CLR we have a different behavior
                // The result is that on functions expecting the same input value through the ref
                // it won't be anymore true because the managed could have modified the value before
                // burst
                var resultNative = nativeDelegateCaller(compiledFunction, nativeArgs);
                var resultClr    = _originalMethod.Method.Invoke(context.TestObject, arguments);

                var overrideResultOnMono = _originalMethod.Properties.Get("OverrideResultOnMono");
                if (overrideResultOnMono != null)
                {
                    Console.WriteLine($"Using OverrideResultOnMono: `{overrideResultOnMono}` instead of `{resultClr}` compare to burst `{resultNative}`");
                    resultClr = overrideResultOnMono;
                }

                // Use our own version (for handling correctly float precision)
                AssertHelper.AreEqual(resultClr, resultNative, GetULP());

                // Validate deterministic outputs - Disabled for now
                //RunDeterminismValidation(_originalMethod, resultNative);

                // Allow to process native result
                ProcessNativeResult(_originalMethod, resultNative);

                context.CurrentResult.SetResult(ResultState.Success);
            }

            // Check that the method is actually in the registry
            Assert.True(isInRegistry, "The test method is not in the registry, recompile the project with the updated StaticDelegateRegistry.generated.cs");

            // Make an attempt to clean up arguments (to reduce wasted native heap memory)
            DisposeObjects(arguments);
            DisposeObjects(nativeArgs);


            CompleteTest(context);

            return(context.CurrentResult);
        }
        private TestResult ExecuteMethod(ExecutionContext context)
        {
            Setup();
            var methodInfo = _originalMethod.Method.MethodInfo;

            // Special case for Compiler Expceptions when IL can't be translated
            if (_expectCompilerException)
            {
                return(HandleCompilerException(context, methodInfo));
            }

            var arguments = GetArgumentsArray(_originalMethod);

            object[] nativeArgs;
            Type[]   nativeArgTypes;
            TransformArguments(_originalMethod.Method.MethodInfo, arguments, out nativeArgs, out nativeArgTypes);

            bool isInRegistry = false;
            Func <object, object[], object> nativeDelegateCaller;
            var delegateType = CreateNativeDelegateType(_originalMethod.Method.MethodInfo.ReturnType, nativeArgTypes, out isInRegistry, out nativeDelegateCaller);

            if (!isInRegistry)
            {
                Console.WriteLine($"Warning, the delegate for the method `{_originalMethod.Method}` has not been generated");
            }

            var compiledFunction = CompileDelegate(context, methodInfo, delegateType);

            if (compiledFunction == null)
            {
                return(context.CurrentResult);
            }

            // Special case if we have an expected exception
            if (_expectedException != null)
            {
                TryExpectedException(context, () => _originalMethod.Method.Invoke(context.TestObject, arguments), ".NET", type => type == _expectedException, _expectedException.FullName, false);
                if (context.CurrentResult.ResultState.Equals(ResultState.Success))
                {
                    TryExpectedException(context, () => nativeDelegateCaller(compiledFunction, nativeArgs), "Native", type => type == _expectedException, _expectedException.FullName, true);
                }
            }
            else
            {
                var resultNative = nativeDelegateCaller(compiledFunction, nativeArgs);
                var resultClr    = _originalMethod.Method.Invoke(context.TestObject, arguments);

                var overrideResultOnMono = _originalMethod.Properties.Get("OverrideResultOnMono");
                if (overrideResultOnMono != null)
                {
                    Console.WriteLine($"Using OverrideResultOnMono: `{overrideResultOnMono}` instead of `{resultClr}` compare to burst `{resultNative}`");
                    resultClr = overrideResultOnMono;
                }

                // Use our own version (for handling correctly float precision)
                AssertHelper.AreEqual(resultClr, resultNative, GetULP());

                // Allow to process native result
                ProcessNativeResult(_originalMethod, resultNative);

                context.CurrentResult.SetResult(ResultState.Success);
            }

            // Check that the method is actually in the registry
            Assert.True(isInRegistry, "The test method is not in the registry, recompile the project with the updated StaticDelegateRegistry.generated.cs");

            // Make an attempt to clean up arguments (to reduce wasted native heap memory)
            DisposeObjects(arguments);
            DisposeObjects(nativeArgs);


            CompleteTest(context);

            return(context.CurrentResult);
        }
 protected abstract unsafe Delegate CompileDelegate(ExecutionContext context, MethodInfo methodInfo, Type delegateType, byte *returnBox, out Type returnBoxType);
 protected virtual void PostAssert(ExecutionContext context)
 {
 }
        private unsafe TestResult ExecuteMethod(ExecutionContext context)
        {
            byte *returnBox = stackalloc byte[MaxReturnBoxSize];

            Setup();
            var methodInfo = _originalMethod.Method.MethodInfo;

            var arguments = GetArgumentsArray(_originalMethod);

            // Special case for Compiler Exceptions when IL can't be translated
            if (_expectCompilerException)
            {
                // We still need to transform arguments here in case there's a function pointer that we expect to fail compilation.
                var expectedExceptionResult = TryExpectedException(
                    context,
                    () => TransformArguments(_originalMethod.Method.MethodInfo, arguments, out _, out _, returnBox, out _),
                    "Transforming arguments",
                    type => true,
                    "Any exception",
                    false,
                    false);
                if (expectedExceptionResult != TryExpectedExceptionResult.DidNotThrowException)
                {
                    return(context.CurrentResult);
                }

                return(HandleCompilerException(context, methodInfo));
            }

            object[] nativeArgs;
            Type[]   nativeArgTypes;
            TransformArguments(_originalMethod.Method.MethodInfo, arguments, out nativeArgs, out nativeArgTypes, returnBox, out Type returnBoxType);

            bool isInRegistry = false;
            Func <object, object[], object> nativeDelegateCaller;
            var delegateType = CreateNativeDelegateType(_originalMethod.Method.MethodInfo.ReturnType, nativeArgTypes, out isInRegistry, out nativeDelegateCaller);

            if (!isInRegistry)
            {
                Console.WriteLine($"Warning, the delegate for the method `{_originalMethod.Method}` has not been generated");
            }

            Delegate compiledFunction;

            try
            {
                compiledFunction = CompileDelegate(context, methodInfo, delegateType, returnBox, out _);
            }
            catch (Exception ex) when(_expectedException != null && ex.GetType() == _expectedException)
            {
                context.CurrentResult.SetResult(ResultState.Success);
                return(context.CurrentResult);
            }

            Assert.IsTrue(returnBoxType == null || Marshal.SizeOf(returnBoxType) <= MaxReturnBoxSize);

            if (compiledFunction == null)
            {
                return(context.CurrentResult);
            }

            // Check for expected compiler warnings (we'll check for compiler errors below,
            // but this is for tests that we expect to pass but still log a warning).
            if (!CheckExpectedDiagnostics(context, "Compiling code"))
            {
                return(context.CurrentResult);
            }

            if (_compileOnly) // If the test only wants to compile the code, bail now.
            {
                return(context.CurrentResult);
            }
            else if (_expectedException != null) // Special case if we have an expected exception
            {
                if (TryExpectedException(context, () => _originalMethod.Method.Invoke(context.TestObject, arguments), ".NET", type => type == _expectedException, _expectedException.FullName, false) != TryExpectedExceptionResult.ThrewExpectedException)
                {
                    return(context.CurrentResult);
                }

                if (TryExpectedException(context, () => nativeDelegateCaller(compiledFunction, nativeArgs), "Native", type => type == _expectedException, _expectedException.FullName, true) != TryExpectedExceptionResult.ThrewExpectedException)
                {
                    return(context.CurrentResult);
                }
            }
            else
            {
                object resultNative = null;

                // We are forced to run native before managed, because on IL2CPP, if a parameter
                // is a ref, it will keep the same memory location for both managed and burst
                // while in .NET CLR we have a different behavior
                // The result is that on functions expecting the same input value through the ref
                // it won't be anymore true because the managed could have modified the value before
                // burst

                // ------------------------------------------------------------------
                // Run Native (Before)
                // ------------------------------------------------------------------
                if (!RunManagedBeforeNative)
                {
                    resultNative = nativeDelegateCaller(compiledFunction, nativeArgs);
                    if (returnBoxType != null)
                    {
                        resultNative = Marshal.PtrToStructure((IntPtr)returnBox, returnBoxType);
                    }
                }

                // ------------------------------------------------------------------
                // Run Managed
                // ------------------------------------------------------------------
                object resultClr;
                // This option skips running the managed version completely
                var overrideManagedResult = _originalMethod.Properties.Get("OverrideManagedResult");
                if (overrideManagedResult != null)
                {
                    Console.WriteLine($"Using OverrideManagedResult: `{overrideManagedResult}` to compare to burst `{resultNative}`, managed version not run");
                    resultClr = overrideManagedResult;
                }
                else
                {
                    resultClr = _originalMethod.Method.Invoke(context.TestObject, arguments);

                    if (returnBoxType != null)
                    {
                        resultClr = Marshal.PtrToStructure((IntPtr)returnBox, returnBoxType);
                    }
                }

                var overrideResultOnMono = _originalMethod.Properties.Get("OverrideResultOnMono");
                if (overrideResultOnMono != null)
                {
                    Console.WriteLine($"Using OverrideResultOnMono: `{overrideResultOnMono}` instead of `{resultClr}` compare to burst `{resultNative}`");
                    resultClr = overrideResultOnMono;
                }

                // ------------------------------------------------------------------
                // Run Native (After)
                // ------------------------------------------------------------------
                if (RunManagedBeforeNative)
                {
                    resultNative = nativeDelegateCaller(compiledFunction, nativeArgs);
                    if (returnBoxType != null)
                    {
                        resultNative = Marshal.PtrToStructure((IntPtr)returnBox, returnBoxType);
                    }
                }

                // Use our own version (for handling correctly float precision)
                AssertHelper.AreEqual(resultClr, resultNative, GetULP());

                // Validate deterministic outputs - Disabled for now
                //RunDeterminismValidation(_originalMethod, resultNative);

                // Allow to process native result
                ProcessNativeResult(_originalMethod, resultNative);

                context.CurrentResult.SetResult(ResultState.Success);

                PostAssert(context);
            }

            // Check that the method is actually in the registry
            Assert.True(isInRegistry, "The test method is not in the registry, recompile the project with the updated StaticDelegateRegistry.generated.cs");

            // Compile the method once again, this time for Arm CPU to check against gold asm images
            CompileDelegateForArm(methodInfo);

            // Make an attempt to clean up arguments (to reduce wasted native heap memory)
            DisposeObjects(arguments);
            DisposeObjects(nativeArgs);

            CompleteTest(context);

            return(context.CurrentResult);
        }