Files
Gnuboard7/tests/Unit/Console/Helpers/ConsoleConfirmTest.php
T
2026-05-11 11:29:41 +09:00

174 lines
5.7 KiB
PHP

<?php
namespace Tests\Unit\Console\Helpers;
use App\Console\Helpers\ConsoleConfirm;
use PHPUnit\Framework\Attributes\DataProvider;
use Tests\TestCase;
/**
* ConsoleConfirm 헬퍼 단위 테스트.
*
* - parse(): 입력 정규화 규칙 (대소문자/공백/empty/유효값/무효값)
* - ask(): STDIN 루프 동작 (1회 결정/재질문/EOF/non-tty)
*/
class ConsoleConfirmTest extends TestCase
{
/**
* @return array<string, array{string, bool, bool|null}>
*/
public static function parseCases(): array
{
return [
'empty + default true' => ['', true, true],
'empty + default false' => ['', false, false],
'yes lowercase' => ['yes', false, true],
'y short' => ['y', false, true],
'Y uppercase' => ['Y', false, true],
'YES uppercase' => ['YES', false, true],
'yes with surrounding whitespace' => [' yes ', false, true],
'yes with newline (fgets style)' => ["\nyes\n", false, true],
'no lowercase' => ['no', true, false],
'n short' => ['n', true, false],
'N uppercase + default true' => ['N', true, false],
'NO uppercase' => ['NO', true, false],
'invalid - yell_no (default false)' => ['yell_no', false, null],
'invalid - nope (default true)' => ['nope', true, null],
'invalid - yeah (y로 시작이지만 무관)' => ['yeah', false, null],
'invalid - 1 (numeric truthy)' => ['1', false, null],
'invalid - 0 (numeric falsy)' => ['0', false, null],
'invalid - true literal' => ['true', false, null],
'invalid - false literal' => ['false', false, null],
'invalid - 한글 예 (비ASCII)' => ['예', false, null],
'invalid - 한글 네 (비ASCII)' => ['네', false, null],
'whitespace-only → empty → default' => [" \t \n", true, true],
];
}
#[DataProvider('parseCases')]
public function test_parse_normalizes_input(string $raw, bool $default, ?bool $expected): void
{
$this->assertSame($expected, ConsoleConfirm::parse($raw, $default));
}
public function test_ask_returns_immediately_on_first_valid_input(): void
{
$stdin = $this->makeStdin(["yes\n"]);
$output = '';
$result = ConsoleConfirm::ask(
'진행할까요?',
false,
$stdin,
function (string $text) use (&$output) {
$output .= $text;
},
);
$this->assertTrue($result);
$this->assertStringContainsString('진행할까요? (yes/no) [no]: ', $output);
$this->assertStringNotContainsString('yes, y, no, n', $output);
}
public function test_ask_loops_on_invalid_input_then_resolves(): void
{
$stdin = $this->makeStdin(["abc\n", "y\n"]);
$output = '';
$result = ConsoleConfirm::ask(
'진행할까요?',
false,
$stdin,
function (string $text) use (&$output) {
$output .= $text;
},
);
$this->assertTrue($result);
$this->assertStringContainsString('yes, y, no, n 중 하나로 입력해 주세요.', $output);
// 질문이 정확히 2회 출력되어야 함
$this->assertSame(2, substr_count($output, '진행할까요? (yes/no) [no]: '));
}
public function test_ask_loops_multiple_times_on_invalid_input(): void
{
$stdin = $this->makeStdin(["a\n", "b\n", "no\n"]);
$output = '';
$result = ConsoleConfirm::ask(
'진행할까요?',
true,
$stdin,
function (string $text) use (&$output) {
$output .= $text;
},
);
$this->assertFalse($result);
$this->assertSame(2, substr_count($output, 'yes, y, no, n 중 하나로 입력해 주세요.'));
$this->assertSame(3, substr_count($output, '진행할까요? (yes/no) [yes]: '));
}
public function test_ask_returns_default_on_eof(): void
{
$stdin = $this->makeStdin([]);
$resultDefaultTrue = ConsoleConfirm::ask('Q?', true, $stdin, fn () => null);
$this->assertTrue($resultDefaultTrue);
$stdin2 = $this->makeStdin([]);
$resultDefaultFalse = ConsoleConfirm::ask('Q?', false, $stdin2, fn () => null);
$this->assertFalse($resultDefaultFalse);
}
public function test_ask_returns_default_on_empty_input(): void
{
$stdin = $this->makeStdin(["\n"]);
$result = ConsoleConfirm::ask('Q?', true, $stdin, fn () => null);
$this->assertTrue($result);
}
public function test_ask_uses_yes_hint_when_default_true(): void
{
$stdin = $this->makeStdin(["yes\n"]);
$output = '';
ConsoleConfirm::ask('Q?', true, $stdin, function (string $text) use (&$output) {
$output .= $text;
});
$this->assertStringContainsString('Q? (yes/no) [yes]: ', $output);
}
public function test_ask_uses_no_hint_when_default_false(): void
{
$stdin = $this->makeStdin(["no\n"]);
$output = '';
ConsoleConfirm::ask('Q?', false, $stdin, function (string $text) use (&$output) {
$output .= $text;
});
$this->assertStringContainsString('Q? (yes/no) [no]: ', $output);
}
/**
* 메모리 기반 STDIN 리소스 생성.
*
* @param array<string> $lines fgets() 가 차례로 반환할 줄 (개행 포함 권장)
* @return resource
*/
private function makeStdin(array $lines)
{
$stream = fopen('php://memory', 'r+');
foreach ($lines as $line) {
fwrite($stream, $line);
}
rewind($stream);
return $stream;
}
}