Exemple #1
0
 /**
  * Runs this module
  *
  * @throws \Exception
  */
 public function run()
 {
     // Create a suite to add spec files
     $suite = new Spec\TestSuite();
     // For every argument given check what files it matches
     foreach ($this->result->args['files'] as $file) {
         if (is_file($file)) {
             $suite->addTestFile($file);
         } else {
             if (is_dir($file)) {
                 $this->searchForSpecs($suite, $file);
             } else {
                 $glob = basename($file);
                 $file = dirname($file);
                 $this->searchForSpecs($suite, $file, $glob);
             }
         }
     }
     // Check if we just want to list the available groups
     if (!empty($this->result->options['list_groups'])) {
         print "Available test group(s):\n";
         $groups = $suite->getGroups();
         sort($groups);
         foreach ($groups as $group) {
             print " - {$group}\n";
         }
         exit(0);
     }
     // Create a printer instance
     if ($this->result->options['story']) {
         $this->result->options['format'] = 'story';
     }
     // @todo Allow custom class names
     switch (strtolower($this->result->options['format'])) {
         case 'd':
         case 'dots':
             $formatter = '\\DrSlump\\Spec\\Cli\\ResultPrinter\\Dots';
             break;
         case 's':
         case 'story':
             $formatter = '\\DrSlump\\Spec\\Cli\\ResultPrinter\\Story';
             break;
         default:
             throw new \RuntimeException('Unknown format option');
     }
     $printer = new $formatter(NULL, (bool) $this->result->options['verbose'], (bool) $this->result->options['color'], (bool) $this->result->options['debug']);
     // Create a PHPUnit result manager
     $result = new \PHPUnit_Framework_TestResult();
     // Append our custom printer as a listener
     $result->addListener($printer);
     // Register beeping listener
     if ($this->result->options['beep']) {
         $result->addListener(new Spec\Cli\BeepListener());
     }
     // Configure filter
     $filter = false;
     if (!empty($this->result->options['filter'])) {
         // Escape delimiters in regular expression.
         $filter = '/(' . implode(')|(', $this->result->options['filter']) . ')/i';
     }
     // Configure groups
     $groups = array();
     if (!empty($this->result->options['groups'])) {
         foreach ($this->result->options['groups'] as $opt) {
             $groups = array_merge($groups, explode(',', $opt));
         }
         $groups = array_map('trim', $groups);
         $groups = array_filter($groups);
         $groups = array_unique($groups);
     }
     // Configure excluded groups
     $excluded = array();
     if (!empty($this->result->options['exclude_groups'])) {
         foreach ($this->result->options['exclude_groups'] as $opt) {
             $excluded = array_merge($excluded, explode(',', $opt));
         }
         $excluded = array_map('trim', $excluded);
         $excluded = array_filter($excluded);
         $excluded = array_unique($excluded);
     }
     try {
         // Run the suite
         $suite->run($result, $filter, $groups, $excluded, false);
     } catch (\Exception $e) {
         // Recursive function to flag all tests in a suite as failed
         $fail = function ($suite) use(&$result, &$fail, &$e) {
             foreach ($suite->tests() as $test) {
                 if ($test instanceof \PHPUnit_Framework_TestSuite) {
                     $fail($test);
                     continue;
                 }
                 // Only flag as failed the ones that haven't been run yet
                 if (NULL === $test->getStatus()) {
                     $result->addError($test, $e, 0);
                 }
             }
         };
         // Check starting at the current suite since it's the one that have failed
         $fail(Spec::suite());
     }
     unset($suite);
     $result->flushListeners();
     $printer->printResult($result);
 }
Exemple #2
0
//  This source file is subject to the MIT license that is bundled
//  with this package in the file LICENSE.
//  It is also available through the world-wide-web at this URL:
//  http://creativecommons.org/licenses/MIT/
use DrSlump\Spec;
// Include Hamcrest matchers library
require_once 'Hamcrest/MatcherAssert.php';
require_once 'Hamcrest/Matchers.php';
// Hamcrest does not include these ones by default
require_once 'Hamcrest/Type/IsNumeric.php';
require_once 'Hamcrest/Type/IsCallable.php';
// Matcher names should be written as if they were to complete the
// sentence "value should ...". Words like 'be', 'to', 'at', 'the' ...
// will be automatically ignored but when Spec finds two conflicting
// matchers they will be used to disambiguate.
$matchers = Spec::matchers();
$matchers['be equal to'] = '\\Hamcrest_Matchers::equalTo';
$matchers['be eq to'] = '\\Hamcrest_Matchers::equalTo';
$matchers['be the same to'] = '\\Hamcrest_Matchers::identicalTo';
$matchers['be identical to'] = '\\Hamcrest_Matchers::identicalTo';
$matchers['be exactly'] = '\\Hamcrest_Matchers::identicalTo';
$matchers['be exactly equal to'] = '\\Hamcrest_Matchers::identicalTo';
$matchers['be at most'] = '\\Hamcrest_Matchers::lessThanOrEqualTo';
$matchers['be less equal to'] = '\\Hamcrest_Matchers::lessThanOrEqualTo';
$matchers['be less equal than'] = '\\Hamcrest_Matchers::lessThanOrEqualTo';
$matchers['be le to'] = '\\Hamcrest_Matchers::lessThanOrEqualTo';
$matchers['be le than'] = '\\Hamcrest_Matchers::lessThanOrEqualTo';
$matchers['be at least'] = '\\Hamcrest_Matchers::greaterThanOrEqualTo';
$matchers['be more equal to'] = '\\Hamcrest_Matchers::greaterThanOrEqualTo';
$matchers['be more equal than'] = '\\Hamcrest_Matchers::greaterThanOrEqualTo';
$matchers['be greater equal to'] = '\\Hamcrest_Matchers::greaterThanOrEqualTo';
Exemple #3
0
 /**
  * Prepares a test to be run. This method executes before setUp.
  *
  * @param Spec\TestCaseInterface  $test
  */
 public function prepareTest(Spec\TestCaseInterface $test)
 {
     $ann = $test->annotations;
     /* @todo Shouldn't this be already done by PHPUnit
             if (!empty($ann['outputBuffering'])) {
                 $enabled = filter_var($ann['outputBuffering'][0], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
                 $test->setUseOutputBuffering($enabled);
             }
     
             if (!empty($ann['errorHandler'])) {
                 $enabled = filter_var($ann['errorHandler'][0], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
                 $test->setUseErrorHandler($enabled);
             }
             */
     // Check @throws annotation
     // @todo can this be moved to setUp so it overrides PHPUnit annotations?
     if (!empty($ann['throws'])) {
         $regexp = '/([:.\\w\\\\x7f-\\xff]+)(?:[\\t ]+(\\S*))?(?:[\\t ]+(\\S*))?\\s*$/';
         if (preg_match($regexp, $ann['throws'][0], $m)) {
             $class = $code = $message = null;
             if (is_numeric($m[1])) {
                 $code = $m[1];
             } else {
                 $class = $m[1];
             }
             $message = isset($m[2]) ? $m[2] : null;
             $code = isset($m[3]) ? (int) $m[3] : $code;
             $test->setExpectedException($class, $message, $code);
         }
     }
     // Register the current test case as the active one
     Spec::test($test);
 }
Exemple #4
0
 /**
  * Create a test
  *
  * @see Spec::it
  * @param string $msg
  * @param callback $cb
  */
 function it($msg, $cb)
 {
     Spec::it($msg, $cb);
 }
Exemple #5
0
 public function assert($name, $args)
 {
     $name = trim($name, '_');
     // Convert camelCase to underscores
     $name = preg_replace_callback('/([a-z])([A-Z])/', function ($m) {
         return $m[1] . '_' . $m[2];
     }, $name);
     // Make it all lowercase
     $name = strtolower($name);
     // Remove 'to' if it's at the beginning since it might be used
     // when manually calling expect()
     $name = preg_replace('/^to_/', '', $name);
     // Extract ORs/ANDs/BUTs/AS from name
     if (preg_match('/^[a-z]+_(or|and|but|as)_?$/i', $name)) {
         // We need to disable implicit assertion if set
         $origImplicit = $this->implicitAssert;
         $this->implicitAssert = false;
         $parts = preg_split('/\\b(or|and|but|as)\\b/i', $name, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
         $prefix = '';
         do {
             $part = array_shift($parts);
             if (empty($part)) {
                 break;
             }
             // Should be an "as"
             $this->assert($prefix . $part, count($parts) ? array() : $args);
             $prefix = array_shift($parts);
         } while (count($parts));
         if (strtolower($prefix) === 'as') {
             $this->describedAs($args[0]);
         }
         if ($origImplicit) {
             $this->implicitAssert = true;
             $this->doAssert();
         }
         return $this;
     }
     // Explode by the underscore
     $parts = explode('_', $name);
     // Calculate if it's a negation
     $isNegation = false;
     foreach ($parts as $part) {
         if ($part === 'not' || $part == 'no') {
             $isNegation = !$isNegation;
         }
     }
     // Manage coordination operators
     switch ($parts[0]) {
         case 'described':
             if (empty($parts[1]) || $parts[1] !== 'as') {
                 break;
             }
         case 'as':
             $this->describedAs($args[0]);
             return $this;
         case 'and':
             $this->expression->addOperator('AND', 10);
             array_shift($parts);
             break;
         case 'or':
             $this->expression->addOperator('OR', 5);
             array_shift($parts);
             break;
         case 'but':
             $this->expression->addOperator('BUT', 1);
             array_shift($parts);
             break;
         default:
             // If no operator was given assume OR
             if (NULL !== $this->prevMatcher) {
                 $this->expression->addOperator('OR', 5);
             }
     }
     // If nothing left reuse previous matcher
     if (empty($parts)) {
         if (NULL === $this->prevMatcher) {
             throw new \RuntimeException("Unable to re-use previous matcher since it's empty");
         } else {
             if (empty($args)) {
                 throw new \RuntimeException("Unable to re-use previous matcher without arguments being given");
             }
         }
         $matcher = $this->prevMatcher;
     } else {
         $matcher = implode(' ', $parts);
         $this->prevMatcher = $matcher;
     }
     // Find the matcher for the given name
     $callback = Spec::matchers()->find($matcher);
     if (FALSE === $callback) {
         // Remove special words from the original matcher name
         $parts = explode('_', $name);
         $parts = array_diff($parts, $this->specialWords);
         $name = implode('_', $parts);
         $msg = "Matcher '" . str_replace('_', ' ', $name) . "' not found.";
         $suggestions = Spec::matchers()->suggest($name, 0.5);
         if (count($suggestions)) {
             $msg .= " Perhaps you meant to use '" . array_shift($suggestions) . "' ?";
         }
         throw new \Exception($msg);
     }
     // Instantiate the matcher
     $matcher = call_user_func_array($callback, $args);
     if ($isNegation) {
         $matcher = \Hamcrest_Core_IsNot::not($matcher);
     }
     $this->expression->addOperand($matcher);
     // Run the assertion now if the implicit flag is set
     if ($this->implicitAssert) {
         $this->doAssert();
     }
     return $this;
 }
Exemple #6
0
 /**
  * Wraps both <code>addTest()</code> and <code>addTestSuite</code>
  * as well as the separate import statements for the user's convenience.
  *
  * If the named file cannot be read or there are no new tests that can be
  * added, a <code>PHPUnit_Framework_Warning</code> will be created instead,
  * leaving the current test run untouched.
  *
  * @param  string  $filename
  * @param  boolean $syntaxCheck
  * @param  array   $phptOptions Array with ini settings for the php instance
  *                              run, key being the name if the setting,
  *                              value the ini value.
  * @throws InvalidArgumentException
  */
 public function addTestFile($filename, $syntaxCheck = FALSE, $phptOptions = array())
 {
     if (!is_string($filename)) {
         throw \PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
     }
     // Ensure we can read the file
     if (!$filename || !is_readable($filename)) {
         throw new \RuntimeException(sprintf('Cannot open file "%s".' . "\n", $filename));
     }
     // Try to convert it to a relative path
     if (strpos($filename, getcwd()) === 0) {
         $filename = substr($filename, strlen(getcwd()) + 1);
     } else {
         if (strpos($filename, './') === 0) {
             $filename = substr($filename, strlen('./'));
         }
     }
     // Use stream wrapper for spec files
     $furl = Spec::SCHEME . '://' . $filename;
     // Setup the environment to collect tests
     \DrSlump\Spec::reset($this);
     \PHPUnit_Util_Fileloader::load($furl);
     $this->numTests = -1;
 }