5 // Jonathan Pryor <jpryor@novell.com>
7 // Copyright (C) 2008 Novell (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.ComponentModel;
33 using System.Globalization;
42 using Cadenza.Collections.Tests;
44 using NUnit.Framework;
47 namespace Tests.NDesk.Options
49 namespace MonoTests.Mono.Options
52 class FooConverter : TypeConverter {
53 public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
55 if (sourceType == typeof (string))
57 return base.CanConvertFrom (context, sourceType);
60 public override object ConvertFrom (ITypeDescriptorContext context,
61 CultureInfo culture, object value)
63 string v = value as string;
66 case "A": return Foo.A;
67 case "B": return Foo.B;
71 return base.ConvertFrom (context, culture, value);
75 [TypeConverter (typeof(FooConverter))]
77 public static readonly Foo A = new Foo ("A");
78 public static readonly Foo B = new Foo ("B");
80 Foo (string s) { this.s = s; }
81 public override string ToString () {return s;}
84 class TestArgumentSource : ArgumentSource, IEnumerable {
88 public TestArgumentSource (string[] names, string desc)
94 Dictionary<string, string[]> args = new Dictionary<string, string[]>();
96 public void Add (string key, params string[] values)
98 args.Add (key, values);
101 public override string[] GetNames ()
106 public override string Description {
110 public override bool GetArguments (string value, out IEnumerable<string> replacement)
115 if (args.TryGetValue (value, out values)) {
116 replacement = values;
124 IEnumerator IEnumerable.GetEnumerator ()
126 return args.GetEnumerator ();
131 public class OptionSetTest : ListContract<Option> {
133 protected override ICollection<Option> CreateCollection (IEnumerable<Option> values)
135 OptionSet set = new OptionSet();
136 foreach (Option value in values)
141 protected override Option CreateValueA ()
143 return new CustomOption ("A", null, 0, null);
146 protected override Option CreateValueB ()
148 return new CustomOption ("B", null, 0, null);
151 protected override Option CreateValueC ()
153 return new CustomOption ("C", null, 0, null);
156 static IEnumerable<string> _ (params string[] a)
162 public void BundledValues ()
164 BundledValues (_("-DNAME", "-D", "NAME2", "-Debug", "-L/foo", "-L", "/bar", "-EDNAME3"));
165 BundledValues (_("@s1", "-D", "@s2", "-L/foo", "@s4"));
168 public void BundledValues (IEnumerable<string> args)
170 var defines = new List<string> ();
171 var libs = new List<string> ();
173 var p = new OptionSet () {
174 { "D|define=", v => defines.Add (v) },
175 { "L|library:", v => libs.Add (v) },
176 { "Debug", v => debug = v != null },
177 { "E", v => { /* ignore */ } },
178 new TestArgumentSource (null, null) {
180 { "@s2", "NAME2", "@s3" },
182 { "@s4", "-L", "/bar", "-EDNAME3" },
186 Assert.AreEqual (defines.Count, 3);
187 Assert.AreEqual (defines [0], "NAME");
188 Assert.AreEqual (defines [1], "NAME2");
189 Assert.AreEqual (defines [2], "NAME3");
190 Assert.AreEqual (debug, true);
191 Assert.AreEqual (libs.Count, 2);
192 Assert.AreEqual (libs [0], "/foo");
193 Assert.AreEqual (libs [1], null);
195 Utils.AssertException (typeof(OptionException),
196 "Cannot use unregistered option 'V' in bundle '-EVALUENOTSUP'.",
197 p, v => { v.Parse (_("-EVALUENOTSUP")); });
201 public void RequiredValues ()
203 RequiredValues (_("a", "-a", "s", "-n=42", "n"));
204 RequiredValues (_("@s1", "s", "@s2", "n"));
207 void RequiredValues (IEnumerable<string> args)
211 OptionSet p = new OptionSet () {
212 { "a=", v => a = v },
213 { "n=", (int v) => n = v },
214 new TestArgumentSource (null, null) {
215 { "@s1", "a", "-a" },
219 List<string> extra = p.Parse (args);
220 Assert.AreEqual (extra.Count, 2);
221 Assert.AreEqual (extra [0], "a");
222 Assert.AreEqual (extra [1], "n");
223 Assert.AreEqual (a, "s");
224 Assert.AreEqual (n, 42);
226 extra = p.Parse (_("-a="));
227 Assert.AreEqual (extra.Count, 0);
228 Assert.AreEqual (a, "");
232 public void OptionalValues ()
237 OptionSet p = new OptionSet () {
238 { "a:", v => a = v },
239 { "n:", (int? v) => n = v },
240 { "f:", (Foo v) => f = v },
243 Assert.AreEqual (a, "s");
245 Assert.AreEqual (a, null);
247 Assert.AreEqual (a, "");
249 p.Parse (_("-f", "A"));
250 Assert.AreEqual (f, null);
252 Assert.AreEqual (f, null);
254 Assert.AreEqual (f, Foo.A);
257 Assert.AreEqual (f, Foo.A);
260 Assert.AreEqual (n.Value, 42);
261 p.Parse (_("-n", "42"));
262 Assert.AreEqual (n.HasValue, false);
263 p.Parse (_("-n=42"));
264 Assert.AreEqual (n.Value, 42);
266 Assert.AreEqual (n.HasValue, false);
267 Utils.AssertException (typeof(OptionException),
268 "Could not convert string `' to type Int32 for option `-n'.",
269 p, v => { v.Parse (_("-n=")); });
273 public void EnumValues ()
276 OptionSet p = new OptionSet () {
277 { "a=", (DayOfWeek v) => a = v },
279 p.Parse (_ ("-a=Monday"));
280 Assert.AreEqual (a, DayOfWeek.Monday);
281 p.Parse (_ ("-a=tuesday"));
282 Assert.AreEqual (a, DayOfWeek.Tuesday);
283 p.Parse (_ ("-a=3"));
284 Assert.AreEqual (a, DayOfWeek.Wednesday);
285 p.Parse (_ ("-a=Monday,Tuesday"));
286 Assert.AreEqual (a, DayOfWeek.Monday | DayOfWeek.Tuesday);
287 Utils.AssertException (typeof (OptionException),
288 "Could not convert string `Noday' to type DayOfWeek for option `-a'.",
289 p, v => { v.Parse (_ ("-a=Noday")); });
293 public void BooleanValues ()
296 OptionSet p = new OptionSet () {
297 { "a", v => a = v != null },
300 Assert.AreEqual (a, true);
302 Assert.AreEqual (a, true);
304 Assert.AreEqual (a, false);
308 public void CombinationPlatter ()
310 CombinationPlatter (new string[]{"foo", "-v", "-a=42", "/b-",
311 "-a", "64", "bar", "--f", "B", "/h", "-?", "--help", "-v"});
312 CombinationPlatter (_("@s1", "-a=42", "@s3", "-a", "64", "bar", "@s4"));
315 void CombinationPlatter (IEnumerable<string> args)
318 string av = null, bv = null;
322 OptionSet p = new OptionSet () {
323 { "a=", v => { a = 1; av = v; } },
324 { "b", "desc", v => {b = 2; bv = v;} },
325 { "f=", (Foo v) => f = v },
326 { "v", v => { ++verbose; } },
327 { "h|?|help", (v) => { switch (v) {
328 case "h": help |= 0x1; break;
329 case "?": help |= 0x2; break;
330 case "help": help |= 0x4; break;
332 new TestArgumentSource (null, null) {
333 { "@s1", "foo", "-v", "@s2" },
336 { "@s4", "--f", "B", "/h", "-?", "--help", "-v" },
339 List<string> e = p.Parse (args);
341 Assert.AreEqual (e.Count, 2);
342 Assert.AreEqual (e[0], "foo");
343 Assert.AreEqual (e[1], "bar");
344 Assert.AreEqual (a, 1);
345 Assert.AreEqual (av, "64");
346 Assert.AreEqual (b, 2);
347 Assert.AreEqual (bv, null);
348 Assert.AreEqual (verbose, 2);
349 Assert.AreEqual (help, 0x7);
350 Assert.AreEqual (f, Foo.B);
354 public void Exceptions ()
357 var p = new OptionSet () {
358 { "a=", v => a = v },
361 { "n=", (int v) => { } },
362 { "f=", (Foo v) => { } },
365 Utils.AssertException (typeof(OptionException),
366 "Missing required value for option '-a'.",
367 p, v => { v.Parse (_("-a")); });
368 // another named option while expecting one -- follow Getopt::Long
369 Utils.AssertException (null, null,
370 p, v => { v.Parse (_("-a", "-a")); });
371 Assert.AreEqual (a, "-a");
372 // no exception when an unregistered named option follows.
373 Utils.AssertException (null, null,
374 p, v => { v.Parse (_("-a", "-b")); });
375 Assert.AreEqual (a, "-b");
376 Utils.AssertException (typeof(ArgumentNullException),
377 "Value cannot be null.\nParameter name: option",
378 p, v => { v.Add ((Option) null); });
379 Utils.AssertException (typeof(ArgumentNullException),
380 "Value cannot be null.\nParameter name: header",
381 p, v => { v.Add ((string) null); });
384 Utils.AssertException (typeof(OptionException),
385 "Could not convert string `value' to type Int32 for option `-n'.",
386 p, v => { v.Parse (_("-n", "value")); });
387 Utils.AssertException (typeof(OptionException),
388 "Could not convert string `invalid' to type Foo for option `--f'.",
389 p, v => { v.Parse (_("--f", "invalid")); });
391 // try to bundle with an option requiring a value
392 Utils.AssertException (typeof(OptionException),
393 "Cannot use unregistered option 'z' in bundle '-cz'.",
394 p, v => { v.Parse (_("-cz", "extra")); });
396 Utils.AssertException (typeof(ArgumentNullException),
397 "Value cannot be null.\nParameter name: action",
398 p, v => { v.Add ("foo", (Action<string>) null); });
399 Utils.AssertException (typeof(ArgumentException),
400 "Cannot provide maxValueCount of 2 for OptionValueType.None.\nParameter name: maxValueCount",
401 p, v => { v.Add ("foo", (k, val) => {/* ignore */}); });
405 public void WriteOptionDescriptions ()
407 var p = new OptionSet () {
409 { "hidden", "hidden option, invisible in help", v => {}, true },
410 { "hidden2=", "hidden option, invisible in help", (k, v) => {}, true },
411 { "p|indicator-style=", "append / indicator to directories", v => {} },
412 { "color:", "controls color info", v => {} },
413 { "color2:", "set {color}", v => {} },
414 { "rk=", "required key/value option", (k, v) => {} },
415 { "rk2=", "required {{foo}} {0:key}/{1:value} option", (k, v) => {} },
416 { "ok:", "optional key/value option", (k, v) => {} },
418 "This has a really\nlong, multi-line description that also\ntests\n" +
419 "the-builtin-supercalifragilisticexpialidicious-break-on-hyphen. " +
425 "IWantThisDescriptionToBreakInsideAWordGeneratingAutoWordHyphenation. ",
428 "OnlyOnePeriod.AndNoWhitespaceShouldBeSupportedEvenWithLongDescriptions",
431 "Lots of spaces in the middle 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 and more until the end.",
434 "Lots of spaces in the middle - . - . - . - . - . - . - . - and more until the end.",
437 "==This is a really long category name which will involve line wrapping, just because...==",
439 "The {DIRECTORY} to place the generated files and directories.\n\n" +
440 "If not specified, defaults to\n`dirname FILE`/cache/`basename FILE .tree`.",
444 { "h|?|help", "show help text", v => {} },
445 { "version", "output version information and exit", v => {} },
447 new TestArgumentSource (new[]{"@s1", "@s2"}, "Read Response File for More Options"),
450 StringWriter expected = new StringWriter ();
451 expected.WriteLine ("");
452 expected.WriteLine (":Category 1:");
453 expected.WriteLine (" -p, --indicator-style=VALUE");
454 expected.WriteLine (" append / indicator to directories");
455 expected.WriteLine (" --color[=VALUE] controls color info");
456 expected.WriteLine (" --color2[=color] set color");
457 expected.WriteLine (" --rk=VALUE1:VALUE2 required key/value option");
458 expected.WriteLine (" --rk2=key:value required {foo} key/value option");
459 expected.WriteLine (" --ok[=VALUE1:VALUE2] optional key/value option");
460 expected.WriteLine (" --long-desc This has a really");
461 expected.WriteLine (" long, multi-line description that also");
462 expected.WriteLine (" tests");
463 expected.WriteLine (" the-builtin-supercalifragilisticexpialidicious-");
464 expected.WriteLine (" break-on-hyphen. Also, a list:");
465 expected.WriteLine (" item 1");
466 expected.WriteLine (" item 2");
467 expected.WriteLine (" --long-desc2 IWantThisDescriptionToBreakInsideAWordGeneratingAu-");
468 expected.WriteLine (" toWordHyphenation.");
469 expected.WriteLine (" --long-desc3 OnlyOnePeriod.");
470 expected.WriteLine (" AndNoWhitespaceShouldBeSupportedEvenWithLongDesc-");
471 expected.WriteLine (" riptions");
472 expected.WriteLine (" --long-desc4 Lots of spaces in the middle 1 2 3 4 5 6 7 8 9 0 1");
473 expected.WriteLine (" 2 3 4 5 and more until the end.");
474 expected.WriteLine (" --long-desc5 Lots of spaces in the middle - . - . - . - . - . -");
475 expected.WriteLine (" . - . - and more until the end.");
476 expected.WriteLine ("");
477 expected.WriteLine ("==This is a really long category name which will involve line wrapping, just");
478 expected.WriteLine ("because...==");
479 expected.WriteLine (" -o, --out=DIRECTORY The DIRECTORY to place the generated files and");
480 expected.WriteLine (" directories.");
481 expected.WriteLine (" ");
482 expected.WriteLine (" If not specified, defaults to");
483 expected.WriteLine (" `dirname FILE`/cache/`basename FILE .tree`.");
484 expected.WriteLine ("");
485 expected.WriteLine ("Category 3:");
486 expected.WriteLine (" -h, -?, --help show help text");
487 expected.WriteLine (" --version output version information and exit");
488 expected.WriteLine (" @s1, @s2 Read Response File for More Options");
490 StringWriter actual = new StringWriter ();
491 p.WriteOptionDescriptions (actual);
493 Assert.AreEqual (expected.ToString (), actual.ToString ());
497 public void OptionBundling ()
499 OptionBundling (_ ("-abcf", "foo", "bar"));
500 OptionBundling (_ ("@s1", "foo", "bar"));
503 void OptionBundling (IEnumerable<string> args)
506 a = b = c = f = null;
507 var p = new OptionSet () {
508 { "a", v => a = "a" },
509 { "b", v => b = "b" },
510 { "c", v => c = "c" },
511 { "f=", v => f = v },
512 new TestArgumentSource (null, null) {
516 List<string> extra = p.Parse (args);
517 Assert.AreEqual (extra.Count, 1);
518 Assert.AreEqual (extra [0], "bar");
519 Assert.AreEqual (a, "a");
520 Assert.AreEqual (b, "b");
521 Assert.AreEqual (c, "c");
522 Assert.AreEqual (f, "foo");
526 public void HaltProcessing ()
528 var p = new OptionSet () {
531 new TestArgumentSource (null, null) {
532 { "@s1", "-a", "-b" },
535 List<string> e = p.Parse (_ ("-a", "-b", "--", "-a", "-b"));
536 Assert.AreEqual (e.Count, 2);
537 Assert.AreEqual (e [0], "-a");
538 Assert.AreEqual (e [1], "-b");
540 e = p.Parse (_ ("@s1", "--", "@s1"));
541 Assert.AreEqual (e.Count, 1);
542 Assert.AreEqual (e [0], "@s1");
546 public void KeyValueOptions ()
548 var a = new Dictionary<string, string> ();
549 var b = new Dictionary<int, char> ();
550 var p = new OptionSet () {
551 { "a=", (k,v) => a.Add (k, v) },
552 { "b=", (int k, char v) => b.Add (k, v) },
553 { "c:", (k, v) => {if (k != null) a.Add (k, v);} },
554 { "d={=>}{-->}", (k, v) => a.Add (k, v) },
555 { "e={}", (k, v) => a.Add (k, v) },
556 { "f=+/", (k, v) => a.Add (k, v) },
557 new TestArgumentSource (null, null) {
558 { "@s1", "-a", "A" },
559 { "@s2", @"C:\tmp", "-a" },
560 { "@s3", "C=D", @"-a=E=F:\tmp" },
561 { "@s4", "-a:G:H", "-aI=J" },
562 { "@s5", "-b", "1" },
563 { "@s6", "a", "-b" },
565 { "@s8", "-dA=>B", "-d" },
566 { "@s9", "C-->D", "-d:E" },
567 { "@s10", "F", "-d" },
568 { "@s11", "G", "H" },
569 { "@s12", "-dJ-->K" }
572 p.Parse (_("-a", "A", @"C:\tmp", "-a", "C=D", @"-a=E=F:\tmp", "-a:G:H", "-aI=J", "-b", "1", "a", "-b", "2", "b"));
573 Action assert = () => {
588 p.Parse (_("@s1", "@s2", "@s3", "@s4", "@s5", "@s6", "@s7"));
594 Assert.AreEqual (a.Count, 0);
595 p.Parse (_("-c", "a"));
596 Assert.AreEqual (a.Count, 0);
598 AssertDictionary (a, "a", null);
600 p.Parse (_("-ca=b"));
601 AssertDictionary (a, "a", "b");
604 p.Parse (_("-dA=>B", "-d", "C-->D", "-d:E", "F", "-d", "G", "H", "-dJ-->K"));
616 p.Parse (_("@s8", "@s9", "@s10", "@s11", "@s12"));
620 p.Parse (_("-eA=B", "-eC=D", "-eE", "F", "-e:G", "H"));
627 p.Parse (_("-f1/2", "-f=3/4", "-f:5+6", "-f7", "8", "-f9=10", "-f11=12"));
636 static void AssertDictionary<TKey, TValue> (Dictionary<TKey, TValue> dict, params string[] set)
638 TypeConverter k = TypeDescriptor.GetConverter (typeof (TKey));
639 TypeConverter v = TypeDescriptor.GetConverter (typeof (TValue));
641 Assert.AreEqual (dict.Count, set.Length / 2);
642 for (int i = 0; i < set.Length; i += 2) {
643 TKey key = (TKey) k.ConvertFromString (set [i]);
644 Assert.AreEqual (dict.ContainsKey (key), true);
645 if (set [i+1] == null)
646 Assert.AreEqual (dict [key], default (TValue));
648 Assert.AreEqual (dict [key], (TValue) v.ConvertFromString (set [i+1]));
652 class CustomOption : Option {
653 Action<OptionValueCollection> action;
655 public CustomOption (string p, string d, int c, Action<OptionValueCollection> a)
661 protected override void OnParseComplete (OptionContext c)
663 action (c.OptionValues);
668 public void CustomKeyValue ()
670 var a = new Dictionary<string, string> ();
671 var b = new Dictionary<string, string[]> ();
672 var p = new OptionSet () {
673 new CustomOption ("a==:", null, 2, v => a.Add (v [0], v [1])),
674 new CustomOption ("b==:", null, 3, v => b.Add (v [0], new string[]{v [1], v [2]})),
676 p.Parse (_(@"-a=b=C:\tmp", "-a=d", @"C:\e", @"-a:f=C:\g", @"-a:h:C:\i", "-a", @"j=C:\k", "-a", @"l:C:\m"));
677 Assert.AreEqual (a.Count, 6);
678 Assert.AreEqual (a ["b"], @"C:\tmp");
679 Assert.AreEqual (a ["d"], @"C:\e");
680 Assert.AreEqual (a ["f"], @"C:\g");
681 Assert.AreEqual (a ["h"], @"C:\i");
682 Assert.AreEqual (a ["j"], @"C:\k");
683 Assert.AreEqual (a ["l"], @"C:\m");
685 Utils.AssertException (typeof(OptionException),
686 "Missing required value for option '-a'.",
687 p, v => {v.Parse (_("-a=b"));});
689 p.Parse (_("-b", "a", "b", @"C:\tmp", @"-b:d:e:F:\tmp", @"-b=g=h:i:\tmp", @"-b:j=k:l:\tmp"));
690 Assert.AreEqual (b.Count, 4);
691 Assert.AreEqual (b ["a"][0], "b");
692 Assert.AreEqual (b ["a"][1], @"C:\tmp");
693 Assert.AreEqual (b ["d"][0], "e");
694 Assert.AreEqual (b ["d"][1], @"F:\tmp");
695 Assert.AreEqual (b ["g"][0], "h");
696 Assert.AreEqual (b ["g"][1], @"i:\tmp");
697 Assert.AreEqual (b ["j"][0], "k");
698 Assert.AreEqual (b ["j"][1], @"l:\tmp");
702 public void Localization ()
704 var p = new OptionSet (f => "hello!") {
705 { "n=", (int v) => { } },
707 Utils.AssertException (typeof(OptionException), "hello!",
708 p, v => { v.Parse (_("-n=value")); });
710 StringWriter expected = new StringWriter ();
711 expected.WriteLine (" -nhello! hello!");
713 StringWriter actual = new StringWriter ();
714 p.WriteOptionDescriptions (actual);
716 Assert.AreEqual (actual.ToString (), expected.ToString ());
719 class CiOptionSet : OptionSet {
720 protected override void InsertItem (int index, Option item)
722 if (item.Prototype.ToLower () != item.Prototype)
723 throw new ArgumentException ("prototypes must be null!");
724 base.InsertItem (index, item);
727 protected override bool Parse (string option, OptionContext c)
729 if (c.Option != null)
730 return base.Parse (option, c);
732 if (!GetOptionParts (option, out f, out n, out s, out v)) {
733 return base.Parse (option, c);
735 return base.Parse (f + n.ToLower () + (v != null && s != null ? s + v : ""), c);
738 public new Option GetOptionForName (string n)
740 return base.GetOptionForName (n);
743 public void CheckOptionParts (string option, bool er, string ef, string en, string es, string ev)
746 bool r = GetOptionParts (option, out f, out n, out s, out v);
747 Assert.AreEqual (r, er);
748 Assert.AreEqual (f, ef);
749 Assert.AreEqual (n, en);
750 Assert.AreEqual (s, es);
751 Assert.AreEqual (v, ev);
756 public void DerivedType ()
759 var p = new CiOptionSet () {
760 { "h|help", v => help = v != null },
763 Assert.AreEqual (help, true);
765 p.Parse (_("-HELP"));
766 Assert.AreEqual (help, true);
768 Assert.AreEqual (p.GetOptionForName ("h"), p [0]);
769 Assert.AreEqual (p.GetOptionForName ("help"), p [0]);
770 Assert.AreEqual (p.GetOptionForName ("invalid"), null);
772 Utils.AssertException (typeof(ArgumentException), "prototypes must be null!",
773 p, v => { v.Add ("N|NUM=", (int n) => {}); });
774 Utils.AssertException (typeof(ArgumentNullException),
775 "Value cannot be null.\nParameter name: option",
776 p, v => { v.GetOptionForName (null); });
780 public void OptionParts ()
782 var p = new CiOptionSet ();
783 p.CheckOptionParts ("A", false, null, null, null, null);
784 p.CheckOptionParts ("A=B", false, null, null, null, null);
785 p.CheckOptionParts ("-A=B", true, "-", "A", "=", "B");
786 p.CheckOptionParts ("-A:B", true, "-", "A", ":", "B");
787 p.CheckOptionParts ("--A=B", true, "--", "A", "=", "B");
788 p.CheckOptionParts ("--A:B", true, "--", "A", ":", "B");
789 p.CheckOptionParts ("/A=B", true, "/", "A", "=", "B");
790 p.CheckOptionParts ("/A:B", true, "/", "A", ":", "B");
791 p.CheckOptionParts ("-A=B=C", true, "-", "A", "=", "B=C");
792 p.CheckOptionParts ("-A:B=C", true, "-", "A", ":", "B=C");
793 p.CheckOptionParts ("-A:B:C", true, "-", "A", ":", "B:C");
794 p.CheckOptionParts ("--A=B=C", true, "--", "A", "=", "B=C");
795 p.CheckOptionParts ("--A:B=C", true, "--", "A", ":", "B=C");
796 p.CheckOptionParts ("--A:B:C", true, "--", "A", ":", "B:C");
797 p.CheckOptionParts ("/A=B=C", true, "/", "A", "=", "B=C");
798 p.CheckOptionParts ("/A:B=C", true, "/", "A", ":", "B=C");
799 p.CheckOptionParts ("/A:B:C", true, "/", "A", ":", "B:C");
800 p.CheckOptionParts ("-AB=C", true, "-", "AB", "=", "C");
801 p.CheckOptionParts ("-AB:C", true, "-", "AB", ":", "C");
804 class ContextCheckerOption : Option {
805 string eName, eValue;
808 public ContextCheckerOption (string p, string d, string eName, string eValue, int index)
812 this.eValue = eValue;
816 protected override void OnParseComplete (OptionContext c)
818 Assert.AreEqual (c.OptionValues.Count, 1);
819 Assert.AreEqual (c.OptionValues [0], eValue);
820 Assert.AreEqual (c.OptionName, eName);
821 Assert.AreEqual (c.OptionIndex, index);
822 Assert.AreEqual (c.Option, this);
823 Assert.AreEqual (c.Option.Description, base.Description);
828 public void OptionContext ()
830 var p = new OptionSet () {
831 new ContextCheckerOption ("a=", "a desc", "/a", "a-val", 1),
832 new ContextCheckerOption ("b", "b desc", "--b+", "--b+", 2),
833 new ContextCheckerOption ("c=", "c desc", "--c", "C", 3),
834 new ContextCheckerOption ("d", "d desc", "/d-", null, 4),
836 Assert.AreEqual (p.Count, 4);
837 p.Parse (_("/a", "a-val", "--b+", "--c=C", "/d-"));
841 public void DefaultHandler ()
843 var extra = new List<string> ();
844 var p = new OptionSet () {
845 { "<>", v => extra.Add (v) },
847 var e = p.Parse (_("-a", "b", "--c=D", "E"));
848 Assert.AreEqual (e.Count, 0);
849 Assert.AreEqual (extra.Count, 4);
850 Assert.AreEqual (extra [0], "-a");
851 Assert.AreEqual (extra [1], "b");
852 Assert.AreEqual (extra [2], "--c=D");
853 Assert.AreEqual (extra [3], "E");
857 public void MixedDefaultHandler ()
859 var tests = new List<string> ();
860 var p = new OptionSet () {
861 { "t|<>=", v => tests.Add (v) },
863 var e = p.Parse (_("-tA", "-t:B", "-t=C", "D", "--E=F"));
864 Assert.AreEqual (e.Count, 0);
865 Assert.AreEqual (tests.Count, 5);
866 Assert.AreEqual (tests [0], "A");
867 Assert.AreEqual (tests [1], "B");
868 Assert.AreEqual (tests [2], "C");
869 Assert.AreEqual (tests [3], "D");
870 Assert.AreEqual (tests [4], "--E=F");
874 public void DefaultHandlerRuns ()
876 var formats = new Dictionary<string, List<string>> ();
877 string format = "foo";
878 var p = new OptionSet () {
879 { "f|format=", v => format = v },
883 if (!formats.TryGetValue (format, out f)) {
884 f = new List<string> ();
885 formats.Add (format, f);
890 var e = p.Parse (_("a", "b", "-fbar", "c", "d", "--format=baz", "e", "f"));
891 Assert.AreEqual (e.Count, 0);
892 Assert.AreEqual (formats.Count, 3);
893 Assert.AreEqual (formats ["foo"].Count, 2);
894 Assert.AreEqual (formats ["foo"][0], "a");
895 Assert.AreEqual (formats ["foo"][1], "b");
896 Assert.AreEqual (formats ["bar"].Count, 2);
897 Assert.AreEqual (formats ["bar"][0], "c");
898 Assert.AreEqual (formats ["bar"][1], "d");
899 Assert.AreEqual (formats ["baz"].Count, 2);
900 Assert.AreEqual (formats ["baz"][0], "e");
901 Assert.AreEqual (formats ["baz"][1], "f");
905 public void ReportInvalidDuplication ()
908 var p = new OptionSet () {
909 { "v", v => verbosity = v != null ? verbosity + 1 : verbosity },
912 p.Parse (new []{"-v-v-v"});
913 Assert.Fail ("Should not be reached.");
914 } catch (OptionException e) {
915 Assert.AreEqual (null, e.OptionName);
916 Assert.AreEqual ("Cannot use unregistered option '-' in bundle '-v-v-v'.", e.Message);