~anuraj.p/nunitv2/GUIFindTest

« back to all changes in this revision

Viewing changes to src/NUnitCore/core/AsyncInvocationRegion.cs

  • Committer: Simone
  • Author(s): Simone Busoli
  • Date: 2012-10-28 14:36:34 UTC
  • Revision ID: simone.busoli@vienna-20121028143634-3bbd7uuche6vub4h
Support for async anonymous delegates in Throws assertions

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if CLR_2_0 || CLR_4_0
 
2
using System;
 
3
using System.Collections.Generic;
 
4
using System.Reflection;
 
5
using System.Runtime.Serialization;
 
6
using System.Threading;
 
7
 
 
8
namespace NUnit.Core
 
9
{
 
10
        internal abstract class AsyncInvocationRegion : IDisposable
 
11
        {
 
12
                private static readonly Type AsyncStateMachineAttribute = Type.GetType("System.Runtime.CompilerServices.AsyncStateMachineAttribute");
 
13
 
 
14
                private AsyncInvocationRegion()
 
15
                {
 
16
                }
 
17
 
 
18
                public static AsyncInvocationRegion Create(MethodInfo method)
 
19
                {
 
20
                        if (!IsAsyncOperation(method))
 
21
                                throw new InvalidOperationException(@"Either asynchronous support is not available or an attempt 
 
22
at wrapping a non-async method invocation in an async region was done");
 
23
 
 
24
                        if (method.ReturnType == typeof(void))
 
25
                                return new AsyncVoidInvocationRegion();
 
26
 
 
27
                        return new AsyncTaskInvocationRegion();
 
28
                }
 
29
 
 
30
                public static AsyncInvocationRegion Create(Delegate @delegate)
 
31
                {
 
32
                        return Create(@delegate.Method);
 
33
                }
 
34
 
 
35
                public static bool IsAsyncOperation(MethodInfo method)
 
36
                {
 
37
                        return AsyncStateMachineAttribute != null && method.IsDefined(AsyncStateMachineAttribute, false);
 
38
                }
 
39
 
 
40
                public static bool IsAsyncOperation(Delegate @delegate)
 
41
                {
 
42
                        return IsAsyncOperation(@delegate.Method);
 
43
                }
 
44
 
 
45
                /// <summary>
 
46
                /// Waits for pending asynchronous operations to complete, if appropriate,
 
47
                /// and returns a proper result of the invocation by unwrapping task results
 
48
                /// </summary>
 
49
                /// <param name="invocationResult">The raw result of the method invocation</param>
 
50
                /// <returns>The unwrapped result, if necessary</returns>
 
51
                /// <exception cref="AsyncInvocationException">If any exception is thrown while waiting for completion</exception>
 
52
                public abstract object WaitForPendingOperationsToComplete(object invocationResult);
 
53
 
 
54
                public virtual void Dispose()
 
55
                { }
 
56
 
 
57
                private class AsyncVoidInvocationRegion : AsyncInvocationRegion
 
58
                {
 
59
                        private readonly SynchronizationContext _previousContext;
 
60
                        private readonly AsyncSynchronizationContext _currentContext;
 
61
 
 
62
                        public AsyncVoidInvocationRegion()
 
63
                        {
 
64
                                _previousContext = SynchronizationContext.Current;
 
65
                                _currentContext = new AsyncSynchronizationContext();
 
66
                                SynchronizationContext.SetSynchronizationContext(_currentContext);
 
67
                        }
 
68
 
 
69
                        public override void Dispose()
 
70
                        {
 
71
                                SynchronizationContext.SetSynchronizationContext(_previousContext);
 
72
                        }
 
73
 
 
74
                        public override object WaitForPendingOperationsToComplete(object invocationResult)
 
75
                        {
 
76
                                try
 
77
                                {
 
78
                                        _currentContext.WaitForPendingOperationsToComplete();
 
79
                                        return invocationResult;
 
80
                                }
 
81
                                catch (Exception e)
 
82
                                {
 
83
                                        throw new AsyncInvocationException(e);
 
84
                                }
 
85
                        }
 
86
                }
 
87
 
 
88
                private class AsyncTaskInvocationRegion : AsyncInvocationRegion
 
89
                {
 
90
                        private const string TaskWaitMethod = "Wait";
 
91
                        private const string TaskResultProperty = "Result";
 
92
                        private const string SystemAggregateException = "System.AggregateException";
 
93
                        private const string InnerExceptionsProperty = "InnerExceptions";
 
94
                        private const BindingFlags TaskResultPropertyBindingFlags = BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public;
 
95
 
 
96
                        public override object WaitForPendingOperationsToComplete(object invocationResult)
 
97
                        {
 
98
                                try
 
99
                                {
 
100
                                        invocationResult.GetType().GetMethod(TaskWaitMethod, new Type[0]).Invoke(invocationResult, null);
 
101
                                }
 
102
                                catch (TargetInvocationException e)
 
103
                                {
 
104
                                        var innerExceptions = GetAllExceptions(e.InnerException);
 
105
 
 
106
                                        throw new AsyncInvocationException(innerExceptions[0]);
 
107
                                }
 
108
 
 
109
                                var taskResultProperty = invocationResult.GetType().GetProperty(TaskResultProperty, TaskResultPropertyBindingFlags);
 
110
 
 
111
                                return taskResultProperty != null ? taskResultProperty.GetValue(invocationResult, null) : invocationResult;
 
112
                        }
 
113
 
 
114
                        private static IList<Exception> GetAllExceptions(Exception exception)
 
115
                        {
 
116
                                if (SystemAggregateException.Equals(exception.GetType().FullName))
 
117
                                        return (IList<Exception>)exception.GetType().GetProperty(InnerExceptionsProperty).GetValue(exception, null);
 
118
 
 
119
                                return new[] { exception };
 
120
                        }
 
121
                }
 
122
        }
 
123
 
 
124
        [Serializable]
 
125
        internal class AsyncInvocationException : Exception
 
126
        {
 
127
                public AsyncInvocationException(Exception innerException)
 
128
                        : base("An exception has occurred during an asynchronous operation", innerException)
 
129
                {
 
130
                }
 
131
 
 
132
                protected AsyncInvocationException(SerializationInfo info, StreamingContext context)
 
133
                        : base(info, context)
 
134
                {
 
135
                }
 
136
        }
 
137
}
 
138
#endif
 
 
b'\\ No newline at end of file'