Mercurial > projects > ldc
comparison tango/tango/util/Arguments.d @ 132:1700239cab2e trunk
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos.
Lots of bugfixes...
This build is not suitable for most things.
author | lindquist |
---|---|
date | Fri, 11 Jan 2008 17:57:40 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
131:5825d48b27d1 | 132:1700239cab2e |
---|---|
1 /******************************************************************************* | |
2 copyright: Copyright (c) 2007 Darryl Bleau. All rights reserved. | |
3 | |
4 license: BSD style: $(LICENSE) | |
5 | |
6 version: Oct2007 | |
7 author: Darryl B, Jeff D | |
8 | |
9 History: | |
10 --- | |
11 Date Who What | |
12 Sep2006 Darryl Bleau Original C module | |
13 Sep2007 Jeff Davey Ported to D, added comments. | |
14 Oct2007 Darryl Bleau Added validation delegates/functions, more comments. | |
15 --- | |
16 *******************************************************************************/ | |
17 | |
18 /******************************************************************************* | |
19 | |
20 This module is used to parse arguments, and give easy access to them. | |
21 | |
22 *******************************************************************************/ | |
23 | |
24 module tango.util.Arguments; | |
25 | |
26 private import tango.core.Exception : TracedException; | |
27 | |
28 /*********************************************************************** | |
29 | |
30 This exception is thrown during argument validation. | |
31 | |
32 ***********************************************************************/ | |
33 | |
34 public class ArgumentException : TracedException | |
35 { | |
36 /*********************************************************************** | |
37 | |
38 The reason the exception was thrown | |
39 | |
40 ***********************************************************************/ | |
41 | |
42 enum ExceptionReason | |
43 { | |
44 /*********************************************************************** | |
45 An invalid parameter was passed | |
46 ***********************************************************************/ | |
47 | |
48 INVALID_PARAMETER, | |
49 /*********************************************************************** | |
50 A parameter wasn't passed to an argument when it was expected | |
51 ***********************************************************************/ | |
52 | |
53 MISSING_PARAMETER, | |
54 /*********************************************************************** | |
55 An argument was missing | |
56 ***********************************************************************/ | |
57 | |
58 MISSING_ARGUMENT | |
59 } | |
60 | |
61 private char[] _name; | |
62 private char[] _parameter; | |
63 private ExceptionReason _reason; | |
64 | |
65 /*********************************************************************** | |
66 | |
67 The name of the specific argument | |
68 | |
69 ***********************************************************************/ | |
70 | |
71 char[] name() { return _name; } | |
72 | |
73 /*********************************************************************** | |
74 | |
75 The parameter to the argument | |
76 | |
77 ***********************************************************************/ | |
78 | |
79 char[] parameter() { return _parameter; } | |
80 | |
81 /*********************************************************************** | |
82 | |
83 The enum to the reason it failed | |
84 | |
85 ***********************************************************************/ | |
86 | |
87 ExceptionReason reason() { return _reason; } | |
88 | |
89 this(char[] msg, char[] name, char[] parameter, ExceptionReason reason) | |
90 { | |
91 _name = name; | |
92 _parameter = parameter; | |
93 _reason = reason; | |
94 super(msg); | |
95 } | |
96 } | |
97 | |
98 /*********************************************************************** | |
99 | |
100 The Arguments class is used to parse arguments and encapsulate the | |
101 parameters passed by an application user. | |
102 | |
103 The command line arguments into an array of found arguments and their | |
104 respective parameters (if any). | |
105 | |
106 Arguments can be short (-), long (--), or implicit. Arguments can | |
107 optionally be passed parameters. For example, this module | |
108 parses command lines such as: "-a -b -c --long --argument=parameter" | |
109 | |
110 Example: | |
111 --- | |
112 char[][] arguments = [ "programname", "-a:on", "-abc:on", "--this=good", "-x:on" ]; | |
113 Arguments args = new Arguments(arguments); | |
114 if (args) | |
115 { | |
116 args.addValidation("b", true, false); | |
117 args.addValidation("c", true, true); | |
118 args.addValidation("x", false, true); | |
119 args.addValidation("this", false, true); | |
120 args.addValidation("this", (char[] a) { (return a.length < 5); }); | |
121 try | |
122 { | |
123 args.validate(); | |
124 return Test.Status.Success; | |
125 } | |
126 catch (ArgumentException ex) | |
127 { | |
128 messages ~= Stdout.layout.convert("{}: {} - {}", ex.name, ex.msg, ex.reason == ArgumentException.ExceptionReason.INVALID_PARAMETER ? "invalid parameter" : ex.reason == ArgumentException.ExceptionReason.MISSING_PARAMETER ? "missing parameter" : "missing argument"); | |
129 } | |
130 } | |
131 --- | |
132 | |
133 Syntax: | |
134 --- | |
135 Short Argument - -[x][:=]?[ parameter]... | |
136 Long Argument - --[long][:=]?[ parameter]... | |
137 Implicit Arguments - [implicitName]... Multiple implicit arguments are allowed. | |
138 --- | |
139 | |
140 Usage: | |
141 | |
142 Short options can be grouped in a single dash. The following are equivalent. | |
143 --- | |
144 - "myprogram -a -b -c" | |
145 - "myprogram -abc" | |
146 --- | |
147 | |
148 Arguments can be passed with space, '=', or ':'. The following are equivalent. | |
149 --- | |
150 - "myprogram -c arg" | |
151 - "myprogram -c=arg" | |
152 - "myprogram -c:arg" | |
153 --- | |
154 | |
155 As are these. | |
156 --- | |
157 - "myprogram --long arg" | |
158 - "myprogram --long=arg" | |
159 - "myprogram --long:arg" | |
160 --- | |
161 | |
162 Arguments can contain either '=' or ':', but not both. For example. | |
163 the following results in the argument 'long' being set to 'arg=other' | |
164 and 'arg:other', respectively. | |
165 --- | |
166 - "myprogram --long:arg=other" | |
167 - "myprogram --long=arg:other" | |
168 --- | |
169 | |
170 Blank dashes are ignored. The following are all equivalent. | |
171 --- | |
172 - "myprogram -c -- -a" | |
173 - "myprogram -c - -a" | |
174 - "myprogram - - - -a -- -c" | |
175 --- | |
176 | |
177 In the absence of implicit arguments, short options can be infered when | |
178 they come first. Given no implicit arguments, the following are equivalent. | |
179 --- | |
180 - "myprogram abc" | |
181 - "myprogram -abc" | |
182 - "myprogram -a -b -c" | |
183 --- | |
184 | |
185 Short options are case sensitive, while long options are not. The following | |
186 are equivalent. | |
187 --- | |
188 - "myprogram -a -A -LONG" | |
189 - "myprogram -a -A -Long" | |
190 - "myprogram -a -A -long" | |
191 --- | |
192 | |
193 In the event of multiple definitions of an argument, any parameters given | |
194 will be concatenated. The following are equivalent. | |
195 --- | |
196 - "myprogram -a one two three" | |
197 - "myprogram -a one -a two -a three" | |
198 - "myprogram -a:one two -a=three" | |
199 --- | |
200 | |
201 Multiple parameters can be iterated through using via the opIndex operator. | |
202 For example, given: | |
203 --- | |
204 - "myprogram -collect one two three '4 5 6'" | |
205 --- | |
206 args["collect"] will return a char[][] array ["one", "two", "three", "4 5 6"]. | |
207 | |
208 Implicit arguments can be defined by passing in an implicit arguments array, | |
209 which may look something like: ["first", "second"]. | |
210 Given implicit arguments, any non-argument command line parameters will be | |
211 automatically assigned to the implicit arguments, | |
212 in the order they were given. | |
213 For example, given the implicit arguments ["first", "second"] and command line: | |
214 --- | |
215 - "myprogram hello there bob" | |
216 --- | |
217 The argument 'first' will be assigned 'hello', and the argument 'second' will | |
218 be assigned both 'there' and 'bob'. | |
219 | |
220 Any intervening arguments will end the assignment. For example, given: | |
221 --- | |
222 - "myprogram hello there bob -a how are you" | |
223 --- | |
224 'first' is assigned 'hello', 'second' is assigned 'there' and 'bob', and 'a' | |
225 is assigned 'how', 'are', and 'you'. | |
226 | |
227 Implicit arguments also allows programs to support non-option arguments, | |
228 given implicit arguments ["actions"], and a command line such as: | |
229 --- | |
230 - "myprogram mop sweep get_coffee -time:now" | |
231 --- | |
232 args["actions"] will contain ["mop", "sweep", "get_coffee"], and | |
233 args["time"] will contain "now". | |
234 | |
235 ***********************************************************************/ | |
236 | |
237 public class Arguments | |
238 { | |
239 /// Function used to validate multiple parameters at once. | |
240 alias bool function(char[][] params, inout char[] invalidParam) validationFunctionMulti; | |
241 /// Delegate used to validate multiple parameters at once. | |
242 alias bool delegate(char[][] params, inout char[] invalidParam) validationDelegateMulti; | |
243 /// Function used to validate single parameters at a time. | |
244 alias bool function(char[] param) validationFunction; | |
245 /// Delegate used to validate single parameters at a time. | |
246 alias bool delegate(char[] param) validationDelegate; | |
247 | |
248 private char[][][char[]] _args; | |
249 private char[] _program; | |
250 private struct validation | |
251 { | |
252 validationFunction[] validF; | |
253 validationDelegate[] validD; | |
254 validationFunctionMulti[] validFM; | |
255 validationDelegateMulti[] validDM; | |
256 bool required; | |
257 bool paramRequired; | |
258 } | |
259 private validation[char[]] _validations; | |
260 | |
261 private char[] parseLongArgument(char[] arg) | |
262 { | |
263 char[] rtn; | |
264 | |
265 int locate(char[] arg, char c) { | |
266 foreach (i, a; arg) | |
267 if (a is c) | |
268 return i; | |
269 return arg.length; | |
270 } | |
271 | |
272 | |
273 if (arg) | |
274 { | |
275 int equalDelim = locate(arg, '='); | |
276 int colonDelim = locate(arg, ':'); | |
277 int paramPos = ((equalDelim != arg.length) && (colonDelim != arg.length)) ? (equalDelim < colonDelim ? equalDelim : colonDelim) : (equalDelim != arg.length) ? equalDelim : colonDelim; | |
278 if (paramPos != arg.length) | |
279 { | |
280 char[] argName = arg[0 .. paramPos]; | |
281 char[] value = arg[(paramPos + 1) .. arg.length]; | |
282 setArg(argName, value); | |
283 rtn = argName; | |
284 } | |
285 else | |
286 { | |
287 setArg(arg, null); | |
288 rtn = arg; | |
289 } | |
290 } | |
291 return rtn; | |
292 } | |
293 | |
294 private void setArg(char[] arg, char[] value) | |
295 { | |
296 if (arg) | |
297 { | |
298 if ((arg in _args) || (value !is null)) | |
299 _args[arg] ~= value; | |
300 else | |
301 _args[arg] = null; | |
302 } | |
303 } | |
304 | |
305 private char[] parseShortArgument(char[] arg) | |
306 { | |
307 char[] rtn; | |
308 | |
309 if (arg) | |
310 { | |
311 char[] argName; | |
312 uint i; | |
313 for (i = 0; i < arg.length; i++) | |
314 { | |
315 if (arg[i] != '=' && arg[i] != ':') | |
316 { | |
317 argName = arg[i .. i + 1]; | |
318 setArg(argName, null); | |
319 } | |
320 else if (((arg.length) - i) > 1) | |
321 { | |
322 setArg(argName, arg[i+1 .. arg.length]); | |
323 break; | |
324 } | |
325 } | |
326 rtn = argName; | |
327 } | |
328 return rtn; | |
329 } | |
330 | |
331 /*********************************************************************** | |
332 | |
333 Allows external argument assignment, works the same as command line | |
334 in that it appends to any values already assigned to the given key. | |
335 | |
336 Params: | |
337 value = assigned value | |
338 key = key to assign to | |
339 | |
340 ***********************************************************************/ | |
341 | |
342 void opIndexAssign(char[] value, char[] key) | |
343 { | |
344 setArg(key, value); | |
345 } | |
346 | |
347 /*********************************************************************** | |
348 | |
349 Allows removal of keys from the arguments. Useful if you want to replace | |
350 values for a given key rather than to append to them. | |
351 | |
352 Params: | |
353 key = key to remove values from. | |
354 | |
355 ***********************************************************************/ | |
356 | |
357 void remove(char[] key) | |
358 { | |
359 _args[key] = null; | |
360 } | |
361 | |
362 /*********************************************************************** | |
363 | |
364 Directly access an argument's parameters via opIndex operator as an | |
365 array. | |
366 This is to cover something like: param1 "parm with space" param2 | |
367 | |
368 ***********************************************************************/ | |
369 | |
370 char[][] opIndex(char[] key) | |
371 { | |
372 char[][] rtn = null; | |
373 if (key && (key in _args)) | |
374 rtn = _args[key]; | |
375 return rtn; | |
376 } | |
377 | |
378 /*********************************************************************** | |
379 | |
380 Operator is used to check if the argument exists | |
381 | |
382 ***********************************************************************/ | |
383 | |
384 bool opIn_r(char[] key) | |
385 { | |
386 bool rtn = false; | |
387 if (key) | |
388 rtn = (key in _args) != null; | |
389 return rtn; | |
390 } | |
391 | |
392 /*********************************************************************** | |
393 | |
394 Adds a validation to the arguments | |
395 | |
396 Params: | |
397 argument = the argument name | |
398 required = specifies if this argument is required | |
399 paramRequired = specifies if this argument requires a parameter | |
400 | |
401 ***********************************************************************/ | |
402 | |
403 void addValidation(char[] argument, bool required, bool paramRequired) | |
404 { | |
405 if (argument) | |
406 { | |
407 validation* val = getValidation(argument); | |
408 if (val !is null) | |
409 { | |
410 val.required = required; | |
411 val.paramRequired = paramRequired; | |
412 } | |
413 } | |
414 } | |
415 | |
416 /*********************************************************************** | |
417 | |
418 Adds a validation to the arguments | |
419 | |
420 Params: | |
421 argument = the argument name | |
422 validF = a validation function for single parameters | |
423 | |
424 ***********************************************************************/ | |
425 | |
426 void addValidation(char[] argument, validationFunction validF) | |
427 { | |
428 if (argument && validF) | |
429 { | |
430 validation* val = getValidation(argument); | |
431 if (val !is null) | |
432 val.validF ~= validF; | |
433 } | |
434 } | |
435 | |
436 /*********************************************************************** | |
437 | |
438 Adds a validation to the arguments | |
439 | |
440 Params: | |
441 argument = the argument name | |
442 validD = a validation delegate for single parameters | |
443 | |
444 ***********************************************************************/ | |
445 | |
446 void addValidation(char[] argument, validationDelegate validD) | |
447 { | |
448 if (argument && validD) | |
449 { | |
450 validation* val = getValidation(argument); | |
451 if (val !is null) | |
452 val.validD ~= validD; | |
453 } | |
454 } | |
455 | |
456 /*********************************************************************** | |
457 | |
458 Adds a validation to the arguments | |
459 | |
460 Params: | |
461 argument = the argument name | |
462 validF = a validation function for multiple parameters | |
463 | |
464 ***********************************************************************/ | |
465 | |
466 void addValidation(char[] argument, validationFunctionMulti validFM) | |
467 { | |
468 if (argument && validFM) | |
469 { | |
470 validation* val = getValidation(argument); | |
471 if (val !is null) | |
472 val.validFM ~= validFM; | |
473 } | |
474 } | |
475 | |
476 /*********************************************************************** | |
477 | |
478 Adds a validation to the arguments | |
479 | |
480 Params: | |
481 argument = the argument name | |
482 validD = a validation delegate for multiple parameters | |
483 | |
484 ***********************************************************************/ | |
485 | |
486 void addValidation(char[] argument, validationDelegateMulti validDM) | |
487 { | |
488 if (argument && validDM) | |
489 { | |
490 validation* val = getValidation(argument); | |
491 if (val !is null) | |
492 val.validDM ~= validDM; | |
493 } | |
494 } | |
495 | |
496 private validation* getValidation(char[] argument) | |
497 { | |
498 validation* rtn = null; | |
499 if (!(argument in _validations)) | |
500 { | |
501 validation newValidation; | |
502 _validations[argument] = newValidation; | |
503 } | |
504 if (argument in _validations) | |
505 rtn = &(_validations[argument]); | |
506 return rtn; | |
507 } | |
508 | |
509 /*********************************************************************** | |
510 | |
511 Validates the parsed arguments. | |
512 | |
513 Throws ArgumentException if it finds something wrong. | |
514 | |
515 ***********************************************************************/ | |
516 | |
517 void validate() | |
518 { | |
519 foreach(char[] argument, validation val; _validations) | |
520 { | |
521 if (val.required && !(argument in _args)) | |
522 throw new ArgumentException("Argument required.", argument, null, ArgumentException.ExceptionReason.MISSING_ARGUMENT); | |
523 if (val.paramRequired && (argument in _args) && (_args[argument].length == 0)) | |
524 throw new ArgumentException("Parameter required.", argument, null, ArgumentException.ExceptionReason.MISSING_PARAMETER); | |
525 if ((argument in _args) && (_args[argument].length > 0)) | |
526 { | |
527 char[] invalidParameter = null; | |
528 foreach(validationFunctionMulti validFM; val.validFM) | |
529 if (!validFM(_args[argument], invalidParameter)) | |
530 break; | |
531 if (invalidParameter is null) | |
532 { | |
533 foreach(validationDelegateMulti validDM; val.validDM) | |
534 if (!validDM(_args[argument], invalidParameter)) | |
535 break; | |
536 if (invalidParameter is null) | |
537 { | |
538 foreach(char[] arg; _args[argument]) | |
539 { | |
540 foreach(validationFunction validF; val.validF) | |
541 { | |
542 if (!validF(arg)) | |
543 { | |
544 invalidParameter = arg; | |
545 break; | |
546 } | |
547 } | |
548 if (invalidParameter is null) | |
549 { | |
550 foreach(validationDelegate validD; val.validD) | |
551 { | |
552 if (!validD(arg)) | |
553 { | |
554 invalidParameter = arg; | |
555 break; | |
556 } | |
557 } | |
558 } | |
559 } | |
560 } | |
561 } | |
562 if (invalidParameter !is null) | |
563 throw new ArgumentException("Invalid parameter.", argument, invalidParameter, ArgumentException.ExceptionReason.INVALID_PARAMETER); | |
564 } | |
565 } | |
566 } | |
567 | |
568 /*********************************************************************** | |
569 | |
570 Parse the arguments according to the passed implicitArg list | |
571 and aliases. | |
572 | |
573 ***********************************************************************/ | |
574 | |
575 | |
576 void parse(char[][] arguments, char[][] implicitArgs, char[][][] aliases) | |
577 { | |
578 char[] lastArgumentSet; | |
579 uint currentImplicitArg = 0; | |
580 for (uint i = 1; i < arguments.length; i++) | |
581 { | |
582 char[] currentArgument = arguments[i]; | |
583 if (currentArgument) | |
584 { | |
585 if (currentArgument[0] == '-') | |
586 { | |
587 if (currentArgument.length > 1) | |
588 { | |
589 if (currentArgument[1] == '-') | |
590 { | |
591 if (currentArgument.length > 2) | |
592 lastArgumentSet = parseLongArgument(currentArgument[2 .. currentArgument.length]); // long argument | |
593 } | |
594 else | |
595 lastArgumentSet = parseShortArgument(currentArgument[1 .. currentArgument.length]); // short argument | |
596 } | |
597 } | |
598 else | |
599 { | |
600 char[] argName; | |
601 // implicit argument / previously set argument | |
602 if (implicitArgs && (currentImplicitArg < implicitArgs.length)) | |
603 lastArgumentSet = argName = implicitArgs[currentImplicitArg++]; | |
604 else | |
605 argName = lastArgumentSet; | |
606 | |
607 if (argName) | |
608 setArg(argName, currentArgument); | |
609 else | |
610 lastArgumentSet = parseShortArgument(currentArgument); | |
611 } | |
612 } | |
613 } | |
614 | |
615 if (aliases) | |
616 { | |
617 for (uint i = 0; i < aliases.length; i++) | |
618 { | |
619 bool foundOne = false; | |
620 char[][] currentValues; | |
621 for (uint j = 0; j < aliases[i].length; j++) | |
622 { | |
623 if (aliases[i][j] in _args) | |
624 { | |
625 foundOne = true; | |
626 currentValues ~= _args[aliases[i][j]]; | |
627 } | |
628 } | |
629 | |
630 if (foundOne) | |
631 { | |
632 for (uint j = 0; j < aliases[i].length; j++) | |
633 _args[aliases[i][j]] = currentValues; | |
634 } | |
635 } | |
636 } | |
637 } | |
638 | |
639 /*********************************************************************** | |
640 | |
641 Constructor that supports all features | |
642 | |
643 Params: | |
644 arguments = the list of arguments (usually from main) | |
645 implicitArgs = assigns values using these keys in order from the arguments array. | |
646 aliases = aliases specific arguments to each other to concat parameters. looks like aliases[0] = [ "alias1", "alias2", "alias3" ]; (which groups all these arguments together) | |
647 | |
648 ***********************************************************************/ | |
649 | |
650 this(char[][] arguments, char[][] implicitArgs, char[][][] aliases) | |
651 { | |
652 _program = arguments[0]; | |
653 this.parse(arguments, implicitArgs, aliases); | |
654 } | |
655 | |
656 /*********************************************************************** | |
657 | |
658 Basic constructor which only deals with arguments | |
659 | |
660 Params: | |
661 arguments = array usually from main() | |
662 | |
663 ***********************************************************************/ | |
664 | |
665 this(char[][] arguments) | |
666 { | |
667 this(arguments, null, null); | |
668 } | |
669 | |
670 | |
671 /*********************************************************************** | |
672 | |
673 This constructor allows implicitArgs to be set as well | |
674 | |
675 Params: | |
676 arguments = array usually from main() | |
677 implicitArgs = the implicit arguments | |
678 | |
679 ***********************************************************************/ | |
680 | |
681 this(char[][] arguments, char[][] implicitArgs) | |
682 { | |
683 this(arguments, implicitArgs, null); | |
684 } | |
685 | |
686 /*********************************************************************** | |
687 | |
688 This constructor allows aliases | |
689 | |
690 Params: | |
691 arguments = array usually from main | |
692 aliases = the array of arguments to alias | |
693 | |
694 ***********************************************************************/ | |
695 | |
696 this(char[][] arguments, char[][][] aliases) | |
697 { | |
698 this(arguments, null, aliases); | |
699 } | |
700 } | |
701 | |
702 /+ | |
703 | |
704 TODO: Either rewrite this test to not use the Test class, or resolve ticket | |
705 749 to include Test in Tango. | |
706 | |
707 version(UnitTest) | |
708 { | |
709 import tango.util.Test; | |
710 import tango.text.Util; | |
711 import tango.io.Stdout; | |
712 | |
713 unittest | |
714 { | |
715 Test.Status parseTest(inout char[][] messages) | |
716 { | |
717 char[][] arguments = [ "ignoreprogramname", "--accumulate", "one", "-x", "on", "--accumulate:two", "-y", "off", "--accumulate=three", "-abc" ]; | |
718 Arguments args = new Arguments(arguments); | |
719 if (args) | |
720 { | |
721 if (!("ignoreprogramname" in args)) | |
722 { | |
723 if (join(args["accumulate"], " ") == "one two three") | |
724 { | |
725 if (args["x"][0] == "on") | |
726 { | |
727 if (("a" in args) && ("b" in args) && ("c" in args)) | |
728 return Test.Status.Success; | |
729 } | |
730 } | |
731 } | |
732 } | |
733 return Test.Status.Failure; | |
734 } | |
735 | |
736 Test.Status implicitParseTest(inout char[][] messages) | |
737 { | |
738 char[][] arguments = ["ignoreprogramname", "-r", "zero", "one two three", "four five", "-s", "six"]; | |
739 char[][] implicitArgs = [ "first", "second" ]; | |
740 Arguments args = new Arguments(arguments, implicitArgs); | |
741 if (args) | |
742 { | |
743 if (!("ignoreprogramname" in args)) | |
744 { | |
745 if (("r" in args) && !args["r"]) | |
746 { | |
747 if (args["first"][0] == "zero") | |
748 { | |
749 if (join(args["second"], " ") == "one two three four five") | |
750 { | |
751 if (args["second"] == ["one two three", "four five"]) | |
752 { | |
753 if (args["s"][0] == "six") | |
754 return Test.Status.Success; | |
755 } | |
756 } | |
757 } | |
758 } | |
759 } | |
760 } | |
761 return Test.Status.Failure; | |
762 } | |
763 | |
764 Test.Status aliasParseTest(inout char[][] messages) | |
765 { | |
766 char[][] arguments = [ "ignoreprogramname", "abc", "-d", "-e=eee", "--eff=f" ]; | |
767 char[][][4] aliases; | |
768 aliases[0] = [ "lettera", "a" ]; | |
769 aliases[1] = [ "letterbc", "c", "b" ]; | |
770 aliases[2] = [ "letterd", "d" ]; | |
771 aliases[3] = [ "lettere", "eff", "e" ]; | |
772 Arguments args = new Arguments(arguments, aliases); | |
773 if (args) | |
774 { | |
775 if (!("ignoreprogramname" in args) && ("letterbc" in args) && ("a" in args) && ("b" in args) && | |
776 ("c" in args) && ("d" in args) && ("eff" in args)) | |
777 { | |
778 if (("lettera" in args) && ("letterbc" in args) && ("letterd" in args)) | |
779 { | |
780 if (join(args["eff"], " ") == "f eee") | |
781 { | |
782 if (args["eff"] == ["f", "eee"]) | |
783 return Test.Status.Success; | |
784 } | |
785 } | |
786 } | |
787 } | |
788 return Test.Status.Failure; | |
789 } | |
790 | |
791 bool testRan = false; | |
792 bool testValidation(char[] arg) | |
793 { | |
794 bool rtn = true; | |
795 if (arg.length > 5) | |
796 rtn = false; | |
797 testRan = true; | |
798 return rtn; | |
799 } | |
800 | |
801 Test.Status validationTest(inout char[][] messages) | |
802 { | |
803 char[][] arguments = [ "programname", "-a:on", "-abc:on", "--this=good", "-x:on" ]; | |
804 Arguments args = new Arguments(arguments); | |
805 if (args) | |
806 { | |
807 args.addValidation("b", true, false); | |
808 args.addValidation("c", true, true); | |
809 args.addValidation("x", false, true); | |
810 args.addValidation("this", false, true); | |
811 args.addValidation("this", &testValidation); | |
812 try | |
813 { | |
814 args.validate(); | |
815 if (testRan) | |
816 return Test.Status.Success; | |
817 } | |
818 catch (ArgumentException ex) | |
819 { | |
820 messages ~= Stdout.layout.convert("{}: {} - {} ({})", ex.name, ex.msg, ex.reason == ArgumentException.ExceptionReason.INVALID_PARAMETER ? "invalid parameter" : ex.reason == ArgumentException.ExceptionReason.MISSING_PARAMETER ? "missing parameter" : "missing argument", ex.parameter); | |
821 } | |
822 } | |
823 return Test.Status.Failure; | |
824 } | |
825 | |
826 Test argTest = new Test("tetra.util.Arguments"); | |
827 argTest["Normal"] = &parseTest; | |
828 argTest["Implicit"] = &implicitParseTest; | |
829 argTest["Alias"] = &aliasParseTest; | |
830 argTest["Validation"] = &validationTest; | |
831 argTest.run; | |
832 } | |
833 } | |
834 +/ |