diff --git a/bin/InitAppCommand.php b/bin/InitAppCommand.php index 5ed5b00..403d615 100644 --- a/bin/InitAppCommand.php +++ b/bin/InitAppCommand.php @@ -31,6 +31,7 @@ public function exec(): int { } try { + $this->println('Creating new app at "'.$appPath.'" ...'); $this->createAppClass($appPath, $dirName); $this->createEntryPoint($appPath, $dirName, $entry); $this->success('App created successfully.'); @@ -44,8 +45,8 @@ public function exec(): int { } } private function createAppClass(string $appPath, string $dirName) { - $this->println('Creating "'.$dirName.'/app.php"...'); - $file = new File($appPath.DIRECTORY_SEPARATOR.'app.php'); + $this->println('Creating "'.$dirName.'/main.php"...'); + $file = new File($appPath.DIRECTORY_SEPARATOR.'main.php'); if (!$file->isExist()) { $file->append("warning('File app.php already exist!'); + $this->warning('File main.php already exist!'); } private function createEntryPoint(string $appPath, string $dir, string $eName) { $this->println('Creating "'.$dir.'/'.$eName.'"...'); @@ -76,7 +77,7 @@ private function createEntryPoint(string $appPath, string $dir, string $eName) { if (!$file->isExist()) { $data = "#!/usr/bin/env php\n" ."create(true); file_put_contents($file->getDir().DIRECTORY_SEPARATOR.$eName, $data); diff --git a/bin/app.php b/bin/main.php similarity index 100% rename from bin/app.php rename to bin/main.php diff --git a/bin/wfc b/bin/wfc index aec2f9f..571395f 100644 --- a/bin/wfc +++ b/bin/wfc @@ -1,3 +1,3 @@ #!/usr/bin/env php register(new HelloWorldCommand()); - - //Set arguments vector - $runner->setArgsVector([ - 'app.php',//First argument is always name of entry point. - //Can be set to anything since its testing env. - 'hello' - ]); - - //Set user inputs. - //Must be called to use Array as input and output stream even if there are no inputs. - $runner->setInputs(); - - //Start the process - $exitStatus = $runner->start(); - - //Verify test results - $this->assertEquals(0, $exitStatus); + //A basic test case without using arg vector or user inputs $this->assertEquals([ - "Hello World!\n" - ], $runner->getOutput()); + "Hello World!".self::NL + ], $this->executeSingleCommand([new HelloWorldCommand()])); } /** * @test */ public function test01() { - $runner = new Runner(); - $runner->register(new HelloWorldCommand()); - - $runner->setArgsVector([ - 'app.php', - 'hello', - '--person-name' => 'Ibrahim BinAlshikh' - ]); - $runner->setInputs(); - $exitStatus = $runner->start(); - $this->assertEquals(0, $exitStatus); - $this->assertEquals([ - "Hello Ibrahim BinAlshikh!\n" - ], $runner->getOutput()); - } - /** - * @test - */ - public function test03() { - $runner = new Runner(); - $runner->register(new HelpCommand()); - $runner->register(new HelloWorldCommand()); - $runner->setDefaultCommand('help'); - $runner->setArgsVector([ - 'app.php', - ]); - $runner->setInputs(); - $exitStatus = $runner->start(); - $this->assertEquals(0, $exitStatus); + //A test case that uses arg vector $this->assertEquals([ - "Usage:\n", - " command [arg1 arg2=\"val\" arg3...]\n\n", - "Global Arguments:\n", - " --ansi:[Optional] Force the use of ANSI output.\n", - "Available Commands:\n", - " help: Display CLI Help. To display help for specific command, use the argument \"--command-name\" with this command.\n", - " hello: A command to show greetings.\n" - ], $runner->getOutput()); + "Hello Ibrahim BinAlshikh!\n".self::NL + ], $this->executeSingleCommand(new HelloWorldCommand(), [ + '--person-name' => 'Ibrahim BinAlshikh' + ])); } } diff --git a/phpunit.xml b/phpunit.xml index 84ab3c8..9be29bd 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -9,6 +9,7 @@ ./webfiori/cli/Formatter.php ./webfiori/cli/KeysMap.php ./webfiori/cli/Runner.php + ./webfiori/cli/CommandTestCase.php ./webfiori/cli/InputValidator.php ./webfiori/cli/streams/ArrayInputStream.php ./webfiori/cli/streams/ArrayOutputStream.php diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 48b1e17..71b6041 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -41,6 +41,7 @@ require_once $baseDir.DS.'Runner.php'; require_once $baseDir.DS.'Option.php'; require_once $baseDir.DS.'InputValidator.php'; +require_once $baseDir.DS.'CommandTestCase.php'; require_once $baseDir.DS.'streams'.DS.'ArrayInputStream.php'; require_once $baseDir.DS.'streams'.DS.'ArrayOutputStream.php'; require_once $baseDir.DS.'streams'.DS.'FileInputStream.php'; diff --git a/tests/webfiori/tests/cli/CLICommandTest.php b/tests/webfiori/tests/cli/CLICommandTest.php index 2555014..bb8529d 100644 --- a/tests/webfiori/tests/cli/CLICommandTest.php +++ b/tests/webfiori/tests/cli/CLICommandTest.php @@ -11,7 +11,7 @@ use webfiori\tests\cli\TestCommand; use webfiori\tests\TestStudent; -class CLICommandTest extends TestCase { +class CLICommandTestCase extends TestCase { /** * @test */ diff --git a/tests/webfiori/tests/cli/InitAppCommandTest.php b/tests/webfiori/tests/cli/InitAppCommandTest.php index 56a27ed..2259d5c 100644 --- a/tests/webfiori/tests/cli/InitAppCommandTest.php +++ b/tests/webfiori/tests/cli/InitAppCommandTest.php @@ -20,7 +20,7 @@ public function test00() { $r->setDefaultCommand('init'); $r->setInputs([]); $r->setArgsVector([ - 'app.php', + 'main.php', 'init' ]); $this->assertEquals(-1, $r->start()); @@ -37,7 +37,7 @@ public function test01() { $r->setDefaultCommand('init'); $r->setInputs([]); $r->setArgsVector([ - 'app.php', + 'main.php', 'init', '--dir' => "test\0a" ]); @@ -53,13 +53,15 @@ public function test02() { ->setDefaultCommand('init') ->setInputs([]) ->setArgsVector([ - 'app.php', + 'main.php', 'init', '--dir' => 'test' ]); + $appPath = ROOT_DIR.DS.'test'; $this->assertEquals(0, $r->start()); $this->assertEquals([ - "Creating \"test/app.php\"...\n", + "Creating new app at \"$appPath\" ...\n", + "Creating \"test/main.php\"...\n", "Creating \"test/test\"...\n", "Success: App created successfully.\n" ], $r->getOutput()); @@ -74,19 +76,21 @@ public function test03() { $r->setDefaultCommand('init'); $r->setInputs([]); $r->setArgsVector([ - 'app.php', + 'main.php', 'init', '--dir' => 'test' ]); $this->assertEquals(0, $r->start()); + $appPath = ROOT_DIR.DS.'test'; $this->assertEquals([ - "Creating \"test/app.php\"...\n", - "Warning: File app.php already exist!\n", + "Creating new app at \"$appPath\" ...\n", + "Creating \"test/main.php\"...\n", + "Warning: File main.php already exist!\n", "Creating \"test/test\"...\n", "Warning: File test already exist!\n", "Success: App created successfully.\n" ], $r->getOutput()); - unlink(ROOT_DIR.DS.'test'.DS.'app.php'); + unlink(ROOT_DIR.DS.'test'.DS.'main.php'); unlink(ROOT_DIR.DS.'test'.DS.'test'); rmdir(ROOT_DIR.DS.'test'); } @@ -99,20 +103,22 @@ public function test04() { $r->setDefaultCommand('init'); $r->setInputs([]); $r->setArgsVector([ - 'app.php', + 'main.php', 'init', '--dir' => 'test2', '--entry' => 'bang' ]); $this->assertEquals(0, $r->start()); + $appPath = ROOT_DIR.DS.'test2'; $this->assertEquals([ - "Creating \"test2/app.php\"...\n", + "Creating new app at \"$appPath\" ...\n", + "Creating \"test2/main.php\"...\n", "Creating \"test2/bang\"...\n", "Success: App created successfully.\n" ], $r->getOutput()); - unlink(ROOT_DIR.DS.'test2'.DS.'app.php'); - unlink(ROOT_DIR.DS.'test2'.DS.'bang'); - rmdir(ROOT_DIR.DS.'test2'); + unlink($appPath.DS.'main.php'); + unlink($appPath.DS.'bang'); + rmdir($appPath); } } diff --git a/tests/webfiori/tests/cli/RunnerTest.php b/tests/webfiori/tests/cli/RunnerTest.php index e67c589..5f10cdd 100644 --- a/tests/webfiori/tests/cli/RunnerTest.php +++ b/tests/webfiori/tests/cli/RunnerTest.php @@ -1,23 +1,23 @@ register(new Command00()); - $runner->setInputs([]); - $this->assertEquals(-1, $runner->runCommand(null, [ - 'super-hero', - 'name' => 'Ok' - ])); - $this->assertEquals(-1, $runner->getLastCommandExitStatus()); $this->assertEquals([ "Error: The following argument(s) have invalid values: 'name'\n", "Info: Allowed values for the argument 'name':\n", "Ibrahim\n", "Ali\n" - ], $runner->getOutput()); + ], $this->executeSingleCommand(new Command00(), [ + 'super-hero', + 'name' => 'Ok' + ])); + $this->assertEquals(-1, $this->getExitCode()); } /** * @test */ public function testRunner04() { - $runner = new Runner(); - $runner->register(new Command00()); - $runner->setInputs([]); - $this->assertEquals(-1, $runner->runCommand(null, [ - 'super-hero', - 'name' => 'Ok', - '--ansi' - ])); - $this->assertEquals(-1, $runner->getLastCommandExitStatus()); $this->assertEquals([ "\e[1;91mError: \e[0mThe following argument(s) have invalid values: 'name'\n", "\e[1;34mInfo: \e[0mAllowed values for the argument 'name':\n", "Ibrahim\n", "Ali\n" - ], $runner->getOutput()); + ], $this->executeSingleCommand(new Command00(), [ + 'name' => 'Ok', + '--ansi' + ])); + $this->assertEquals(-1, $this->getExitCode()); } /** * @test @@ -166,11 +157,7 @@ public function testRunner05() { * @test */ public function testRunner06() { - $runner = new Runner(); - $runner->register(new Command00()); - $runner->setDefaultCommand('help'); - $runner->setInputs([]); - $this->assertEquals(0, $runner->runCommand(new HelpCommand(), [])); + $this->assertEquals([ "Usage:\n", " command [arg1 arg2=\"val\" arg3...]\n\n", @@ -178,7 +165,12 @@ public function testRunner06() { " --ansi:[Optional] Force the use of ANSI output.\n", "Available Commands:\n", " super-hero: A command to display hero's name.\n", - ], $runner->getOutput()); + " help: Display CLI Help. To display help for specific command, use the argument \"--command-name\" with this command.\n" + ], $this->executeMultiCommand([ + new Command00(), + new HelpCommand() + ], 'help')); + $this->assertEquals(0, $this->getExitCode()); } /** * @test diff --git a/webfiori/cli/CommandTestCase.php b/webfiori/cli/CommandTestCase.php new file mode 100644 index 0000000..51f1d21 --- /dev/null +++ b/webfiori/cli/CommandTestCase.php @@ -0,0 +1,157 @@ +getRunner(true); + + foreach ($commands as $command) { + $runner->register($command); + } + $runner->setDefaultCommand($default); + $this->exec($argv, $userInputs); + + return $this->getOutput(); + } + /** + * Executes a specific command and return its output as an array. + * + * @param CLICommand $command The command that will be tested. + * + * @param array $argv Arguments vector that will be passed to the command. + * This can be an associative array of options and values or just options. + * + * @param array $userInputs A sequence of strings that represents user inputs + * when the command is executing. Each index in the array represents a single + * line of input. + * + * @return array The method will return an array that will hold + * outputs line by line in each index. + */ + public function executeSingleCommand(CLICommand $command, array $argv = [], array $userInputs = []) : array { + $this->getRunner(true)->register($command); + $this->exec($argv, $userInputs, $command); + + return $this->getOutput(); + } + /** + * Returns an integer thar represents exit status of running specific command. + * + * @return int Default return value is 0. + */ + public function getExitCode() : int { + if ($this->exitStatus === null) { + $this->exitStatus = 0; + } + + return $this->exitStatus; + } + /** + * Returns an array that holds all outputs that was generated by running specific + * command. + * + * @return array If no command was executed, the array will be empty. Other + * than that, the array will hold outputs line by line in each index. + */ + public function getOutput() : array { + if ($this->outputs === null) { + $this->outputs = []; + } + + return $this->outputs; + } + /** + * Returns the instance that the class is using to execute the commands. + * + * @param bool $reset If set to true, input stream, output stream and, + * registered commands of the runner will reset to default. + * + * @return Runner The instance that the class is using to execute the commands. + */ + public function getRunner(bool $reset = false) : Runner { + if ($this->runner === null) { + $this->runner = new Runner(); + } + + if ($reset) { + $this->runner->reset(); + } + + return $this->runner; + } + + private function exec(array $argv, array $userInputs, CLICommand $command = null) { + if ($command !== null) { + $key = array_search($command->getName(), $argv); + + if ($key != 0 || $key === false) { + $argv = array_merge(['main.php', $command->getName()], $argv); + } else { + $argv = array_merge(['main.php'], $argv); + } + } else { + $argv = array_merge(['main.php'], $argv); + } + $runner = $this->getRunner(); + + //Set arguments vector + $runner->setArgsVector($argv); + + //Set user inputs. + //Must be called to use Array as input and output stream even if there are no inputs. + $runner->setInputs($userInputs); + + //Start the process + $this->exitStatus = $runner->start(); + + $this->outputs = $runner->getOutput(); + } +}