analyzer = new MethodSignatureAnalyzer(); $this->resolver = new CommandParameterResolver($this->analyzer); }); it('resolves simple string parameter', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithString'); $resolved = $this->resolver->resolveParameters($method, ['--name=John']); expect($resolved)->toHaveCount(1); expect($resolved[0])->toBe('John'); }); it('resolves integer parameter', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithInt'); $resolved = $this->resolver->resolveParameters($method, ['--count=42']); expect($resolved)->toHaveCount(1); expect($resolved[0])->toBe(42); expect($resolved[0])->toBeInt(); }); it('resolves boolean parameter', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithBool'); $resolved = $this->resolver->resolveParameters($method, ['--active=true']); expect($resolved)->toHaveCount(1); expect($resolved[0])->toBeTrue(); }); it('resolves array parameter', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithArray'); $resolved = $this->resolver->resolveParameters($method, ['--items=item1,item2,item3']); expect($resolved)->toHaveCount(1); expect($resolved[0])->toBe(['item1', 'item2', 'item3']); }); it('uses default values for optional parameters', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithDefault'); $resolved = $this->resolver->resolveParameters($method, []); expect($resolved)->toHaveCount(1); expect($resolved[0])->toBe('Guest'); }); it('resolves nullable parameters as null when missing', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithNullable'); $resolved = $this->resolver->resolveParameters($method, []); expect($resolved)->toHaveCount(1); expect($resolved[0])->toBeNull(); }); it('resolves ConsoleInput parameter', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithConsoleInput'); $input = new ConsoleInput([]); $resolved = $this->resolver->resolveParameters($method, [], $input); expect($resolved)->toHaveCount(1); expect($resolved[0])->toBe($input); }); it('resolves ConsoleOutput parameter', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithConsoleOutput'); $output = new ConsoleOutput(); $resolved = $this->resolver->resolveParameters($method, [], null, $output); expect($resolved)->toHaveCount(1); expect($resolved[0])->toBe($output); }); it('resolves both ConsoleInput and ConsoleOutput', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithBoth'); $input = new ConsoleInput([]); $output = new ConsoleOutput(); $resolved = $this->resolver->resolveParameters($method, ['--name=John'], $input, $output); expect($resolved)->toHaveCount(3); expect($resolved[0])->toBe($input); expect($resolved[1])->toBe($output); expect($resolved[2])->toBe('John'); }); it('handles optional framework parameters', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithOptionalFrameworkParams'); $resolved = $this->resolver->resolveParameters($method, ['--name=John']); expect($resolved)->toHaveCount(2); expect($resolved[0])->toBe('John'); expect($resolved[1])->toBeNull(); }); it('throws exception for missing required parameter', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithString'); expect(fn () => $this->resolver->resolveParameters($method, [])) ->toThrow(\InvalidArgumentException::class, "Required parameter 'name' is missing"); }); it('throws exception when ConsoleInput is required but not provided', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithConsoleInput'); expect(fn () => $this->resolver->resolveParameters($method, [])) ->toThrow(\InvalidArgumentException::class, "ConsoleInput is required but not provided"); }); it('validates method signature compatibility', function () { $method = new ReflectionMethod(TestCommandClass::class, 'simpleMethod'); // Should not throw for valid method $this->resolver->validateMethodSignature($method); expect(true)->toBeTrue(); }); it('creates parser for method', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithString'); $parser = $this->resolver->createParserForMethod($method); expect($parser)->toBeInstanceOf(\App\Framework\Console\ArgumentParser::class); }); }); describe('CommandParameterResolver Type Conversion', function () { beforeEach(function () { $this->analyzer = new MethodSignatureAnalyzer(); $this->resolver = new CommandParameterResolver($this->analyzer); }); it('converts string values correctly', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithString'); $resolved = $this->resolver->resolveParameters($method, ['--name=123']); expect($resolved[0])->toBe('123'); expect($resolved[0])->toBeString(); }); it('converts integer values correctly', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithInt'); $resolved = $this->resolver->resolveParameters($method, ['--count=42']); expect($resolved[0])->toBe(42); expect($resolved[0])->toBeInt(); }); it('converts boolean values correctly', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithBool'); $resolved = $this->resolver->resolveParameters($method, ['--active=true']); expect($resolved[0])->toBeTrue(); $resolved = $this->resolver->resolveParameters($method, ['--active=false']); expect($resolved[0])->toBeFalse(); $resolved = $this->resolver->resolveParameters($method, ['--active=1']); expect($resolved[0])->toBeTrue(); $resolved = $this->resolver->resolveParameters($method, ['--active=0']); expect($resolved[0])->toBeFalse(); }); it('converts array values correctly', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithArray'); $resolved = $this->resolver->resolveParameters($method, ['--items=item1,item2,item3']); expect($resolved[0])->toBeArray(); expect($resolved[0])->toBe(['item1', 'item2', 'item3']); }); it('throws exception for invalid type conversion', function () { $method = new ReflectionMethod(TestCommandClass::class, 'methodWithInt'); expect(fn () => $this->resolver->resolveParameters($method, ['--count=not-a-number'])) ->toThrow(\InvalidArgumentException::class); }); });