@@ -594,4 +594,261 @@ public static function provideGetRawTokensTrueTests(): iterable
594
594
yield [['app/console ' , '--no-ansi ' , 'foo:bar ' , 'foo:bar ' ], ['foo:bar ' ]];
595
595
yield [['app/console ' , '--no-ansi ' , 'foo:bar ' , '-- ' , 'argument ' ], ['-- ' , 'argument ' ]];
596
596
}
597
+
598
+ /**
599
+ * @dataProvider unparseProvider
600
+ */
601
+ public function testUnparse (
602
+ ?InputDefinition $ inputDefinition ,
603
+ ArgvInput $ input ,
604
+ ?array $ parsedOptions ,
605
+ array $ expected ,
606
+ ): void
607
+ {
608
+ if (null !== $ inputDefinition ) {
609
+ $ input ->bind ($ inputDefinition );
610
+ }
611
+
612
+ $ actual = null === $ parsedOptions ? $ input ->unparse () : $ input ->unparse ($ parsedOptions );
613
+
614
+ self ::assertSame ($ expected , $ actual );
615
+ }
616
+
617
+ public static function unparseProvider (): iterable
618
+ {
619
+ yield 'empty input and empty definition ' => [
620
+ new InputDefinition (),
621
+ new ArgvInput ([]),
622
+ [],
623
+ [],
624
+ ];
625
+
626
+ yield 'empty input and definition with default values: ignore default values ' => [
627
+ new InputDefinition ([
628
+ new InputArgument (
629
+ 'argWithDefaultValue ' ,
630
+ InputArgument::OPTIONAL ,
631
+ 'Argument with a default value ' ,
632
+ 'arg1DefaultValue ' ,
633
+ ),
634
+ new InputOption (
635
+ 'optWithDefaultValue ' ,
636
+ null ,
637
+ InputOption::VALUE_REQUIRED ,
638
+ 'Option with a default value ' ,
639
+ 'opt1DefaultValue ' ,
640
+ ),
641
+ ]),
642
+ new ArgvInput ([]),
643
+ [],
644
+ [],
645
+ ];
646
+
647
+ $ completeInputDefinition = new InputDefinition ([
648
+ new InputArgument (
649
+ 'requiredArgWithoutDefaultValue ' ,
650
+ InputArgument::REQUIRED ,
651
+ 'Argument without a default value ' ,
652
+ ),
653
+ new InputArgument (
654
+ 'optionalArgWithDefaultValue ' ,
655
+ InputArgument::OPTIONAL ,
656
+ 'Argument with a default value ' ,
657
+ 'argDefaultValue ' ,
658
+ ),
659
+ new InputOption (
660
+ 'optWithoutDefaultValue ' ,
661
+ null ,
662
+ InputOption::VALUE_REQUIRED ,
663
+ 'Option without a default value ' ,
664
+ ),
665
+ new InputOption (
666
+ 'optWithDefaultValue ' ,
667
+ null ,
668
+ InputOption::VALUE_REQUIRED ,
669
+ 'Option with a default value ' ,
670
+ 'optDefaultValue ' ,
671
+ ),
672
+ ]);
673
+
674
+ yield 'arguments & options: returns all passed options but ignore default values ' => [
675
+ $ completeInputDefinition ,
676
+ new ArgvInput (['argValue ' , '--optWithoutDefaultValue=optValue ' ]),
677
+ [],
678
+ ['--optWithoutDefaultValue=optValue ' ],
679
+ ];
680
+
681
+ yield 'arguments & options; explicitly pass the default values: the default values are returned ' => [
682
+ $ completeInputDefinition ,
683
+ new ArgvInput (['argValue ' , 'argDefaultValue ' , '--optWithoutDefaultValue=optValue ' , '--optWithDefaultValue=optDefaultValue ' ]),
684
+ [],
685
+ [
686
+ '--optWithoutDefaultValue=optValue ' ,
687
+ '--optWithDefaultValue=optDefaultValue ' ,
688
+ ],
689
+ ];
690
+
691
+ yield 'arguments & options; no input definition: nothing returned ' => [
692
+ null ,
693
+ new ArgvInput (['argValue ' , 'argDefaultValue ' , '--optWithoutDefaultValue=optValue ' , '--optWithDefaultValue=optDefaultValue ' ]),
694
+ [],
695
+ [],
696
+ ];
697
+
698
+ yield 'arguments & options; parsing an argument name instead of an option name: that option is ignored ' => [
699
+ $ completeInputDefinition ,
700
+ new ArgvInput (['argValue ' ]),
701
+ ['requiredArgWithoutDefaultValue ' ],
702
+ [],
703
+ ];
704
+
705
+ yield 'arguments & options; non passed option: it is ignored ' => [
706
+ $ completeInputDefinition ,
707
+ new ArgvInput (['argValue ' ]),
708
+ ['optWithDefaultValue ' ],
709
+ [],
710
+ ];
711
+
712
+ $ createSingleOptionScenario = static fn (
713
+ InputOption $ option ,
714
+ array $ input ,
715
+ array $ expected
716
+ ) => [
717
+ new InputDefinition ([$ option ]),
718
+ new ArgvInput (['appName ' , ...$ input ]),
719
+ [],
720
+ $ expected ,
721
+ ];
722
+
723
+ yield 'option without value ' => $ createSingleOptionScenario (
724
+ new InputOption (
725
+ 'opt ' ,
726
+ null ,
727
+ InputOption::VALUE_NONE ,
728
+ ),
729
+ ['--opt ' ],
730
+ ['--opt ' ],
731
+ );
732
+
733
+ yield 'option without value by shortcut ' => $ createSingleOptionScenario (
734
+ new InputOption (
735
+ 'opt ' ,
736
+ 'o ' ,
737
+ InputOption::VALUE_NONE ,
738
+ ),
739
+ ['-o ' ],
740
+ ['--opt ' ],
741
+ );
742
+
743
+ yield 'option with value required ' => $ createSingleOptionScenario (
744
+ new InputOption (
745
+ 'opt ' ,
746
+ null ,
747
+ InputOption::VALUE_REQUIRED ,
748
+ ),
749
+ ['--opt=foo ' ],
750
+ ['--opt=foo ' ],
751
+ );
752
+
753
+ yield 'option with non string value (bool) ' => $ createSingleOptionScenario (
754
+ new InputOption (
755
+ 'opt ' ,
756
+ null ,
757
+ InputOption::VALUE_REQUIRED ,
758
+ ),
759
+ ['--opt=1 ' ],
760
+ ['--opt=1 ' ],
761
+ );
762
+
763
+ yield 'option with non string value (int) ' => $ createSingleOptionScenario (
764
+ new InputOption (
765
+ 'opt ' ,
766
+ null ,
767
+ InputOption::VALUE_REQUIRED ,
768
+ ),
769
+ ['--opt=20 ' ],
770
+ ['--opt=20 ' ],
771
+ );
772
+
773
+ yield 'option with non string value (float) ' => $ createSingleOptionScenario (
774
+ new InputOption (
775
+ 'opt ' ,
776
+ null ,
777
+ InputOption::VALUE_REQUIRED ,
778
+ ),
779
+ ['--opt=5.3 ' ],
780
+ ['--opt= \'5.3 \'' ],
781
+ );
782
+
783
+ yield 'option with non string value (array of strings) ' => $ createSingleOptionScenario (
784
+ new InputOption (
785
+ 'opt ' ,
786
+ null ,
787
+ InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY ,
788
+ ),
789
+ ['--opt=v1 ' , '--opt=v2 ' , '--opt=v3 ' ],
790
+ ['--opt=v1--opt=v2--opt=v3 ' ],
791
+ );
792
+
793
+ yield 'negatable option (positive) ' => $ createSingleOptionScenario (
794
+ new InputOption (
795
+ 'opt ' ,
796
+ null ,
797
+ InputOption::VALUE_NEGATABLE ,
798
+ ),
799
+ ['--opt ' ],
800
+ ['--opt ' ],
801
+ );
802
+
803
+ yield 'negatable option (negative) ' => $ createSingleOptionScenario (
804
+ new InputOption (
805
+ 'opt ' ,
806
+ null ,
807
+ InputOption::VALUE_NEGATABLE ,
808
+ ),
809
+ ['--no-opt ' ],
810
+ ['--no-opt ' ],
811
+ );
812
+
813
+ $ createEscapeOptionTokenScenario = static fn (
814
+ string $ optionValue ,
815
+ ?string $ expected
816
+ ) => [
817
+ new InputDefinition ([
818
+ new InputOption (
819
+ 'opt ' ,
820
+ null ,
821
+ InputOption::VALUE_REQUIRED ,
822
+ ),
823
+ ]),
824
+ new ArgvInput (['appName ' , '--opt= ' .$ optionValue ]),
825
+ [],
826
+ ['--opt= ' .$ expected ],
827
+ ];
828
+
829
+ yield 'escape token; string token ' => $ createEscapeOptionTokenScenario (
830
+ 'foo ' ,
831
+ 'foo ' ,
832
+ );
833
+
834
+ yield 'escape token; escaped string token ' => $ createEscapeOptionTokenScenario (
835
+ '"foo" ' ,
836
+ escapeshellarg ('"foo" ' ),
837
+ );
838
+
839
+ yield 'escape token; escaped string token with both types of quotes ' => $ createEscapeOptionTokenScenario (
840
+ '"o_id in( \'20 \')" ' ,
841
+ escapeshellarg ('"o_id in( \'20 \')" ' ),
842
+ );
843
+
844
+ yield 'escape token; string token with spaces ' => $ createEscapeOptionTokenScenario (
845
+ 'a b c d ' ,
846
+ escapeshellarg ('a b c d ' ),
847
+ );
848
+
849
+ yield 'escape token; string token with line return ' => $ createEscapeOptionTokenScenario (
850
+ "A \nB'C " ,
851
+ escapeshellarg ("A \nB'C " ),
852
+ );
853
+ }
597
854
}
0 commit comments