Browse Source

Start integrating ConsoleIo into Shell.

* Update doc blocks.
* Move additional methods into ConsoleIo.
* Update tests.
mark_story 12 years ago
parent
commit
8f26bcb520

+ 40 - 0
src/Console/ConsoleIo.php

@@ -16,6 +16,8 @@ namespace Cake\Console;
 
 use Cake\Console\ConsoleInput;
 use Cake\Console\ConsoleOutput;
+use Cake\Log\Engine\ConsoleLog;
+use Cake\Log\Log;
 
 /**
  * A wrapper around the various IO operations shell tasks need to do.
@@ -234,6 +236,16 @@ class ConsoleIo {
 	}
 
 /**
+ * Change the output mode of the stdout stream
+ *
+ * @param int $mode
+ * @return void
+ */
+	public function outputAs($mode) {
+		$this->_out->outputAs($mode);
+	}
+
+/**
  * Prompts the user for input based on a list of options, and returns it.
  *
  * @param string $prompt Prompt text.
@@ -295,4 +307,32 @@ class ConsoleIo {
 		return $result;
 	}
 
+/**
+ * Connects or disconnects the loggers to the console output.
+ *
+ * Used to enable or disable logging stream output to stdout and stderr
+ * If you don't wish all log output in stdout or stderr
+ * through Cake's Log class, call this function with `$enable=false`.
+ *
+ * @param boolean $enable Whether you want loggers on or off.
+ * @return void
+ */
+	public function setLoggers($enable) {
+		Log::drop('stdout');
+		Log::drop('stderr');
+		if (!$enable) {
+			return;
+		}
+		$stdout = new ConsoleLog([
+			'types' => ['notice', 'info', 'debug'],
+			'stream' => $this->_out
+		]);
+		Log::config('stdout', ['engine' => $stdout]);
+		$stderr = new ConsoleLog([
+			'types' => ['emergency', 'alert', 'critical', 'error', 'warning'],
+			'stream' => $this->_err,
+		]);
+		Log::config('stderr', ['engine' => $stderr]);
+	}
+
 }

+ 0 - 2
src/Console/ConsoleOutput.php

@@ -1,7 +1,5 @@
 <?php
 /**
- * ConsoleOutput file.
- *
  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  *

+ 59 - 153
src/Console/Shell.php

@@ -1,7 +1,5 @@
 <?php
 /**
- * Base class for Shells
- *
  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  *
@@ -16,13 +14,12 @@
  */
 namespace Cake\Console;
 
+use Cake\Console\ConsoleIo;
 use Cake\Core\App;
 use Cake\Core\Configure;
 use Cake\Core\Object;
 use Cake\Core\Plugin;
 use Cake\Error;
-use Cake\Log\Engine\ConsoleLog;
-use Cake\Log\Log;
 use Cake\Utility\ConventionsTrait;
 use Cake\Utility\File;
 use Cake\Utility\Inflector;
@@ -33,6 +30,7 @@ use Cake\Utility\String;
 /**
  * Base class for command-line utilities for automating programmer chores.
  *
+ * Is the equivalent of Cake\Controller\Controller on the command line.
  */
 class Shell extends Object {
 
@@ -44,26 +42,26 @@ class Shell extends Object {
  *
  * @var integer
  */
-	const VERBOSE = 2;
+	const VERBOSE = ConsoleIo::VERBOSE;
 
 /**
  * Output constant for making normal shells.
  *
  * @var integer
  */
-	const NORMAL = 1;
+	const NORMAL = ConsoleIo::NORMAL;
 
 /**
  * Output constants for making quiet shells.
  *
  * @var integer
  */
-	const QUIET = 0;
+	const QUIET = ConsoleIo::QUIET;
 
 /**
  * An instance of ConsoleOptionParser that has been configured for this class.
  *
- * @var ConsoleOptionParser
+ * @var \Cake\Console\ConsoleOptionParser
  */
 	public $OptionParser;
 
@@ -114,7 +112,7 @@ class Shell extends Object {
  * Contains tasks to load and instantiate
  *
  * @var array
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::$tasks
+ * @link http://book.cakephp.org/3.0/en/console-and-shells.html#Shell::$tasks
  */
 	public $tasks = [];
 
@@ -140,48 +138,30 @@ class Shell extends Object {
 	protected $_taskMap = [];
 
 /**
- * stdout object.
- *
- * @var ConsoleOutput
- */
-	public $stdout;
-
-/**
- * stderr object.
- *
- * @var ConsoleOutput
- */
-	public $stderr;
-
-/**
- * stdin object
+ * ConsoleIo instance.
  *
- * @var ConsoleInput
+ * @var \Cake\Console\ConsoleIo
  */
-	public $stdin;
+	protected $_io;
 
 /**
  *  Constructs this Shell instance.
  *
- * @param ConsoleOutput $stdout A ConsoleOutput object for stdout.
- * @param ConsoleOutput $stderr A ConsoleOutput object for stderr.
- * @param ConsoleInput $stdin A ConsoleInput object for stdin.
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell
+ * @param \Cake\Console\ConsoleIo $io An io instance.
+ * @link http://book.cakephp.org/3.0/en/console-and-shells.html#Shell
  */
-	public function __construct(ConsoleOutput $stdout = null, ConsoleOutput $stderr = null, ConsoleInput $stdin = null) {
+	public function __construct(ConsoleIo $io = null) {
 		if (!$this->name) {
 			list(, $class) = namespaceSplit(get_class($this));
 			$this->name = str_replace(['Shell', 'Task'], '', $class);
 		}
+		$this->_io = $io ?: new ConsoleIo();
+
 		$this->_setModelClass($this->name);
 		$this->modelFactory('Table', ['Cake\ORM\TableRegistry', 'get']);
 		$this->Tasks = new TaskRegistry($this);
 
-		$this->stdout = $stdout ? $stdout : new ConsoleOutput('php://stdout');
-		$this->stderr = $stderr ? $stderr : new ConsoleOutput('php://stderr');
-		$this->stdin = $stdin ? $stdin : new ConsoleInput('php://stdin');
-
-		$this->_useLogger();
+		$this->_io->setLoggers(true);
 		$this->_mergeVars(
 			['tasks'],
 			['associative' => ['tasks']]
@@ -189,6 +169,19 @@ class Shell extends Object {
 	}
 
 /**
+ * Get/Set the io object for this shell.
+ *
+ * @param \Cake\Console\ConsoleIo $io
+ * @return \Cake\Console\ConsoleIo
+ */
+	public function io(ConsoleIo $io = null) {
+		if ($io !== null) {
+			$this->_io = $io;
+		}
+		return $this->_io;
+	}
+
+/**
  * Initializes the Shell
  * acts as constructor for subclasses
  * allows configuration of tasks prior to shell execution
@@ -318,8 +311,8 @@ class Shell extends Object {
 			$args = explode(' ', $args[0]);
 		}
 
-		$Dispatcher = new ShellDispatcher($args, false);
-		return $Dispatcher->dispatch();
+		$dispatcher = new ShellDispatcher($args, false);
+		return $dispatcher->dispatch();
 	}
 
 /**
@@ -359,7 +352,11 @@ class Shell extends Object {
 		}
 
 		if (!empty($this->params['quiet'])) {
-			$this->_useLogger(false);
+			$this->_io->level(ConsoleIo::QUIET);
+			$this->_io->setLoggers(false);
+		}
+		if (!empty($this->params['verbose'])) {
+			$this->_io->level(ConsoleIo::VERBOSE);
 		}
 		if (!empty($this->params['plugin'])) {
 			Plugin::load($this->params['plugin']);
@@ -397,7 +394,7 @@ class Shell extends Object {
 		$format = 'text';
 		if (!empty($this->args[0]) && $this->args[0] === 'xml') {
 			$format = 'xml';
-			$this->stdout->outputAs(ConsoleOutput::RAW);
+			$this->_io->outputAs(ConsoleOutput::RAW);
 		} else {
 			$this->_welcome();
 		}
@@ -443,68 +440,16 @@ class Shell extends Object {
  * @param string|array $options Array or string of options.
  * @param string $default Default input value.
  * @return mixed Either the default value, or the user-provided input.
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::in
+ * @link http://book.cakephp.org/3.0/en/console-and-shells.html#Shell::in
  */
 	public function in($prompt, $options = null, $default = null) {
 		if (!$this->interactive) {
 			return $default;
 		}
-		$originalOptions = $options;
-		$in = $this->_getInput($prompt, $originalOptions, $default);
-
-		if ($options && is_string($options)) {
-			if (strpos($options, ',')) {
-				$options = explode(',', $options);
-			} elseif (strpos($options, '/')) {
-				$options = explode('/', $options);
-			} else {
-				$options = [$options];
-			}
-		}
-		if (is_array($options)) {
-			$options = array_merge(
-				array_map('strtolower', $options),
-				array_map('strtoupper', $options),
-				$options
-			);
-			while ($in === '' || !in_array($in, $options)) {
-				$in = $this->_getInput($prompt, $originalOptions, $default);
-			}
-		}
-		return $in;
-	}
-
-/**
- * Prompts the user for input, and returns it.
- *
- * @param string $prompt Prompt text.
- * @param string|array $options Array or string of options.
- * @param string $default Default input value.
- * @return string Either the default value, or the user-provided input.
- */
-	protected function _getInput($prompt, $options, $default) {
-		if (!is_array($options)) {
-			$printOptions = '';
-		} else {
-			$printOptions = '(' . implode('/', $options) . ')';
-		}
-
-		if ($default === null) {
-			$this->stdout->write('<question>' . $prompt . '</question>' . " $printOptions \n" . '> ', 0);
-		} else {
-			$this->stdout->write('<question>' . $prompt . '</question>' . " $printOptions \n" . "[$default] > ", 0);
-		}
-		$result = $this->stdin->read();
-
-		if ($result === false) {
-			return $this->_stop(1);
-		}
-		$result = trim($result);
-
-		if ($default !== null && ($result === '' || $result === null)) {
-			return $default;
+		if ($options) {
+			return $this->_io->askChoice($prompt, $options, $default);
 		}
-		return $result;
+		return $this->_io->ask($prompt, $default);
 	}
 
 /**
@@ -521,7 +466,7 @@ class Shell extends Object {
  * @param string|integer|array $options Array of options to use, or an integer to wrap the text to.
  * @return string Wrapped / indented text
  * @see String::wrap()
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::wrapText
+ * @link http://book.cakephp.org/3.0/en/console-and-shells.html#Shell::wrapText
  */
 	public function wrapText($text, $options = []) {
 		return String::wrap($text, $options);
@@ -542,20 +487,10 @@ class Shell extends Object {
  * @param integer $newlines Number of newlines to append
  * @param integer $level The message's output level, see above.
  * @return integer|boolean Returns the number of bytes returned from writing to stdout.
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::out
+ * @link http://book.cakephp.org/3.0/en/console-and-shells.html#Shell::out
  */
 	public function out($message = null, $newlines = 1, $level = Shell::NORMAL) {
-		$currentLevel = Shell::NORMAL;
-		if (!empty($this->params['verbose'])) {
-			$currentLevel = Shell::VERBOSE;
-		}
-		if (!empty($this->params['quiet'])) {
-			$currentLevel = Shell::QUIET;
-		}
-		if ($level <= $currentLevel) {
-			return $this->stdout->write($message, $newlines);
-		}
-		return true;
+		return $this->_io->out($message, $newlines, $level);
 	}
 
 /**
@@ -565,10 +500,9 @@ class Shell extends Object {
  * @param string|array $message A string or a an array of strings to output
  * @param integer $newlines Number of newlines to append
  * @return void
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::err
  */
 	public function err($message = null, $newlines = 1) {
-		$this->stderr->write($message, $newlines);
+		return $this->_io->err($message, $newlines);
 	}
 
 /**
@@ -576,10 +510,10 @@ class Shell extends Object {
  *
  * @param integer $multiplier Number of times the linefeed sequence should be repeated
  * @return string
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::nl
+ * @link http://book.cakephp.org/3.0/en/console-and-shells.html#Shell::nl
  */
 	public function nl($multiplier = 1) {
-		return str_repeat(ConsoleOutput::LF, $multiplier);
+		return $this->_io->nl($multiplier);
 	}
 
 /**
@@ -588,12 +522,10 @@ class Shell extends Object {
  * @param integer $newlines Number of newlines to pre- and append
  * @param integer $width Width of the line, defaults to 63
  * @return void
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hr
+ * @link http://book.cakephp.org/3.0/en/console-and-shells.html#Shell::hr
  */
 	public function hr($newlines = 0, $width = 63) {
-		$this->out(null, $newlines);
-		$this->out(str_repeat('-', $width));
-		$this->out(null, $newlines);
+		return $this->_io->hr($newlines, $width);
 	}
 
 /**
@@ -606,10 +538,10 @@ class Shell extends Object {
  * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::error
  */
 	public function error($title, $message = null) {
-		$this->err(__d('cake_console', '<error>Error:</error> %s', $title));
+		$this->_io->err(__d('cake_console', '<error>Error:</error> %s', $title));
 
 		if (!empty($message)) {
-			$this->err($message);
+			$this->_io->err($message);
 		}
 		return $this->_stop(1);
 	}
@@ -641,17 +573,17 @@ class Shell extends Object {
 	public function createFile($path, $contents) {
 		$path = str_replace(DS . DS, DS, $path);
 
-		$this->out();
+		$this->_io->out();
 
 		if (is_file($path) && empty($this->params['force'])) {
-			$this->out(__d('cake_console', '<warning>File `%s` exists</warning>', $path));
-			$key = $this->in(__d('cake_console', 'Do you want to overwrite?'), ['y', 'n', 'q'], 'n');
+			$this->_io->out(__d('cake_console', '<warning>File `%s` exists</warning>', $path));
+			$key = $this->_io->askChoice(__d('cake_console', 'Do you want to overwrite?'), ['y', 'n', 'q'], 'n');
 
 			if (strtolower($key) === 'q') {
-				$this->out(__d('cake_console', '<error>Quitting</error>.'), 2);
+				$this->_io->out(__d('cake_console', '<error>Quitting</error>.'), 2);
 				return $this->_stop();
 			} elseif (strtolower($key) !== 'y') {
-				$this->out(__d('cake_console', 'Skip `%s`', $path), 2);
+				$this->_io->out(__d('cake_console', 'Skip `%s`', $path), 2);
 				return false;
 			}
 		} else {
@@ -662,11 +594,11 @@ class Shell extends Object {
 		if ($File->exists() && $File->writable()) {
 			$data = $File->prepare($contents);
 			$File->write($data);
-			$this->out(__d('cake_console', '<success>Wrote</success> `%s`', $path));
+			$this->_io->out(__d('cake_console', '<success>Wrote</success> `%s`', $path));
 			return true;
 		}
 
-		$this->err(__d('cake_console', '<error>Could not write to `%s`</error>.', $path), 2);
+		$this->_io->err(__d('cake_console', '<error>Could not write to `%s`</error>.', $path), 2);
 		return false;
 	}
 
@@ -675,7 +607,7 @@ class Shell extends Object {
  *
  * @param string $file Absolute file path
  * @return string short path
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::shortPath
+ * @link http://book.cakephp.org/3.0/en/console-and-shells.html#Shell::shortPath
  */
 	public function shortPath($file) {
 		$shortPath = str_replace(ROOT, null, $file);
@@ -684,30 +616,4 @@ class Shell extends Object {
 		return str_replace('//', DS, $shortPath);
 	}
 
-/**
- * Used to enable or disable logging stream output to stdout and stderr
- * If you don't wish to see in your stdout or stderr everything that is logged
- * through Cake Log, call this function with first param as false
- *
- * @param boolean $enable wheter to enable Cake Log output or not
- * @return void
- */
-	protected function _useLogger($enable = true) {
-		Log::drop('stdout');
-		Log::drop('stderr');
-		if (!$enable) {
-			return;
-		}
-		$stdout = new ConsoleLog([
-			'types' => ['notice', 'info', 'debug'],
-			'stream' => $this->stdout
-		]);
-		$stderr = new ConsoleLog([
-			'types' => ['emergency', 'alert', 'critical', 'error', 'warning'],
-			'stream' => $this->stderr,
-		]);
-		Log::config('stdout', ['engine' => $stdout]);
-		Log::config('stderr', ['engine' => $stderr]);
-	}
-
 }

+ 1 - 5
src/Console/TaskRegistry.php

@@ -79,11 +79,7 @@ class TaskRegistry extends ObjectRegistry {
  * @return \Cake\Console\Shell The constructed task class.
  */
 	protected function _create($class, $alias, $settings) {
-		return new $class(
-			$this->_Shell->stdout,
-			$this->_Shell->stderr,
-			$this->_Shell->stdin
-		);
+		return new $class($this->_Shell->io());
 	}
 
 }

+ 18 - 0
tests/TestCase/Console/ConsoleIoTest.php

@@ -15,6 +15,7 @@
 namespace Cake\Test\TestCase\Console;
 
 use Cake\Console\ConsoleIo;
+use Cake\Log\Log;
 use Cake\TestSuite\TestCase;
 
 /**
@@ -310,4 +311,21 @@ class ConsoleIoTest extends TestCase {
 		$this->io->overwrite('Less text');
 	}
 
+/**
+ * Tests that setLoggers works properly
+ *
+ * @return void
+ */
+	public function testSetLoggers() {
+		Log::drop('stdout');
+		Log::drop('stderr');
+		$this->io->setLoggers(true);
+		$this->assertNotEmpty(Log::engine('stdout'));
+		$this->assertNotEmpty(Log::engine('stderr'));
+
+		$this->io->setLoggers(false);
+		$this->assertFalse(Log::engine('stdout'));
+		$this->assertFalse(Log::engine('stderr'));
+	}
+
 }

+ 53 - 222
tests/TestCase/Console/ShellTest.php

@@ -1,9 +1,5 @@
 <?php
 /**
- * ShellTest file
- *
- * Test Case for Shell
- *
  * CakePHP :  Rapid Development Framework (http://cakephp.org)
  * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  *
@@ -137,10 +133,8 @@ class ShellTest extends TestCase {
 	public function setUp() {
 		parent::setUp();
 
-		$output = $this->getMock('Cake\Console\ConsoleOutput', array(), array(), '', false);
-		$error = $this->getMock('Cake\Console\ConsoleOutput', array(), array(), '', false);
-		$in = $this->getMock('Cake\Console\ConsoleInput', array(), array(), '', false);
-		$this->Shell = new ShellTestShell($output, $error, $in);
+		$this->io = $this->getMock('Cake\Console\ConsoleIo', [], [], '', false);
+		$this->Shell = new ShellTestShell($this->io);
 
 		if (is_dir(TMP . 'shell_test')) {
 			$Folder = new Folder(TMP . 'shell_test');
@@ -155,9 +149,7 @@ class ShellTest extends TestCase {
  */
 	public function testConstruct() {
 		$this->assertEquals('ShellTestShell', $this->Shell->name);
-		$this->assertInstanceOf('Cake\Console\ConsoleInput', $this->Shell->stdin);
-		$this->assertInstanceOf('Cake\Console\ConsoleOutput', $this->Shell->stdout);
-		$this->assertInstanceOf('Cake\Console\ConsoleOutput', $this->Shell->stderr);
+		$this->assertInstanceOf('Cake\Console\ConsoleIo', $this->Shell->io());
 	}
 
 /**
@@ -211,47 +203,21 @@ class ShellTest extends TestCase {
  * @return void
  */
 	public function testIn() {
-		$this->Shell->stdin->expects($this->at(0))
-			->method('read')
+		$this->io->expects($this->at(0))
+			->method('askChoice')
+			->with('Just a test?', ['y', 'n'], 'n')
 			->will($this->returnValue('n'));
 
-		$this->Shell->stdin->expects($this->at(1))
-			->method('read')
-			->will($this->returnValue('Y'));
-
-		$this->Shell->stdin->expects($this->at(2))
-			->method('read')
-			->will($this->returnValue('y'));
-
-		$this->Shell->stdin->expects($this->at(3))
-			->method('read')
-			->will($this->returnValue('y'));
-
-		$this->Shell->stdin->expects($this->at(4))
-			->method('read')
-			->will($this->returnValue('y'));
-
-		$this->Shell->stdin->expects($this->at(5))
-			->method('read')
-			->will($this->returnValue('0'));
+		$this->io->expects($this->at(1))
+			->method('ask')
+			->with('Just a test?', 'n')
+			->will($this->returnValue('n'));
 
 		$result = $this->Shell->in('Just a test?', array('y', 'n'), 'n');
 		$this->assertEquals('n', $result);
 
-		$result = $this->Shell->in('Just a test?', array('y', 'n'), 'n');
-		$this->assertEquals('Y', $result);
-
-		$result = $this->Shell->in('Just a test?', 'y,n', 'n');
-		$this->assertEquals('y', $result);
-
-		$result = $this->Shell->in('Just a test?', 'y/n', 'n');
-		$this->assertEquals('y', $result);
-
-		$result = $this->Shell->in('Just a test?', 'y', 'y');
-		$this->assertEquals('y', $result);
-
-		$result = $this->Shell->in('Just a test?', array(0, 1, 2), '0');
-		$this->assertEquals('0', $result);
+		$result = $this->Shell->in('Just a test?', null, 'n');
+		$this->assertEquals('n', $result);
 	}
 
 /**
@@ -260,6 +226,11 @@ class ShellTest extends TestCase {
  * @return void
  */
 	public function testInNonInteractive() {
+		$this->io->expects($this->never())
+			->method('askChoice');
+		$this->io->expects($this->never())
+			->method('ask');
+
 		$this->Shell->interactive = false;
 
 		$result = $this->Shell->in('Just a test?', 'y/n', 'n');
@@ -272,67 +243,11 @@ class ShellTest extends TestCase {
  * @return void
  */
 	public function testOut() {
-		$this->Shell->stdout->expects($this->at(0))
-			->method('write')
-			->with("Just a test", 1);
-
-		$this->Shell->stdout->expects($this->at(1))
-			->method('write')
-			->with(array('Just', 'a', 'test'), 1);
-
-		$this->Shell->stdout->expects($this->at(2))
-			->method('write')
-			->with(array('Just', 'a', 'test'), 2);
-
-		$this->Shell->stdout->expects($this->at(3))
-			->method('write')
-			->with('', 1);
+		$this->io->expects($this->once())
+			->method('out')
+			->with('Just a test', 1);
 
 		$this->Shell->out('Just a test');
-
-		$this->Shell->out(array('Just', 'a', 'test'));
-
-		$this->Shell->out(array('Just', 'a', 'test'), 2);
-
-		$this->Shell->out();
-	}
-
-/**
- * test that verbose and quiet output levels work
- *
- * @return void
- */
-	public function testVerboseOutput() {
-		$this->Shell->stdout->expects($this->at(0))->method('write')
-			->with('Verbose', 1);
-		$this->Shell->stdout->expects($this->at(1))->method('write')
-			->with('Normal', 1);
-		$this->Shell->stdout->expects($this->at(2))->method('write')
-			->with('Quiet', 1);
-
-		$this->Shell->params['verbose'] = true;
-		$this->Shell->params['quiet'] = false;
-
-		$this->Shell->out('Verbose', 1, Shell::VERBOSE);
-		$this->Shell->out('Normal', 1, Shell::NORMAL);
-		$this->Shell->out('Quiet', 1, Shell::QUIET);
-	}
-
-/**
- * test that verbose and quiet output levels work
- *
- * @return void
- */
-	public function testQuietOutput() {
-		$this->Shell->stdout->expects($this->once())->method('write')
-			->with('Quiet', 1);
-
-		$this->Shell->params['verbose'] = false;
-		$this->Shell->params['quiet'] = true;
-
-		$this->Shell->out('Verbose', 1, Shell::VERBOSE);
-		$this->Shell->out('Normal', 1, Shell::NORMAL);
-		$this->Shell->out('Quiet', 1, Shell::QUIET);
 	}
 
 /**
@@ -341,29 +256,11 @@ class ShellTest extends TestCase {
  * @return void
  */
 	public function testErr() {
-		$this->Shell->stderr->expects($this->at(0))
-			->method('write')
-			->with("Just a test", 1);
-
-		$this->Shell->stderr->expects($this->at(1))
-			->method('write')
-			->with(array('Just', 'a', 'test'), 1);
-
-		$this->Shell->stderr->expects($this->at(2))
-			->method('write')
-			->with(array('Just', 'a', 'test'), 2);
-
-		$this->Shell->stderr->expects($this->at(3))
-			->method('write')
-			->with('', 1);
+		$this->io->expects($this->once())
+			->method('err')
+			->with('Just a test', 1);
 
 		$this->Shell->err('Just a test');
-
-		$this->Shell->err(array('Just', 'a', 'test'));
-
-		$this->Shell->err(array('Just', 'a', 'test'), 2);
-
-		$this->Shell->err();
 	}
 
 /**
@@ -372,15 +269,11 @@ class ShellTest extends TestCase {
  * @return void
  */
 	public function testNl() {
-		$newLine = "\n";
-		if (DS === '\\') {
-			$newLine = "\r\n";
-		}
-		$this->assertEquals($this->Shell->nl(), $newLine);
-		$this->assertEquals($this->Shell->nl(true), $newLine);
-		$this->assertEquals("", $this->Shell->nl(false));
-		$this->assertEquals($this->Shell->nl(2), $newLine . $newLine);
-		$this->assertEquals($this->Shell->nl(1), $newLine);
+		$this->io->expects($this->once())
+			->method('nl')
+			->with(2);
+
+		$this->Shell->nl(2);
 	}
 
 /**
@@ -389,23 +282,9 @@ class ShellTest extends TestCase {
  * @return void
  */
 	public function testHr() {
-		$bar = '---------------------------------------------------------------';
-
-		$this->Shell->stdout->expects($this->at(0))->method('write')->with('', 0);
-		$this->Shell->stdout->expects($this->at(1))->method('write')->with($bar, 1);
-		$this->Shell->stdout->expects($this->at(2))->method('write')->with('', 0);
-
-		$this->Shell->stdout->expects($this->at(3))->method('write')->with("", true);
-		$this->Shell->stdout->expects($this->at(4))->method('write')->with($bar, 1);
-		$this->Shell->stdout->expects($this->at(5))->method('write')->with("", true);
-
-		$this->Shell->stdout->expects($this->at(6))->method('write')->with("", 2);
-		$this->Shell->stdout->expects($this->at(7))->method('write')->with($bar, 1);
-		$this->Shell->stdout->expects($this->at(8))->method('write')->with("", 2);
-
-		$this->Shell->hr();
-
-		$this->Shell->hr(true);
+		$this->io->expects($this->once())
+			->method('hr')
+			->with(2);
 
 		$this->Shell->hr(2);
 	}
@@ -416,22 +295,13 @@ class ShellTest extends TestCase {
  * @return void
  */
 	public function testError() {
-		$this->Shell->stderr->expects($this->at(0))
-			->method('write')
-			->with("<error>Error:</error> Foo Not Found", 1);
-
-		$this->Shell->stderr->expects($this->at(1))
-			->method('write')
-			->with("<error>Error:</error> Foo Not Found", 1);
-
-		$this->Shell->stderr->expects($this->at(2))
-			->method('write')
-			->with("Searched all...", 1);
+		$this->io->expects($this->at(0))
+			->method('err')
+			->with('<error>Error:</error> Foo Not Found');
 
-		$this->Shell->error('Foo Not Found');
-		$this->assertSame($this->Shell->stopped, 1);
-
-		$this->Shell->stopped = null;
+		$this->io->expects($this->at(1))
+			->method('err')
+			->with("Searched all...");
 
 		$this->Shell->error('Foo Not Found', 'Searched all...');
 		$this->assertSame($this->Shell->stopped, 1);
@@ -555,8 +425,8 @@ class ShellTest extends TestCase {
 
 		new Folder($path, true);
 
-		$this->Shell->stdin->expects($this->once())
-			->method('read')
+		$this->io->expects($this->once())
+			->method('askChoice')
 			->will($this->returnValue('n'));
 
 		touch($file);
@@ -581,8 +451,8 @@ class ShellTest extends TestCase {
 
 		new Folder($path, true);
 
-		$this->Shell->stdin->expects($this->once())
-			->method('read')
+		$this->io->expects($this->once())
+			->method('askChoice')
 			->will($this->returnValue('y'));
 
 		touch($file);
@@ -802,62 +672,23 @@ TEXT;
 	}
 
 /**
- * Test file and console and logging
- *
- * @return void
- */
-	public function testFileAndConsoleLogging() {
-		// file logging
-		$this->Shell->log_something();
-		$this->assertTrue(file_exists(LOGS . 'error.log'));
-
-		unlink(LOGS . 'error.log');
-		$this->assertFalse(file_exists(LOGS . 'error.log'));
-
-		$mock = $this->getMock(
-			'Cake\Log\Engine\ConsoleLog',
-			['write'],
-			[['types' => 'error']]
-		);
-		Log::config('console', $mock);
-		$mock->expects($this->once())
-			->method('write')
-			->with('error', $this->Shell->testMessage);
-		$this->Shell->log_something();
-		$this->assertTrue(file_exists(LOGS . 'error.log'));
-		$contents = file_get_contents(LOGS . 'error.log');
-		$this->assertContains($this->Shell->testMessage, $contents);
-
-		Log::drop('console');
-	}
-
-/**
- * Tests that _useLogger works properly
- *
- * @return void
- */
-	public function testProtectedUseLogger() {
-		Log::drop('stdout');
-		Log::drop('stderr');
-		$this->Shell->useLogger(true);
-		$this->assertNotEmpty(Log::engine('stdout'));
-		$this->assertNotEmpty(Log::engine('stderr'));
-		$this->Shell->useLogger(false);
-		$this->assertFalse(Log::engine('stdout'));
-		$this->assertFalse(Log::engine('stderr'));
-	}
-
-/**
  * Test file and console and logging quiet output
  *
  * @return void
  */
 	public function testQuietLog() {
-		$output = $this->getMock('Cake\Console\ConsoleOutput', array(), array(), '', false);
-		$error = $this->getMock('Cake\Console\ConsoleOutput', array(), array(), '', false);
-		$in = $this->getMock('Cake\Console\ConsoleInput', array(), array(), '', false);
-		$this->Shell = $this->getMock(__NAMESPACE__ . '\ShellTestShell', array('_useLogger'), array($output, $error, $in));
-		$this->Shell->expects($this->once())->method('_useLogger')->with(false);
+		$io = $this->getMock('Cake\Console\ConsoleIo', [], [], '', false);
+		$io->expects($this->once())
+			->method('level')
+			->with(Shell::QUIET);
+		$io->expects($this->at(0))
+			->method('setLoggers')
+			->with(true);
+		$io->expects($this->at(2))
+			->method('setLoggers')
+			->with(false);
+
+		$this->Shell = $this->getMock(__NAMESPACE__ . '\ShellTestShell', array('_useLogger'), array($io));
 		$this->Shell->runCommand('foo', array('--quiet'));
 	}