[NUI] Rebase develnui (DevelNUI only patches --> master) (#3910)
[platform/core/csapi/tizenfx.git] / test / Tizen.NUI.Devel.Tests.Ubuntu / nunit.framework / Attributes / TestCaseSourceAttribute.cs
1 // ***********************************************************************
2 // Copyright (c) 2008-2015 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 #define PORTABLE
24 #define TIZEN
25 #define NUNIT_FRAMEWORK
26 #define NUNITLITE
27 #define NET_4_5
28 #define PARALLEL
29 using System;
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.Reflection;
33 using NUnit.Compatibility;
34 using NUnit.Framework.Interfaces;
35 using NUnit.Framework.Internal;
36 using NUnit.Framework.Internal.Builders;
37
38 namespace NUnit.Framework
39 {
40     /// <summary>
41     /// TestCaseSourceAttribute indicates the source to be used to
42     /// provide test cases for a test method.
43     /// </summary>
44     [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
45     public class TestCaseSourceAttribute : NUnitAttribute, ITestBuilder, IImplyFixture
46     {
47
48         private NUnitTestCaseBuilder _builder = new NUnitTestCaseBuilder();
49
50         #region Constructors
51
52         /// <summary>
53         /// Construct with the name of the method, property or field that will provide data
54         /// </summary>
55         /// <param name="sourceName">The name of a static method, property or field that will provide data.</param>
56         public TestCaseSourceAttribute(string sourceName)
57         {
58             this.SourceName = sourceName;
59         }
60
61         /// <summary>
62         /// Construct with a Type and name
63         /// </summary>
64         /// <param name="sourceType">The Type that will provide data</param>
65         /// <param name="sourceName">The name of a static method, property or field that will provide data.</param>
66         /// <param name="methodParams">A set of parameters passed to the method, works only if the Source Name is a method. 
67         ///                     If the source name is a field or property has no effect.</param>
68         public TestCaseSourceAttribute(Type sourceType, string sourceName, object[] methodParams)
69         {
70             this.MethodParams = methodParams;
71             this.SourceType = sourceType;
72             this.SourceName = sourceName;
73         }
74         /// <summary>
75         /// Construct with a Type and name
76         /// </summary>
77         /// <param name="sourceType">The Type that will provide data</param>
78         /// <param name="sourceName">The name of a static method, property or field that will provide data.</param>
79         public TestCaseSourceAttribute(Type sourceType, string sourceName)
80         {
81             this.SourceType = sourceType;
82             this.SourceName = sourceName;
83         }
84
85         /// <summary>
86         /// Construct with a Type
87         /// </summary>
88         /// <param name="sourceType">The type that will provide data</param>
89         public TestCaseSourceAttribute(Type sourceType)
90         {
91             this.SourceType = sourceType;
92         }
93
94         #endregion
95
96         #region Properties
97         /// <summary>
98         /// A set of parameters passed to the method, works only if the Source Name is a method. 
99         /// If the source name is a field or property has no effect.
100         /// </summary>
101         public object[] MethodParams { get; private set; }
102         /// <summary>
103         /// The name of a the method, property or fiend to be used as a source
104         /// </summary>
105         public string SourceName { get; private set; }
106
107         /// <summary>
108         /// A Type to be used as a source
109         /// </summary>
110         public Type SourceType { get; private set; }
111
112         /// <summary>
113         /// Gets or sets the category associated with every fixture created from
114         /// this attribute. May be a single category or a comma-separated list.
115         /// </summary>
116         public string Category { get; set; }
117
118         #endregion
119
120         #region ITestBuilder Members
121
122         /// <summary>
123         /// Construct one or more TestMethods from a given MethodInfo,
124         /// using available parameter data.
125         /// </summary>
126         /// <param name="method">The IMethod for which tests are to be constructed.</param>
127         /// <param name="suite">The suite to which the tests will be added.</param>
128         /// <returns>One or more TestMethods</returns>
129         public IEnumerable<TestMethod> BuildFrom(IMethodInfo method, Test suite)
130         {
131             foreach (TestCaseParameters parms in GetTestCasesFor(method))
132                 yield return _builder.BuildTestMethod(method, suite, parms);
133         }
134
135         #endregion
136
137         #region Helper Methods
138
139         /// <summary>
140         /// Returns a set of ITestCaseDataItems for use as arguments
141         /// to a parameterized test method.
142         /// </summary>
143         /// <param name="method">The method for which data is needed.</param>
144         /// <returns></returns>
145         private IEnumerable<ITestCaseData> GetTestCasesFor(IMethodInfo method)
146         {
147             List<ITestCaseData> data = new List<ITestCaseData>();
148
149             try
150             {
151                 IEnumerable source = GetTestCaseSource(method);
152
153                 if (source != null)
154                 {
155                     foreach (object item in source)
156                     {
157                         // First handle two easy cases:
158                         // 1. Source is null. This is really an error but if we
159                         //    throw an exception we simply get an invalid fixture
160                         //    without good info as to what caused it. Passing a
161                         //    single null argument will cause an error to be 
162                         //    reported at the test level, in most cases.
163                         // 2. User provided an ITestCaseData and we just use it.
164                         ITestCaseData parms = item == null
165                             ? new TestCaseParameters(new object[] { null })
166                             : item as ITestCaseData;
167
168                         if (parms == null)
169                         {
170                             // 3. An array was passed, it may be an object[]
171                             //    or possibly some other kind of array, which
172                             //    TestCaseSource can accept.
173                             var args = item as object[];
174                             if (args == null && item is Array)
175                             {
176                                 Array array = item as Array;
177 #if NETCF
178                                 bool netcfOpenType = method.IsGenericMethodDefinition;
179 #else
180                                 bool netcfOpenType = false;
181 #endif
182                                 int numParameters = netcfOpenType ? array.Length : method.GetParameters().Length;
183                                 if (array != null && array.Rank == 1 && array.Length == numParameters)
184                                 {
185                                     // Array is something like int[] - convert it to
186                                     // an object[] for use as the argument array.
187                                     args = new object[array.Length];
188                                     for (int i = 0; i < array.Length; i++)
189                                         args[i] = array.GetValue(i);
190                                 }
191                             }
192
193                             // Check again if we have an object[]
194                             if (args != null)
195                             {
196 #if NETCF
197                                 if (method.IsGenericMethodDefinition)
198                                 {
199                                     var mi = method.MakeGenericMethodEx(args);
200                                     if (mi == null)
201                                         throw new NotSupportedException("Cannot determine generic Type");
202                                     method = mi;
203                                 }
204 #endif
205
206                                 var parameters = method.GetParameters();
207                                 var argsNeeded = parameters.Length;
208                                 var argsProvided = args.Length;
209                
210                                 // If only one argument is needed, our array may actually
211                                 // be the bare argument. If it is, we should wrap it in
212                                 // an outer object[] representing the list of arguments.
213                                 if (argsNeeded == 1)
214                                 {
215                                     var singleParmType = parameters[0].ParameterType;
216                                     
217                                     if (argsProvided == 0 || typeof(object[]).IsAssignableFrom(singleParmType))
218                                     {
219                                         if (argsProvided > 1 || singleParmType.IsAssignableFrom(args.GetType()))
220                                         {
221                                             args = new object[] { item };
222                                         }
223                                     }
224                                 }
225                             }
226                             else // It may be a scalar or a multi-dimensioned array. Wrap it in object[]
227                             {
228                                 args = new object[] { item };
229                             }
230
231                             parms = new TestCaseParameters(args);
232                         }
233
234                         if (this.Category != null)
235                             foreach (string cat in this.Category.Split(new char[] { ',' }))
236                                 parms.Properties.Add(PropertyNames.Category, cat);
237
238                         data.Add(parms);
239                     }
240                 }
241             }
242             catch (Exception ex)
243             {
244                 data.Clear();
245                 data.Add(new TestCaseParameters(ex));
246             }
247
248             return data;
249         }
250
251         private IEnumerable GetTestCaseSource(IMethodInfo method)
252         {
253             Type sourceType = SourceType ?? method.TypeInfo.Type;
254
255             // Handle Type implementing IEnumerable separately
256             if (SourceName == null)
257                 return Reflect.Construct(sourceType, null) as IEnumerable;
258
259             MemberInfo[] members = sourceType.GetMember(SourceName,
260                     BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
261
262             if (members.Length == 1)
263             {
264                 MemberInfo member = members[0];
265
266                 var field = member as FieldInfo;
267                 if (field != null)
268                     return field.IsStatic
269                         ? (MethodParams == null ? (IEnumerable)field.GetValue(null) 
270                                                 : ReturnErrorAsParameter(ParamGivenToField))
271                         : ReturnErrorAsParameter(SourceMustBeStatic);
272
273                 var property = member as PropertyInfo;
274                 if (property != null)
275                     return property.GetGetMethod(true).IsStatic
276                         ? (MethodParams == null ? (IEnumerable)property.GetValue(null, null) 
277                                                 : ReturnErrorAsParameter(ParamGivenToProperty))
278                         : ReturnErrorAsParameter(SourceMustBeStatic);
279
280                 var m = member as MethodInfo;
281                 
282
283                     if (m != null)
284                     return m.IsStatic
285                         ? (MethodParams == null || m.GetParameters().Length == MethodParams.Length ? (IEnumerable)m.Invoke(null, MethodParams) 
286                                                               : ReturnErrorAsParameter(NumberOfArgsDoesNotMatch))
287                         : ReturnErrorAsParameter(SourceMustBeStatic);
288             }
289
290             return null;
291         }
292         
293         private static IEnumerable ReturnErrorAsParameter(string errorMessage)
294         {
295             var parms = new TestCaseParameters();
296             parms.RunState = RunState.NotRunnable;
297             parms.Properties.Set(PropertyNames.SkipReason, errorMessage);
298             return new TestCaseParameters[] { parms };
299         }
300
301         private const string SourceMustBeStatic =
302             "The sourceName specified on a TestCaseSourceAttribute must refer to a static field, property or method.";
303         private const string ParamGivenToField = "You have specified a data source field but also given a set of parameters. Fields cannot take parameters, " +
304                                                  "please revise the 3rd parameter passed to the TestCaseSourceAttribute and either remove " +
305                                                  "it or specify a method.";
306         private const string ParamGivenToProperty = "You have specified a data source property but also given a set of parameters. " +
307                                                     "Properties cannot take parameters, please revise the 3rd parameter passed to the " +
308                                                     "TestCaseSource attribute and either remove it or specify a method.";
309         private const string NumberOfArgsDoesNotMatch = "You have given the wrong number of arguments to the method in the TestCaseSourceAttribute" +
310                                                         ", please check the number of parameters passed in the object is correct in the 3rd parameter for the " +
311                                                         "TestCaseSourceAttribute and this matches the number of parameters in the target method and try again.";
312
313 #endregion
314     }
315 }