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);
}
}