Test the command line parsing

This commit is contained in:
Master Yoda 2018-05-03 10:27:12 -07:00
parent 03407e5488
commit 0b9f26761f
No known key found for this signature in database
GPG Key ID: CED549230775AD5B
3 changed files with 138 additions and 47 deletions

View File

@ -35,7 +35,6 @@
* @since Version 3.0.0
* @filesource
*/
use CodeIgniter\CLI\Exceptions\CLIException;
/**
@ -46,10 +45,12 @@ use CodeIgniter\CLI\Exceptions\CLIException;
*
* Portions of this code were initially from the FuelPHP Framework,
* version 1.7.x, and used here under the MIT license they were
* originally made available under.
*
* http://fuelphp.com
* originally made available under. Reference: http://fuelphp.com
*
* Some of the code in this class is Windows-specific, and not
* possible to test using travis-ci. It has been phpunit-annotated
* to prevent messing up code coverage.
*
* @package CodeIgniter\HTTP
*/
class CLI
@ -120,6 +121,7 @@ class CLI
* @var array
*/
protected static $segments = [];
/**
* @var array
*/
@ -137,6 +139,10 @@ class CLI
// http://www.php.net/manual/en/readline.installation.php
static::$readline_support = extension_loaded('readline');
// clear segments & options to keep testing clean
static::$segments = [];
static::$options = [];
static::parseCommandLine();
static::$initialized = true;
@ -151,8 +157,8 @@ class CLI
* php index.php user -v --v -name=John --name=John
*
* @param string $prefix
*
* @return string
*/
public static function input(string $prefix = null): string
{
@ -190,6 +196,7 @@ class CLI
* @param string $validation Validation rules
*
* @return string The user input
*/
public static function prompt($field, $options = null, $validation = null): string
{
@ -198,7 +205,7 @@ class CLI
if (is_string($options))
{
$extra_output = ' [' . static::color($options, 'white') .']';
$extra_output = ' [' . static::color($options, 'white') . ']';
$default = $options;
}
@ -215,8 +222,8 @@ class CLI
}
else
{
$extra_output = ' [' .$extra_output_default.', '. implode(', ', $opts) . ']';
$validation .= '|in_list['. implode(',', $options) .']';
$extra_output = ' [' . $extra_output_default . ', ' . implode(', ', $opts) . ']';
$validation .= '|in_list[' . implode(',', $options) . ']';
$validation = trim($validation, '|');
}
@ -226,11 +233,11 @@ class CLI
fwrite(STDOUT, $field . $extra_output . ': ');
// Read the input from keyboard.
$input = trim(static::input()) ? : $default;
$input = trim(static::input()) ?: $default;
if (isset($validation))
{
while (! static::validate($field, $input, $validation))
while ( ! static::validate($field, $input, $validation))
{
$input = static::prompt($field, $options, $validation);
}
@ -387,6 +394,7 @@ class CLI
* Clears the screen of output
*
* @return void
* @codeCoverageIgnore
*/
public static function clearScreen()
{
@ -416,7 +424,9 @@ class CLI
{
if (static::isWindows() && ! isset($_SERVER['ANSICON']))
{
// @codeCoverageIgnoreStart
return $text;
// @codeCoverageIgnoreEnd
}
if ( ! array_key_exists($foreground, static::$foreground_colors))
@ -461,7 +471,9 @@ class CLI
{
if (static::isWindows() || (int) shell_exec('tput cols') == 0)
{
// @codeCoverageIgnoreStart
return $default;
// @codeCoverageIgnoreEnd
}
return (int) shell_exec('tput cols');
@ -482,7 +494,9 @@ class CLI
{
if (static::isWindows())
{
// @codeCoverageIgnoreStart
return $default;
// @codeCoverageIgnoreEnd
}
return (int) shell_exec('tput lines');
@ -606,6 +620,7 @@ class CLI
{
$optionsFound = false;
// start picking segments off from #1, ignoring the invoking program
for ($i = 1; $i < $_SERVER['argc']; $i ++ )
{
// If there's no '-' at the beginning of the argument
@ -621,15 +636,10 @@ class CLI
// value belonging to this option.
$optionsFound = true;
if (mb_substr($_SERVER['argv'][$i], 0, 1) != '-')
{
continue;
}
$arg = str_replace('-', '', $_SERVER['argv'][$i]);
$value = null;
// if the next item doesn't have a dash it's a value.
// if there is a following segment, and it doesn't start with a dash, it's a value.
if (isset($_SERVER['argv'][$i + 1]) && mb_substr($_SERVER['argv'][$i + 1], 0, 1) != '-')
{
$value = $_SERVER['argv'][$i + 1];
@ -685,6 +695,18 @@ class CLI
//--------------------------------------------------------------------
/**
* Returns the raw array of segments found.
*
* @return array
*/
public static function getSegments()
{
return static::$segments;
}
//--------------------------------------------------------------------
/**
* Gets a single command-line option. Returns TRUE if the option
* exists, but doesn't have a value, and is simply acting as a flag.
@ -722,7 +744,7 @@ class CLI
//--------------------------------------------------------------------
/**
* Returns the options a string, suitable for passing along on
* Returns the options as a string, suitable for passing along on
* the CLI to other commands.
*
* @return string
@ -767,7 +789,7 @@ class CLI
$table_rows = [];
// We need only indexes and not keys
if (! empty($thead))
if ( ! empty($thead))
{
$table_rows[] = array_values($thead);
}
@ -789,7 +811,7 @@ class CLI
$max_cols_lengths = [];
// Read row by row and define the longest columns
for ($row = 0; $row < $total_rows; $row++)
for ($row = 0; $row < $total_rows; $row ++)
{
$column = 0; // Current column index
foreach ($table_rows[$row] as $col)
@ -800,19 +822,19 @@ class CLI
// If the current column does not have a value among the larger ones
// or the value of this is greater than the existing one
// then, now, this assumes the maximum length
if (! isset($max_cols_lengths[$column]) || $all_cols_lengths[$row][$column] > $max_cols_lengths[$column])
if ( ! isset($max_cols_lengths[$column]) || $all_cols_lengths[$row][$column] > $max_cols_lengths[$column])
{
$max_cols_lengths[$column] = $all_cols_lengths[$row][$column];
}
// We can go check the size of the next column...
$column++;
$column ++;
}
}
// Read row by row and add spaces at the end of the columns
// to match the exact column length
for ($row = 0; $row < $total_rows; $row++)
for ($row = 0; $row < $total_rows; $row ++)
{
$column = 0;
foreach ($table_rows[$row] as $col)
@ -822,14 +844,14 @@ class CLI
{
$table_rows[$row][$column] = $table_rows[$row][$column] . str_repeat(' ', $diff);
}
$column++;
$column ++;
}
}
$table = '';
// Joins columns and append the well formatted rows to the table
for ($row = 0; $row < $total_rows; $row++)
for ($row = 0; $row < $total_rows; $row ++)
{
// Set the table border-top
if ($row === 0)

View File

@ -2,6 +2,7 @@
class CLITest extends \CIUnitTestCase
{
private $stream_filter;
public function setUp()
@ -189,9 +190,58 @@ EOT;
public function testWrap()
{
$this->assertEquals('', CLI::wrap(''));
$this->assertEquals('1234'. PHP_EOL .' 5678'. PHP_EOL .' 90'. PHP_EOL .' abc'. PHP_EOL .' de'. PHP_EOL .' fghij'. PHP_EOL .' 0987654321', CLI::wrap('1234 5678 90'. PHP_EOL .'abc de fghij'. PHP_EOL .'0987654321', 5, 1));
$this->assertEquals('1234 5678 90'. PHP_EOL .' abc de fghij'. PHP_EOL .' 0987654321', CLI::wrap('1234 5678 90'. PHP_EOL .'abc de fghij'. PHP_EOL .'0987654321', 999, 2));
$this->assertEquals('1234 5678 90'. PHP_EOL .'abc de fghij'. PHP_EOL .'0987654321', CLI::wrap('1234 5678 90'. PHP_EOL .'abc de fghij'. PHP_EOL .'0987654321'));
$this->assertEquals('1234' . PHP_EOL . ' 5678' . PHP_EOL . ' 90' . PHP_EOL . ' abc' . PHP_EOL . ' de' . PHP_EOL . ' fghij' . PHP_EOL . ' 0987654321', CLI::wrap('1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321', 5, 1));
$this->assertEquals('1234 5678 90' . PHP_EOL . ' abc de fghij' . PHP_EOL . ' 0987654321', CLI::wrap('1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321', 999, 2));
$this->assertEquals('1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321', CLI::wrap('1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321'));
}
public function testParseCommand()
{
$_SERVER['argv'] = ['ignored', 'b', 'c'];
$_SERVER['argc'] = 3;
CLI::init();
$this->assertEquals(null, CLI::getSegment(3));
$this->assertEquals('b', CLI::getSegment(1));
$this->assertEquals('c', CLI::getSegment(2));
$this->assertEquals('b/c', CLI::getURI());
$this->assertEquals([],CLI::getOptions());
$this->assertEmpty(CLI::getOptionString());
$this->assertEquals(['b', 'c'], CLI::getSegments());
}
public function testParseCommandMixed()
{
$_SERVER['argv'] = ['ignored', 'b', 'c', 'd', '-parm', 'pvalue', 'd2'];
$_SERVER['argc'] = 7;
CLI::init();
$this->assertEquals(null, CLI::getSegment(7));
$this->assertEquals('b', CLI::getSegment(1));
$this->assertEquals('c', CLI::getSegment(2));
$this->assertEquals('d', CLI::getSegment(3));
$this->assertEquals(['b', 'c', 'd', 'd2'], CLI::getSegments());
}
public function testParseCommandOption()
{
$_SERVER['argv'] = ['ignored', 'b', 'c', '-parm', 'pvalue', 'd'];
$_SERVER['argc'] = 6;
CLI::init();
$this->assertEquals(['parm' => 'pvalue'], CLI::getOptions());
$this->assertEquals('pvalue', CLI::getOption('parm'));
$this->assertEquals('-parm pvalue ', CLI::getOptionString());
$this->assertNull(CLI::getOption('bogus'));
$this->assertEquals(['b', 'c', 'd'], CLI::getSegments());
}
public function testParseCommandMultipleOptions()
{
$_SERVER['argv'] = ['ignored', 'b', 'c', '-parm', 'pvalue', 'd', '-p2', '-p3', 'value 3'];
$_SERVER['argc'] = 9;
CLI::init();
$this->assertEquals(['parm' => 'pvalue', 'p2' => null, 'p3' => 'value 3'], CLI::getOptions());
$this->assertEquals('pvalue', CLI::getOption('parm'));
$this->assertEquals('-parm pvalue -p2 -p3 "value 3" ', CLI::getOptionString());
$this->assertEquals(['b', 'c', 'd'], CLI::getSegments());
}
/**
@ -209,8 +259,8 @@ EOT;
public function tableProvider()
{
$head = ['ID', 'Title'];
$one_row = [['id' => 1, 'foo' => 'bar']];
$head = ['ID', 'Title'];
$one_row = [['id' => 1, 'foo' => 'bar']];
$many_rows = [
['id' => 1, 'foo' => 'bar'],
['id' => 2, 'foo' => 'bar * 2'],
@ -219,42 +269,45 @@ EOT;
return [
[$one_row, [], "+---+-----+\n" .
"| 1 | bar |\n" .
"+---+-----+\n"],
"| 1 | bar |\n" .
"+---+-----+\n"],
[$one_row, $head, "+----+-------+\n" .
"| ID | Title |\n" .
"+----+-------+\n" .
"| 1 | bar |\n" .
"+----+-------+\n"],
"| ID | Title |\n" .
"+----+-------+\n" .
"| 1 | bar |\n" .
"+----+-------+\n"],
[$many_rows, [], "+---+-----------------+\n" .
"| 1 | bar |\n" .
"| 2 | bar * 2 |\n" .
"| 3 | bar + bar + bar |\n" .
"+---+-----------------+\n"],
"| 1 | bar |\n" .
"| 2 | bar * 2 |\n" .
"| 3 | bar + bar + bar |\n" .
"+---+-----------------+\n"],
[$many_rows, $head, "+----+-----------------+\n" .
"| ID | Title |\n" .
"+----+-----------------+\n" .
"| 1 | bar |\n" .
"| 2 | bar * 2 |\n" .
"| 3 | bar + bar + bar |\n" .
"+----+-----------------+\n"],
"| ID | Title |\n" .
"+----+-----------------+\n" .
"| 1 | bar |\n" .
"| 2 | bar * 2 |\n" .
"| 3 | bar + bar + bar |\n" .
"+----+-----------------+\n"],
];
}
}
}
class CLITestStreamFilter extends \php_user_filter
{
public static $buffer = '';
public function filter($in, $out, &$consumed, $closing)
{
while ($bucket = stream_bucket_make_writeable($in)) {
while ($bucket = stream_bucket_make_writeable($in))
{
self::$buffer .= $bucket->data;
$consumed += $bucket->datalen;
}
return PSFS_PASS_ON;
}
}
stream_filter_register('CLITestStreamFilter', 'CodeIgniter\CLI\CLITestStreamFilter');

View File

@ -224,3 +224,19 @@ pass ``false`` as the first parameter and the progress bar will be removed.
| 7 | A great item title | 2017-11-16 10:35:02 | 1 |
| 8 | Another great item title | 2017-11-16 13:46:54 | 0 |
+----+--------------------------+---------------------+--------+
**wait()**
Waits a certain number of seconds, optionally showing a wait message and
waiting for a key press.
::
// wait for specified interval, with countdown displayed
CLI::wait($seconds, true);
// show continuation message and wait for input
CLI::wait(0, false);
// wait for specified interval
CLI::wait($seconds, false);