diff --git a/src/ExpectObj.hack b/src/ExpectObj.hack index fd9a934..524b509 100644 --- a/src/ExpectObj.hack +++ b/src/ExpectObj.hack @@ -525,9 +525,12 @@ class ExpectObj extends Assert { * * expect( () ==> invariant_violation('...') )->notToThrow(); // would fail */ - public function notToThrow(?string $msg = null, mixed ...$args): void { + public function notToThrow( + ?string $msg = null, + mixed ...$args + ): void where T as (function(): mixed) { $msg = \vsprintf($msg, $args); - $e = $this->tryCallWithArgsReturnException(varray[], \Exception::class); + $e = $this->tryCallReturnException(\Exception::class); if ($e !== null) { $msg = Str\format( "%s was thrown: %s\n%s", @@ -572,7 +575,7 @@ class ExpectObj extends Assert { mixed ...$args ): TException where T = (function(): TRet) { $msg = \vsprintf($msg ?? '', $args); - $exception = $this->tryCallWithArgsReturnException(vec[], $exception_class); + $exception = $this->tryCallReturnException($exception_class); if (!$exception) { throw new \Exception( @@ -652,13 +655,12 @@ class ExpectObj extends Assert { **** Private implementation details *** *************************************** ***************************************/ - private function tryCallWithArgsReturnException( - Container $args, + private function tryCallReturnException( classname $expected_exception_type, - ): ?Tclass { + ): ?Tclass where T as (function(): mixed) { try { $callable = $this->var; - $returned = \call_user_func_array($callable, $args); + $returned = $callable(); if ($returned is Awaitable<_>) { /* HHAST_IGNORE_ERROR[DontUseAsioJoin] */ diff --git a/tests/ExpectObjTest.hack b/tests/ExpectObjTest.hack index 967a076..0a18c4a 100644 --- a/tests/ExpectObjTest.hack +++ b/tests/ExpectObjTest.hack @@ -536,4 +536,25 @@ final class ExpectObjTest extends HackTest { \restore_error_handler(); expect($previous)->toEqual('not_a_function', 'Error handler contaminated'); } + + /** + * Test that all reasonable ways of providing a (function(): mixed) work. + */ + public function testCallables(): void { + expect(() ==> self::exampleStaticCallable()) + ->toThrow(\Exception::class, 'Static method called!'); + expect(class_meth(self::class, 'exampleStaticCallable')) + ->toThrow(\Exception::class, 'Static method called!'); + expect(inst_meth($this, 'exampleInstanceCallable')) + ->toThrow(\Exception::class, 'Instance method called!'); + expect(fun('time'))->notToThrow(); + } + + public static function exampleStaticCallable(): void { + throw new \Exception('Static method called!'); + } + + public function exampleInstanceCallable(): void { + throw new \Exception('Instance method called!'); + } }