Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Helper test listener.
  19   *
  20   * @package    core
  21   * @category   phpunit
  22   * @copyright  2012 Petr Skoda {@link http://skodak.org}
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  
  27  /**
  28   * Helper test listener that prints command necessary
  29   * for execution of failed test.
  30   *
  31   * @package    core
  32   * @category   phpunit
  33   * @copyright  2012 Petr Skoda {@link http://skodak.org}
  34   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   */
  36  class Hint_ResultPrinter extends PHPUnit\TextUI\ResultPrinter {
  37      public function __construct() {
  38          // ARRGH - PHPUnit does not give us commandline arguments or xml config, so let's hack hard!
  39          if (defined('DEBUG_BACKTRACE_PROVIDE_OBJECT')) {
  40              $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);
  41              if (isset($backtrace[2]['object']) and ($backtrace[2]['object'] instanceof PHPUnit\TextUI\Command)) {
  42                  list($verbose, $colors, $debug) = Hacky_TextUI_Command_reader::get_settings_hackery($backtrace[2]['object']);
  43                  parent::__construct(null, $verbose, $colors, $debug);
  44                  return;
  45              }
  46          }
  47          // Fallback if something goes wrong.
  48          parent::__construct(null, false, self::COLOR_DEFAULT, false);
  49      }
  50  
  51      protected function printDefectTrace(PHPUnit\Framework\TestFailure $defect): void {
  52          global $CFG;
  53  
  54          parent::printDefectTrace($defect);
  55  
  56          $failedTest = $defect->failedTest();
  57          $testName = get_class($failedTest);
  58  
  59          $exception = $defect->thrownException();
  60          $trace = $exception->getTrace();
  61  
  62          if (class_exists('ReflectionClass')) {
  63              $reflection = new ReflectionClass($testName);
  64              $file = $reflection->getFileName();
  65  
  66          } else {
  67              $file = false;
  68              $dirroot = realpath($CFG->dirroot).DIRECTORY_SEPARATOR;
  69              $classpath = realpath("$CFG->dirroot/lib/phpunit/classes").DIRECTORY_SEPARATOR;
  70              foreach ($trace as $item) {
  71                  if (strpos($item['file'], $dirroot) === 0 and strpos($item['file'], $classpath) !== 0) {
  72                      if ($content = file_get_contents($item['file'])) {
  73                          if (preg_match('/class\s+'.$testName.'\s+extends/', $content)) {
  74                              $file = $item['file'];
  75                              break;
  76                          }
  77                      }
  78                  }
  79              }
  80          }
  81  
  82          if ($file === false) {
  83              return;
  84          }
  85  
  86          $cwd = getcwd();
  87          if (strpos($file, $cwd) === 0) {
  88              $file = substr($file, strlen($cwd)+1);
  89              $file = testing_cli_fix_directory_separator($file);
  90          }
  91  
  92          $pathprefix = testing_cli_argument_path('/');
  93          if ($pathprefix) {
  94              $pathprefix .= DIRECTORY_SEPARATOR;
  95          }
  96  
  97          // There is only vendor/bin/phpunit executable. There is no .cmd or .bat files.
  98          $executable = $pathprefix . 'vendor' . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'phpunit';
  99          $executable = testing_cli_fix_directory_separator($executable);
 100  
 101          // Add server arguments to the rerun if passed.
 102          if (isset($_SERVER['argv'][0])) {
 103              if (preg_match('/phpunit(\.bat|\.cmd)?$/', $_SERVER['argv'][0])) {
 104                  for($i=1;$i<count($_SERVER['argv']);$i++) {
 105                      if (!isset($_SERVER['argv'][$i])) {
 106                          break;
 107                      }
 108                      if (in_array($_SERVER['argv'][$i], array('--colors', '--verbose', '-v', '--debug'))) {
 109                          $executable .= ' '.$_SERVER['argv'][$i];
 110                      } else if (in_array($_SERVER['argv'][$i], array('-c', '--config'))) {
 111                          $executable .= ' '.$_SERVER['argv'][$i] . ' ' . $_SERVER['argv'][++$i];
 112                      } else if (strpos($_SERVER['argv'][$i], '--config') === 0) {
 113                          $executable .= ' '.$_SERVER['argv'][$i];
 114                      }
 115                  }
 116              }
 117          }
 118  
 119          $this->write("\nTo re-run:\n $executable \"$testName\" $file\n");
 120      }
 121  }
 122  
 123  
 124  /**
 125   * Class used in bloody hack that works around result printer constructor troubles.
 126   *
 127   * @package    core
 128   * @category   phpunit
 129   * @copyright  2012 Petr Skoda {@link http://skodak.org}
 130   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 131   */
 132  class Hacky_TextUI_Command_reader extends PHPUnit\TextUI\Command {
 133      public static function get_settings_hackery(PHPUnit\TextUI\Command $toread) {
 134          $arguments = $toread->arguments;
 135          $config = PHPUnit\Util\Configuration::getInstance($arguments['configuration'])->getPHPUnitConfiguration();
 136  
 137          $verbose = isset($config['verbose']) ? $config['verbose'] : false;
 138          $verbose = isset($arguments['verbose']) ? $arguments['verbose'] : $verbose;
 139  
 140          $colors = isset($config['colors']) ? $config['colors'] : Hint_ResultPrinter::COLOR_DEFAULT;
 141          $colors = isset($arguments['colors']) ? $arguments['colors'] : $colors;
 142  
 143          $debug = isset($config['debug']) ? $config['debug'] : false;
 144          $debug = isset($arguments['debug']) ? $arguments['debug'] : $debug;
 145  
 146          return array($verbose, $colors, $debug);
 147      }
 148  }