From 63bdda94a0207019893187166f1747790b19d3ab Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 01:43:07 +0300 Subject: [PATCH 01/18] Update StdIn.php --- WebFiori/Cli/Streams/StdIn.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/WebFiori/Cli/Streams/StdIn.php b/WebFiori/Cli/Streams/StdIn.php index 425d457..bb816c4 100644 --- a/WebFiori/Cli/Streams/StdIn.php +++ b/WebFiori/Cli/Streams/StdIn.php @@ -25,7 +25,14 @@ public function read(int $bytes = 1) : string { $input = ''; while (strlen($input) < $bytes) { - $char = KeysMap::map(fgetc(STDIN)); + $rawChar = fgetc(STDIN); + + // Handle EOF + if ($rawChar === false) { + break; + } + + $char = KeysMap::map($rawChar); if ($char == 'BACKSPACE' && strlen($input) > 0) { $input = substr($input, 0, strlen($input) - 1); From d26476d086bb994e434bcca84420222d026d9970 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 01:43:56 +0300 Subject: [PATCH 02/18] Update KeysMap.php --- WebFiori/Cli/KeysMap.php | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/WebFiori/Cli/KeysMap.php b/WebFiori/Cli/KeysMap.php index bdd6449..1a22811 100644 --- a/WebFiori/Cli/KeysMap.php +++ b/WebFiori/Cli/KeysMap.php @@ -97,6 +97,31 @@ public static function read(InputStream $stream, $bytes = 1) : string { */ public static function readAndTranslate(InputStream $stream) : string { $keypress = $stream->read(); + + // Handle EOF + if ($keypress === '') { + return ''; + } + + // Handle escape sequences (multi-byte) + if ($keypress === "\033") { + try { + // Read the next character to see if it's part of an escape sequence + $next = $stream->read(); + if ($next === '[') { + // Read the final character of the sequence + $final = $stream->read(); + $sequence = $keypress . $next . $final; + return self::map($sequence); + } else { + // Not a complete escape sequence, return ESC + return self::map($keypress); + } + } catch (\Exception $e) { + // If we can't read more bytes, just return ESC + return self::map($keypress); + } + } return self::map($keypress); } @@ -134,18 +159,14 @@ private static function appendChar($ch, &$input) { if ($ch == 'BACKSPACE' && strlen($input) > 0) { $input = substr($input, 0, strlen($input) - 1); } else if ($ch == 'ESC') { - $input .= "\e"; + // Ignore ESC key } else if ($ch == "CR") { // Do nothing - don't add CR to input } else if ($ch == "LF") { // Do nothing - don't add LF to input (readLine should not include line ending) - } else if ($ch == 'DOWN') { - // read history; - //$input .= ' '; - } else if ($ch == 'UP') { - // read history; - //$input .= ' '; - } else if ($ch != 'CR' && $ch != 'LF') { + } else if ($ch == 'DOWN' || $ch == 'UP' || $ch == 'LEFT' || $ch == 'RIGHT') { + // Ignore arrow keys for now - they don't add to input + } else { if ($ch == 'SPACE') { $input .= ' '; } else { From 080a6320ad4229688cc97af3ee562dc7affb86a4 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 01:44:11 +0300 Subject: [PATCH 03/18] Update KeysMapTest.php --- tests/WebFiori/Tests/Cli/KeysMapTest.php | 84 +++++++++++++++++------- 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/tests/WebFiori/Tests/Cli/KeysMapTest.php b/tests/WebFiori/Tests/Cli/KeysMapTest.php index 3bb713a..eda39c3 100644 --- a/tests/WebFiori/Tests/Cli/KeysMapTest.php +++ b/tests/WebFiori/Tests/Cli/KeysMapTest.php @@ -4,39 +4,77 @@ use PHPUnit\Framework\TestCase; use WebFiori\Cli\KeysMap; use WebFiori\Cli\Streams\ArrayInputStream; + /** - * Description of KeysMapTest - * - * @author Ibrahim + * Test cases for KeysMap class arrow key handling. */ class KeysMapTest extends TestCase { + + /** + * Test that arrow key escape sequences are properly detected. + */ + public function testArrowKeyDetection() { + // Test UP arrow + $inputStream = new ArrayInputStream(["\033[A"]); + $result = KeysMap::readAndTranslate($inputStream); + $this->assertEquals('UP', $result); + + // Test DOWN arrow + $inputStream = new ArrayInputStream(["\033[B"]); + $result = KeysMap::readAndTranslate($inputStream); + $this->assertEquals('DOWN', $result); + + // Test RIGHT arrow + $inputStream = new ArrayInputStream(["\033[C"]); + $result = KeysMap::readAndTranslate($inputStream); + $this->assertEquals('RIGHT', $result); + + // Test LEFT arrow + $inputStream = new ArrayInputStream(["\033[D"]); + $result = KeysMap::readAndTranslate($inputStream); + $this->assertEquals('LEFT', $result); + } + + /** + * Test that arrow keys don't appear in readline input. + */ + public function testArrowKeysIgnoredInReadLine() { + // Input with arrow keys mixed with regular text + $inputStream = new ArrayInputStream(["\033[A\033[Bhello\033[C\033[D\n"]); + $result = KeysMap::readLine($inputStream); + + // Should only contain "hello", arrow keys should be ignored + $this->assertEquals('hello', $result); + } + /** - * @test + * Test that regular characters still work normally. */ - public function test00() { - $stream = new ArrayInputStream([ - chr(27) // ESC character - ]); - $this->assertEquals("ESC", KeysMap::readAndTranslate($stream)); + public function testRegularCharacters() { + $inputStream = new ArrayInputStream(["hello world\n"]); + $result = KeysMap::readLine($inputStream); + + $this->assertEquals('hello world', $result); } + /** - * @test + * Test backspace functionality still works. */ - public function test01() { - $stream = new ArrayInputStream([ - "\r" - ]); - $this->assertEquals("CR", KeysMap::readAndTranslate($stream)); + public function testBackspaceWithArrowKeys() { + // Type "hello", backspace once, arrow keys (ignored), type "p" + $inputStream = new ArrayInputStream(["hello\177\033[A\033[Bp\n"]); + $result = KeysMap::readLine($inputStream); + + // Should be "hellp" (hello -> hell -> hell -> hell -> hellp) + $this->assertEquals('hellp', $result); } + /** - * @test + * Test ESC key handling. */ - public function test02() { - $stream = new ArrayInputStream([ - "\r", - "\n" - ]); - $this->assertEquals("CR", KeysMap::readAndTranslate($stream)); - $this->assertEquals("LF", KeysMap::readAndTranslate($stream)); + public function testEscapeKey() { + $inputStream = new ArrayInputStream(["\ehello\n"]); + $result = KeysMap::readAndTranslate($inputStream); + $this->assertEquals('ESC', $result); } } From de1353710c933ba1054b2ae85c4652e650a39511 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 01:53:10 +0300 Subject: [PATCH 04/18] Update KeysMap.php --- WebFiori/Cli/KeysMap.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WebFiori/Cli/KeysMap.php b/WebFiori/Cli/KeysMap.php index 1a22811..289fe6f 100644 --- a/WebFiori/Cli/KeysMap.php +++ b/WebFiori/Cli/KeysMap.php @@ -103,7 +103,7 @@ public static function readAndTranslate(InputStream $stream) : string { return ''; } - // Handle escape sequences (multi-byte) + // Handle escape sequences (multi-byte) - kept for future use if ($keypress === "\033") { try { // Read the next character to see if it's part of an escape sequence @@ -165,7 +165,7 @@ private static function appendChar($ch, &$input) { } else if ($ch == "LF") { // Do nothing - don't add LF to input (readLine should not include line ending) } else if ($ch == 'DOWN' || $ch == 'UP' || $ch == 'LEFT' || $ch == 'RIGHT') { - // Ignore arrow keys for now - they don't add to input + // Ignore arrow keys - kept for future navigation features } else { if ($ch == 'SPACE') { $input .= ' '; From bc2ce0862f2f3ba7df85206fbeea7ea14ac22af9 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 01:53:24 +0300 Subject: [PATCH 05/18] Update StdIn.php --- WebFiori/Cli/Streams/StdIn.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/WebFiori/Cli/Streams/StdIn.php b/WebFiori/Cli/Streams/StdIn.php index bb816c4..425d457 100644 --- a/WebFiori/Cli/Streams/StdIn.php +++ b/WebFiori/Cli/Streams/StdIn.php @@ -25,14 +25,7 @@ public function read(int $bytes = 1) : string { $input = ''; while (strlen($input) < $bytes) { - $rawChar = fgetc(STDIN); - - // Handle EOF - if ($rawChar === false) { - break; - } - - $char = KeysMap::map($rawChar); + $char = KeysMap::map(fgetc(STDIN)); if ($char == 'BACKSPACE' && strlen($input) > 0) { $input = substr($input, 0, strlen($input) - 1); From 702b34f117284dbf875e583566949d52a19f5f21 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 02:16:55 +0300 Subject: [PATCH 06/18] Update RunnerTest.php --- tests/WebFiori/Tests/Cli/RunnerTest.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/WebFiori/Tests/Cli/RunnerTest.php b/tests/WebFiori/Tests/Cli/RunnerTest.php index 0728a58..97690cb 100644 --- a/tests/WebFiori/Tests/Cli/RunnerTest.php +++ b/tests/WebFiori/Tests/Cli/RunnerTest.php @@ -220,8 +220,6 @@ public function testRunner08() { "\e[1;33m super-hero\e[0m: A command to display hero's name.\n", "\e[1;94m Supported Arguments:\e[0m\n", "\e[1;33m name:\e[0m The name of the hero\n", - "\e[1;33m help:\e[0m[Optional] Display command help.\n", - " -h:[Optional] \n" ], $runner->getOutput()); } /** @@ -263,8 +261,6 @@ public function testRunner10() { " super-hero: A command to display hero's name.\n", " Supported Arguments:\n", " name: The name of the hero\n", - " help:[Optional] Display command help.\n", - " -h:[Optional] \n" ], $runner->getOutput()); } /** @@ -370,8 +366,6 @@ public function testRunner14() { ">> super-hero: A command to display hero's name.\n", " Supported Arguments:\n", " name: The name of the hero\n", - " help:[Optional] Display command help.\n", - " -h:[Optional] \n", ">> Hello hero Ibrahim\n", ">> " ], $runner->getOutput()); @@ -411,8 +405,6 @@ public function testRunner15() { ">>  super-hero: A command to display hero's name.\n", " Supported Arguments:\n", " name: The name of the hero\n", - " help:[Optional] Display command help.\n", - " -h:[Optional] \n", "Command Exit Status: 0\n", ">> Error: An exception was thrown.\n", "Exception Message: Call to undefined method WebFiori\Tests\Cli\TestCommands\WithExceptionCommand::notExist()\n", From 30f00eba51162a27de1e67baeef9f29393da341f Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 02:25:20 +0300 Subject: [PATCH 07/18] Update RunnerTest.php --- tests/WebFiori/Tests/Cli/RunnerTest.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/WebFiori/Tests/Cli/RunnerTest.php b/tests/WebFiori/Tests/Cli/RunnerTest.php index 97690cb..8adf75e 100644 --- a/tests/WebFiori/Tests/Cli/RunnerTest.php +++ b/tests/WebFiori/Tests/Cli/RunnerTest.php @@ -160,7 +160,7 @@ public function testRunner05() { "Usage:\n", " command [arg1 arg2=\"val\" arg3...]\n\n", "Available Commands:\n", - " help: Display CLI Help. To display help for specific command, use the argument \"--command-name\" with this command.\n", + " help: Display CLI Help. To display help for specific command, use the argument \"--command\" with this command.\n", " super-hero: A command to display hero's name.\n" ], $runner->getOutput()); } @@ -175,7 +175,7 @@ public function testRunner06() { "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", + " help: Display CLI Help. To display help for specific command, use the argument \"--command\" with this command.\n", " super-hero: A command to display hero's name.\n" ], $this->executeMultiCommand([], [], [ new Command00() @@ -201,7 +201,7 @@ public function testRunner07() { "\e[1;93mGlobal Arguments:\e[0m\n", "\e[1;33m --ansi:\e[0m[Optional] Force the use of ANSI output.\n", "\e[1;93mAvailable Commands:\e[0m\n", - "\e[1;33m help\e[0m: Display CLI Help. To display help for specific command, use the argument \"--command-name\" with this command.\n", + "\e[1;33m help\e[0m: Display CLI Help. To display help for specific command, use the argument \"--command\" with this command.\n", "\e[1;33m super-hero\e[0m: A command to display hero's name.\n" ], $runner->getOutput()); } @@ -214,7 +214,7 @@ public function testRunner08() { $runner->setInputs([]); $this->assertEquals(0, $runner->runCommand(new HelpCommand(), [ '--ansi', - '--command-name' => 'super-hero' + '--command' => 'super-hero' ])); $this->assertEquals([ "\e[1;33m super-hero\e[0m: A command to display hero's name.\n", @@ -238,7 +238,7 @@ public function testRunner09() { "Usage:\n", " command [arg1 arg2=\"val\" arg3...]\n\n", "Available Commands:\n", - " help: Display CLI Help. To display help for specific command, use the argument \"--command-name\" with this command.\n", + " help: Display CLI Help. To display help for specific command, use the argument \"--command\" with this command.\n", " super-hero: A command to display hero's name.\n" ], $runner->getOutput()); $this->assertEquals(0, $runner->getLastCommandExitStatus()); @@ -254,7 +254,7 @@ public function testRunner10() { $runner->setArgsVector([ 'entry.php', 'help', - '--command-name' => 'super-hero' + '--command' => 'super-hero' ]); $runner->start(); $this->assertEquals([ @@ -272,7 +272,7 @@ public function testRunner11() { $r->setArgsVector([ 'entry.php', 'help', - '--command-name' => 'super hero', + '--command' => 'super hero', '--ansi' ]); $r->register(new Command00()); @@ -335,7 +335,7 @@ public function testRunner13() { "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", + " help: Display CLI Help. To display help for specific command, use the argument \"--command\" with this command.\n", " super-hero: A command to display hero's name.\n", ">> ", ], $runner->getOutput()); @@ -355,7 +355,7 @@ public function testRunner14() { '-i', ]); $runner->setInputs([ - 'help --ansi --command-name=super-hero', + 'help --ansi --command=super-hero', 'super-hero name=Ibrahim', 'exit' ]); @@ -387,7 +387,7 @@ public function testRunner15() { '-i', ]); $runner->setInputs([ - 'help --command-name=super-hero', + 'help --command=super-hero', 'with-exception', 'exit' ]); From 0f71a226671004af77fd20f6b27f94e89c9136eb Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 02:37:58 +0300 Subject: [PATCH 08/18] Update AliasingIntegrationTest.php --- tests/WebFiori/Tests/Cli/AliasingIntegrationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/WebFiori/Tests/Cli/AliasingIntegrationTest.php b/tests/WebFiori/Tests/Cli/AliasingIntegrationTest.php index 04cf849..d38a02f 100644 --- a/tests/WebFiori/Tests/Cli/AliasingIntegrationTest.php +++ b/tests/WebFiori/Tests/Cli/AliasingIntegrationTest.php @@ -28,7 +28,7 @@ public function testAliasingWithHelpCommand() { $runner->register($aliasCommand); // Test help for command via direct name (not alias, as help might not resolve aliases) - $runner->setArgsVector(['script.php', 'help', '--command-name=alias-test']); + $runner->setArgsVector(['script.php', 'help', '--command=alias-test']); $exitCode = $runner->start(); $output = $runner->getOutputStream()->getOutputArray(); From 588549afc0199c6f744b0441240570918ca587f2 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 11:09:54 +0300 Subject: [PATCH 09/18] Update InitAppCommandTest.php --- .../WebFiori/Tests/Cli/InitAppCommandTest.php | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/tests/WebFiori/Tests/Cli/InitAppCommandTest.php b/tests/WebFiori/Tests/Cli/InitAppCommandTest.php index 5fef869..0c84c8b 100644 --- a/tests/WebFiori/Tests/Cli/InitAppCommandTest.php +++ b/tests/WebFiori/Tests/Cli/InitAppCommandTest.php @@ -57,12 +57,20 @@ public function test02() { 'init', '--dir' => 'test' ]); + // Cleanup existing files $appPath = ROOT_DIR.DS.'test'; + if (file_exists($appPath)) { + if (file_exists($appPath.DS.'main.php')) unlink($appPath.DS.'main.php'); + if (file_exists($appPath.DS.'test')) unlink($appPath.DS.'test'); + if (file_exists($appPath.DS.'HelloCommand.php')) unlink($appPath.DS.'HelloCommand.php'); + if (is_dir($appPath)) rmdir($appPath); + } $this->assertEquals(0, $r->start()); $this->assertEquals([ "Creating new app at \"$appPath\" ...\n", "Creating \"test/main.php\"...\n", - "Creating \"test/test\"...\n", + "Creating \"test/main\"...\n", + "Creating \"test/HelloCommand.php\"...\n", "Success: App created successfully.\n" ], $r->getOutput()); } @@ -80,18 +88,22 @@ public function test03() { 'init', '--dir' => 'test' ]); + // Don't cleanup - this test expects files to exist $this->assertEquals(0, $r->start()); $appPath = ROOT_DIR.DS.'test'; $this->assertEquals([ "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", + "Creating \"test/main\"...\n", + "Warning: File main already exist!\n", + "Creating \"test/HelloCommand.php\"...\n", + "Warning: File HelloCommand.php already exist!\n", "Success: App created successfully.\n" ], $r->getOutput()); unlink(ROOT_DIR.DS.'test'.DS.'main.php'); - unlink(ROOT_DIR.DS.'test'.DS.'test'); + unlink(ROOT_DIR.DS.'test'.DS.'HelloCommand.php'); + unlink(ROOT_DIR.DS.'test'.DS.'main'); rmdir(ROOT_DIR.DS.'test'); } /** @@ -108,12 +120,20 @@ public function test04() { '--dir' => 'test2', '--entry' => 'bang' ]); + // Cleanup existing files + $appPath = ROOT_DIR.DS.'test2'; + if (file_exists($appPath)) { + if (file_exists($appPath.DS.'bang')) unlink($appPath.DS.'bang'); + if (file_exists($appPath.DS.'HelloCommand.php')) unlink($appPath.DS.'HelloCommand.php'); + if (is_dir($appPath)) rmdir($appPath); + } $this->assertEquals(0, $r->start()); $appPath = ROOT_DIR.DS.'test2'; $this->assertEquals([ "Creating new app at \"$appPath\" ...\n", "Creating \"test2/main.php\"...\n", "Creating \"test2/bang\"...\n", + "Creating \"test2/HelloCommand.php\"...\n", "Success: App created successfully.\n" ], $r->getOutput()); unlink($appPath.DS.'main.php'); From 203688f07d914abf07ed58b25543772324e1a362 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 11:10:07 +0300 Subject: [PATCH 10/18] Update RunnerTest.php --- tests/WebFiori/Tests/Cli/RunnerTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/WebFiori/Tests/Cli/RunnerTest.php b/tests/WebFiori/Tests/Cli/RunnerTest.php index 8adf75e..c1bfc7e 100644 --- a/tests/WebFiori/Tests/Cli/RunnerTest.php +++ b/tests/WebFiori/Tests/Cli/RunnerTest.php @@ -15,8 +15,6 @@ use WebFiori\Tests\Cli\TestCommands\WithExceptionCommand; use WebFiori\Tests\Cli\TestCommands\Command03; use WebFiori\Tests\Cli\TestCommand; -use const DS; -use const ROOT_DIR; /** @@ -409,7 +407,7 @@ public function testRunner15() { ">> Error: An exception was thrown.\n", "Exception Message: Call to undefined method WebFiori\Tests\Cli\TestCommands\WithExceptionCommand::notExist()\n", "Code: 0\n", - "At: ".\ROOT_DIR."tests".\DS."WebFiori".\DS."Tests".\DS."Cli".\DS."TestCommands".\DS."WithExceptionCommand.php\n", + "At: ".ROOT_DIR."tests".DS."WebFiori".DS."Tests".DS."Cli".DS."TestCommands".DS."WithExceptionCommand.php\n", "Line: 13\n", "Stack Trace: \n\n", null, From 1aadc71221925a4682c960234a1717d2fc59a250 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 12:36:25 +0300 Subject: [PATCH 11/18] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 36ce007..2e8fcfc 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ test/* tests/clover.xml cache/commands.json *.Identifier +/test2 +/home/ibrahim/cli/test2 From bcd2d34c12529313e660f5dcbbbb3712956143f8 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 12:36:37 +0300 Subject: [PATCH 12/18] Update phpunit10.xml --- tests/phpunit10.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit10.xml b/tests/phpunit10.xml index 9f549e3..2287efc 100644 --- a/tests/phpunit10.xml +++ b/tests/phpunit10.xml @@ -1,5 +1,5 @@ - + From 5a3c0666be1747dc0d6d7de2b18cddb17162a059 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 12:36:51 +0300 Subject: [PATCH 13/18] Update InitAppCommandTest.php --- .../WebFiori/Tests/Cli/InitAppCommandTest.php | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/WebFiori/Tests/Cli/InitAppCommandTest.php b/tests/WebFiori/Tests/Cli/InitAppCommandTest.php index 0c84c8b..eb2a2e1 100644 --- a/tests/WebFiori/Tests/Cli/InitAppCommandTest.php +++ b/tests/WebFiori/Tests/Cli/InitAppCommandTest.php @@ -42,10 +42,15 @@ public function test01() { '--dir' => "test\0a" ]); $this->assertEquals(-1, $r->start()); + $this->assertEquals([ + "Creating new app at \"/home/ibrahim/cli/test\000a\" ...\n", + "Creating \"test\000a/main.php\"...\n", + "Error: Unable to initialize due to an exception:\n", + "0 - mkdir(): Argument #1 (\$directory) must not contain any null bytes\n" + ], $r->getOutput()); } /** * @test - * @depends test01 */ public function test02() { $r = new Runner(); @@ -58,12 +63,12 @@ public function test02() { '--dir' => 'test' ]); // Cleanup existing files - $appPath = ROOT_DIR.DS.'test'; + $appPath = ROOT_DIR.'test'; if (file_exists($appPath)) { - if (file_exists($appPath.DS.'main.php')) unlink($appPath.DS.'main.php'); - if (file_exists($appPath.DS.'test')) unlink($appPath.DS.'test'); - if (file_exists($appPath.DS.'HelloCommand.php')) unlink($appPath.DS.'HelloCommand.php'); - if (is_dir($appPath)) rmdir($appPath); + unlink(ROOT_DIR.DS.'test'.DS.'main.php'); + unlink(ROOT_DIR.DS.'test'.DS.'HelloCommand.php'); + unlink(ROOT_DIR.DS.'test'.DS.'main'); + rmdir(ROOT_DIR.DS.'test'); } $this->assertEquals(0, $r->start()); $this->assertEquals([ @@ -90,7 +95,7 @@ public function test03() { ]); // Don't cleanup - this test expects files to exist $this->assertEquals(0, $r->start()); - $appPath = ROOT_DIR.DS.'test'; + $appPath = ROOT_DIR.'test'; $this->assertEquals([ "Creating new app at \"$appPath\" ...\n", "Creating \"test/main.php\"...\n", @@ -121,14 +126,14 @@ public function test04() { '--entry' => 'bang' ]); // Cleanup existing files - $appPath = ROOT_DIR.DS.'test2'; + $appPath = ROOT_DIR.'test2'; if (file_exists($appPath)) { - if (file_exists($appPath.DS.'bang')) unlink($appPath.DS.'bang'); - if (file_exists($appPath.DS.'HelloCommand.php')) unlink($appPath.DS.'HelloCommand.php'); - if (is_dir($appPath)) rmdir($appPath); + unlink($appPath.DS.'main.php'); + unlink($appPath.DS.'bang'); + unlink($appPath.DS.'HelloCommand.php'); + rmdir($appPath); } $this->assertEquals(0, $r->start()); - $appPath = ROOT_DIR.DS.'test2'; $this->assertEquals([ "Creating new app at \"$appPath\" ...\n", "Creating \"test2/main.php\"...\n", @@ -138,6 +143,7 @@ public function test04() { ], $r->getOutput()); unlink($appPath.DS.'main.php'); unlink($appPath.DS.'bang'); + unlink($appPath.DS.'HelloCommand.php'); rmdir($appPath); } } From 27dd0ad57030b0efb1544d4ddcc41dc17c163f86 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 12:37:02 +0300 Subject: [PATCH 14/18] Update RunnerTest.php --- tests/WebFiori/Tests/Cli/RunnerTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/WebFiori/Tests/Cli/RunnerTest.php b/tests/WebFiori/Tests/Cli/RunnerTest.php index c1bfc7e..38783ee 100644 --- a/tests/WebFiori/Tests/Cli/RunnerTest.php +++ b/tests/WebFiori/Tests/Cli/RunnerTest.php @@ -392,11 +392,12 @@ public function testRunner15() { $runner->start(); $output = $runner->getOutput(); // Null out the stack trace content as it can vary - for ($i = 14; $i < count($output) - 2; $i++) { + for ($i = 12; $i < count($output) - 2; $i++) { if ($output[$i] !== null && strpos($output[$i], 'Command Exit Status: -1') === false && strpos($output[$i], '>> ') === false) { $output[$i] = null; } } + $this->assertEquals([ ">> Running in interactive mode.\n", ">> Type command name or 'exit' to close.\n", From 6c5eb316cbd342698b8c742cdbaa5a2c3a5b300b Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 12:37:13 +0300 Subject: [PATCH 15/18] Update InitAppCommand.php --- WebFiori/Cli/Commands/InitAppCommand.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/WebFiori/Cli/Commands/InitAppCommand.php b/WebFiori/Cli/Commands/InitAppCommand.php index b89ecb4..459080b 100644 --- a/WebFiori/Cli/Commands/InitAppCommand.php +++ b/WebFiori/Cli/Commands/InitAppCommand.php @@ -31,7 +31,11 @@ public function exec(): int { } if (defined('ROOT_DIR')) { - $appPath = ROOT_DIR.DIRECTORY_SEPARATOR.$dirName; + $path = ROOT_DIR; + if ($path[strlen($path) - 1] != DIRECTORY_SEPARATOR) { + $path .= DIRECTORY_SEPARATOR; + } + $appPath = $path.$dirName; } else { $appPath = getcwd().DIRECTORY_SEPARATOR.$dirName; } @@ -44,7 +48,7 @@ public function exec(): int { $this->success('App created successfully.'); return 0; - } catch (\Exception $ex) { + } catch (\Throwable $ex) { $this->error('Unable to initialize due to an exception:'); $this->println($ex->getCode().' - '.$ex->getMessage()); From 907add2e383ba6f91a645f2560900d6cc6f6b5a8 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 17:23:13 +0300 Subject: [PATCH 16/18] Update InitAppCommandTest.php --- tests/WebFiori/Tests/Cli/InitAppCommandTest.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/WebFiori/Tests/Cli/InitAppCommandTest.php b/tests/WebFiori/Tests/Cli/InitAppCommandTest.php index eb2a2e1..b465e80 100644 --- a/tests/WebFiori/Tests/Cli/InitAppCommandTest.php +++ b/tests/WebFiori/Tests/Cli/InitAppCommandTest.php @@ -42,12 +42,13 @@ public function test01() { '--dir' => "test\0a" ]); $this->assertEquals(-1, $r->start()); - $this->assertEquals([ - "Creating new app at \"/home/ibrahim/cli/test\000a\" ...\n", - "Creating \"test\000a/main.php\"...\n", - "Error: Unable to initialize due to an exception:\n", - "0 - mkdir(): Argument #1 (\$directory) must not contain any null bytes\n" - ], $r->getOutput()); + $output = $r->getOutput(); + // Check key elements instead of exact match due to binary string representation differences + $this->assertCount(4, $output); + $this->assertStringContainsString('Creating new app at', $output[0]); + $this->assertStringContainsString('Creating "test', $output[1]); + $this->assertStringContainsString('Error: Unable to initialize', $output[2]); + $this->assertStringContainsString('null bytes', $output[3]); } /** * @test From 2fb89d712cad4451b2fa2f77984da159fb977ad2 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 23:05:21 +0300 Subject: [PATCH 17/18] test: Added Coverage --- tests/phpunit.xml | 20 +------------------- tests/phpunit10.xml | 28 +++++----------------------- 2 files changed, 6 insertions(+), 42 deletions(-) diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 905bd7d..86e6b9b 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -4,25 +4,7 @@ - ../WebFiori/Cli/Command.php - ../WebFiori/Cli/CommandArgument.php - ../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 - ../WebFiori/Cli/Streams/FileInputStream.php - ../WebFiori/Cli/Streams/FileOutputStream.php - ../WebFiori/Cli/Discovery/CommandDiscovery.php - ../WebFiori/Cli/Discovery/CommandMetadata.php - ../WebFiori/Cli/Discovery/CommandCache.php - ../WebFiori/Cli/Discovery/AutoDiscoverable.php - ../WebFiori/Cli/Exceptions/CommandDiscoveryException.php - ../WebFiori/Cli/Progress/ProgressBar.php - ../WebFiori/Cli/Progress/ProgressBarStyle.php - ../WebFiori/Cli/Progress/ProgressBarFormat.php + ../WebFiori/Cli diff --git a/tests/phpunit10.xml b/tests/phpunit10.xml index 2287efc..77a1e2b 100644 --- a/tests/phpunit10.xml +++ b/tests/phpunit10.xml @@ -5,6 +5,11 @@ + + + ../WebFiori/Cli + + @@ -13,27 +18,4 @@ ./WebFiori/Tests/Cli - - - ../WebFiori/Cli/Command.php - ../WebFiori/Cli/CommandArgument.php - ../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 - ../WebFiori/Cli/Streams/FileInputStream.php - ../WebFiori/Cli/Streams/FileOutputStream.php - ../WebFiori/Cli/Discovery/CommandDiscovery.php - ../WebFiori/Cli/Discovery/CommandMetadata.php - ../WebFiori/Cli/Discovery/CommandCache.php - ../WebFiori/Cli/Discovery/AutoDiscoverable.php - ../WebFiori/Cli/Exceptions/CommandDiscoveryException.php - ../WebFiori/Cli/Progress/ProgressBar.php - ../WebFiori/Cli/Progress/ProgressBarStyle.php - ../WebFiori/Cli/Progress/ProgressBarFormat.php - - From 1fefd288a39444bf49b02abd1313862d7edfd101 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Thu, 25 Sep 2025 23:14:20 +0300 Subject: [PATCH 18/18] Update phpunit.xml --- tests/phpunit.xml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 86e6b9b..7ba7bbf 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -1,12 +1,23 @@ - + + + + - + + ../WebFiori/Cli - + + + ./WebFiori/Tests/Cli