Skip to content
Snippets Groups Projects
run-tests.sh 43.5 KiB
Newer Older
  $results = simpletest_script_load_messages_by_test_id($test_ids);

  $test_class = '';
  $xml_files = array();

  foreach ($results as $result) {
    if (isset($results_map[$result->status])) {
      if ($result->test_class != $test_class) {
        // We've moved onto a new class, so write the last classes results to a file:
        if (isset($xml_files[$test_class])) {
          file_put_contents($args['xml'] . '/' . str_replace('\\', '_', $test_class) . '.xml', $xml_files[$test_class]['doc']->saveXML());
          unset($xml_files[$test_class]);
        }
        $test_class = $result->test_class;
        if (!isset($xml_files[$test_class])) {
          $doc = new DomDocument('1.0');
          $root = $doc->createElement('testsuite');
          $root = $doc->appendChild($root);
          $xml_files[$test_class] = array('doc' => $doc, 'suite' => $root);
        }
      }

      // For convenience:
      $dom_document = &$xml_files[$test_class]['doc'];

      // Create the XML element for this test case:
      $case = $dom_document->createElement('testcase');
      $case->setAttribute('classname', $test_class);
      if (strpos($result->function, '->') !== FALSE) {
        list($class, $name) = explode('->', $result->function, 2);
      }
      else {
        $name = $result->function;
      }
      $case->setAttribute('name', $name);

      // Passes get no further attention, but failures and exceptions get to add more detail:
      if ($result->status == 'fail') {
        $fail = $dom_document->createElement('failure');
        $fail->setAttribute('type', 'failure');
        $fail->setAttribute('message', $result->message_group);
        $text = $dom_document->createTextNode($result->message);
        $fail->appendChild($text);
        $case->appendChild($fail);
      }
      elseif ($result->status == 'exception') {
        // In the case of an exception the $result->function may not be a class
        // method so we record the full function name:
        $case->setAttribute('name', $result->function);

        $fail = $dom_document->createElement('error');
        $fail->setAttribute('type', 'exception');
        $fail->setAttribute('message', $result->message_group);
        $full_message = $result->message . "\n\nline: " . $result->line . "\nfile: " . $result->file;
        $text = $dom_document->createTextNode($full_message);
        $fail->appendChild($text);
        $case->appendChild($fail);
      }
      // Append the test case XML to the test suite:
      $xml_files[$test_class]['suite']->appendChild($case);
    }
  }
  // The last test case hasn't been saved to a file yet, so do that now:
  if (isset($xml_files[$test_class])) {
    file_put_contents($args['xml'] . '/' . str_replace('\\', '_', $test_class) . '.xml', $xml_files[$test_class]['doc']->saveXML());
    unset($xml_files[$test_class]);
  }
}

/**
 * Stop the test timer.
 */
function simpletest_script_reporter_timer_stop() {
  $end = Timer::stop('run-tests');
  echo "Test run duration: " . \Drupal::service('date.formatter')->formatInterval($end['time'] / 1000);
}

/**
 * Display test results.
 */
function simpletest_script_reporter_display_results() {
    echo "Detailed test results\n";
    echo "---------------------\n";
    $results = simpletest_script_load_messages_by_test_id($test_ids);
      if (isset($results_map[$result->status])) {
        if ($result->test_class != $test_class) {
          // Display test class every time results are for new test class.
          echo "\n\n---- $result->test_class ----\n\n\n";
          $test_class = $result->test_class;
          // Print table header.
          echo "Status    Group      Filename          Line Function                            \n";
          echo "--------------------------------------------------------------------------------\n";
/**
 * Format the result so that it fits within the default 80 character
 * terminal size.
 *
 * @param $result The result object to format.
 */
function simpletest_script_format_result($result) {
  global $args, $results_map, $color;
  $summary = sprintf("%-9.9s %-10.10s %-17.17s %4.4s %-35.35s\n",
    $results_map[$result->status], $result->message_group, basename($result->file), $result->line, $result->function);

  simpletest_script_print($summary, simpletest_script_color_code($result->status));
  $message = trim(strip_tags($result->message));
  if ($args['non-html']) {
    $message = Html::decodeEntities($message, ENT_QUOTES, 'UTF-8');
  }
  $lines = explode("\n", wordwrap($message), 76);
 * Print error message prefixed with "  ERROR: " and displayed in fail color
 * if color output is enabled.
 *
 * @param $message The message to print.
function simpletest_script_print_error($message) {
  simpletest_script_print("  ERROR: $message\n", SIMPLETEST_SCRIPT_COLOR_FAIL);
/**
 * Print a message to the console, if color is enabled then the specified
 * color code will be used.
 *
 * @param $message The message to print.
 * @param $color_code The color code to use for coloring.
 */
function simpletest_script_print($message, $color_code) {
  global $args;
  if ($args['color']) {
    echo "\033[" . $color_code . "m" . $message . "\033[0m";
  }
  else {
    echo $message;
  }
}

/**
 * Get the color code associated with the specified status.
 *
 * @param $status The status string to get code for.
 * @return Color code.
 */
function simpletest_script_color_code($status) {
  switch ($status) {
    case 'pass':
      return SIMPLETEST_SCRIPT_COLOR_PASS;
    case 'fail':
      return SIMPLETEST_SCRIPT_COLOR_FAIL;
    case 'exception':
      return SIMPLETEST_SCRIPT_COLOR_EXCEPTION;
  }
  return 0; // Default formatting.
}

/**
 * Prints alternative test names.
 *
 * Searches the provided array of string values for close matches based on the
 * Levenshtein algorithm.
 *
 * @see http://php.net/manual/en/function.levenshtein.php
 *
 * @param string $string
 *   A string to test.
 * @param array $array
 *   A list of strings to search.
 * @param int $degree
 *   The matching strictness. Higher values return fewer matches. A value of
 *   4 means that the function will return strings from $array if the candidate
 *   string in $array would be identical to $string by changing 1/4 or fewer of
 *   its characters.
 */
function simpletest_script_print_alternatives($string, $array, $degree = 4) {
  $alternatives = array();
  foreach ($array as $item) {
    $lev = levenshtein($string, $item);
    if ($lev <= strlen($item) / $degree || FALSE !== strpos($string, $item)) {
      $alternatives[] = $item;
    }
  }
  if (!empty($alternatives)) {
    simpletest_script_print("  Did you mean?\n", SIMPLETEST_SCRIPT_COLOR_FAIL);
    foreach ($alternatives as $alternative) {
      simpletest_script_print("  - $alternative\n", SIMPLETEST_SCRIPT_COLOR_FAIL);
    }
  }
}

/**
 * Loads the simpletest messages from the database.
 *
 * Messages are ordered by test class and message id.
 *
 * @param array $test_ids
 *   Array of test IDs of the messages to be loaded.
 *
 * @return array
 *   Array of simpletest messages from the database.
 */
function simpletest_script_load_messages_by_test_id($test_ids) {
  global $args;
  $results = array();

  // Sqlite has a maximum number of variables per query. If required, the
  // database query is split into chunks.
  if (count($test_ids) > SIMPLETEST_SCRIPT_SQLITE_VARIABLE_LIMIT && !empty($args['sqlite'])) {
    $test_id_chunks = array_chunk($test_ids, SIMPLETEST_SCRIPT_SQLITE_VARIABLE_LIMIT);
  }
  else {
    $test_id_chunks = array($test_ids);
  }

  foreach ($test_id_chunks as $test_id_chunk) {
    $result_chunk = Database::getConnection('default', 'test-runner')
      ->query("SELECT * FROM {simpletest} WHERE test_id IN ( :test_ids[] ) ORDER BY test_class, message_id", array(
        ':test_ids[]' => $test_id_chunk,
      ))->fetchAll();
    if ($result_chunk) {
      $results = array_merge($results, $result_chunk);
    }
  }

  return $results;
}

/**
 * Display test results.
 */
function simpletest_script_open_browser() {
  global $test_ids;

  $connection = Database::getConnection('default', 'test-runner');
  $results = $connection->select('simpletest')
    ->fields('simpletest')
    ->condition('test_id', $test_ids, 'IN')
    ->orderBy('test_class')
    ->orderBy('message_id')
    ->execute()
    ->fetchAll();

  // Get the results form.
  $form = array();
  SimpletestResultsForm::addResultForm($form, $results);

  // Get the assets to make the details element collapsible and theme the result
  // form.
  $assets = new \Drupal\Core\Asset\AttachedAssets();
  $assets->setLibraries(['core/drupal.collapse', 'system/admin', 'simpletest/drupal.simpletest']);
  $resolver = \Drupal::service('asset.resolver');
  list($js_assets_header, $js_assets_footer) = $resolver->getJsAssets($assets, FALSE);
  $js_collection_renderer = \Drupal::service('asset.js.collection_renderer');
  $js_assets_header = $js_collection_renderer->render($js_assets_header);
  $js_assets_footer = $js_collection_renderer->render($js_assets_footer);
  $css_assets = \Drupal::service('asset.css.collection_renderer')->render($resolver->getCssAssets($assets, FALSE));

  // Make the html page to write to disk.
  $render_service = \Drupal::service('renderer');
  $html = '<head>' . $render_service->renderPlain($js_assets_header) . $render_service->renderPlain($css_assets) . '</head><body>' . $render_service->renderPlain($form) . $render_service->renderPlain($js_assets_footer) .'</body>';

  // Ensure we have assets verbose directory - tests with no verbose output will not
  // have created one.
  $directory = PublicStream::basePath() . '/simpletest/verbose';
  file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
  $uuid = new Php();
  $filename = $directory .'/results-'. $uuid->generate() .'.html';
  file_put_contents($filename, $html);

  // See if we can find an OS helper to open URLs in default browser.
  $browser = FALSE;
  if (shell_exec('which xdg-open')) {
    $browser = 'xdg-open';
  }
  elseif (shell_exec('which open')) {
    $browser = 'open';
  }
  elseif (substr(PHP_OS, 0, 3) == 'WIN') {
    $browser = 'start';
  }

  if ($browser) {
    shell_exec($browser . ' ' . escapeshellarg($filename));
  }
  else {
    // Can't find assets valid browser.
    print 'Open file://' . realpath($filename) . ' in your browser to see the verbose output.';
  }
}