Skip to content

Commit 7aa6c66

Browse files
committed
Update startup and options to use Cake 3's OptionParser correctly.
The new OptionParser doesn't incorrectly grab arguments after boolean options anymore, but it also doesn't easily permit a variable number of arguments and still allow you to generate help output for them. Code and tests updated to match the new reality of field use.
1 parent 3208cdf commit 7aa6c66

2 files changed

Lines changed: 133 additions & 124 deletions

File tree

src/Shell/ConfigReadShell.php

Lines changed: 40 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ class ConfigReadShell extends Shell {
4141
public $formatSerialize = false;
4242

4343
/**
44-
* Overrides the defaul welcome function in order to supporess the
45-
* normal "Welcome to CakePHP" Cake banner.
44+
* Overrides the default welcome function in order to suppress the
45+
* normal "Welcome to CakePHP" banner.
4646
*
4747
* @return void
4848
*/
@@ -51,34 +51,23 @@ public function _welcome() {
5151
}
5252

5353
/**
54-
* Sets internal state.
54+
* Sets internal state, validate options/arguments.
5555
*
5656
* @return void
5757
*/
5858
public function startup() {
5959
parent::startup();
6060

61-
$this->_io->outputAs(ConsoleOutput::RAW);
62-
63-
if (isset($this->params['h'])) {
64-
return $this->help();
65-
}
61+
$this->formatBash = ($this->params['bash'] || count($this->args) > 1);
62+
$this->formatSerialize = $this->params['serialize'];
6663

67-
if (isset($this->params['b'])) {
68-
$this->formatBash = true;
69-
// Make up for Cake snagging the next arg as the value for `-b`.
70-
array_unshift($this->args, $this->params['b']);
64+
if (empty($this->args)) {
65+
$this->_displayHelp('');
66+
$this->error(__('No Configure keys provided.'));
7167
}
7268

73-
if (count($this->args) > 1) {
74-
$this->formatBash = true;
75-
}
76-
77-
if (isset($this->params['s'])) {
78-
$this->formatSerialize = true;
79-
// Make up for Cake snagging the next arg as the value for `-s`.
80-
array_unshift($this->args, $this->params['s']);
81-
}
69+
// All other output should not be processed by the Shell.
70+
$this->_io->outputAs(ConsoleOutput::RAW);
8271
}
8372

8473
/**
@@ -96,25 +85,6 @@ public function main() {
9685
}
9786
}
9887

99-
/**
100-
* Iterate over provided args, printing them to the console as we go.
101-
*
102-
* Used to handle single scalar values and all --bash formatted output.
103-
*
104-
* @return void
105-
*/
106-
protected function simpleFetchAndPrint() {
107-
foreach ($this->args as $key) {
108-
$val = $this->fetchVal($key);
109-
110-
// One-way switch. Will enable bash variable formatting if the
111-
// value is an array, and it will "stick on" after that.
112-
$this->formatBash = ($this->formatBash || is_array($val));
113-
114-
$this->iterateOnKey($key, $val);
115-
}
116-
}
117-
11888
/**
11989
* Iterate over provided args, collecting them for serialization.
12090
*
@@ -138,6 +108,25 @@ protected function serializedFetchAndPrint() {
138108
$this->out(serialize($unserialized), 0, Shell::QUIET);
139109
}
140110

111+
/**
112+
* Iterate over provided args, printing them to the console as we go.
113+
*
114+
* Used to handle single scalar values and all --bash formatted output.
115+
*
116+
* @return void
117+
*/
118+
protected function simpleFetchAndPrint() {
119+
foreach ($this->args as $key) {
120+
$val = $this->fetchVal($key);
121+
122+
// One-way switch. Will enable bash variable formatting if the
123+
// value is an array, and it will "stick on" after that.
124+
$this->formatBash = ($this->formatBash || is_array($val));
125+
126+
$this->iterateOnKey($key, $val);
127+
}
128+
}
129+
141130
/**
142131
* Value fetcher.
143132
*
@@ -218,29 +207,24 @@ protected function printVal($key, $val) {
218207
public function getOptionParser() {
219208
$parser = parent::getOptionParser();
220209
$parser
221-
->addArgument('key', array(
222-
'help' => 'The Key.name to fetch from Configure::read().',
223-
'required' => true,
224-
))
225-
->addArgument('key2', array(
226-
'help' => 'Multiple keys may be specified, separated by spaces.',
227-
'required' => false,
228-
))
229-
->addOption('bash', array(
210+
->addOption('bash', [
230211
'short' => 'b',
231212
'boolean' => true,
232213
'default' => false,
233214
'help' => __('Always use bash variable deinfition formatting. When enabled, output will be formatted as `KEY_NAME=\'value\'`. This option is auto-enabled if multiple keys are provided on the command line, or if the value for the requested key is itself an array. When multiple values are returned, each will be output on its own line.')
234-
))
235-
->addOption('serialize', array(
215+
])
216+
->addOption('serialize', [
236217
'short' => 's',
237218
'boolean' => true,
238219
'default' => false,
239-
'help' => __('Encode all output using PHP\'s `serialize()` method. Makes the Shell\'s output suitable for consumption by other PHP console scripts. Always overrides the --bash option. A single requested key will be serialized directly. Multiple requested keys will be combined into an associative array and then serialized.')
240-
))
241-
->description(__('Provides CLI access to variables defined in the Configure class of the host
242-
CakePHP application. Will output the value of any keys passed as arguments.
243-
Equivelant to `Configure::read(\'Key.Name\')`.'));
220+
'help' => __('Encode all output using PHP\'s `serialize()` method. Makes the Shell\'s output suitable for consumption by other PHP console scripts. Always overrides the --bash option. A single requested key will be serialized directly. Multiple requested keys will be combined into an associative array with the provided arguments as key names and then serialized.')
221+
])
222+
->description(
223+
__('Provides CLI access to variables defined in the Configure class of the host CakePHP application. Will output the value of any keys passed as arguments. Equivelant to `Configure::read(\'Key.Name\')`. Unrecognized keys will produce empty string or `null` output.')
224+
)
225+
->epilog(
226+
__('Provide the Key.name(s) to fetch from Configure::read() as arguments. Multiple keys may be specified, separated by spaces.')
227+
);
244228
return $parser;
245229
}
246230
}

tests/TestCase/Shell/ConfigReadShellTest.php

Lines changed: 93 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
namespace ConfigRead\Test\TestCase\Shell;
66

7+
use Cake\Cache\Cache;
78
use Cake\Console\ConsoleOptionParser;
89
use Cake\Console\Shell;
910
use Cake\Core\Configure;
@@ -156,7 +157,7 @@ protected function getSUTClassName() {
156157
*/
157158
protected function initSUT($additionalMocks = []) {
158159
$defaultMocks = [
159-
'help', //'in', 'out', 'hr', 'error', 'err', '_stop', 'initialize', '_run', 'clear',
160+
'_displayHelp', 'error',
160161
];
161162

162163
$this->io = $this->getMock('\Cake\Console\ConsoleIo', [], [], '', false);
@@ -174,15 +175,26 @@ protected function initSUT($additionalMocks = []) {
174175
[$this->io]
175176
);
176177

178+
$shell->expects($this->any())
179+
->method('error')
180+
->with($this->anything())
181+
->will($this->returnCallback([$this, 'outputCollector']));
177182
$shell->OptionParser = $this->getMock('\Cake\Console\ConsoleOptionParser', [], [null, false]);
183+
$shell->params = [
184+
'help' => false,
185+
'verbose' => false,
186+
'quiet' => false,
187+
'bash' => false,
188+
'serialize' => false,
189+
];
178190

179191
//@TODO: Update this Cake2-centric code to load models in a Cake 3 Shell.
180192
// Load and attach all fixtures defined in this test case.
181-
// foreach ($this->fixtures as $fixture) {
182-
// $modelName = str_replace('App.', '', implode('.', array_map('Inflector::classify', explode('.', $fixture))));
183-
// $propName = str_replace('.', '', $modelName);
184-
// $shell->{$propName} = ClassRegistry::init($modelName);
185-
// }
193+
//foreach ($this->fixtures as $fixture) {
194+
// $modelName = str_replace('App.', '', implode('.', array_map('Inflector::classify', explode('.', $fixture))));
195+
// $propName = str_replace('.', '', $modelName);
196+
// $shell->{$propName} = ClassRegistry::init($modelName);
197+
//}
186198
return $shell;
187199
}
188200

@@ -192,73 +204,90 @@ protected function initSUT($additionalMocks = []) {
192204
* @return void
193205
*/
194206
public function testStartupHelp() {
195-
$this->Shell->params = ['h' => true];
196207
$this->Shell->expects($this->once())
197-
->method('help')
198-
->will($this->returnValue('canary'));
199-
$this->assertEquals(
200-
'canary',
201-
$this->Shell->startup(),
202-
'Shell should return help() when -h is passed.'
203-
);
204-
}
205-
206-
/**
207-
* Confirm that startup() engages bash output mode when -b flag is present.
208-
*
209-
* @return void
210-
*/
211-
public function testStartupBashModeFlag() {
212-
$this->Shell->params = ['b' => 'canary'];
208+
->method('_displayHelp');
213209

210+
Cache::config('_cake_core_', [
211+
'className' => 'File',
212+
]);
214213
$this->Shell->startup();
215-
216-
$this->assertEquals(
217-
['canary'],
218-
$this->Shell->args,
219-
'Shell args should contain the value mistakenly captured by the -b option.'
220-
);
221-
$this->assertTrue(
222-
$this->Shell->formatBash,
223-
'Bash output formatting should be enabled by the presence of the -b option.'
214+
215+
$this->assertContains(
216+
'No Configure keys provided.',
217+
$this->output,
218+
'Shell should output help() when no args are provided.'
224219
);
225220
}
226221

227222
/**
228-
* Confirm that startup() engages bash output mode when multiple args are present.
223+
* Confirm that startup() engages bash output mode when -b flag is present.
229224
*
230225
* @return void
226+
* @dataProvider provideStartupArgs
231227
*/
232-
public function testStartupBashModeMultiArgs() {
233-
$this->Shell->args = ['debug', 'Datasources.default.host'];
228+
public function testStartupFlags($params, $args, $expected) {
229+
$this->Shell->params = array_merge($this->Shell->params, $params);
230+
$this->Shell->args = $args;
234231

235232
$this->Shell->startup();
236233

237-
$this->assertTrue(
238-
$this->Shell->formatBash,
239-
'Bash output formatting should be enabled by the presence of multiple arguments.'
240-
);
234+
foreach ($expected as $prop => $check) {
235+
$this->assertEquals(
236+
$check['val'],
237+
$this->Shell->{$prop},
238+
$check['msg']
239+
);
240+
}
241241
}
242242

243-
/**
244-
* Confirm that startup() engages serialized output mode when -s flag is present.
245-
*
246-
* @return void
247-
*/
248-
public function testStartupSerializeModeFlag() {
249-
$this->Shell->params = ['s' => 'canary'];
250-
251-
$this->Shell->startup();
252-
253-
$this->assertEquals(
254-
['canary'],
255-
$this->Shell->args,
256-
'Shell args should contain the value mistakenly captured by the -s option.'
257-
);
258-
$this->assertTrue(
259-
$this->Shell->formatSerialize,
260-
'Serialized output formatting should be enabled by the presence of the -s option.'
261-
);
243+
public function provideStartupArgs() {
244+
return [
245+
[
246+
['bash' => true], // params overrides
247+
['dummy'], // args
248+
[
249+
'formatBash' => [
250+
'val' => true,
251+
'msg' => 'Bash output formatting should be enabled by the presence of the -b option.',
252+
],
253+
'formatSerialize' => [
254+
'val' => false,
255+
'msg' => 'Serialized output should remain off unless explicitly enabled.',
256+
],
257+
],
258+
],
259+
260+
[
261+
[],
262+
['dummy', 'dummy2'],
263+
[
264+
'formatBash' => [
265+
'val' => true,
266+
'msg' => 'Bash output formatting should be enabled by the presence of multiple arguments.',
267+
],
268+
'formatSerialize' => [
269+
'val' => false,
270+
'msg' => 'Serialized output should remain off unless explicitly enabled.',
271+
],
272+
],
273+
],
274+
275+
[
276+
['serialize' => true],
277+
['dummy', 'dummy2'],
278+
[
279+
'formatBash' => [
280+
'val' => true,
281+
'msg' => 'Bash output formatting should be enabled by the presence of multiple arguments, regardless of serialization option.',
282+
],
283+
'formatSerialize' => [
284+
'val' => true,
285+
'msg' => 'Serialized output formatting should be enabled by the presence of the -s option.',
286+
],
287+
],
288+
],
289+
290+
];
262291
}
263292

264293
/**
@@ -342,14 +371,13 @@ public function testMainSimpleIntegration() {
342371
/**
343372
* test main(), including associated protected methods, using simple output.
344373
*
345-
* @param array $params Array of params to seed the Shell->params with.
346374
* @param array $args Array of arguments to seed the Shell->args with.
347375
* @param array $expected Array of generated output lines to compare to ::$output.
348376
* @param string $msg Optional PHPUnit assertion failure message.
349377
* @return void
350378
* @dataProvider provideSerializedArgs
351379
*/
352-
public function testMainSerializedIntegration($params, $args, $expected, $msg = '') {
380+
public function testMainSerializedIntegration($args, $expected, $msg = '') {
353381
$configure = [
354382
'key' => 'val',
355383
'debug' => true,
@@ -362,7 +390,7 @@ public function testMainSerializedIntegration($params, $args, $expected, $msg =
362390
];
363391

364392
Configure::write($configure);
365-
$this->Shell->params = $params;
393+
$this->Shell->params['serialize'] = true;
366394
$this->Shell->args = $args;
367395

368396
$this->Shell->startup();
@@ -382,7 +410,7 @@ public function testMainSerializedIntegration($params, $args, $expected, $msg =
382410
/**
383411
* Provides input arguments to testMainSerializedIntegration().
384412
*
385-
* All keys named in the [params] and [args] elements must exist in
413+
* All keys named in the [args] elements must exist in
386414
* $configure as defined in testMainSerializedIntegration() above.
387415
*
388416
* @return void
@@ -391,22 +419,19 @@ public function testMainSerializedIntegration($params, $args, $expected, $msg =
391419
public function provideSerializedArgs() {
392420
return [
393421
[
394-
['s' => ''], // Params to load in the Shell.
395-
[], // Args to load in the Shell.
422+
[''], // Args to load in the Shell.
396423
['N;'], // Expected lines of output.
397424
'Empty input should produce a serialized `null` string.', // PHPUnit assertion failure message.
398425
],
399426

400427
[
401-
['s' => 'key'],
402-
[],
428+
['key'],
403429
['s:3:"val";'],
404430
'Single scalar value should be serialized directly.',
405431
],
406432

407433
[
408-
['s' => 'key'],
409-
['ary.stdClass'],
434+
['key', 'ary.stdClass'],
410435
['a:2:{s:3:"key";s:3:"val";s:12:"ary.stdClass";O:8:"stdClass":0:{}}'],
411436
'Multiple requested keys should be combined into a (serialized) associative array.',
412437
],

0 commit comments

Comments
 (0)