minitest/HackTest.hack (69 lines of code) (raw):

namespace HH\__Private\MiniTest; abstract class HackTest { private ?arraykey $dataName; protected static function fail(string $message): noreturn { invariant_violation('%s', $message); } protected static function markTestSkipped(string $message): noreturn { throw new SkippedTestException($message); } final public async function runAsync(): Awaitable<void> { \printf("--- %s::%s()\n", static::class, __FUNCTION__); $rc = new \ReflectionClass($this); static::beforeFirstTest(); foreach ($rc->getMethods() as $method) { if (!$method->isPublic()) { continue; } $name = $method->getName(); if (\strlen($name) < 4 || \substr($name, 0, 4) !== 'test') { continue; } \printf("----- %s::%s()\n", static::class, $name); $dp = $method->getAttributeClass(DataProvider::class); if (!$dp) { try { $ret = $method->invoke($this); if ($ret is Awaitable<_>) { await $ret; } } catch (SkippedTestException $ex) { \printf("------- SKIPPED: %s\n", $ex->getMessage()); } } else { try { $dp = $rc->getMethod($dp->provider); } catch (\ReflectionException $_) { \printf("!!!!! DataProvider %s::%s() does not exist\n", static::class, $dp->provider); exit(1); } if (!$dp->isPublic() && $dp->isStatic()) { \printf("!!!!! DataProvider %s::%s() must be public static\n", static::class, $dp->name); exit(1); } \printf("----- Invoking DataProvider %s::%s()\n", static::class, $dp->name); $values = $dp->invoke($this); foreach($values as $k => $args) { $this->dataName = $k; \printf("----- Invoking with data set %s...\n", \var_export($k, true)); try { $ret = $method->invokeArgs($this, $args); if ($ret is Awaitable<_>) { await $ret; } } catch (SkippedTestException $ex) { \printf("------- SKIPPED: %s\n", $ex->getMessage()); } $this->dataName = null; } } } static::afterLastTest(); \printf("OK: %s\n", static::class); } final public function getDataLabel(): arraykey { return $this->dataName as nonnull; } public static function beforeFirstTest(): void {} public static function afterLastTest(): void {} }