diff --git a/library/Mockery/Generator/Parameter.php b/library/Mockery/Generator/Parameter.php index 45d327676..4e08710b4 100644 --- a/library/Mockery/Generator/Parameter.php +++ b/library/Mockery/Generator/Parameter.php @@ -48,7 +48,7 @@ public function getTypeHintAsString() if ((version_compare(PHP_VERSION, '5.4.1') >= 0)) { try { if ($this->rfp->getClass()) { - return $this->rfp->getClass()->getName(); + return $this->getOptionalSign() . $this->rfp->getClass()->getName(); } } catch (\ReflectionException $re) { // noop @@ -56,7 +56,7 @@ public function getTypeHintAsString() } if (version_compare(PHP_VERSION, '7.0.0-dev') >= 0 && $this->rfp->hasType()) { - return (string) $this->rfp->getType(); + return $this->getOptionalSign() . $this->rfp->getType(); } if (preg_match('/^Parameter #[0-9]+ \[ \<(required|optional)\> (?\S+ )?.*\$' . $this->rfp->getName() . ' .*\]$/', $this->rfp->__toString(), $typehintMatch)) { @@ -68,6 +68,15 @@ public function getTypeHintAsString() return ''; } + private function getOptionalSign() + { + if (version_compare(PHP_VERSION, '7.1.0-dev', '>=') && $this->rfp->allowsNull() && !$this->rfp->isVariadic()) { + return '?'; + } + + return ''; + } + /** * Some internal classes have funny looking definitions... */ @@ -87,9 +96,6 @@ public function getName() */ public function isVariadic() { - if (version_compare(PHP_VERSION, '5.6.0') < 0) { - return false; - } - return $this->rfp->isVariadic(); + return version_compare(PHP_VERSION, '5.6.0') >= 0 && $this->rfp->isVariadic(); } } diff --git a/tests/Mockery/Fixtures/MethodWithNullableParameters.php b/tests/Mockery/Fixtures/MethodWithNullableParameters.php new file mode 100644 index 000000000..17700e7e6 --- /dev/null +++ b/tests/Mockery/Fixtures/MethodWithNullableParameters.php @@ -0,0 +1,49 @@ +container = new \Mockery\Container; + } + + protected function tearDown() + { + $this->container->mockery_close(); + } + + /** + * @test + */ + public function itShouldAllowNonNullableTypeToBeSet() + { + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->shouldReceive('nonNullablePrimitive')->with('a string'); + $mock->nonNullablePrimitive('a string'); + } + + /** + * @test + * @expectedException \TypeError + */ + public function itShouldNotAllowNonNullToBeNull() + { + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->nonNullablePrimitive(null); + } + + /** + * @test + */ + public function itShouldAllowPrimitiveNullableToBeNull() + { + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->shouldReceive('nullablePrimitive')->with(null); + $mock->nullablePrimitive(null); + } + + /** + * @test + */ + public function itShouldAllowPrimitiveNullabeToBeSet() + { + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->shouldReceive('nullablePrimitive')->with('a string'); + $mock->nullablePrimitive('a string'); + } + /** + * @test + */ + public function itShouldAllowSelfToBeSet() + { + $obj = new \test\Mockery\Fixtures\MethodWithNullableParameters; + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->shouldReceive('nonNullableSelf')->with($obj); + $mock->nonNullableSelf($obj); + } + + /** + * @test + * @expectedException \TypeError + */ + public function itShouldNotAllowSelfToBeNull() + { + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->nonNullableSelf(null); + } + + /** + * @test + */ + public function itShouldAllowNullalbeSelfToBeSet() + { + $obj = new \test\Mockery\Fixtures\MethodWithNullableParameters; + + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->shouldReceive('nullableSelf')->with($obj); + $mock->nullableSelf($obj); + } + + /** + * @test + */ + public function itShouldAllowNullableSelfToBeNull() + { + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->shouldReceive('nullableClass')->with(null); + $mock->nullableClass(null); + } + + /** + * @test + */ + public function itShouldAllowClassToBeSet() + { + $obj = new \test\Mockery\Fixtures\MethodWithNullableParameters; + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->shouldReceive('nonNullableClass')->with($obj); + $mock->nonNullableClass($obj); + } + + /** + * @test + * @expectedException \TypeError + */ + public function itShouldNotAllowClassToBeNull() + { + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->nonNullableClass(null); + } + + /** + * @test + */ + public function itShouldAllowNullalbeClassToBeSet() + { + $obj = new \test\Mockery\Fixtures\MethodWithNullableParameters; + + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->shouldReceive('nullableClass')->with($obj); + $mock->nullableClass($obj); + } + + /** + * @test + */ + public function itShouldAllowNullableClassToBeNull() + { + $mock = $this->container->mock('test\Mockery\Fixtures\MethodWithNullableParameters'); + + $mock->shouldReceive('nullableClass')->with(null); + $mock->nullableClass(null); + } +}