public function __invoke(callable $assertion) { $sizes = Size::withTriangleGrowth($this->maxSize)->limit($this->iterations); try { $redTestException = null; $this->notifyListeners('startPropertyVerification'); for ($iteration = 0; $iteration < $this->iterations && !$this->terminationConditionsAreSatisfied(); $iteration++) { $generatedValues = []; $values = []; foreach ($this->generators as $name => $generator) { $value = $generator($sizes->at($iteration), $this->rand); if (!$value instanceof GeneratedValue) { throw new RuntimeException("The value returned by a generator should be an instance of GeneratedValue, but it is " . var_export($value, true)); } $generatedValues[] = $value; $values[] = $value->unbox(); } $generation = GeneratedValue::fromValueAndInput($values, $generatedValues, 'tuple'); $this->notifyListeners('newGeneration', $generation->unbox(), $iteration); if (!$this->antecedentsAreSatisfied($values)) { continue; } $this->ordinaryEvaluations++; Evaluation::of($assertion)->with($generation)->onFailure(function ($generatedValues, $exception) use($assertion) { $this->notifyListeners('failure', $generatedValues->unbox(), $exception); if (!$this->shrinkingEnabled) { throw $exception; } $shrinking = $this->shrinkerFactory->random($this->generators, $assertion); // MAYBE: put into ShrinkerFactory? $shrinking->addGoodShrinkCondition(function (GeneratedValue $generatedValues) { return $this->antecedentsAreSatisfied($generatedValues->unbox()); })->onAttempt(function (GeneratedValue $generatedValues) { $this->notifyListeners('shrinking', $generatedValues->unbox()); })->from($generatedValues, $exception); })->execute(); } } catch (Exception $e) { $redTestException = $e; $wrap = (bool) getenv('ERIS_ORIGINAL_INPUT'); if ($wrap) { $message = "Original input: " . var_export($values, true) . PHP_EOL . "Possibly shrinked input follows." . PHP_EOL; throw new RuntimeException($message, -1, $e); } else { throw $e; } } finally { $this->notifyListeners('endPropertyVerification', $this->ordinaryEvaluations, $this->iterations, $redTestException); } }