PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/project/core/tasks/NCoverProfileTask.cs

https://bitbucket.org/davcamer/ccnet
C# | 491 lines | 299 code | 50 blank | 142 comment | 10 complexity | 654d7d11e5ad2e4d758b3f8c459c5623 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Exortech.NetReflector;
  5. using ThoughtWorks.CruiseControl.Core.Util;
  6. using System.IO;
  7. namespace ThoughtWorks.CruiseControl.Core.Tasks
  8. {
  9. /// <summary>
  10. /// Perform an analysis using NCover 3.0.
  11. /// </summary>
  12. [ReflectorType("ncoverProfile")]
  13. public class NCoverProfileTask
  14. : BaseExecutableTask
  15. {
  16. #region Private consts
  17. private const string defaultExecutable = "NCover.Console";
  18. #endregion
  19. #region Private fields
  20. private string rootPath;
  21. #endregion
  22. #region Constructors
  23. /// <summary>
  24. /// Initialise a new <see cref="NCoverProfileTask"/>.
  25. /// </summary>
  26. public NCoverProfileTask()
  27. : this(new ProcessExecutor())
  28. {
  29. }
  30. /// <summary>
  31. /// Initialise a new <see cref="NCoverProfileTask"/> with a <see cref="ProcessExecutor"/>.
  32. /// </summary>
  33. /// <param name="executor"></param>
  34. public NCoverProfileTask(ProcessExecutor executor)
  35. {
  36. this.executor = executor;
  37. this.Publish = true;
  38. this.TimeOut = 600;
  39. this.LogLevel = NCoverLogLevel.Default;
  40. }
  41. #endregion
  42. #region Public properties
  43. #region ProgramToCover
  44. /// <summary>
  45. /// The program to execute and collect coverage stats from.
  46. /// </summary>
  47. [ReflectorProperty("program", Required = false)]
  48. public string ProgramToCover { get; set; }
  49. #endregion
  50. #region TestProject
  51. /// <summary>
  52. /// The project that contains the tests.
  53. /// </summary>
  54. [ReflectorProperty("testProject", Required = false)]
  55. public string TestProject { get; set; }
  56. #endregion
  57. #region ProgramParameters
  58. /// <summary>
  59. /// The parameters to pass to the program.
  60. /// </summary>
  61. [ReflectorProperty("programParameters", Required = false)]
  62. public string ProgramParameters { get; set; }
  63. #endregion
  64. #region Executable
  65. /// <summary>
  66. /// The executable to use.
  67. /// </summary>
  68. [ReflectorProperty("executable", Required = false)]
  69. public string Executable { get; set; }
  70. #endregion
  71. #region TimeOut
  72. /// <summary>
  73. /// The time-out period in seconds.
  74. /// </summary>
  75. [ReflectorProperty("timeout", Required = false)]
  76. public int TimeOut { get; set; }
  77. #endregion
  78. #region BaseDirectory
  79. /// <summary>
  80. /// The base directory to use.
  81. /// </summary>
  82. [ReflectorProperty("baseDir", Required = false)]
  83. public string BaseDirectory { get; set; }
  84. #endregion
  85. #region WorkingDirectory
  86. /// <summary>
  87. /// The working directory to use.
  88. /// </summary>
  89. [ReflectorProperty("workingDir", Required = false)]
  90. public string WorkingDirectory { get; set; }
  91. #endregion
  92. #region Publish
  93. /// <summary>
  94. /// Whether to publish the output files or not.
  95. /// </summary>
  96. [ReflectorProperty("publish", Required = false)]
  97. public bool Publish { get; set; }
  98. #endregion
  99. #region LogFile
  100. /// <summary>
  101. /// The location of the NCover log file.
  102. /// </summary>
  103. [ReflectorProperty("logFile", Required = false)]
  104. public string LogFile { get; set; }
  105. #endregion
  106. #region LogLevel
  107. /// <summary>
  108. /// The profiler log level.
  109. /// </summary>
  110. [ReflectorProperty("logLevel", Required = false)]
  111. public NCoverLogLevel LogLevel { get; set; }
  112. #endregion
  113. #region ProjectName
  114. /// <summary>
  115. /// The name of the project (used in the HTML report).
  116. /// </summary>
  117. [ReflectorProperty("projectName", Required = false)]
  118. public string ProjectName { get; set; }
  119. #endregion
  120. #region CoverageFile
  121. /// <summary>
  122. /// The location to write the coverage file to.
  123. /// </summary>
  124. [ReflectorProperty("coverageFile", Required = false)]
  125. public string CoverageFile { get; set; }
  126. #endregion
  127. #region CoverageMetric
  128. /// <summary>
  129. /// The coverage metric to use.
  130. /// </summary>
  131. [ReflectorProperty("coverageMetric", Required = false)]
  132. public string CoverageMetric { get; set; }
  133. #endregion
  134. #region ExcludedAttributes
  135. /// <summary>
  136. /// The attributes to exclude.
  137. /// </summary>
  138. [ReflectorProperty("excludedAttributes", Required = false)]
  139. public string ExcludedAttributes { get; set; }
  140. #endregion
  141. #region ExcludedAssemblies
  142. /// <summary>
  143. /// The assemblies to exclude.
  144. /// </summary>
  145. [ReflectorProperty("excludedAssemblies", Required = false)]
  146. public string ExcludedAssemblies { get; set; }
  147. #endregion
  148. #region ExcludedFiles
  149. /// <summary>
  150. /// The files to exclude.
  151. /// </summary>
  152. [ReflectorProperty("excludedFiles", Required = false)]
  153. public string ExcludedFiles { get; set; }
  154. #endregion
  155. #region ExcludedMethods
  156. /// <summary>
  157. /// The methods to exclude.
  158. /// </summary>
  159. [ReflectorProperty("excludedMethods", Required = false)]
  160. public string ExcludedMethods { get; set; }
  161. #endregion
  162. #region ExcludedTypes
  163. /// <summary>
  164. /// The types to exclude.
  165. /// </summary>
  166. [ReflectorProperty("excludedTypes", Required = false)]
  167. public string ExcludedTypes { get; set; }
  168. #endregion
  169. #region IncludedAttributes
  170. /// <summary>
  171. /// The attributes to include.
  172. /// </summary>
  173. [ReflectorProperty("includedAttributes", Required = false)]
  174. public string IncludedAttributes { get; set; }
  175. #endregion
  176. #region IncludedAssemblies
  177. /// <summary>
  178. /// The assemblies to include.
  179. /// </summary>
  180. [ReflectorProperty("includedAssemblies", Required = false)]
  181. public string IncludedAssemblies { get; set; }
  182. #endregion
  183. #region IncludedFiles
  184. /// <summary>
  185. /// The files to include.
  186. /// </summary>
  187. [ReflectorProperty("includedFiles", Required = false)]
  188. public string IncludedFiles { get; set; }
  189. #endregion
  190. #region IncludedTypes
  191. /// <summary>
  192. /// The types to include.
  193. /// </summary>
  194. [ReflectorProperty("includedTypes", Required = false)]
  195. public string IncludedTypes { get; set; }
  196. #endregion
  197. #region DisableAutoexclusion
  198. /// <summary>
  199. /// Whether to turn off autoexclusion or not.
  200. /// </summary>
  201. [ReflectorProperty("disableAutoexclusion", Required = false)]
  202. public bool DisableAutoexclusion { get; set; }
  203. #endregion
  204. #region ProcessModule
  205. /// <summary>
  206. /// The module to process.
  207. /// </summary>
  208. [ReflectorProperty("processModule", Required = false)]
  209. public string ProcessModule { get; set; }
  210. #endregion
  211. #region SymbolSearch
  212. /// <summary>
  213. /// The symbol search policy to use.
  214. /// </summary>
  215. [ReflectorProperty("symbolSearch", Required = false)]
  216. public string SymbolSearch { get; set; }
  217. #endregion
  218. #region TrendFile
  219. /// <summary>
  220. /// The location to write the trend file to.
  221. /// </summary>
  222. [ReflectorProperty("trendFile", Required = false)]
  223. public string TrendFile { get; set; }
  224. #endregion
  225. #region BuildId
  226. /// <summary>
  227. /// A custom build id to attach.
  228. /// </summary>
  229. [ReflectorProperty("buildId", Required = false)]
  230. public string BuildId { get; set; }
  231. #endregion
  232. #region SettingsFile
  233. /// <summary>
  234. /// The location to read the settings from.
  235. /// </summary>
  236. [ReflectorProperty("settingsFile", Required = false)]
  237. public string SettingsFile { get; set; }
  238. #endregion
  239. #region Register
  240. /// <summary>
  241. /// Temporarily enable NCover.
  242. /// </summary>
  243. [ReflectorProperty("register", Required = false)]
  244. public bool Register { get; set; }
  245. #endregion
  246. #region ApplicationLoadWait
  247. /// <summary>
  248. /// The amount of time that NCover will wait for the application to start up.
  249. /// </summary>
  250. [ReflectorProperty("applicationLoadWait", Required = false)]
  251. public int ApplicationLoadWait { get; set; }
  252. #endregion
  253. #region CoverIis
  254. /// <summary>
  255. /// Whether to cover IIS or not.
  256. /// </summary>
  257. [ReflectorProperty("iis", Required = false)]
  258. public bool CoverIis { get; set; }
  259. #endregion
  260. #region ServiceTimeout
  261. /// <summary>
  262. /// The timeout period for covering a service.
  263. /// </summary>
  264. [ReflectorProperty("serviceTimeout", Required = false)]
  265. public int ServiceTimeout { get; set; }
  266. #endregion
  267. #region WindowsService
  268. /// <summary>
  269. /// The windows service to cover.
  270. /// </summary>
  271. [ReflectorProperty("windowsService", Required = false)]
  272. public string WindowsService { get; set; }
  273. #endregion
  274. #endregion
  275. #region Protected methods
  276. #region Execute()
  277. /// <summary>
  278. /// Run the task.
  279. /// </summary>
  280. /// <param name="result"></param>
  281. protected override bool Execute(IIntegrationResult result)
  282. {
  283. result.BuildProgressInformation.SignalStartRunTask(!string.IsNullOrEmpty(Description) ? Description : "Running NCover profile");
  284. // Make sure there is a root directory
  285. rootPath = BaseDirectory;
  286. if (string.IsNullOrEmpty(rootPath)) rootPath = result.WorkingDirectory;
  287. // Run the executable
  288. var processResult = TryToRun(CreateProcessInfo(result), result);
  289. result.AddTaskResult(new ProcessTaskResult(processResult));
  290. if (Publish && !processResult.Failed)
  291. {
  292. var coverageFile = string.IsNullOrEmpty(CoverageFile) ? "coverage.xml" : CoverageFile;
  293. result.AddTaskResult(new FileTaskResult(RootPath(coverageFile, false)));
  294. }
  295. return !processResult.Failed;
  296. }
  297. #endregion
  298. #region GetProcessFilename()
  299. /// <summary>
  300. /// Retrieve the executable to use.
  301. /// </summary>
  302. /// <returns></returns>
  303. protected override string GetProcessFilename()
  304. {
  305. string path;
  306. if (string.IsNullOrEmpty(Executable))
  307. {
  308. path = RootPath(defaultExecutable, true);
  309. }
  310. else
  311. {
  312. path = RootPath(Executable, true);
  313. }
  314. return path;
  315. }
  316. #endregion
  317. #region GetProcessBaseDirectory()
  318. /// <summary>
  319. /// Retrieve the base directory.
  320. /// </summary>
  321. /// <param name="result"></param>
  322. /// <returns></returns>
  323. protected override string GetProcessBaseDirectory(IIntegrationResult result)
  324. {
  325. string path = string.IsNullOrEmpty(WorkingDirectory) ? RootPath(rootPath, true) : RootPath(WorkingDirectory, true);
  326. return path;
  327. }
  328. #endregion
  329. #region GetProcessTimeout()
  330. /// <summary>
  331. /// Get the time-out period.
  332. /// </summary>
  333. /// <returns></returns>
  334. protected override int GetProcessTimeout()
  335. {
  336. return TimeOut * 1000;
  337. }
  338. #endregion
  339. #region GetProcessArguments()
  340. /// <summary>
  341. /// Retrieve the arguments
  342. /// </summary>
  343. /// <param name="result"></param>
  344. /// <returns></returns>
  345. protected override string GetProcessArguments(IIntegrationResult result)
  346. {
  347. ProcessArgumentBuilder buffer = new ProcessArgumentBuilder();
  348. buffer.Append(RootPath(ProgramToCover, true));
  349. if (!string.IsNullOrEmpty(TestProject))
  350. {
  351. string testProject;
  352. if (!string.IsNullOrEmpty(WorkingDirectory))
  353. {
  354. testProject = Path.Combine(RootPath(WorkingDirectory, false), TestProject);
  355. testProject = StringUtil.AutoDoubleQuoteString(testProject);
  356. }
  357. else
  358. {
  359. testProject = RootPath(TestProject, true);
  360. }
  361. buffer.AppendArgument(testProject);
  362. }
  363. buffer.AppendArgument(ProgramParameters);
  364. // Add all the NCover arguments
  365. buffer.AppendIf(!string.IsNullOrEmpty(LogFile), "//l \"{0}\"", RootPath(LogFile, false));
  366. buffer.AppendIf(LogLevel != NCoverLogLevel.Default, "//ll {0}", LogLevel.ToString());
  367. buffer.AppendIf(!string.IsNullOrEmpty(ProjectName), "//p \"{0}\"", ProjectName);
  368. buffer.AppendIf(!string.IsNullOrEmpty(CoverageFile), "//x \"{0}\"", RootPath(CoverageFile, false));
  369. buffer.AppendIf(string.IsNullOrEmpty(CoverageFile), "//x \"{0}\"", RootPath("Coverage.xml", false));
  370. buffer.AppendIf(!string.IsNullOrEmpty(CoverageMetric), "//ct \"{0}\"", CoverageMetric);
  371. buffer.AppendIf(!string.IsNullOrEmpty(ExcludedAttributes), "//ea \"{0}\"", ExcludedAttributes);
  372. buffer.AppendIf(!string.IsNullOrEmpty(ExcludedAssemblies), "//eas \"{0}\"", ExcludedAssemblies);
  373. buffer.AppendIf(!string.IsNullOrEmpty(ExcludedFiles), "//ef \"{0}\"", ExcludedFiles);
  374. buffer.AppendIf(!string.IsNullOrEmpty(ExcludedMethods), "//em \"{0}\"", ExcludedMethods);
  375. buffer.AppendIf(!string.IsNullOrEmpty(ExcludedTypes), "//et \"{0}\"", ExcludedTypes);
  376. buffer.AppendIf(!string.IsNullOrEmpty(IncludedAttributes), "//ia \"{0}\"", IncludedAttributes);
  377. buffer.AppendIf(!string.IsNullOrEmpty(IncludedAssemblies), "//ias \"{0}\"", IncludedAssemblies);
  378. buffer.AppendIf(!string.IsNullOrEmpty(IncludedFiles), "//if \"{0}\"", IncludedFiles);
  379. buffer.AppendIf(!string.IsNullOrEmpty(IncludedTypes), "//it \"{0}\"", IncludedTypes);
  380. buffer.AppendIf(DisableAutoexclusion, "//na");
  381. buffer.AppendIf(!string.IsNullOrEmpty(ProcessModule), "//pm \"{0}\"", ProcessModule);
  382. buffer.AppendIf(!string.IsNullOrEmpty(SymbolSearch), "//ssp \"{0}\"", SymbolSearch);
  383. buffer.AppendIf(!string.IsNullOrEmpty(TrendFile), "//at \"{0}\"", RootPath(TrendFile, false));
  384. buffer.AppendArgument("//bi \"{0}\"", !string.IsNullOrEmpty(BuildId) ? BuildId : result.Label);
  385. buffer.AppendIf(!string.IsNullOrEmpty(SettingsFile), "//cr \"{0}\"", RootPath(SettingsFile, false));
  386. buffer.AppendIf(Register, "//reg");
  387. buffer.AppendIf(!string.IsNullOrEmpty(WorkingDirectory), "//w \"{0}\"", RootPath(WorkingDirectory, false));
  388. buffer.AppendIf(ApplicationLoadWait > 0, "//wal {0}", ApplicationLoadWait.ToString());
  389. buffer.AppendIf(CoverIis, "//iis");
  390. buffer.AppendIf(ServiceTimeout > 0, "//st {0}", ServiceTimeout.ToString());
  391. buffer.AppendIf(!string.IsNullOrEmpty(WindowsService), "//svc {0}", WindowsService);
  392. return buffer.ToString();
  393. }
  394. #endregion
  395. #endregion
  396. #region Private methods
  397. #region RootPath()
  398. /// <summary>
  399. /// Ensures that a path is rooted.
  400. /// </summary>
  401. /// <param name="path"></param>
  402. /// <returns></returns>
  403. private string RootPath(string path, bool doubleQuote)
  404. {
  405. string actualPath;
  406. if (Path.IsPathRooted(path))
  407. {
  408. actualPath = path;
  409. }
  410. else
  411. {
  412. if (string.IsNullOrEmpty(path))
  413. {
  414. actualPath = Path.Combine(rootPath, "NCoverResults");
  415. }
  416. else
  417. {
  418. actualPath = Path.Combine(rootPath, path);
  419. }
  420. }
  421. if (doubleQuote) actualPath = StringUtil.AutoDoubleQuoteString(actualPath);
  422. return actualPath;
  423. }
  424. #endregion
  425. #endregion
  426. #region Enumerations
  427. #region NCoverLogLevel
  428. /// <summary>
  429. /// The allowed logging levels.
  430. /// </summary>
  431. public enum NCoverLogLevel
  432. {
  433. Default,
  434. None,
  435. Normal,
  436. Verbose
  437. }
  438. #endregion
  439. #endregion
  440. }
  441. }