diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -632,6 +632,8 @@ 'LinesOfALargeFile' => 'filesystem/linesofalarge/LinesOfALargeFile.php', 'LinesOfALargeFileTestCase' => 'filesystem/linesofalarge/__tests__/LinesOfALargeFileTestCase.php', 'MFilterTestHelper' => 'utils/__tests__/MFilterTestHelper.php', + 'MethodCallFuture' => 'future/MethodCallFuture.php', + 'MethodCallFutureTestCase' => 'future/__tests__/MethodCallFutureTestCase.php', 'NoseTestEngine' => 'unit/engine/NoseTestEngine.php', 'PHPASTParserTestCase' => 'parser/xhpast/__tests__/PHPASTParserTestCase.php', 'PhageAction' => 'phage/action/PhageAction.php', @@ -1695,6 +1697,8 @@ 'LinesOfALargeFile' => 'LinesOfALarge', 'LinesOfALargeFileTestCase' => 'PhutilTestCase', 'MFilterTestHelper' => 'Phobject', + 'MethodCallFuture' => 'Future', + 'MethodCallFutureTestCase' => 'PhutilTestCase', 'NoseTestEngine' => 'ArcanistUnitTestEngine', 'PHPASTParserTestCase' => 'PhutilTestCase', 'PhageAction' => 'Phobject', diff --git a/src/future/MethodCallFuture.php b/src/future/MethodCallFuture.php new file mode 100644 --- /dev/null +++ b/src/future/MethodCallFuture.php @@ -0,0 +1,36 @@ +callObject = $object; + $this->callMethod = $method; + $this->callArgv = array_slice($argv, 2); + } + + public function isReady() { + + $call = array($this->callObject, $this->callMethod); + $argv = $this->callArgv; + + $result = call_user_func_array($call, $argv); + $this->setResult($result); + + return true; + } + +} diff --git a/src/future/__tests__/MethodCallFutureTestCase.php b/src/future/__tests__/MethodCallFutureTestCase.php new file mode 100644 --- /dev/null +++ b/src/future/__tests__/MethodCallFutureTestCase.php @@ -0,0 +1,57 @@ +resolve(); + + $this->assertEqual(6, $result, pht('MethodCallFuture: getSum(1, 2, 3)')); + + $future = new MethodCallFuture($this, 'getSum'); + $result = $future->resolve(); + + $this->assertEqual(0, $result, pht('MethodCallFuture: getSum()')); + } + + public function testMethodCallFutureExceptions() { + $future = new MethodCallFuture($this, 'raiseException'); + + // See T13666. Using "FutureIterator" to advance the future until it is + // ready to resolve should NOT throw an exception. + + foreach (new FutureIterator(array($future)) as $resolvable) { + // Continue below... + } + + $caught = null; + try { + $future->resolve(); + } catch (PhutilMethodNotImplementedException $ex) { + $caught = $ex; + } + + $this->assertTrue( + ($caught instanceof PhutilMethodNotImplementedException), + pht('MethodCallFuture: exceptions raise at resolution.')); + } + + public function getSum(/* ... */) { + $args = func_get_args(); + + $sum = 0; + foreach ($args as $arg) { + $sum += $arg; + } + + return $sum; + } + + public function raiseException() { + // We just want to throw any narrow exception so the test isn't catching + // too broad an exception type. This is simulating some exception during + // future resolution. + throw new PhutilMethodNotImplementedException(); + } + +}