PageRenderTime 53ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/src/tests/Text/HelpTextFixture.cs

https://github.com/sflanker/commandline
C# | 473 lines | 303 code | 75 blank | 95 comment | 4 complexity | cbf32cbc3b9723a27a7b277937150131 MD5 | raw file
Possible License(s): Apache-2.0
  1. #region License
  2. //
  3. // Command Line Library: HelpTextFixture.cs
  4. //
  5. // Author:
  6. // Giacomo Stelluti Scala (gsscoder@gmail.com)
  7. // Contributor(s):
  8. // Steven Evans
  9. //
  10. // Copyright (C) 2005 - 2013 Giacomo Stelluti Scala
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining a copy
  13. // of this software and associated documentation files (the "Software"), to deal
  14. // in the Software without restriction, including without limitation the rights
  15. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  16. // copies of the Software, and to permit persons to whom the Software is
  17. // furnished to do so, subject to the following conditions:
  18. //
  19. // The above copyright notice and this permission notice shall be included in
  20. // all copies or substantial portions of the Software.
  21. //
  22. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  24. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  25. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  26. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  27. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  28. // THE SOFTWARE.
  29. #endregion
  30. #region Using Directives
  31. using System;
  32. using System.Collections.Generic;
  33. using System.ComponentModel;
  34. using System.IO;
  35. using System.Text;
  36. using System.Globalization;
  37. using Xunit;
  38. using FluentAssertions;
  39. using CommandLine.Tests.Mocks;
  40. #endregion
  41. namespace CommandLine.Text.Tests
  42. {
  43. public class HelpTextFixture
  44. {
  45. #region Mock Objects
  46. class MockOptions
  47. {
  48. [Option('v', "verbose")]
  49. public bool Verbose { get; set; }
  50. [Option("input-file")]
  51. public string FileName { get; set; }
  52. }
  53. class MockOptionsWithMetaValue
  54. {
  55. [Option('v', "verbose", HelpText = "Comment extensively every operation.")]
  56. public bool Verbose { get; set; }
  57. [Option('i', "input-file", MetaValue="FILE", Required = true, HelpText = "Specify input FILE to be processed.")]
  58. public string FileName { get; set; }
  59. }
  60. class MockOptionsWithDescription
  61. {
  62. [Option('v', "verbose", HelpText = "Comment extensively every operation.")]
  63. public bool Verbose { get; set; }
  64. [Option('i', "input-file", Required = true, HelpText = "Specify input file to be processed.")]
  65. public string FileName { get; set; }
  66. }
  67. private class MockOptionsWithLongDescription
  68. {
  69. [Option('v', "verbose", HelpText = "This is the description of the verbosity to test out the wrapping capabilities of the Help Text.")]
  70. public bool Verbose { get; set; }
  71. [Option("input-file", HelpText = "This is a very long description of the Input File argument that gets passed in. It should be passed in as a string.")]
  72. public string FileName { get; set; }
  73. }
  74. private class MockOptionsWithLongDescriptionAndNoSpaces
  75. {
  76. [Option('v', "verbose", HelpText = "Before 012345678901234567890123 After")]
  77. public bool Verbose { get; set; }
  78. [Option("input-file", HelpText = "Before 012345678901234567890123456789 After")]
  79. public string FileName { get; set; }
  80. }
  81. public class MockOptionsSimple
  82. {
  83. [Option('s', "something", HelpText = "Input something here.")]
  84. public string Something { get; set; }
  85. }
  86. public class ComplexOptionsWithHelp : ComplexOptions
  87. {
  88. [Option('a', "all", HelpText = "Read the file completely.", MutuallyExclusiveSet = "reading")]
  89. public bool ReadAll { get; set; }
  90. [Option('p', "part", HelpText = "Read the file partially.", MutuallyExclusiveSet = "reading")]
  91. public bool ReadPartially { get; set; }
  92. [HelpOption(HelpText ="Displays this help screen.")]
  93. public string GetUsage()
  94. {
  95. var help = new HelpText(new HeadingInfo("unittest", "1.9"));
  96. help.AdditionalNewLineAfterOption = true;
  97. help.Copyright = new CopyrightInfo("CommandLine.dll Author", 2005, 2011);
  98. // handling parsing error code
  99. string errors = help.RenderParsingErrorsText(this, 2); // indent with two spaces
  100. if (!string.IsNullOrEmpty(errors))
  101. {
  102. help.AddPreOptionsLine(string.Concat(Environment.NewLine, "ERROR(S):"));
  103. help.AddPreOptionsLine(errors);
  104. }
  105. help.AddPreOptionsLine("This is free software. You may redistribute copies of it under the terms of");
  106. help.AddPreOptionsLine("the MIT License <http://www.opensource.org/licenses/mit-license.php>.");
  107. help.AddPreOptionsLine("Usage: Please run the unit...");
  108. help.AddOptions(this);
  109. return help;
  110. }
  111. }
  112. #endregion
  113. [Fact]
  114. public void Add_an_empty_pre_options_line_is_allowed()
  115. {
  116. var helpText = new HelpText(new HeadingInfo("CommandLine.Tests.dll", "1.9.4.131"));
  117. helpText.AddPreOptionsLine(string.Empty);
  118. }
  119. /// <summary>
  120. /// Ref.: #REQ0002
  121. /// </summary>
  122. [Fact]
  123. public void Post_options_lines_feature_added()
  124. {
  125. var local = new HelpText("Heading Info.");
  126. local.AddPreOptionsLine("This is a first pre-options line.");
  127. local.AddPreOptionsLine("This is a second pre-options line.");
  128. local.AddOptions(new MockOptions());
  129. local.AddPostOptionsLine("This is a first post-options line.");
  130. local.AddPostOptionsLine("This is a second post-options line.");
  131. string help = local.ToString();
  132. string[] lines = help.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
  133. lines[lines.Length - 2].Should().Be("This is a first post-options line.");
  134. lines[lines.Length - 1].Should().Be("This is a second post-options line.");
  135. }
  136. [Fact]
  137. public void Meta_value()
  138. {
  139. var local = new HelpText("Meta Value.");
  140. local.AddOptions(new MockOptionsWithMetaValue());
  141. string help = local.ToString();
  142. string[] lines = help.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
  143. lines[lines.Length - 2].Should().Be(" i FILE, input-file=FILE Required. Specify input FILE to be processed.");
  144. }
  145. [Fact]
  146. public void When_help_text_is_longer_than_width_it_will_wrap_around_as_if_in_a_column()
  147. {
  148. var helpText = new HelpText(new HeadingInfo("CommandLine.Tests.dll", "1.9.4.131"));
  149. helpText.MaximumDisplayWidth = 40;
  150. helpText.AddOptions(new MockOptionsWithLongDescription());
  151. string help = helpText.ToString();
  152. string[] lines = help.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
  153. lines[2].Should().Be(" v, verbose This is the description"); //"The first line should have the arguments and the start of the Help Text.");
  154. //string formattingMessage = "Beyond the second line should be formatted as though it's in a column.";
  155. lines[3].Should().Be(" of the verbosity to ");
  156. lines[4].Should().Be(" test out the wrapping ");
  157. lines[5].Should().Be(" capabilities of the ");
  158. lines[6].Should().Be(" Help Text.");
  159. }
  160. [Fact]
  161. public void Long_help_text_without_spaces()
  162. {
  163. var helpText = new HelpText(new HeadingInfo("CommandLine.Tests.dll", "1.9.4.131"));
  164. helpText.MaximumDisplayWidth = 40;
  165. helpText.AddOptions(new MockOptionsWithLongDescriptionAndNoSpaces());
  166. string help = helpText.ToString();
  167. string[] lines = help.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
  168. lines[2].Should().Be(" v, verbose Before ");
  169. lines[3].Should().Be(" 012345678901234567890123");
  170. lines[4].Should().Be(" After");
  171. lines[5].Should().Be(" input-file Before ");
  172. lines[6].Should().Be(" 012345678901234567890123");
  173. lines[7].Should().Be(" 456789 After");
  174. }
  175. [Fact]
  176. public void Long_pre_and_post_lines_without_spaces()
  177. {
  178. var local = new HelpText("Heading Info.");
  179. local.MaximumDisplayWidth = 40;
  180. local.AddPreOptionsLine("Before 0123456789012345678901234567890123456789012 After");
  181. local.AddOptions(new MockOptions());
  182. local.AddPostOptionsLine("Before 0123456789012345678901234567890123456789 After");
  183. string help = local.ToString();
  184. string[] lines = help.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
  185. lines[1].Should().Be("Before ");
  186. lines[2].Should().Be("0123456789012345678901234567890123456789");
  187. lines[3].Should().Be("012 After");
  188. lines[lines.Length - 3].Should().Be("Before ");
  189. lines[lines.Length - 2].Should().Be("0123456789012345678901234567890123456789");
  190. lines[lines.Length - 1].Should().Be(" After");
  191. }
  192. [Fact]
  193. public void Customize_options_format()
  194. {
  195. var local = new HelpText("Customizing Test.");
  196. local.FormatOptionHelpText += new EventHandler<FormatOptionHelpTextEventArgs>(CustomizeOptionsFormat_FormatOptionHelpText);
  197. local.AddPreOptionsLine("Pre-Options.");
  198. local.AddOptions(new MockOptionsWithDescription());
  199. local.AddPostOptionsLine("Post-Options.");
  200. string help = local.ToString();
  201. Console.WriteLine(help);
  202. string[] lines = help.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
  203. lines[0].Should().Be("Customizing Test.");
  204. lines[1].Should().Be("Pre-Options.");
  205. lines[3].Should().Be(" v, verbose Kommentar umfassend Operationen.");
  206. lines[4].Should().Be(" i, input-file Erforderlich. Gibt den Eingang an zu bearbeitenden Datei.");
  207. lines[6].Should().Be("Post-Options.");
  208. }
  209. [Fact]
  210. public void Instancing_with_parameterless_constructor()
  211. {
  212. var year = DateTime.Now.Year;
  213. var local = new HelpText();
  214. local.Heading = new HeadingInfo("Parameterless Constructor Test.");
  215. local.Copyright = new CopyrightInfo("Author", year);
  216. local.AddPreOptionsLine("Pre-Options.");
  217. local.AddOptions(new MockOptionsSimple());
  218. local.AddPostOptionsLine("Post-Options.");
  219. string help = local.ToString();
  220. Console.WriteLine(help);
  221. string[] lines = help.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
  222. lines[0].Should().Be("Parameterless Constructor Test.");
  223. lines[1].Should().Be(string.Format(CultureInfo.InvariantCulture, "Copyright (C) {0} Author", year));
  224. lines[2].Should().Be("Pre-Options.");
  225. lines[4].Should().Be(" s, something Input something here.");
  226. lines[6].Should().Be("Post-Options.");
  227. }
  228. [Fact]
  229. public void Add_options_with_dashes()
  230. {
  231. var local = new HelpText {
  232. AddDashesToOption = true,
  233. Heading = new HeadingInfo("AddOptionsWithDashes"),
  234. Copyright = new CopyrightInfo("Author", DateTime.Now.Year)
  235. };
  236. local.AddOptions(new MockOptionsSimple());
  237. string help = local.ToString();
  238. Console.WriteLine(help);
  239. string[] lines = help.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
  240. lines[3].Should().Be(" -s, --something Input something here.");
  241. }
  242. [Fact]
  243. public void Create_basic_instance()
  244. {
  245. var local = new HelpText();
  246. local.ToString().Should().Be("");
  247. }
  248. [Fact]
  249. public void Invoke_render_parsing_errors_text()
  250. {
  251. var sw = new StringWriter();
  252. var options = new RPEOptions();
  253. var parser = new Parser(new ParserSettings {
  254. MutuallyExclusive = true, CaseSensitive = true, HelpWriter = sw});
  255. var result = parser.ParseArguments(new string[] {"--option-b", "hello", "-cWORLD"}, options);
  256. result.Should().BeFalse();
  257. var outsw = sw.ToString();
  258. Console.WriteLine(outsw);
  259. var lines = outsw.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
  260. lines[0].Should().Be("--option-b option violates format.");
  261. lines[1].Should().Be("-c/--option-c option violates format.");
  262. lines[2].Should().Be("-a required option is missing.");
  263. }
  264. /*
  265. [Fact]
  266. public void Auto_build_with_render_parsing_errors_helper()
  267. {
  268. var sw = new StringWriter();
  269. var options = new RPEOptionsForAutoBuild();
  270. var parser = new Parser(new ParserSettings {
  271. MutuallyExclusive = true, CaseSensitive = true, HelpWriter = sw});
  272. var result = parser.ParseArguments(new string[] {"--option-b", "hello", "-cWORLD"}, options);
  273. Assert.IsFalse(result);
  274. var outsw = sw.ToString();
  275. Console.WriteLine(outsw);
  276. var lines = outsw.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
  277. Assert.AreEqual(lines[0], "CommandLine.Tests 1.9");
  278. Assert.AreEqual(lines[1], "Copyright (C) 2005 - 2012 Giacomo Stelluti Scala");
  279. Assert.AreEqual(lines[3], "ERROR(S):");
  280. Assert.AreEqual(lines[4], " --option-b option violates format.");
  281. Assert.AreEqual(lines[5], " -c/--option-c option violates format.");
  282. Assert.AreEqual(lines[6], " -a required option is missing.");
  283. Assert.AreEqual(lines[8], "This is free software. You may redistribute copies of it under the terms of");
  284. Assert.AreEqual(lines[9], "the MIT License <http://www.opensource.org/licenses/mit-license.php>.");
  285. Assert.AreEqual(lines[10], "[no usage, this is a dll]");
  286. Assert.AreEqual(lines[12], " -a Required. This string option is defined A.");
  287. Assert.AreEqual(lines[14], " --option-b This integer option is defined B.");
  288. Assert.AreEqual(lines[16], " -c, --option-c This double option is defined C.");
  289. Assert.AreEqual(lines[18], " --help Display this help screen.");
  290. }
  291. [Fact]
  292. public void Auto_build()
  293. {
  294. var sw = new StringWriter();
  295. var options = new SimpleOptionsForAutoBuid();
  296. var parser = new Parser(new ParserSettings {
  297. MutuallyExclusive = true, CaseSensitive = true, HelpWriter = sw});
  298. var result = parser.ParseArguments(new string[] {}, options);
  299. Assert.IsFalse(result);
  300. var outsw = sw.ToString();
  301. Console.WriteLine(outsw);
  302. var lines = outsw.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
  303. Assert.AreEqual(lines[0], "CommandLine.Tests 1.9");
  304. Assert.AreEqual(lines[1], "Copyright (C) 2005 - 2012 Giacomo Stelluti Scala");
  305. Assert.AreEqual(lines[2], "This is free software. You may redistribute copies of it under the terms of");
  306. Assert.AreEqual(lines[3], "the MIT License <http://www.opensource.org/licenses/mit-license.php>.");
  307. Assert.AreEqual(lines[4], "[no usage, this is a dll]");
  308. Assert.AreEqual(lines[6], " -m, --mock Required. Force required.");
  309. Assert.AreEqual(lines[8], " -s, --string ");
  310. Assert.AreEqual(lines[10], " -i ");
  311. Assert.AreEqual(lines[12], " --switch ");
  312. Assert.AreEqual(lines[14], " --help Display this help screen.");
  313. }*/
  314. #region Parsing Errors Subsystem Test, related to Help Text building
  315. [Fact]
  316. public void Detailed_help_with_bad_format()
  317. {
  318. var options = new ComplexOptionsWithHelp();
  319. bool result = new Parser(new ParserSettings(Console.Out)).ParseArguments(
  320. new string[] { "-iIN.FILE", "-oOUT.FILE", "--offset", "abc" }, options);
  321. result.Should().BeFalse();
  322. }
  323. [Fact]
  324. public void Detailed_help_with_missing_required()
  325. {
  326. var options = new ComplexOptionsWithHelp();
  327. bool result = new Parser(new ParserSettings(Console.Out)).ParseArguments(
  328. new string[] { "-j0" }, options);
  329. result.Should().BeFalse();
  330. }
  331. [Fact]
  332. public void Detailed_help_with_missing_required_and_bad_format()
  333. {
  334. var options = new ComplexOptionsWithHelp();
  335. bool result = new Parser(new ParserSettings(Console.Out)).ParseArguments(
  336. new string[] { "-i0" }, options);
  337. result.Should().BeFalse();
  338. }
  339. [Fact]
  340. public void Detailed_help_with_bad_mutual_exclusiveness()
  341. {
  342. var options = new ComplexOptionsWithHelp();
  343. bool result = new Parser(new ParserSettings(true, true, Console.Out)).ParseArguments(
  344. new string[] { "-iIN.FILE", "-oOUT.FILE", "--offset", "0", "-ap" }, options);
  345. result.Should().BeFalse();
  346. }
  347. [Fact]
  348. public void Detailed_help_with_bad_format_and_mutual_exclusiveness()
  349. {
  350. var options = new ComplexOptionsWithHelp();
  351. bool result = new Parser(new ParserSettings(true, true, Console.Out)).ParseArguments(
  352. new string[] { "-iIN.FILE", "-oOUT.FILE", "--offset", "zero", "-pa" }, options);
  353. result.Should().BeFalse();
  354. }
  355. [Fact]
  356. public void Multiple_required_fields_with_more_than_one_required_field_not_specified_reports_all_missing_required_fields()
  357. {
  358. var options = new ComplexOptions();
  359. using (var writer = new StringWriter())
  360. {
  361. new Parser(new ParserSettings(false, false, writer)).ParseArguments(new string[0], options, writer);
  362. options.LastParserState.Errors.Should().HaveCount(n => n == 2);
  363. }
  364. }
  365. #endregion
  366. private void CustomizeOptionsFormat_FormatOptionHelpText(object sender, FormatOptionHelpTextEventArgs e)
  367. {
  368. // Simulating a localization process.
  369. string optionHelp = null;
  370. switch (e.Option.ShortName.Value)
  371. {
  372. case 'v':
  373. optionHelp = "Kommentar umfassend Operationen.";
  374. break;
  375. case 'i':
  376. optionHelp = "Gibt den Eingang an zu bearbeitenden Datei.";
  377. break;
  378. }
  379. if (e.Option.Required)
  380. {
  381. optionHelp = "Erforderlich. " + optionHelp;
  382. }
  383. e.Option.HelpText = optionHelp;
  384. }
  385. }
  386. }