add CliArgsTest
authorMichael Wallner <mike@php.net>
Thu, 5 Mar 2015 08:03:13 +0000 (09:03 +0100)
committerMichael Wallner <mike@php.net>
Thu, 5 Mar 2015 08:03:13 +0000 (09:03 +0100)
bin/pharext
src/pharext/CliArgs.php
src/pharext/Installer.php
tests/autoload.php [new file with mode: 0644]
tests/src/pharext/CliArgsTest.php [new file with mode: 0644]

index 1239579392e15e386a889d58aabf1595e0304896..1bf30535c091bbbde04a4297bc9691681c1f608c 100755 (executable)
Binary files a/bin/pharext and b/bin/pharext differ
index fb9a7ec5895ab02d31ef765b3cba31a81d1f2d7e..f720b3c1d840964642246fac1e07b31f7c9fc911 100644 (file)
@@ -88,6 +88,14 @@ class CliArgs implements \ArrayAccess
                return $this;
        }
        
+       /**
+        * Get compiled spec
+        * @return array
+        */
+       public function getSpec() {
+               return $this->spec;
+       }
+       
        /**
         * Parse command line arguments according to the compiled spec.
         * 
@@ -103,7 +111,7 @@ class CliArgs implements \ArrayAccess
                for ($i = 0; $i < $argc; ++$i) {
                        $o = $argv[$i];
                        
-                       if ($o{0} === '-' && strlen($o) > 1 && $o{1} !== '-') {
+                       if ($o{0} === '-' && strlen($o) > 2 && $o{1} !== '-') {
                                // multiple short opts, .e.g -vps
                                $argc += strlen($o) - 2;
                                array_splice($argv, $i, 1, array_map(function($s) {
@@ -113,13 +121,13 @@ class CliArgs implements \ArrayAccess
                        }
 
                        if (!isset($this->spec[$o])) {
-                               yield sprintf("Unknown option %s", $argv[$i]);
+                               yield sprintf("Unknown option %s", $o);
                        } elseif (!$this->optAcceptsArg($o)) {
                                $this[$o] = true;
                        } elseif ($i+1 < $argc && !isset($this->spec[$argv[$i+1]])) {
                                $this[$o] = $argv[++$i];
-                       } elseif ($this->optNeedsArg($o)) {
-                               yield sprintf("Option --%s needs an argument", $this->optLongName($o));
+                       } elseif ($this->optRequiresArg($o)) {
+                               yield sprintf("Option --%s requires an argument", $this->optLongName($o));
                        } else {
                                // OPTARG
                                $this[$o] = $this->optDefaultArg($o);
@@ -217,14 +225,26 @@ class CliArgs implements \ArrayAccess
                return "";
        }
 
+       /**
+        * Retrieve option's flags
+        * @param string $o
+        * @return int
+        */
+       private function optFlags($o) {
+               $o = $this->opt($o);
+               if (isset($this->spec[$o])) {
+                       return $this->spec[$o][3];
+               }
+               return null;
+       }
+       
        /**
         * Check whether an option is flagged for halting argument processing
         * @param string $o
         * @return boolean
         */
        private function optHalts($o) {
-               $o = $this->opt($o);
-               return $this->spec[$o][3] & self::HALT;
+               return $this->optFlags($o) & self::HALT;
        }
        
        /**
@@ -232,9 +252,8 @@ class CliArgs implements \ArrayAccess
         * @param string $o
         * @return boolean
         */
-       private function optNeedsArg($o) {
-               $o = $this->opt($o);
-               return $this->spec[$o][3] & self::REQARG;
+       private function optRequiresArg($o) {
+               return $this->optFlags($o) & self::REQARG;
        }
        
        /**
@@ -243,8 +262,7 @@ class CliArgs implements \ArrayAccess
         * @return boolean
         */
        private function optAcceptsArg($o) {
-               $o = $this->opt($o);
-               return $this->spec[$o][3] & 0xf00;
+               return $this->optFlags($o) & 0xf00;
        }
        
        /**
@@ -253,8 +271,7 @@ class CliArgs implements \ArrayAccess
         * @return boolean
         */
        private function optIsMulti($o) {
-               $o = $this->opt($o);
-               return $this->spec[$o][3] & self::MULTI;
+               return $this->optFlags($o) & self::MULTI;
        }
        
        /**
index ccbc385213cf2300a7d7e13e46defb0b98d8c28f..cd15ba04486c02a5a918da5ecd9fcdb2261ef533 100644 (file)
@@ -21,7 +21,7 @@ class Installer implements Command
        public function __construct() {
                $this->args = new CliArgs([
                        ["h", "help", "Display help", 
-                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
+                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG|CliArgs::HALT],
                        ["v", "verbose", "More output",
                                CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
                        ["q", "quiet", "Less output",
diff --git a/tests/autoload.php b/tests/autoload.php
new file mode 100644 (file)
index 0000000..d914f3f
--- /dev/null
@@ -0,0 +1,7 @@
+<?php
+spl_autoload_register(function($class) {
+       if (strncmp($class, "pharext\\", strlen("pharext\\"))) {
+               return false;
+       }
+       return include __DIR__."/../src/".strtr($class, "_\\", "//").".php";
+});
diff --git a/tests/src/pharext/CliArgsTest.php b/tests/src/pharext/CliArgsTest.php
new file mode 100644 (file)
index 0000000..bdfdb15
--- /dev/null
@@ -0,0 +1,151 @@
+<?php
+
+namespace pharext;
+
+require __DIR__."/../../autoload.php";
+
+class CliArgsTest extends \PHPUnit_Framework_TestCase
+{
+       /**
+        * @var CliArgs
+        */
+       protected $args;
+       
+       /**
+        * @var array
+        */
+       protected $spec;
+
+       protected function setUp() {
+               $this->spec = [
+                       ["h", "help", "Display help", 
+                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG|CliArgs::HALT],
+                       ["v", "verbose", "More output",
+                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
+                       ["q", "quiet", "Less output",
+                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
+                       ["p", "prefix", "PHP installation prefix if phpize is not in \$PATH, e.g. /opt/php7",
+                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::REQARG],
+                       ["n", "common-name", "PHP common program name, e.g. php5 or zts-php",
+                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::REQARG, 
+                               "php"],
+                       ["c", "configure", "Additional extension configure flags, e.g. -c --with-flag",
+                               CliArgs::OPTIONAL|CliArgs::MULTI|CliArgs::REQARG],
+                       ["s", "sudo", "Installation might need increased privileges",
+                               CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::OPTARG,
+                               "sudo -S %s"]
+               ];
+               $this->args = new CliArgs($this->spec);
+       }
+
+       public function testCompile() {
+               $args = $this->args->compile($this->spec);
+               $this->assertSame($args, $this->args);
+               foreach ($this->spec as $arg) {
+                       $spec["-".$arg[0]] = $arg;
+                       $spec["--".$arg[1]] = $arg;
+               }
+               $this->assertSame($args->getSpec(), $spec);
+       }
+
+       public function testParseNothing() {
+               $generator = $this->args->parse(0, []);
+               $this->assertInstanceOf("Generator", $generator);
+               foreach ($generator as $error) {
+                       throw new \Exception("Unexpected parse error: $error");
+               }
+       }
+       
+       public function testParseHalt() {
+               foreach ($this->args->parse(1, ["-hv"]) as $error) {
+                       throw new \Exception("Unexpected parse error: $error");
+               }
+               $this->assertTrue($this->args->help, "help");
+               $this->assertNull($this->args->verbose, "verbose");
+               $this->assertNull($this->args->quiet, "quiet");
+               foreach ($this->args->parse(1, ["-vhq"]) as $error) {
+                       throw new \Exception("Unexpected parse error: $error");
+               }
+               $this->assertTrue($this->args->help);
+               $this->assertTrue($this->args->verbose);
+               $this->assertNull($this->args->quiet);
+       }
+       
+       public function testOptArg() {
+               $this->assertFalse(isset($this->args->sudo));
+               $this->assertSame("sudo -S %s", $this->args->sudo);
+               foreach ($this->args->parse(1, ["--sudo"]) as $error) {
+                       throw new \Exception("Unexpected parse error: $error");
+               }
+               $this->assertSame("sudo -S %s", $this->args->sudo);
+               $this->assertNull($this->args->quiet);
+               foreach ($this->args->parse(2, ["--sudo", "--quiet"]) as $error) {
+                       throw new \Exception("Unexpected parse error: $error");
+               }
+               $this->assertSame("sudo -S %s", $this->args->sudo);
+               $this->assertTrue($this->args->quiet);
+               foreach ($this->args->parse(3, ["--sudo", "su -c '%s'", "--quiet"]) as $error) {
+                       throw new \Exception("Unexpected parse error: $error");
+               }
+               $this->assertSame("su -c '%s'", $this->args->sudo);
+       }
+       
+       public function testReqArg() {
+               $this->assertNull($this->args->configure);
+               foreach ($this->args->parse(1, ["-c"]) as $error) {
+                       $this->assertStringMatchesFormat("%s--configure%srequires%sargument", $error);
+               }
+               $this->assertTrue(isset($error));
+       }
+       
+       public function testMulti() {
+               foreach ($this->args->parse(4, ["-c", "--with-foo", "--configure", "--enable-bar"]) as $error) {
+                       throw new \Exception("Unexpected parse error: $error");
+               }
+               $this->assertSame(["--with-foo", "--enable-bar"], $this->args->configure);
+       }
+       
+       public function testUnknown() {
+               $this->assertNull($this->args->configure);
+               foreach ($this->args->parse(1, ["--unknown"]) as $error) {
+                       $this->assertStringMatchesFormat("%SUnknown%s--unknown%S", $error);
+               }
+               $this->assertTrue(isset($error));
+       }
+
+       public function testValidate() {
+               $this->args->compile([
+                       ["r", "required-option", "This option is required",
+                               CliArgs::REQUIRED|CliArgs::NOARG]
+               ]);
+               foreach ($this->args->parse(0, []) as $error) {
+                       throw new \Exception("Unexpected parse error: $error");
+               }
+               foreach ($this->args->validate() as $error) {
+                       $this->assertStringMatchesFormat("%srequired-option%srequired", $error);
+               }
+               $this->assertTrue(isset($error));
+       }
+
+       public function testHelp() {
+               $this->expectOutputString(<<<EOF
+
+Usage:
+
+  $ testprog [-h|-v|-q|-s] [-p|-n|-c <arg>]
+
+    -h|--help                    Display help 
+    -v|--verbose                 More output 
+    -q|--quiet                   Less output 
+    -p|--prefix <arg>            PHP installation prefix if phpize is not in \$PATH, e.g. /opt/php7 
+    -n|--common-name <arg>       PHP common program name, e.g. php5 or zts-php  [php]
+    -c|--configure <arg>         Additional extension configure flags, e.g. -c --with-flag 
+    -s|--sudo [<arg>]            Installation might need increased privileges  [sudo -S %s]
+
+
+EOF
+               );
+               $this->args->help("testprog");
+       }
+
+}