From dcf1beb1b9e264396495aa120a3752fddfbeca95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n?= Date: Thu, 10 Sep 2020 17:43:51 -0700 Subject: [PATCH] get rid of call_user_func (#32) `call_user_func_array` is deprecated in the latest nightly builds, changing to `$callable()`. I added a test to confirm this still works with all *reasonable* ways of providing callables (lambda, fun, class_meth, inst_meth). This likely breaks `'func_name'` and `varray['ClassName', 'methodName']` but those would be broken soon anyway by the HHVM migration to use native function pointers. --- src/ExpectObj.hack | 16 +++++++++------- tests/ExpectObjTest.hack | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) 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!'); + } }