<commit_before><?php namespace CodeIgniter\CLI;

class CLITest extends \CIUnitTestCase
{

	private $stream_filter;

	public function setUp()
	{
		CLITestStreamFilter::$buffer = '';
		$this->stream_filter = stream_filter_append(STDOUT, 'CLITestStreamFilter');
	}

	public function tearDown()
	{
		stream_filter_remove($this->stream_filter);
	}

	public function testNew()
	{
		$actual = new CLI();
		$this->assertInstanceOf(CLI::class, $actual);
	}

	public function testBeep()
	{
		$this->expectOutputString("\x07");
		CLI::beep();
	}

	public function testBeep4()
	{
		$this->expectOutputString("\x07\x07\x07\x07");
		CLI::beep(4);
	}

	public function testWait()
	{
		$time = time();
		CLI::wait(1, true);
		$this->assertEquals(1, time() - $time);

		$time = time();
		CLI::wait(1);
		$this->assertEquals(1, time() - $time);
	}

	public function testIsWindows()
	{
		$this->assertEquals(('\\' === DIRECTORY_SEPARATOR), CLI::isWindows());
		$this->assertEquals(defined('PHP_WINDOWS_VERSION_MAJOR'), CLI::isWindows());
	}

	public function testNewLine()
	{
		$this->expectOutputString('');
		CLI::newLine();
	}

	/**
	 * @expectedException        RuntimeException
	 * @expectedExceptionMessage Invalid foreground color: Foreground
	 */
	public function testColorExceptionForeground()
	{
		CLI::color('test', 'Foreground');
	}

	/**
	 * @expectedException        RuntimeException
	 * @expectedExceptionMessage Invalid background color: Background
	 */
	public function testColorExceptionBackground()
	{
		CLI::color('test', 'white', 'Background');
	}

	public function testColor()
	{
		$this->assertEquals("\033[1;37m\033[42m\033[4mtest\033[0m", CLI::color('test', 'white', 'green', 'underline'));
	}

	public function testWrite()
	{
		CLI::write('test');
		$expected = <<<EOT
test

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testWriteForeground()
	{
		CLI::write('test', 'red');
		$expected = <<<EOT
\033[0;31mtest\033[0m

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testWriteBackground()
	{
		CLI::write('test', 'red', 'green');
		$expected = <<<EOT
\033[0;31m\033[42mtest\033[0m

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testError()
	{
		$this->stream_filter = stream_filter_append(STDERR, 'CLITestStreamFilter');
		CLI::error('test');
		// red expected cuz stderr
		$expected = <<<EOT
\033[1;31mtest\033[0m

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testErrorForeground()
	{
		$this->stream_filter = stream_filter_append(STDERR, 'CLITestStreamFilter');
		CLI::error('test', 'purple');
		$expected = <<<EOT
\033[0;35mtest\033[0m

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testErrorBackground()
	{
		$this->stream_filter = stream_filter_append(STDERR, 'CLITestStreamFilter');
		CLI::error('test', 'purple', 'green');
		$expected = <<<EOT
\033[0;35m\033[42mtest\033[0m

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testShowProgress()
	{
		CLI::write('first.');
		CLI::showProgress(1, 20);
		CLI::showProgress(10, 20);
		CLI::showProgress(20, 20);
		CLI::write('second.');
		CLI::showProgress(1, 20);
		CLI::showProgress(10, 20);
		CLI::showProgress(20, 20);
		CLI::write('third.');
		CLI::showProgress(1, 20);

		$expected = <<<EOT
first.
[\033[32m#.........\033[0m]   5% Complete
\033[1A[\033[32m#####.....\033[0m]  50% Complete
\033[1A[\033[32m##########\033[0m] 100% Complete
second.
[\033[32m#.........\033[0m]   5% Complete
\033[1A[\033[32m#####.....\033[0m]  50% Complete
\033[1A[\033[32m##########\033[0m] 100% Complete
third.
[\033[32m#.........\033[0m]   5% Complete

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testShowProgressWithoutBar()
	{
		CLI::write('first.');
		CLI::showProgress(false, 20);
		CLI::showProgress(false, 20);
		CLI::showProgress(false, 20);

		$expected = <<<EOT
first.
\007\007\007
EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	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'));
	}

	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());
	}

	public function testWindow()
	{
		$this->assertTrue(is_int(CLI::getHeight()));
		$this->assertTrue(is_int(CLI::getWidth()));
	}

	/**
	 * @dataProvider tableProvider
	 *
	 * @param  array $tbody
	 * @param  array $thead
	 * @param  array $expected
	 */
	public function testTable($tbody, $thead, $expected)
	{
		CLI::table($tbody, $thead);
		$this->assertEquals(CLITestStreamFilter::$buffer, $expected);
	}

	public function tableProvider()
	{
		$head = ['ID', 'Title'];
		$one_row = [['id' => 1, 'foo' => 'bar']];
		$many_rows = [
			['id' => 1, 'foo' => 'bar'],
			['id' => 2, 'foo' => 'bar * 2'],
			['id' => 3, 'foo' => 'bar + bar + bar'],
		];

		return [
			[$one_row, [], "+---+-----+\n" .
				"| 1 | bar |\n" .
				"+---+-----+\n"],
			[$one_row, $head, "+----+-------+\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"],
			[$many_rows, $head, "+----+-----------------+\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))
		{
			self::$buffer .= $bucket->data;
			$consumed += $bucket->datalen;
		}
		return PSFS_PASS_ON;
	}

}

stream_filter_register('CLITestStreamFilter', 'CodeIgniter\CLI\CLITestStreamFilter');<commit_msg>Test the URI-related CLI methods<commit_after><?php namespace CodeIgniter\CLI;

class CLITest extends \CIUnitTestCase
{

	private $stream_filter;

	public function setUp()
	{
		CLITestStreamFilter::$buffer = '';
		$this->stream_filter = stream_filter_append(STDOUT, 'CLITestStreamFilter');
	}

	public function tearDown()
	{
		stream_filter_remove($this->stream_filter);
	}

	public function testNew()
	{
		$actual = new CLI();
		$this->assertInstanceOf(CLI::class, $actual);
	}

	public function testBeep()
	{
		$this->expectOutputString("\x07");
		CLI::beep();
	}

	public function testBeep4()
	{
		$this->expectOutputString("\x07\x07\x07\x07");
		CLI::beep(4);
	}

	public function testWait()
	{
		$time = time();
		CLI::wait(1, true);
		$this->assertEquals(1, time() - $time);

		$time = time();
		CLI::wait(1);
		$this->assertEquals(1, time() - $time);

		// Leaving the code fragment below in, to remind myself (or others)
		// of what appears to be the most likely path to test this last
		// bit of wait() functionality.
		// The problem: if the block below is enabled, the phpunit tests
		// go catatonic when it is executed, presumably because of
		// the CLI::input() waiting for a key press
//		// test the press any key to continue...
//		CLITestKeyboardFilter::$spoofed = ' \n';
//		stream_filter_register('CLITestKeyboardFilter', 'CodeIgniter\CLI\CLITestKeyboardFilter');
//		$spoofed = stream_filter_prepend(STDIN, 'CLITestKeyboardFilter');
//		$time = time();
//		CLI::wait(0);
//		stream_filter_remove($spoofed);
//		$this->assertEquals(10, time() - $time);
	}

	public function testIsWindows()
	{
		$this->assertEquals(('\\' === DIRECTORY_SEPARATOR), CLI::isWindows());
		$this->assertEquals(defined('PHP_WINDOWS_VERSION_MAJOR'), CLI::isWindows());
	}

	public function testNewLine()
	{
		$this->expectOutputString('');
		CLI::newLine();
	}

	/**
	 * @expectedException        RuntimeException
	 * @expectedExceptionMessage Invalid foreground color: Foreground
	 */
	public function testColorExceptionForeground()
	{
		CLI::color('test', 'Foreground');
	}

	/**
	 * @expectedException        RuntimeException
	 * @expectedExceptionMessage Invalid background color: Background
	 */
	public function testColorExceptionBackground()
	{
		CLI::color('test', 'white', 'Background');
	}

	public function testColor()
	{
		$this->assertEquals("\033[1;37m\033[42m\033[4mtest\033[0m", CLI::color('test', 'white', 'green', 'underline'));
	}

	public function testWrite()
	{
		CLI::write('test');
		$expected = <<<EOT
test

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testWriteForeground()
	{
		CLI::write('test', 'red');
		$expected = <<<EOT
\033[0;31mtest\033[0m

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testWriteBackground()
	{
		CLI::write('test', 'red', 'green');
		$expected = <<<EOT
\033[0;31m\033[42mtest\033[0m

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testError()
	{
		$this->stream_filter = stream_filter_append(STDERR, 'CLITestStreamFilter');
		CLI::error('test');
		// red expected cuz stderr
		$expected = <<<EOT
\033[1;31mtest\033[0m

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testErrorForeground()
	{
		$this->stream_filter = stream_filter_append(STDERR, 'CLITestStreamFilter');
		CLI::error('test', 'purple');
		$expected = <<<EOT
\033[0;35mtest\033[0m

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testErrorBackground()
	{
		$this->stream_filter = stream_filter_append(STDERR, 'CLITestStreamFilter');
		CLI::error('test', 'purple', 'green');
		$expected = <<<EOT
\033[0;35m\033[42mtest\033[0m

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testShowProgress()
	{
		CLI::write('first.');
		CLI::showProgress(1, 20);
		CLI::showProgress(10, 20);
		CLI::showProgress(20, 20);
		CLI::write('second.');
		CLI::showProgress(1, 20);
		CLI::showProgress(10, 20);
		CLI::showProgress(20, 20);
		CLI::write('third.');
		CLI::showProgress(1, 20);

		$expected = <<<EOT
first.
[\033[32m#.........\033[0m]   5% Complete
\033[1A[\033[32m#####.....\033[0m]  50% Complete
\033[1A[\033[32m##########\033[0m] 100% Complete
second.
[\033[32m#.........\033[0m]   5% Complete
\033[1A[\033[32m#####.....\033[0m]  50% Complete
\033[1A[\033[32m##########\033[0m] 100% Complete
third.
[\033[32m#.........\033[0m]   5% Complete

EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	public function testShowProgressWithoutBar()
	{
		CLI::write('first.');
		CLI::showProgress(false, 20);
		CLI::showProgress(false, 20);
		CLI::showProgress(false, 20);

		$expected = <<<EOT
first.
\007\007\007
EOT;
		$this->assertEquals($expected, CLITestStreamFilter::$buffer);
	}

	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'));
	}

	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());
	}

	public function testWindow()
	{
		$this->assertTrue(is_int(CLI::getHeight()));
		$this->assertTrue(is_int(CLI::getWidth()));
	}

	/**
	 * @dataProvider tableProvider
	 *
	 * @param  array $tbody
	 * @param  array $thead
	 * @param  array $expected
	 */
	public function testTable($tbody, $thead, $expected)
	{
		CLI::table($tbody, $thead);
		$this->assertEquals(CLITestStreamFilter::$buffer, $expected);
	}

	public function tableProvider()
	{
		$head = ['ID', 'Title'];
		$one_row = [['id' => 1, 'foo' => 'bar']];
		$many_rows = [
			['id' => 1, 'foo' => 'bar'],
			['id' => 2, 'foo' => 'bar * 2'],
			['id' => 3, 'foo' => 'bar + bar + bar'],
		];

		return [
			[$one_row, [], "+---+-----+\n" .
				"| 1 | bar |\n" .
				"+---+-----+\n"],
			[$one_row, $head, "+----+-------+\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"],
			[$many_rows, $head, "+----+-----------------+\n" .
				"| ID | Title           |\n" .
				"+----+-----------------+\n" .
				"| 1  | bar             |\n" .
				"| 2  | bar * 2         |\n" .
				"| 3  | bar + bar + bar |\n" .
				"+----+-----------------+\n"],
		];
	}

}

// class to extract output snapshot
class CLITestStreamFilter extends \php_user_filter
{

	public static $buffer = '';

	public function filter($in, $out, &$consumed, $closing)
	{
		while ($bucket = stream_bucket_make_writeable($in))
		{
			self::$buffer .= $bucket->data;
			$consumed += $bucket->datalen;
		}
		return PSFS_PASS_ON;
	}

}

// class to spoof keyboard input
class CLITestKeyboardFilter extends \php_user_filter
{

	public static $buffer = '';
	public static $spoofed = '';

	public function filter($in, $out, &$consumed, $closing)
	{
		while ($bucket = stream_bucket_make_writeable($in))
		{
			$consumed += $bucket->datalen;
			$bucket = $spoofed;
			stream_bucket_append($out, $bucket);
		}
		return PSFS_PASS_ON;
	}

}

stream_filter_register('CLITestStreamFilter', 'CodeIgniter\CLI\CLITestStreamFilter');
{'fraction_non_alphanumeric': 0.2307907549387207, 'fraction_numerical': 0.04381890424757961, 'mean_word_length': 3.8454446854663775, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 133, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2202473', 'n_tokens_mistral': 7550, 'n_tokens_neox': 6538, 'n_words': 1228}