diff --git a/classes/Kohana/Minion/CLI.php b/classes/Kohana/Minion/CLI.php index 13c1de6..955ec38 100644 --- a/classes/Kohana/Minion/CLI.php +++ b/classes/Kohana/Minion/CLI.php @@ -33,6 +33,16 @@ class Kohana_Minion_CLI { 'light_gray' => '47', ); + /** + * @var resource The configured output stream + */ + protected static $_stdout = STDOUT; + + /** + * @var resource The configured input stream + */ + protected static $_stdin = STDIN; + /** * Returns one or more command-line options. Options are specified using * standard CLI syntax: @@ -130,10 +140,10 @@ public static function read($text = '', array $options = NULL) $options_output = ' [ '.implode(', ', $options).' ]'; } - fwrite(STDOUT, $text.$options_output.': '); + fwrite(Minion_CLI::$_stdout, $text.$options_output.': '); // Read the input from keyboard. - $input = trim(fgets(STDIN)); + $input = trim(fgets(Minion_CLI::$_stdin)); // If options are provided and the choice is not in the array, tell them to try again if ( ! empty($options) && ! in_array($input, $options)) @@ -202,7 +212,7 @@ public static function write($text = '') } else { - fwrite(STDOUT, $text.PHP_EOL); + fwrite(Minion_CLI::$_stdout, $text.PHP_EOL); } } @@ -226,7 +236,7 @@ public static function write_replace($text = '', $end_line = FALSE) { // Append a newline if $end_line is TRUE $text = $end_line ? $text.PHP_EOL : $text; - fwrite(STDOUT, "\r\033[K".$text); + fwrite(Minion_CLI::$_stdout, "\r\033[K".$text); } /** @@ -248,7 +258,7 @@ public static function wait($seconds = 0, $countdown = false) while ($time > 0) { - fwrite(STDOUT, $time.'... '); + fwrite(Minion_CLI::$_stdout, $time.'... '); sleep(1); $time--; } @@ -312,4 +322,37 @@ public static function color($text, $foreground, $background = null) return $string; } + /** + * Sets the output stream. + * + * @param resource $stream the output stream + * @return bool true if the stream was set successfully + */ + public static function set_stdout($stream) + { + if (is_resource($stream) AND get_resource_type($stream) == 'stream') + { + Minion_CLI::$_stdout = $stream; + return TRUE; + } + + return FALSE; + } + + /** + * Sets the input stream. + * + * @param resource $stream the input stream + * @return bool true if the stream was set successfully + */ + public static function set_stdin($stream) + { + if (is_resource($stream) AND get_resource_type($stream) == 'stream') + { + Minion_CLI::$_stdin = $stream; + return TRUE; + } + + return FALSE; + } } diff --git a/tests/minion/cli.php b/tests/minion/cli.php new file mode 100644 index 0000000..a10cf26 --- /dev/null +++ b/tests/minion/cli.php @@ -0,0 +1,96 @@ +assertFalse(Minion_CLI::set_stdout('invalid')); + $this->assertFalse(Minion_CLI::set_stdout(1)); + + $stream = fopen('php://memory', 'rw'); + $this->assertTrue(Minion_CLI::set_stdout($stream)); + fclose($stream); + + $this->assertFalse(Minion_CLI::set_stdin('invalid')); + $this->assertFalse(Minion_CLI::set_stdin(1)); + + $stream = fopen('php://memory', 'rw'); + $this->assertTrue(Minion_CLI::set_stdin($stream)); + fclose($stream); + } + + /** + * Tests that any output can be captured effectively. + * + * @covers Minion_CLI::write + */ + public function test_writing_to_and_reading_from_output_stream() + { + $stream = fopen('php://memory', 'rw'); + Minion_CLI::set_stdout($stream); + + $msg = 'first test message'; + Minion_CLI::write($msg); + rewind($stream); + + $this->assertSame($msg, trim(fgets($stream))); + rewind($stream); + + $msg = 'second test message'; + Minion_CLI::write($msg); + rewind($stream); + + $this->assertSame($msg, trim(fgets($stream))); + fclose($stream); + } + + /** + * Tests that any input can be handled effectively. + * + * @covers Minion_CLI::read + */ + public function test_writing_to_and_reading_from_input_stream() + { + $output = fopen('php://memory', 'rw'); + $input = fopen('php://memory', 'rw'); + $this->assertNotSame($output, $input); + + Minion_CLI::set_stdout($output); + Minion_CLI::set_stdin($input); + + fwrite($input, 'y'.PHP_EOL.'red'.PHP_EOL); + rewind($input); + + $read = Minion_CLI::read('Choose', array('y', 'n')); + $this->assertSame('y', $read); + + $read = Minion_CLI::read('Choose', array('red', 'blue')); + $this->assertSame('red', $read); + + fclose($output); + fclose($input); + } + + public static function tearDownAfterClass() + { + // Restore the default streams + Minion_CLI::set_stdin(STDIN); + Minion_CLI::set_stdout(STDOUT); + } +}