OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library args_test; | 5 library args_test; |
6 | 6 |
7 import 'package:unittest/unittest.dart'; | 7 import 'package:unittest/unittest.dart'; |
8 import 'package:args/args.dart'; | 8 import 'package:args/args.dart'; |
9 | 9 |
10 main() { | 10 main() { |
11 group('ArgParser.addFlag()', () { | |
12 test('throws ArgumentError if the flag already exists', () { | |
13 var parser = new ArgParser(); | |
14 parser.addFlag('foo'); | |
15 throwsIllegalArg(() => parser.addFlag('foo')); | |
16 }); | |
17 | |
18 test('throws ArgumentError if the option already exists', () { | |
19 var parser = new ArgParser(); | |
20 parser.addOption('foo'); | |
21 throwsIllegalArg(() => parser.addFlag('foo')); | |
22 }); | |
23 | |
24 test('throws ArgumentError if the abbreviation exists', () { | |
25 var parser = new ArgParser(); | |
26 parser.addFlag('foo', abbr: 'f'); | |
27 throwsIllegalArg(() => parser.addFlag('flummox', abbr: 'f')); | |
28 }); | |
29 | |
30 test('throws ArgumentError if the abbreviation is longer ' | |
31 'than one character', () { | |
32 var parser = new ArgParser(); | |
33 throwsIllegalArg(() => parser.addFlag('flummox', abbr: 'flu')); | |
34 }); | |
35 }); | |
36 | |
37 group('ArgParser.addOption()', () { | |
38 test('throws ArgumentError if the flag already exists', () { | |
39 var parser = new ArgParser(); | |
40 parser.addFlag('foo'); | |
41 throwsIllegalArg(() => parser.addOption('foo')); | |
42 }); | |
43 | |
44 test('throws ArgumentError if the option already exists', () { | |
45 var parser = new ArgParser(); | |
46 parser.addOption('foo'); | |
47 throwsIllegalArg(() => parser.addOption('foo')); | |
48 }); | |
49 | |
50 test('throws ArgumentError if the abbreviation exists', () { | |
51 var parser = new ArgParser(); | |
52 parser.addFlag('foo', abbr: 'f'); | |
53 throwsIllegalArg(() => parser.addOption('flummox', abbr: 'f')); | |
54 }); | |
55 | |
56 test('throws ArgumentError if the abbreviation is longer ' | |
57 'than one character', () { | |
58 var parser = new ArgParser(); | |
59 throwsIllegalArg(() => parser.addOption('flummox', abbr: 'flu')); | |
60 }); | |
61 }); | |
62 | |
63 group('ArgParser.parse()', () { | 11 group('ArgParser.parse()', () { |
64 group('flags', () { | 12 group('flags', () { |
65 test('are true if present', () { | 13 test('are true if present', () { |
66 var parser = new ArgParser(); | 14 var parser = new ArgParser(); |
67 parser.addFlag('verbose'); | 15 parser.addFlag('verbose'); |
68 | 16 |
69 var args = parser.parse(['--verbose']); | 17 var args = parser.parse(['--verbose']); |
70 expect(args['verbose'], isTrue); | 18 expect(args['verbose'], isTrue); |
71 }); | 19 }); |
72 | 20 |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 | 368 |
421 test('returns the default value for multi-valued arguments ' | 369 test('returns the default value for multi-valued arguments ' |
422 'if not explicitly set', () { | 370 'if not explicitly set', () { |
423 var parser = new ArgParser(); | 371 var parser = new ArgParser(); |
424 parser.addOption('define', defaultsTo: '0', allowMultiple: true); | 372 parser.addOption('define', defaultsTo: '0', allowMultiple: true); |
425 var args = parser.parse(['']); | 373 var args = parser.parse(['']); |
426 expect(args['define'], equals(['0'])); | 374 expect(args['define'], equals(['0'])); |
427 }); | 375 }); |
428 }); | 376 }); |
429 | 377 |
430 group('query default values', () { | |
431 test('queries the default value', () { | |
432 var parser = new ArgParser(); | |
433 parser.addOption('define', defaultsTo: '0'); | |
434 expect(()=>parser.getDefault('undefine'), | |
435 throwsArgumentError); | |
436 }); | |
437 | |
438 test('queries the default value for an unknown option', () { | |
439 var parser = new ArgParser(); | |
440 parser.addOption('define', defaultsTo: '0'); | |
441 expect(()=>parser.getDefault('undefine'), | |
442 throwsArgumentError); | |
443 }); | |
444 }); | |
445 | |
446 group('gets the option names from an ArgsResult', () { | |
447 test('queries the set options', () { | |
448 var parser = new ArgParser(); | |
449 parser.addFlag('woof', defaultsTo: false); | |
450 parser.addOption('meow', defaultsTo: 'kitty'); | |
451 var args = parser.parse([]); | |
452 expect(args.options, hasLength(2)); | |
453 expect(args.options.any((o) => o == 'woof'), isTrue); | |
454 expect(args.options.any((o) => o == 'meow'), isTrue); | |
455 }); | |
456 }); | |
457 | |
458 group('remaining args', () { | 378 group('remaining args', () { |
459 test('stops parsing args when a non-option-like arg is encountered', () { | 379 test('stops parsing args when a non-option-like arg is encountered', () { |
460 var parser = new ArgParser(); | 380 var parser = new ArgParser(); |
461 parser.addFlag('woof'); | 381 parser.addFlag('woof'); |
462 parser.addOption('meow'); | 382 parser.addOption('meow'); |
463 parser.addOption('tweet', defaultsTo: 'bird'); | 383 parser.addOption('tweet', defaultsTo: 'bird'); |
464 | 384 |
465 var results = parser.parse(['--woof', '--meow', 'v', 'not', 'option']); | 385 var results = parser.parse(['--woof', '--meow', 'v', 'not', 'option']); |
466 expect(results['woof'], isTrue); | 386 expect(results['woof'], isTrue); |
467 expect(results['meow'], equals('v')); | 387 expect(results['meow'], equals('v')); |
(...skipping 15 matching lines...) Expand all Loading... |
483 test('handles options with case-sensitivity', () { | 403 test('handles options with case-sensitivity', () { |
484 var parser = new ArgParser(); | 404 var parser = new ArgParser(); |
485 parser.addFlag('recurse', defaultsTo: false, abbr:'R'); | 405 parser.addFlag('recurse', defaultsTo: false, abbr:'R'); |
486 var results = parser.parse(['-R']); | 406 var results = parser.parse(['-R']); |
487 expect(results['recurse'], isTrue); | 407 expect(results['recurse'], isTrue); |
488 expect(results.rest, [ ]); | 408 expect(results.rest, [ ]); |
489 throwsFormat(parser, ['-r']); | 409 throwsFormat(parser, ['-r']); |
490 }); | 410 }); |
491 }); | 411 }); |
492 }); | 412 }); |
493 | |
494 group('ArgParser.getUsage()', () { | |
495 test('negatable flags show "no-" in title', () { | |
496 var parser = new ArgParser(); | |
497 parser.addFlag('mode', help: 'The mode'); | |
498 | |
499 validateUsage(parser, | |
500 ''' | |
501 --[no-]mode The mode | |
502 '''); | |
503 }); | |
504 | |
505 test('non-negatable flags don\'t show "no-" in title', () { | |
506 var parser = new ArgParser(); | |
507 parser.addFlag('mode', negatable: false, help: 'The mode'); | |
508 | |
509 validateUsage(parser, | |
510 ''' | |
511 --mode The mode | |
512 '''); | |
513 }); | |
514 | |
515 test('if there are no abbreviations, there is no column for them', () { | |
516 var parser = new ArgParser(); | |
517 parser.addFlag('mode', help: 'The mode'); | |
518 | |
519 validateUsage(parser, | |
520 ''' | |
521 --[no-]mode The mode | |
522 '''); | |
523 }); | |
524 | |
525 test('options are lined up past abbreviations', () { | |
526 var parser = new ArgParser(); | |
527 parser.addFlag('mode', abbr: 'm', help: 'The mode'); | |
528 parser.addOption('long', help: 'Lacks an abbreviation'); | |
529 | |
530 validateUsage(parser, | |
531 ''' | |
532 -m, --[no-]mode The mode | |
533 --long Lacks an abbreviation | |
534 '''); | |
535 }); | |
536 | |
537 test('help text is lined up past the longest option', () { | |
538 var parser = new ArgParser(); | |
539 parser.addFlag('mode', abbr: 'm', help: 'Lined up with below'); | |
540 parser.addOption('a-really-long-name', help: 'Its help text'); | |
541 | |
542 validateUsage(parser, | |
543 ''' | |
544 -m, --[no-]mode Lined up with below | |
545 --a-really-long-name Its help text | |
546 '''); | |
547 }); | |
548 | |
549 test('leading empty lines are ignored in help text', () { | |
550 var parser = new ArgParser(); | |
551 parser.addFlag('mode', help: '\n\n\n\nAfter newlines'); | |
552 | |
553 validateUsage(parser, | |
554 ''' | |
555 --[no-]mode After newlines | |
556 '''); | |
557 }); | |
558 | |
559 test('trailing empty lines are ignored in help text', () { | |
560 var parser = new ArgParser(); | |
561 parser.addFlag('mode', help: 'Before newlines\n\n\n\n'); | |
562 | |
563 validateUsage(parser, | |
564 ''' | |
565 --[no-]mode Before newlines | |
566 '''); | |
567 }); | |
568 | |
569 test('options are documented in the order they were added', () { | |
570 var parser = new ArgParser(); | |
571 parser.addFlag('zebra', help: 'First'); | |
572 parser.addFlag('monkey', help: 'Second'); | |
573 parser.addFlag('wombat', help: 'Third'); | |
574 | |
575 validateUsage(parser, | |
576 ''' | |
577 --[no-]zebra First | |
578 --[no-]monkey Second | |
579 --[no-]wombat Third | |
580 '''); | |
581 }); | |
582 | |
583 test('the default value for a flag is shown if on', () { | |
584 var parser = new ArgParser(); | |
585 parser.addFlag('affirm', help: 'Should be on', defaultsTo: true); | |
586 parser.addFlag('negate', help: 'Should be off', defaultsTo: false); | |
587 | |
588 validateUsage(parser, | |
589 ''' | |
590 --[no-]affirm Should be on | |
591 (defaults to on) | |
592 | |
593 --[no-]negate Should be off | |
594 '''); | |
595 }); | |
596 | |
597 test('the default value for an option with no allowed list is shown', () { | |
598 var parser = new ArgParser(); | |
599 parser.addOption('any', help: 'Can be anything', defaultsTo: 'whatevs'); | |
600 | |
601 validateUsage(parser, | |
602 ''' | |
603 --any Can be anything | |
604 (defaults to "whatevs") | |
605 '''); | |
606 }); | |
607 | |
608 test('the allowed list is shown', () { | |
609 var parser = new ArgParser(); | |
610 parser.addOption('suit', help: 'Like in cards', | |
611 allowed: ['spades', 'clubs', 'hearts', 'diamonds']); | |
612 | |
613 validateUsage(parser, | |
614 ''' | |
615 --suit Like in cards | |
616 [spades, clubs, hearts, diamonds] | |
617 '''); | |
618 }); | |
619 | |
620 test('the default is highlighted in the allowed list', () { | |
621 var parser = new ArgParser(); | |
622 parser.addOption('suit', help: 'Like in cards', defaultsTo: 'clubs', | |
623 allowed: ['spades', 'clubs', 'hearts', 'diamonds']); | |
624 | |
625 validateUsage(parser, | |
626 ''' | |
627 --suit Like in cards | |
628 [spades, clubs (default), hearts, diamonds] | |
629 '''); | |
630 }); | |
631 | |
632 test('the allowed help is shown', () { | |
633 var parser = new ArgParser(); | |
634 parser.addOption('suit', help: 'Like in cards', defaultsTo: 'clubs', | |
635 allowed: ['spades', 'clubs', 'diamonds', 'hearts'], | |
636 allowedHelp: { | |
637 'spades': 'Swords of a soldier', | |
638 'clubs': 'Weapons of war', | |
639 'diamonds': 'Money for this art', | |
640 'hearts': 'The shape of my heart' | |
641 }); | |
642 | |
643 validateUsage(parser, | |
644 ''' | |
645 --suit Like in cards | |
646 | |
647 [clubs] Weapons of war | |
648 [diamonds] Money for this art | |
649 [hearts] The shape of my heart | |
650 [spades] Swords of a soldier | |
651 '''); | |
652 }); | |
653 }); | |
654 | |
655 group('ArgResults[]', () { | |
656 test('throws if the name is not an option', () { | |
657 var parser = new ArgParser(); | |
658 var results = parser.parse([]); | |
659 throwsIllegalArg(() => results['unknown']); | |
660 }); | |
661 }); | |
662 } | 413 } |
663 | 414 |
664 throwsIllegalArg(function) { | 415 throwsIllegalArg(function) { |
665 expect(function, throwsArgumentError); | 416 expect(function, throwsArgumentError); |
666 } | 417 } |
667 | 418 |
668 throwsFormat(ArgParser parser, List<String> args) { | 419 throwsFormat(ArgParser parser, List<String> args) { |
669 expect(() => parser.parse(args), throwsFormatException); | 420 expect(() => parser.parse(args), throwsFormatException); |
670 } | 421 } |
671 | |
672 validateUsage(ArgParser parser, String expected) { | |
673 expected = unindentString(expected); | |
674 expect(parser.getUsage(), equals(expected)); | |
675 } | |
676 | |
677 // TODO(rnystrom): Replace one in test_utils. | |
678 String unindentString(String text) { | |
679 var lines = text.split('\n'); | |
680 | |
681 // Count the indentation of the last line. | |
682 var whitespace = new RegExp('^ *'); | |
683 var indent = whitespace.firstMatch(lines[lines.length - 1])[0].length; | |
684 | |
685 // Drop the last line. It only exists for specifying indentation. | |
686 lines.removeLast(); | |
687 | |
688 // Strip indentation from the remaining lines. | |
689 for (var i = 0; i < lines.length; i++) { | |
690 var line = lines[i]; | |
691 if (line.length <= indent) { | |
692 // It's short, so it must be nothing but whitespace. | |
693 if (line.trim() != '') { | |
694 throw new ArgumentError( | |
695 'Line "$line" does not have enough indentation.'); | |
696 } | |
697 | |
698 lines[i] = ''; | |
699 } else { | |
700 if (line.substring(0, indent).trim() != '') { | |
701 throw new ArgumentError( | |
702 'Line "$line" does not have enough indentation.'); | |
703 } | |
704 | |
705 lines[i] = line.substring(indent); | |
706 } | |
707 } | |
708 | |
709 return Strings.join(lines, '\n'); | |
710 } | |
OLD | NEW |