summaryrefslogtreecommitdiffstatshomepage
path: root/core/lib/Drupal/Core/Test/JUnitConverter.php
blob: 8c1e817ba1ec603c637eec7df4fb557581e1bd98 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<?php

namespace Drupal\Core\Test;

use Drupal\TestTools\PhpUnitTestCaseJUnitResult;

/**
 * Converts JUnit XML to Drupal's {simpletest} schema.
 *
 * This is mainly for converting PHPUnit test results.
 *
 * This class is @internal and not considered to be API.
 */
class JUnitConverter {

  /**
   * Converts PHPUnit's JUnit XML output file to {simpletest} schema.
   *
   * @param int $test_id
   *   The current test ID.
   * @param string $phpunit_xml_file
   *   Path to the PHPUnit XML file.
   *
   * @return array[]
   *   The results as array of rows in a format that can be inserted into the
   *   {simpletest} table of the results database.
   *
   * @internal
   */
  public static function xmlToRows($test_id, $phpunit_xml_file) {
    $contents = @file_get_contents($phpunit_xml_file);
    if (!$contents) {
      return [];
    }
    return static::xmlElementToRows($test_id, new \SimpleXMLElement($contents));
  }

  /**
   * Parse test cases from XML to {simpletest} schema.
   *
   * @param int $test_id
   *   The current test ID.
   * @param \SimpleXMLElement $element
   *   The XML data from the JUnit file.
   *
   * @return array[]
   *   The results as array of rows in a format that can be inserted into the
   *   {simpletest} table of the results database.
   *
   * @internal
   */
  public static function xmlElementToRows($test_id, \SimpleXMLElement $element) {
    $records = [];
    $test_cases = static::findTestCases($element);
    foreach ($test_cases as $test_case) {
      $records[] = static::convertTestCaseToSimpletestRow($test_id, $test_case);
    }
    return $records;
  }

  /**
   * Finds all test cases recursively from a test suite list.
   *
   * @param \SimpleXMLElement $element
   *   The PHPUnit xml to search for test cases.
   * @param \SimpleXMLElement $parent
   *   (Optional) The parent of the current element. Defaults to NULL.
   *
   * @return array
   *   A list of all test cases.
   *
   * @internal
   */
  public static function findTestCases(\SimpleXMLElement $element, ?\SimpleXMLElement $parent = NULL): array {
    if ($element->getName() === 'testcase') {
      return [$element];
    }

    $test_cases = [];
    foreach ($element as $child) {
      $test_cases[] = static::findTestCases($child, $element);
    }

    return array_merge(...$test_cases);
  }

  /**
   * Converts a PHPUnit test case result to a {simpletest} result row.
   *
   * @param int $test_id
   *   The current test ID.
   * @param \SimpleXMLElement $test_case
   *   The PHPUnit test case represented as XML element.
   *
   * @return array
   *   An array containing the {simpletest} result row.
   *
   * @internal
   */
  public static function convertTestCaseToSimpletestRow($test_id, \SimpleXMLElement $test_case): array {
    $status = static::getTestCaseResult($test_case);
    $attributes = $test_case->attributes();

    $message = match ($status) {
      PhpUnitTestCaseJUnitResult::Fail => (string) $test_case->failure[0],
      PhpUnitTestCaseJUnitResult::Error => (string) $test_case->error[0],
      default => '',
    };

    return [
      'test_id' => $test_id,
      'test_class' => (string) $attributes->class,
      'status' => $status->value,
      'message' => $message,
      'message_group' => 'Other',
      'function' => $attributes->name,
      'line' => (int) $attributes->line ?: 0,
      'file' => (string) $attributes->file,
      'time' => (float) $attributes->time,
    ];
  }

  /**
   * Determine a status string for the given testcase.
   *
   * @param \SimpleXMLElement $test_case
   *   The test case XML element.
   *
   * @return \Drupal\TestTools\PhpUnitTestCaseJUnitResult
   *   The status value to insert into the {simpletest} record.
   */
  protected static function getTestCaseResult(\SimpleXMLElement $test_case): PhpUnitTestCaseJUnitResult {
    if ($test_case->error) {
      return PhpUnitTestCaseJUnitResult::Error;
    }
    if ($test_case->failure) {
      return PhpUnitTestCaseJUnitResult::Fail;
    }
    if ($test_case->skipped) {
      return PhpUnitTestCaseJUnitResult::Skip;
    }
    return PhpUnitTestCaseJUnitResult::Pass;
  }

}