/**
  * Invoke the encapsulation shunter.
  *
  * @param   \Hoa\Praspel\Preambler\Handler  $preambler    Preambler.
  * @return  void
  * @throws  \Hoa\Praspel\Exception\Preambler
  */
 public function __invoke(Handler $preambler)
 {
     $callable = $preambler->__getCallable();
     $reflection = $callable->getReflection();
     $registry = Praspel::getRegistry();
     if ($reflection instanceof \ReflectionClass) {
         $_object = $reflection->newInstance();
         $preambler->__setCallable(xcallable($_object, '__construct'));
     } elseif (!$reflection instanceof \ReflectionMethod) {
         throw new Praspel\Exception\Preambler('The callable must be a class and a (dynamic) method name.', 0);
     } else {
         $callback = $callable->getValidCallback();
         if (!is_object($callback[0])) {
             $reflectionClass = $reflection->getDeclaringClass();
             $_reflectionClass = $reflectionClass;
             while (null === ($constructor = $_reflectionClass->getConstructor()) && false !== ($_reflectionClass = $_reflectionClass->getParentClass())) {
             }
             if (null === $constructor) {
                 $_object = $reflectionClass->newInstance();
             } else {
                 $className = $_reflectionClass->getName();
                 $id = $className . '::__construct';
                 if (!isset($registry[$id])) {
                     $registry[$id] = Praspel::interpret(Praspel::extractFromComment($constructor->getDocComment()), $className);
                 }
                 $assertionChecker = $this->getAssertionChecker();
                 if (null === $assertionChecker) {
                     $assertionChecker = '\\Hoa\\Praspel\\AssertionChecker';
                 }
                 $arguments = $assertionChecker::generateData($registry[$id]);
                 $_object = $reflectionClass->newInstanceArgs($arguments);
             }
             $preambler->__setCallable(xcallable($_object, $callback[1]));
         }
     }
     $reflectionObject = $preambler->__getReflectionObject($object);
     $className = $reflectionObject->getName();
     $properties = $reflectionObject->getProperties();
     foreach ($properties as $property) {
         $propertyName = $property->getName();
         $id = $className . '::$' . $propertyName;
         if (false === isset($registry[$id])) {
             $registry[$id] = Praspel::interpret(Praspel::extractFromComment($property->getDocComment()), $className);
         }
         $specification = $registry[$id];
         if (false === $specification->clauseExists('invariant')) {
             throw new Praspel\Exception\Preambler('Cannot generate a value from %s because it has no ' . '@invariant clause.', 1, $id);
         }
         $preambler->{$propertyName} = $specification->getClause('invariant')->getVariable($propertyName)->sample();
     }
     return;
 }
Exemple #2
0
 /**
  * Runtime assertion checker.
  *
  * @param   \Hoa\Praspel\Trace  $trace    Trace.
  * @return  bool
  * @throws  \Hoa\Praspel\Exception\AssertionChecker
  * @throws  \Hoa\Praspel\Exception\Group
  */
 public function evaluate(&$trace = false)
 {
     // Start.
     $registry = Praspel::getRegistry();
     $verdict = true;
     $callable = $this->getCallable();
     $reflection = $callable->getReflection();
     $specification = $this->getSpecification();
     $exceptions = new Praspel\Exception\Group('The Runtime Assertion Checker has detected failures for %s.', 0, $callable);
     $classname = null;
     $isConstructor = false;
     if ($reflection instanceof \ReflectionMethod) {
         $reflection->setAccessible(true);
         if ('__construct' === $reflection->getName()) {
             $isConstructor = true;
         }
         if (false === $reflection->isStatic()) {
             $_callback = $callable->getValidCallback();
             $_object = $_callback[0];
             $specification->getImplicitVariable('this')->bindTo($_object);
         }
         $classname = $reflection->getDeclaringClass()->getName();
     }
     if (false !== $trace && !$trace instanceof Trace) {
         $trace = new Praspel\Trace();
     }
     // Prepare data.
     if (null === ($data = $this->getData())) {
         if (true === $this->canGenerateData()) {
             $data = static::generateData($specification);
             $this->setData($data);
         } else {
             throw new Praspel\Exception\AssertionChecker('No data were given. The System Under Test %s needs data ' . 'to be executed.', 1, $callable);
         }
     }
     $arguments = $this->getArgumentData($reflection, $data, $numberOfRequiredArguments);
     // Check invariant.
     $invariant = $specification->getClause('invariant');
     $attributes = $this->getAttributeData($callable);
     foreach ($attributes as $name => $_) {
         $entryName = $classname . '::$' . $name;
         if (!isset($registry[$entryName])) {
             continue;
         }
         $entry = $registry[$entryName];
         if (true === $entry->clauseExists('invariant')) {
             foreach ($entry->getClause('invariant') as $variable) {
                 $invariant->addVariable($variable->getName(), $variable);
             }
         }
     }
     if (false === $isConstructor) {
         $verdict &= $this->checkClause($invariant, $attributes, $exceptions, 'Hoa\\Praspel\\Exception\\Failure\\Invariant', true, $trace);
         if (0 < count($exceptions)) {
             throw $exceptions;
         }
     }
     // Check requires and behaviors.
     $behavior = $specification;
     $verdict &= $this->checkBehavior($behavior, $arguments, $exceptions, true, $trace);
     if (0 < count($exceptions)) {
         throw $exceptions;
     }
     $rootBehavior = $behavior instanceof Praspel\Model\Specification;
     $numberOfArguments = count($arguments);
     if ($numberOfArguments < $numberOfRequiredArguments) {
         $exceptions[] = new Praspel\Exception\Failure\Precondition('Callable %s needs %d arguments; %d given.', 2, [$callable, $numberOfRequiredArguments, $numberOfArguments]);
         throw $exceptions;
     }
     $_exceptions = true === $rootBehavior ? $exceptions : new Praspel\Exception\Group('Behavior %s is broken.', 3, $behavior->getIdentifier());
     try {
         // Invoke.
         $return = $this->invoke($callable, $reflection, $arguments, $isConstructor);
         $arguments['\\result'] = $return;
         // Check normal postcondition.
         if (true === $behavior->clauseExists('ensures')) {
             $ensures = $behavior->getClause('ensures');
             $verdict &= $this->checkClause($ensures, $arguments, $_exceptions, 'Hoa\\Praspel\\Exception\\Failure\\Postcondition', false, $trace);
         }
     } catch (Praspel\Exception $internalException) {
         $_exceptions[] = new Praspel\Exception\Failure\InternalPrecondition('The System Under Test has broken an internal contract.', 4, null, $internalException);
     } catch (\Exception $exception) {
         $arguments['\\result'] = $exception;
         // Check exceptional postcondition.
         if (true === $behavior->clauseExists('throwable')) {
             $throwable = $behavior->getClause('throwable');
             $verdict &= $this->checkExceptionalClause($throwable, $arguments);
             if (false == $verdict) {
                 $_exceptions[] = new Praspel\Exception\Failure\Exceptional('The exception %s has been unexpectedly thrown.', 5, get_class($arguments['\\result']), $exception);
             }
         } else {
             $verdict &= false;
             $_exceptions[] = new Praspel\Exception\Failure\Exceptional('The System Under Test cannot terminate exceptionally ' . 'because no exceptional postcondition has been specified ' . '(there is no @throwable clause).', 6, [], $exception);
         }
     }
     if (0 < count($_exceptions) && false === $rootBehavior) {
         $_behavior = $behavior;
         while (null !== ($_behavior = $_behavior->getParent()) && !$_behavior instanceof Praspel\Model\Specification) {
             $handle = new Praspel\Exception\Group('Behavior %s is broken.', 7, $_behavior->getIdentifier());
             $handle[] = $_exceptions;
             $_exceptions = $handle;
         }
         $exceptions[] = $_exceptions;
     }
     if (0 < count($exceptions)) {
         throw $exceptions;
     }
     // Check invariant.
     $attributes = $this->getAttributeData($callable);
     $verdict &= $this->checkClause($invariant, $attributes, $exceptions, 'Hoa\\Praspel\\Exception\\Failure\\Invariant', true, $trace);
     if (0 < count($exceptions)) {
         throw $exceptions;
     }
     return (bool) $verdict;
 }
Exemple #3
0
 /**
  * Compute dynamic resolution.
  *
  * @param   string  $name    Name.
  * @return  void
  * @throws  \Hoa\Praspel\Exception\Model
  */
 protected function computeDynamicResolution($name)
 {
     $this->_type = static::TYPE_EXTERNAL;
     $clause = $this->getClause();
     $parts = explode('->', $name);
     $head = array_shift($parts);
     if ('this' !== $head) {
         throw new Praspel\Exception\Model('Not yet implemented!');
     }
     $registry = Praspel::getRegistry();
     $root = $clause->getRoot();
     $bindedClass = $root->getBindedClass();
     if (null === $bindedClass) {
         throw new Praspel\Exception\Model('Cannot resolve the dynamic identifier %s; ' . '%s::getBindedClass returned null.', 3, [$name, get_class($root)]);
     }
     $attribute = array_shift($parts);
     $id = $bindedClass . '::$' . $attribute;
     if (!isset($registry[$id])) {
         throw new Praspel\Exception\Model('The contract identifier %s does not exist in the registry.', 4, $name);
     }
     $entry = $registry[$id];
     if (false === $entry->clauseExists('invariant')) {
         throw new Praspel\Exception\Model('%s is not declared with an @invariant clause.', 5, $id);
     }
     $targetedClause = $entry->getClause('invariant');
     if (!isset($targetedClause[$attribute])) {
         throw new Praspel\Exception\Model('The identifier %s does not exist.', 6, $attribute);
     }
     $variable = $targetedClause[$attribute];
     $this->_variable = $variable;
     return;
 }