~a-schlapsi/nunit-3.0/linux-makefile

« back to all changes in this revision

Viewing changes to src/framework/NUnitLite/TestCase.cs

  • Committer: Andreas Schlapsi
  • Date: 2010-01-23 23:14:05 UTC
  • mfrom: (18.1.137 work)
  • Revision ID: a.schlapsi@gmx.at-20100123231405-17deqoh18nfnbq1j
Merged with trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// ***********************************************************************
2
 
// Copyright (c) 2007 Charlie Poole
3
 
//
4
 
// Permission is hereby granted, free of charge, to any person obtaining
5
 
// a copy of this software and associated documentation files (the
6
 
// "Software"), to deal in the Software without restriction, including
7
 
// without limitation the rights to use, copy, modify, merge, publish,
8
 
// distribute, sublicense, and/or sell copies of the Software, and to
9
 
// permit persons to whom the Software is furnished to do so, subject to
10
 
// the following conditions:
11
 
// 
12
 
// The above copyright notice and this permission notice shall be
13
 
// included in all copies or substantial portions of the Software.
14
 
// 
15
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
 
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
 
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
 
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
 
// ***********************************************************************
23
 
 
24
 
using System;
25
 
using System.Reflection;
26
 
using System.Collections;
27
 
using NUnit.Framework;
28
 
 
29
 
namespace NUnitLite
30
 
{
31
 
    /// <summary>
32
 
    /// TestCase represents a single executable test
33
 
    /// </summary>
34
 
    public class TestCase : ITest
35
 
    {
36
 
        #region Instance Variables
37
 
        private string name;
38
 
        private string fullName;
39
 
 
40
 
        private object fixture;
41
 
        private MethodInfo method;
42
 
 
43
 
        private MethodInfo setup;
44
 
        private MethodInfo teardown;
45
 
 
46
 
        private RunState runState = RunState.Runnable;
47
 
        private string ignoreReason;
48
 
 
49
 
        private IDictionary properties;
50
 
 
51
 
        private object[] args;
52
 
        #endregion
53
 
 
54
 
        #region Constructors
55
 
        /// <summary>
56
 
        /// Initializes a new instance of the <see cref="TestCase"/> class.
57
 
        /// </summary>
58
 
        /// <param name="name">The name of the test.</param>
59
 
        public TestCase(string name)
60
 
        {
61
 
            this.name = this.fullName = name;
62
 
        }
63
 
 
64
 
        /// <summary>
65
 
        /// Initializes a new instance of the <see cref="TestCase"/> class.
66
 
        /// </summary>
67
 
        /// <param name="method">The method implementing this test case.</param>
68
 
        public TestCase(MethodInfo method)
69
 
        {
70
 
            Initialize(method, null, null);
71
 
        }
72
 
 
73
 
        /// <summary>
74
 
        /// Initializes a new instance of the <see cref="TestCase"/> class.
75
 
        /// </summary>
76
 
        /// <param name="name">The name.</param>
77
 
        /// <param name="fixture">The fixture.</param>
78
 
        public TestCase(string name, object fixture)
79
 
        {
80
 
            Initialize(fixture.GetType().GetMethod(name), fixture, null);
81
 
        }
82
 
 
83
 
        private void Initialize(MethodInfo method, object fixture, object[] args)
84
 
        {
85
 
            this.method = method;
86
 
            this.args = args;
87
 
 
88
 
            this.name = MethodHelper.GetDisplayName(method, args);
89
 
 
90
 
            this.fullName = method.ReflectedType.FullName + "." + this.name;
91
 
            this.fixture = fixture;
92
 
            if ( fixture == null )
93
 
                this.fixture = Reflect.Construct(method.ReflectedType, null);
94
 
 
95
 
            if (HasValidSignature(method, args))
96
 
            {
97
 
                IgnoreAttribute ignore = (IgnoreAttribute)Reflect.GetAttribute(this.method, typeof(IgnoreAttribute));
98
 
 
99
 
                if (ignore != null)
100
 
                {
101
 
                    this.runState = RunState.Ignored;
102
 
                    this.ignoreReason = ignore.Reason;
103
 
                }
104
 
            }
105
 
 
106
 
            foreach (MethodInfo m in method.ReflectedType.GetMethods())
107
 
            {
108
 
                if (m.IsDefined(typeof(SetUpAttribute), true))
109
 
                    this.setup = m;
110
 
 
111
 
                if (m.IsDefined(typeof(TearDownAttribute), true))
112
 
                    this.teardown = m;
113
 
            }
114
 
        }
115
 
 
116
 
        /// <summary>
117
 
        /// Initializes a new instance of the <see cref="TestCase"/> class.
118
 
        /// </summary>
119
 
        /// <param name="method">The method implementing the test case.</param>
120
 
        /// <param name="args">The args to be used in calling the method.</param>
121
 
        public TestCase(MethodInfo method, object[] args)
122
 
        {
123
 
            Initialize(method, null, args);
124
 
        }
125
 
        #endregion
126
 
 
127
 
        #region Properties
128
 
        /// <summary>
129
 
        /// Gets the name of the test.
130
 
        /// </summary>
131
 
        /// <value>The name.</value>
132
 
        public string Name
133
 
        {
134
 
            get { return name; }
135
 
        }
136
 
 
137
 
        /// <summary>
138
 
        /// Gets the full name of the test.
139
 
        /// </summary>
140
 
        /// <value>The full name.</value>
141
 
        public string FullName
142
 
        {
143
 
            get { return fullName; }
144
 
        }
145
 
 
146
 
        /// <summary>
147
 
        /// Gets or sets the run state of the test.
148
 
        /// </summary>
149
 
        /// <value>The state of the run.</value>
150
 
        public RunState RunState
151
 
        {
152
 
            get { return runState; }
153
 
            set { runState = value; }
154
 
        }
155
 
 
156
 
        /// <summary>
157
 
        /// Gets or sets the ignore reason.
158
 
        /// </summary>
159
 
        /// <value>The ignore reason.</value>
160
 
        public string IgnoreReason
161
 
        {
162
 
            get { return ignoreReason; }
163
 
            set { ignoreReason = value; }
164
 
        }
165
 
 
166
 
        /// <summary>
167
 
        /// Gets the properties of the test.
168
 
        /// </summary>
169
 
        /// <value>The properties dictionary.</value>
170
 
        public System.Collections.IDictionary Properties
171
 
        {
172
 
            get 
173
 
            {
174
 
                if (properties == null)
175
 
                {
176
 
                    properties = new Hashtable();
177
 
 
178
 
                    object[] attrs = this.method.GetCustomAttributes(typeof(PropertyAttribute), true);
179
 
                    foreach (PropertyAttribute attr in attrs)
180
 
                        foreach( DictionaryEntry entry in attr.Properties )
181
 
                            this.Properties[entry.Key] = entry.Value;
182
 
                }
183
 
 
184
 
                return properties; 
185
 
            }
186
 
        }
187
 
 
188
 
        /// <summary>
189
 
        /// Gets the test case count.
190
 
        /// </summary>
191
 
        /// <value>The test case count.</value>
192
 
        public int TestCaseCount
193
 
        {
194
 
            get { return 1; }
195
 
        }
196
 
        #endregion
197
 
 
198
 
        #region Public Methods
199
 
        /// <summary>
200
 
        /// Runs this test.
201
 
        /// </summary>
202
 
        /// <returns>A TestResult</returns>
203
 
        public TestResult Run()
204
 
        {
205
 
            return Run( new NullListener() );
206
 
        }
207
 
 
208
 
        /// <summary>
209
 
        /// Runs this test
210
 
        /// </summary>
211
 
        /// <param name="listener">A TestListener to handle test events</param>
212
 
        /// <returns>A TestResult</returns>
213
 
        public TestResult Run(TestListener listener)
214
 
        {
215
 
            listener.TestStarted(this);
216
 
 
217
 
            TestResult result = new TestResult(this);
218
 
            Run(result, listener);
219
 
 
220
 
            listener.TestFinished(result);
221
 
 
222
 
            return result;
223
 
        }
224
 
        #endregion
225
 
 
226
 
        #region Protected Methods
227
 
        /// <summary>
228
 
        /// Performs SetUp for the test.
229
 
        /// </summary>
230
 
        protected virtual void SetUp() 
231
 
        {
232
 
            if (setup != null)
233
 
            {
234
 
                Assert.That(HasValidSetUpTearDownSignature(setup), "Invalid SetUp method: must return void and have no arguments");
235
 
                InvokeMethod(setup);
236
 
            }
237
 
        }
238
 
 
239
 
        /// <summary>
240
 
        /// Performs TearDown for the test.
241
 
        /// </summary>
242
 
        protected virtual void TearDown() 
243
 
        {
244
 
            if (teardown != null)
245
 
            {
246
 
                Assert.That(HasValidSetUpTearDownSignature(teardown), "Invalid TearDown method: must return void and have no arguments");
247
 
                InvokeMethod(teardown);
248
 
            }
249
 
        }
250
 
 
251
 
        /// <summary>
252
 
        /// Runs the test and handles any exceptions.
253
 
        /// </summary>
254
 
        /// <param name="result">The result.</param>
255
 
        /// <param name="listener">The listener.</param>
256
 
        protected virtual void Run(TestResult result, TestListener listener)
257
 
        {
258
 
            IgnoreAttribute ignore = (IgnoreAttribute)Reflect.GetAttribute(method, typeof(IgnoreAttribute));
259
 
            if (this.RunState == RunState.NotRunnable)
260
 
                result.Failure(this.ignoreReason);
261
 
            else if ( ignore != null )
262
 
                result.NotRun(ignore.Reason);
263
 
            else
264
 
            {
265
 
                try
266
 
                {
267
 
                    RunBare();
268
 
                    result.Success();
269
 
                }
270
 
                catch (NUnitLiteException nex)
271
 
                {
272
 
                    result.RecordException(nex.InnerException);
273
 
                }
274
 
#if !NETCF_1_0
275
 
                catch (System.Threading.ThreadAbortException)
276
 
                {
277
 
                    throw;
278
 
                }
279
 
#endif
280
 
                catch (Exception ex)
281
 
                {
282
 
                    result.RecordException(ex);
283
 
                }
284
 
            }
285
 
        }
286
 
 
287
 
        /// <summary>
288
 
        /// Runs SetUp, invokes the test and runs TearDown.
289
 
        /// </summary>
290
 
        protected void RunBare()
291
 
        {
292
 
            SetUp();
293
 
            try
294
 
            {
295
 
                RunTest();
296
 
            }
297
 
            finally
298
 
            {
299
 
                TearDown();
300
 
            }
301
 
        }
302
 
 
303
 
        /// <summary>
304
 
        /// Runs the test.
305
 
        /// </summary>
306
 
        protected virtual void RunTest()
307
 
        {
308
 
            try
309
 
            {
310
 
                InvokeMethod( this.method, this.args );
311
 
                ProcessNoException(this.method);
312
 
            }
313
 
            catch (NUnitLiteException ex)
314
 
            {
315
 
                ProcessException(this.method, ex.InnerException);
316
 
            }
317
 
        }
318
 
 
319
 
        /// <summary>
320
 
        /// Invokes a method on the test fixture.
321
 
        /// </summary>
322
 
        /// <param name="method">The method.</param>
323
 
        /// <param name="args">The args.</param>
324
 
        protected void InvokeMethod(MethodInfo method, params object[] args)
325
 
        {
326
 
            Reflect.InvokeMethod(method, this.fixture, args);
327
 
        }
328
 
        #endregion
329
 
 
330
 
        #region Private Methods       
331
 
        /// <summary>
332
 
        /// Determines whether the method has a valid signature and sets
333
 
        /// the RunState to NotRunnable if it does not.
334
 
        /// </summary>
335
 
        /// <param name="method">The method.</param>
336
 
        /// <param name="args">The args.</param>
337
 
        /// <returns>
338
 
        ///     <c>true</c> if the signature is valid; otherwise, <c>false</c>.
339
 
        /// </returns>
340
 
        private bool HasValidSignature(MethodInfo method, object[] args)
341
 
        {
342
 
            if (method.ReturnType != typeof(void))
343
 
            {
344
 
                this.runState = RunState.NotRunnable;
345
 
                this.ignoreReason = "A TestMethod must return void";
346
 
                return false;
347
 
            }
348
 
            
349
 
            int argsNeeded = method.GetParameters().Length;
350
 
            int argsPassed = args == null ? 0 : args.Length;
351
 
 
352
 
            if (argsNeeded == 0 && argsPassed > 0)
353
 
            {
354
 
                this.runState = RunState.NotRunnable;
355
 
                this.ignoreReason = "Arguments may not be specified for a method with no parameters";
356
 
                return false;
357
 
            }
358
 
 
359
 
            if (argsNeeded > 0 && argsPassed == 0)
360
 
            {
361
 
                this.runState = RunState.NotRunnable;
362
 
                this.ignoreReason = "No arguments provided for a method requiring them";
363
 
                return false;
364
 
            }
365
 
 
366
 
            if (argsNeeded != argsPassed)
367
 
            {
368
 
                this.runState = RunState.NotRunnable;
369
 
                this.ignoreReason = string.Format("Expected {0} arguments, but received {1}", argsNeeded, argsPassed);
370
 
                return false;
371
 
            }
372
 
 
373
 
            return true;
374
 
        }
375
 
 
376
 
        private static bool HasValidSetUpTearDownSignature(MethodInfo method)
377
 
        {
378
 
            return method.ReturnType == typeof(void)
379
 
                && method.GetParameters().Length == 0; ;
380
 
        }
381
 
 
382
 
        private static void ProcessNoException(MethodInfo method)
383
 
        {
384
 
            ExpectedExceptionAttribute exceptionAttribute =
385
 
                (ExpectedExceptionAttribute)Reflect.GetAttribute(method, typeof(ExpectedExceptionAttribute));
386
 
 
387
 
            if (exceptionAttribute != null)
388
 
                Assert.Fail("Expected Exception of type <{0}>, but none was thrown", exceptionAttribute.ExpectedException);
389
 
        }
390
 
 
391
 
        private void ProcessException(MethodInfo method, Exception caughtException)
392
 
        {
393
 
            ExpectedExceptionAttribute exceptionAttribute =
394
 
                (ExpectedExceptionAttribute)Reflect.GetAttribute(method, typeof(ExpectedExceptionAttribute));
395
 
 
396
 
            if (exceptionAttribute == null)
397
 
                throw new NUnitLiteException("", caughtException);
398
 
 
399
 
            Type expectedType = exceptionAttribute.ExpectedException;
400
 
            if ( expectedType != null && expectedType != caughtException.GetType() )
401
 
                Assert.Fail("Expected Exception of type <{0}>, but was <{1}>", exceptionAttribute.ExpectedException, caughtException.GetType());
402
 
 
403
 
            MethodInfo handler = GetExceptionHandler(method.ReflectedType, exceptionAttribute.Handler);
404
 
 
405
 
            if (handler != null)
406
 
                InvokeMethod( handler, caughtException );
407
 
        }
408
 
 
409
 
        private MethodInfo GetExceptionHandler(Type type, string handlerName)
410
 
        {
411
 
            if (handlerName == null && Reflect.HasInterface( type, typeof(IExpectException) ) )
412
 
                handlerName = "HandleException";
413
 
 
414
 
            if (handlerName == null)
415
 
                return null;
416
 
 
417
 
            MethodInfo handler = Reflect.GetMethod( type, handlerName,
418
 
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
419
 
                new Type[] { typeof(Exception) });
420
 
 
421
 
            if (handler == null)
422
 
                Assert.Fail("The specified exception handler {0} was not found", handlerName);
423
 
 
424
 
            return handler;
425
 
        }
426
 
        #endregion
427
 
    }
428
 
}