/** * Precondition: $values should fail $this->assertion */ public function from(array $elements, AssertionFailed $exception) { $onBadShrink = function () use(&$exception) { $this->attempts->increase(); $this->attempts->ensureLimit($exception); }; $onGoodShrink = function ($elementsAfterShrink, $exceptionAfterShrink) use(&$elements, &$exception) { $this->attempts->reset(); $elements = $elementsAfterShrink; $exception = $exceptionAfterShrink; }; $this->timeLimit->start(); while (!$this->timeLimit->hasBeenReached()) { $elementsAfterShrink = $this->generator->shrink($elements); if ($elementsAfterShrink === $elements) { $onBadShrink(); continue; } if (!$this->checkGoodShrinkConditions($elementsAfterShrink)) { $onBadShrink(); continue; } Evaluation::of($this->assertion)->with($elementsAfterShrink)->onFailure($onGoodShrink)->onSuccess($onBadShrink)->execute(); } throw new \RuntimeException("Eris has reached the time limit for shrinking, here it is presenting the simplest failure case." . PHP_EOL . "If you can afford to spend more time to find a simpler failing input, increase \$this->shrinkingTimeLimit or set it to null to remove it.", -1, $exception); }
public function __invoke(callable $assertion) { $sizes = $this->sizes($this->maxSize); try { for ($iteration = 0; $iteration < $this->iterations; $iteration++) { $values = []; foreach ($this->generators as $name => $generator) { $currentSizeIndex = $iteration % count($sizes); $value = $generator($sizes[$currentSizeIndex]); $values[] = $value; } if (!$this->antecedentsAreSatisfied($values)) { continue; } $this->evaluations++; Evaluation::of($assertion)->with($values)->onFailure(function ($values, $exception) use($assertion) { $shrinking = $this->shrinkerFactory->random($this->generators, $assertion); // MAYBE: put into ShrinkerFactory? $shrinking->addGoodShrinkCondition(function (array $values) { return $this->antecedentsAreSatisfied($values); }); $shrinking->from($values, $exception); })->execute(); } } catch (Exception $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; } } }
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); } }