[NUI] Rebase develnui (DevelNUI only patches --> master) (#3910)
[platform/core/csapi/tizenfx.git] / test / Tizen.NUI.Devel.Tests.Ubuntu / nunit.framework / Common / CommandLineOptions.cs
1 // ***********************************************************************
2 // Copyright (c) 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.Generic;
31 using System.IO;
32 using NUnit.Options;
33
34 namespace NUnit.Common
35 {
36     /// <summary>
37     /// CommandLineOptions is the base class the specific option classes
38     /// used for nunit3-console and nunitlite. It encapsulates all common
39     /// settings and features of both. This is done to ensure that common
40     /// features remain common and for the convenience of having the code
41     /// in a common location. The class inherits from the Mono
42     /// Options OptionSet class and provides a central location
43     /// for defining and parsing options.
44     /// </summary>
45     public class CommandLineOptions : OptionSet
46     {
47         private bool validated;
48 #if !PORTABLE
49         private bool noresult;
50 #endif
51
52         #region Constructor
53
54         internal CommandLineOptions(IDefaultOptionsProvider defaultOptionsProvider, params string[] args)
55         {
56             // Apply default options
57             if (defaultOptionsProvider == null) throw new ArgumentNullException("defaultOptionsProvider");
58 #if !PORTABLE
59             TeamCity = defaultOptionsProvider.TeamCity;
60 #endif
61             
62             ConfigureOptions();            
63             if (args != null)
64                 Parse(args);
65         }
66
67         public CommandLineOptions(params string[] args)
68         {
69             ConfigureOptions();
70             if (args != null)
71                 Parse(args);
72         }
73         
74         #endregion
75         
76         #region Properties
77
78         // Action to Perform
79
80         public bool Explore { get; private set; }
81
82         public bool ShowHelp { get; private set; }
83
84         public bool ShowVersion { get; private set; }
85
86         // Select tests
87
88         private List<string> inputFiles = new List<string>();
89         public IList<string> InputFiles { get { return inputFiles; } }
90
91         private List<string> testList = new List<string>();
92         public IList<string> TestList { get { return testList; } }
93
94         public string TestParameters { get; private set; }
95
96         public string WhereClause { get; private set; }
97         public bool WhereClauseSpecified { get { return WhereClause != null; } }
98
99         private int defaultTimeout = -1;
100         public int DefaultTimeout { get { return defaultTimeout; } }
101         public bool DefaultTimeoutSpecified { get { return defaultTimeout >= 0; } }
102
103         private int randomSeed = -1;
104         public int RandomSeed { get { return randomSeed; } }
105         public bool RandomSeedSpecified { get { return randomSeed >= 0; } }
106
107         public string DefaultTestNamePattern { get; private set; }
108
109         private int numWorkers = -1;
110         public int NumberOfTestWorkers { get { return numWorkers; } }
111         public bool NumberOfTestWorkersSpecified { get { return numWorkers >= 0; } }
112
113         public bool StopOnError { get; private set; }
114
115         public bool WaitBeforeExit { get; private set; }
116
117         // Output Control
118
119         public bool NoHeader { get; private set; }
120
121         public bool NoColor { get; private set; }
122
123         public bool Verbose { get; private set; }
124
125         public bool TeamCity { get; private set; }
126
127         public string OutFile { get; private set; }
128         public bool OutFileSpecified { get { return OutFile != null; } }
129
130         public string ErrFile { get; private set; }
131         public bool ErrFileSpecified { get { return ErrFile != null; } }
132
133         public string DisplayTestLabels { get; private set; }
134
135 #if !PORTABLE
136         private string workDirectory = null;
137         public string WorkDirectory 
138         {
139             get { return workDirectory ?? NUnit.Env.DefaultWorkDirectory; }
140         }
141         public bool WorkDirectorySpecified { get { return workDirectory != null; } }
142 #endif
143
144         public string InternalTraceLevel { get; private set; }
145         public bool InternalTraceLevelSpecified { get { return InternalTraceLevel != null; } }
146
147         /// <summary>Indicates whether a full report should be displayed.</summary>
148         public bool Full { get; private set; }
149
150 #if !PORTABLE
151         private List<OutputSpecification> resultOutputSpecifications = new List<OutputSpecification>();
152         public IList<OutputSpecification> ResultOutputSpecifications
153         {
154             get
155             {
156                 if (noresult)
157                     return new OutputSpecification[0];
158
159                 if (resultOutputSpecifications.Count == 0)
160                     resultOutputSpecifications.Add(new OutputSpecification("TestResult.xml"));
161
162                 return resultOutputSpecifications;
163             }
164         }
165
166         private List<OutputSpecification> exploreOutputSpecifications = new List<OutputSpecification>();
167         public IList<OutputSpecification> ExploreOutputSpecifications { get { return exploreOutputSpecifications; } }
168 #endif
169         // Error Processing
170
171         public List<string> errorMessages = new List<string>();
172         public IList<string> ErrorMessages { get { return errorMessages; } }
173
174 #endregion
175         
176 #region Public Methods
177
178         public bool Validate()
179         {
180             if (!validated)
181             {
182                 CheckOptionCombinations();
183
184                 validated = true;
185             }
186
187             return ErrorMessages.Count == 0;
188         }
189
190         #endregion
191
192         #region Helper Methods
193
194         protected virtual void CheckOptionCombinations()
195         {
196
197         }
198
199         /// <summary>
200         /// Case is ignored when val is compared to validValues. When a match is found, the
201         /// returned value will be in the canonical case from validValues.
202         /// </summary>
203         protected string RequiredValue(string val, string option, params string[] validValues)
204         {
205             if (string.IsNullOrEmpty(val))
206                 ErrorMessages.Add("Missing required value for option '" + option + "'.");
207
208             bool isValid = true;
209
210             if (validValues != null && validValues.Length > 0)
211             {
212                 isValid = false;
213
214                 foreach (string valid in validValues)
215                     if (string.Compare(valid, val, StringComparison.OrdinalIgnoreCase) == 0)
216                         return valid;
217
218             }
219
220             if (!isValid)
221                 ErrorMessages.Add(string.Format("The value '{0}' is not valid for option '{1}'.", val, option));
222
223             return val;
224         }
225
226         protected int RequiredInt(string val, string option)
227         {
228             // We have to return something even though the value will
229             // be ignored if an error is reported. The -1 value seems
230             // like a safe bet in case it isn't ignored due to a bug.
231             int result = -1;
232
233             if (string.IsNullOrEmpty(val))
234                 ErrorMessages.Add("Missing required value for option '" + option + "'.");
235             else
236             {
237                 // NOTE: Don't replace this with TryParse or you'll break the CF build!
238                 try
239                 {
240                     result = int.Parse(val);
241                 }
242                 catch (Exception)
243                 {
244                     ErrorMessages.Add("An int value was expected for option '{0}' but a value of '{1}' was used");
245                 }
246             }
247
248             return result;
249         }
250
251         private string ExpandToFullPath(string path)
252         {
253             if (path == null) return null;
254
255 #if NETCF || PORTABLE
256             return Path.Combine(NUnit.Env.DocumentFolder, path);
257 #else
258             return Path.GetFullPath(path);
259 #endif
260         }
261
262         protected virtual void ConfigureOptions()
263         {
264             // NOTE: The order in which patterns are added
265             // determines the display order for the help.
266
267             // Select Tests
268             this.Add("test=", "Comma-separated list of {NAMES} of tests to run or explore. This option may be repeated.",
269                 v => ((List<string>)TestList).AddRange(TestNameParser.Parse(RequiredValue(v, "--test"))));
270 #if !PORTABLE
271             this.Add("testlist=", "File {PATH} containing a list of tests to run, one per line. This option may be repeated.",
272                 v =>
273                 {
274                     string testListFile = RequiredValue(v, "--testlist");
275
276                     var fullTestListPath = ExpandToFullPath(testListFile);
277
278                     if (!File.Exists(fullTestListPath))
279                         ErrorMessages.Add("Unable to locate file: " + testListFile);
280                     else
281                     {
282                         try
283                         {
284                             using (var rdr = new StreamReader(fullTestListPath))
285                             {
286                                 while (!rdr.EndOfStream)
287                                 {
288                                     var line = rdr.ReadLine().Trim();
289
290                                     if (!string.IsNullOrEmpty(line) && line[0] != '#')
291                                         ((List<string>)TestList).Add(line);
292                                 }
293                             }
294                         }
295                         catch (IOException)
296                         {
297                             ErrorMessages.Add("Unable to read file: " + testListFile);
298                         }
299                     }
300                 });
301
302 #endif
303             this.Add("where=", "Test selection {EXPRESSION} indicating what tests will be run. See description below.",
304                 v => WhereClause = RequiredValue(v, "--where"));
305
306             this.Add("params|p=", "Define a test parameter.",
307                 v =>
308                 {
309                     string parameters = RequiredValue( v, "--params");
310
311                     foreach (string param in parameters.Split(new[] { ';' }))
312                     {
313                         if (!param.Contains("="))
314                             ErrorMessages.Add("Invalid format for test parameter. Use NAME=VALUE.");
315                     }
316
317                     if (TestParameters == null)
318                         TestParameters = parameters;
319                     else
320                         TestParameters += ";" + parameters;
321                 });
322
323             this.Add("timeout=", "Set timeout for each test case in {MILLISECONDS}.",
324                 v => defaultTimeout = RequiredInt(v, "--timeout"));
325
326             this.Add("seed=", "Set the random {SEED} used to generate test cases.",
327                 v => randomSeed = RequiredInt(v, "--seed"));
328 #if !PORTABLE
329             this.Add("workers=", "Specify the {NUMBER} of worker threads to be used in running tests. If not specified, defaults to 2 or the number of processors, whichever is greater.",
330                 v => numWorkers = RequiredInt(v, "--workers"));
331 #endif
332             this.Add("stoponerror", "Stop run immediately upon any test failure or error.",
333                 v => StopOnError = v != null);
334
335             this.Add("wait", "Wait for input before closing console window.",
336                 v => WaitBeforeExit = v != null);
337 #if !PORTABLE
338             // Output Control
339             this.Add("work=", "{PATH} of the directory to use for output files. If not specified, defaults to the current directory.",
340                 v => workDirectory = RequiredValue(v, "--work"));
341
342             this.Add("output|out=", "File {PATH} to contain text output from the tests.",
343                 v => OutFile = RequiredValue(v, "--output"));
344
345             this.Add("err=", "File {PATH} to contain error output from the tests.",
346                 v => ErrFile = RequiredValue(v, "--err"));
347
348             this.Add("full", "Prints full report of all test results.",
349                 v => Full = v != null);
350
351             this.Add("result=", "An output {SPEC} for saving the test results.\nThis option may be repeated.",
352                 v => resultOutputSpecifications.Add(new OutputSpecification(RequiredValue(v, "--resultxml"))));
353
354             this.Add("explore:", "Display or save test info rather than running tests. Optionally provide an output {SPEC} for saving the test info. This option may be repeated.", v =>
355             {
356                 Explore = true;
357                 if (v != null)
358                     ExploreOutputSpecifications.Add(new OutputSpecification(v));
359             });
360
361             this.Add("noresult", "Don't save any test results.",
362                 v => noresult = v != null);
363 #endif
364             this.Add("labels=", "Specify whether to write test case names to the output. Values: Off, On, All",
365                 v => DisplayTestLabels = RequiredValue(v, "--labels", "Off", "On", "All"));
366
367             this.Add("test-name-format=", "Non-standard naming pattern to use in generating test names.",
368                 v => DefaultTestNamePattern = RequiredValue(v, "--test-name-format"));
369
370 #if !PORTABLE
371             this.Add("trace=", "Set internal trace {LEVEL}.\nValues: Off, Error, Warning, Info, Verbose (Debug)",
372                 v => InternalTraceLevel = RequiredValue(v, "--trace", "Off", "Error", "Warning", "Info", "Verbose", "Debug"));
373
374 #if !NETCF
375             this.Add("teamcity", "Turns on use of TeamCity service messages.",
376                 v => TeamCity = v != null);
377 #endif
378
379             this.Add("noheader|noh", "Suppress display of program information at start of run.",
380                 v => NoHeader = v != null);
381
382             this.Add("nocolor|noc", "Displays console output without color.",
383                 v => NoColor = v != null);
384 #endif
385             this.Add("verbose|v", "Display additional information as the test runs.",
386                 v => Verbose = v != null);
387
388             this.Add("help|h", "Display this message and exit.",
389                 v => ShowHelp = v != null);
390
391             this.Add("version|V", "Display the header and exit.",
392                 v => ShowVersion = v != null);
393
394             // Default
395             this.Add("<>", v =>
396             {
397 #if PORTABLE
398                 if (v.StartsWith("-") || v.StartsWith("/") && Environment.NewLine == "\r\n")
399 #else
400                 if (v.StartsWith("-") || v.StartsWith("/") && Path.DirectorySeparatorChar != '/')
401 #endif
402                     ErrorMessages.Add("Invalid argument: " + v);
403                 else
404                     InputFiles.Add(v);
405             });
406         }
407
408 #endregion
409     }
410 }