Files
michaelschiemer/tests/Framework/Console/ArgumentDefinitionTest.php
Michael Schiemer 8f3c15ddbb fix(console): comprehensive TUI rendering fixes
- Fix Enter key detection: handle multiple Enter key formats (\n, \r, \r\n)
- Reduce flickering: lower render frequency from 60 FPS to 30 FPS
- Fix menu bar visibility: re-render menu bar after content to prevent overwriting
- Fix content positioning: explicit line positioning for categories and commands
- Fix line shifting: clear lines before writing, control newlines manually
- Limit visible items: prevent overflow with maxVisibleCategories/Commands
- Improve CPU usage: increase sleep interval when no events processed

This fixes:
- Enter key not working for selection
- Strong flickering of the application
- Menu bar not visible or being overwritten
- Top half of selection list not displayed
- Lines being shifted/misaligned
2025-11-10 11:06:07 +01:00

197 lines
7.0 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Framework\Console;
use App\Framework\Console\ArgumentDefinition;
use App\Framework\Console\ArgumentType;
describe('ArgumentDefinition', function () {
it('creates required string argument', function () {
$def = ArgumentDefinition::required('name', 'User name');
expect($def->name)->toBe('name');
expect($def->type)->toBe(ArgumentType::STRING);
expect($def->required)->toBeTrue();
expect($def->default)->toBeNull();
expect($def->description)->toBe('User name');
});
it('creates optional string argument with default', function () {
$def = ArgumentDefinition::optional('name', 'Guest', 'User name');
expect($def->name)->toBe('name');
expect($def->type)->toBe(ArgumentType::STRING);
expect($def->required)->toBeFalse();
expect($def->default)->toBe('Guest');
expect($def->description)->toBe('User name');
});
it('creates boolean flag', function () {
$def = ArgumentDefinition::flag('verbose', 'v', 'Enable verbose output');
expect($def->name)->toBe('verbose');
expect($def->type)->toBe(ArgumentType::BOOLEAN);
expect($def->shortName)->toBe('v');
expect($def->description)->toBe('Enable verbose output');
});
it('creates email argument', function () {
$def = ArgumentDefinition::email('email', required: true, description: 'User email');
expect($def->name)->toBe('email');
expect($def->type)->toBe(ArgumentType::EMAIL);
expect($def->required)->toBeTrue();
expect($def->description)->toBe('User email');
});
it('creates integer argument', function () {
$def = ArgumentDefinition::integer('count', required: false, default: 10, description: 'Item count');
expect($def->name)->toBe('count');
expect($def->type)->toBe(ArgumentType::INTEGER);
expect($def->required)->toBeFalse();
expect($def->default)->toBe(10);
expect($def->description)->toBe('Item count');
});
it('creates choice argument', function () {
$def = ArgumentDefinition::choice('mode', ['dev', 'prod', 'test'], required: false, default: 'dev');
expect($def->name)->toBe('mode');
expect($def->type)->toBe(ArgumentType::STRING);
expect($def->allowedValues)->toBe(['dev', 'prod', 'test']);
expect($def->default)->toBe('dev');
});
it('throws exception for empty name', function () {
expect(fn () => new ArgumentDefinition('', ArgumentType::STRING))
->toThrow(\InvalidArgumentException::class, 'Argument name cannot be empty');
});
it('throws exception for invalid short name length', function () {
expect(fn () => new ArgumentDefinition('name', ArgumentType::STRING, shortName: 'ab'))
->toThrow(\InvalidArgumentException::class, 'Short name must be exactly one character');
});
it('throws exception when required argument has default', function () {
expect(fn () => new ArgumentDefinition('name', ArgumentType::STRING, required: true, default: 'Guest'))
->toThrow(\InvalidArgumentException::class, 'Required arguments cannot have default values');
});
it('throws exception when boolean argument has allowed values', function () {
expect(fn () => new ArgumentDefinition('flag', ArgumentType::BOOLEAN, allowedValues: ['true', 'false']))
->toThrow(\InvalidArgumentException::class, 'Boolean arguments cannot have allowed values');
});
it('gets display name with short name', function () {
$def = ArgumentDefinition::flag('verbose', 'v');
expect($def->getDisplayName())->toBe('v, verbose');
});
it('gets display name without short name', function () {
$def = ArgumentDefinition::required('name');
expect($def->getDisplayName())->toBe('name');
});
it('gets usage text for boolean flag', function () {
$def = ArgumentDefinition::flag('verbose', 'v');
expect($def->getUsageText())->toBe('[--verbose]');
});
it('gets usage text for required boolean flag', function () {
$def = new ArgumentDefinition('verbose', ArgumentType::BOOLEAN, required: true);
expect($def->getUsageText())->toBe('--verbose');
});
it('gets usage text for optional boolean flag', function () {
$def = ArgumentDefinition::flag('verbose', 'v');
expect($def->getUsageText())->toBe('[--verbose]');
});
it('gets usage text for required string argument', function () {
$def = ArgumentDefinition::required('name');
expect($def->getUsageText())->toContain('--name');
expect($def->getUsageText())->toContain('<');
});
it('gets usage text for optional string argument', function () {
$def = ArgumentDefinition::optional('name', 'Guest');
expect($def->getUsageText())->toContain('--name');
expect($def->getUsageText())->toContain('[');
});
it('gets usage text with allowed values', function () {
$def = ArgumentDefinition::choice('mode', ['dev', 'prod']);
expect($def->getUsageText())->toContain('dev|prod');
});
it('validates required value', function () {
$def = ArgumentDefinition::required('name');
expect(fn () => $def->validateValue(null))
->toThrow(\InvalidArgumentException::class, "Required argument 'name' is missing");
});
it('validates allowed values', function () {
$def = ArgumentDefinition::choice('mode', ['dev', 'prod', 'test']);
// Should not throw for valid value
$def->validateValue('dev');
expect(true)->toBeTrue();
});
it('throws exception for invalid allowed value', function () {
$def = ArgumentDefinition::choice('mode', ['dev', 'prod', 'test']);
expect(fn () => $def->validateValue('invalid'))
->toThrow(\InvalidArgumentException::class, "Invalid value 'invalid'");
});
it('allows empty value for optional argument', function () {
$def = ArgumentDefinition::optional('name', 'Guest');
// Should not throw
$def->validateValue(null);
$def->validateValue('');
expect(true)->toBeTrue();
});
it('validates value with default', function () {
$def = ArgumentDefinition::optional('name', 'Guest');
// Should not throw
$def->validateValue('John');
expect(true)->toBeTrue();
});
it('creates argument with all properties', function () {
$def = new ArgumentDefinition(
name: 'test',
type: ArgumentType::INTEGER,
required: false,
default: 42,
description: 'Test description',
shortName: 't',
allowedValues: []
);
expect($def->name)->toBe('test');
expect($def->type)->toBe(ArgumentType::INTEGER);
expect($def->required)->toBeFalse();
expect($def->default)->toBe(42);
expect($def->description)->toBe('Test description');
expect($def->shortName)->toBe('t');
});
});