$config, ['config' => 'forced'] ); $this->assertSame('forced', $result, 'A named argument must take precedence over an optional default'); } #[Test] public function namedValueWinsOverTypeBasedResolution(): void { $real = new Exception('the real one', 422); $result = Synapsis::resolve( fn (Exception $exception) => $exception, ['exception' => $real] ); $this->assertSame($real, $result, 'The injected instance must be the named one, not a container-built empty Exception'); } #[Test] public function namedParametersMatchByNameNotPosition(): void { $real = new Exception('matched by name'); [$b, $exception] = Synapsis::resolve( fn (Neuron $b, Exception $exception) => [$b, $exception], ['exception' => $real] ); $this->assertInstanceOf(Neuron::class, $b, 'Parameters without a named match must keep resolving through DI'); $this->assertSame($real, $exception, 'Position of the named parameter must not matter'); } #[Test] public function unmatchedNamedKeysAreIgnored(): void { $result = Synapsis::resolve( fn ($x = 'untouched') => $x, ['foo' => 1] ); $this->assertSame('untouched', $result, 'A key matching no parameter must be silently ignored'); } #[Test] public function renamedParameterFallsBackToContainerResolution(): void { $real = new Exception('never arrives'); // The handler renamed its parameter to $e, so the 'exception' key // matches nothing and $e degrades to DI: a fresh empty Exception. $result = Synapsis::resolve( fn (Exception $e) => $e, ['exception' => $real] ); $this->assertNotSame($real, $result, 'A renamed handler parameter must not receive the named value'); $this->assertSame('', $result->getMessage(), 'The degradation outcome is a container-built empty Exception'); } }