<?php

final class ArcanistEmberTestEngine extends ArcanistUnitTestEngine {
  protected $projectRoot;

  /**
   * Main entry point for the test engine.
   *
   * @return array   Array of test results.
   */
  public function run() {
    $this->projectRoot = $this->getWorkingCopy()->getProjectRoot();

    $folder = Filesystem::resolvePath($this->projectRoot);
    $filename = $folder.'/test-results.xml';

    // ensure that we are not operating on a stale build result
    if (file_exists($filename)) {
      unlink($filename);
    }

    putenv("CI=true");
    $future = new ExecFuture("ember test");
    list($exitCode, $stdout, $stderr) = $future->resolve();

    // if the test run exits with a 1 because of a failed test we want to continue
    // to process the test results, otherwise print stdout/stderr to aid in debugging
    if ($exitCode !== 0 && !file_exists($filename)) {
      throw new ArcanistUsageException(
        "'ember test' exited with an error.\n".
          "stdout:\n\n{$stdout}".
          "stderr:\n\n{$stderr}");
    }

    $results = $this->parseTestResult($filename);

    return $results;
  }

  /**
   * Parses the test results from xUnit.
   *
   * Originally from https://github.com/phacility/arcanist/blob/086f5399bfbb65513b1b0e2c5371522202a9beb7/src/unit/engine/XUnitTestEngine.php#L415
   * with a number of changes now...
   *
   * @param  string  The name of the xUnit results file.
   * @return array   Test results.
   */
  private function parseTestResult($xunit_tmp) {
    $xunit_dom = new DOMDocument();
    $xunit_dom->loadXML(Filesystem::readFile($xunit_tmp));
    $results = array();
    $tests = $xunit_dom->getElementsByTagName('testcase');
    foreach ($tests as $test) {
      $userdata = '';
      $name = $test->getAttribute('name');
      $time = $test->getAttribute('time');
      $reason = $test->getElementsByTagName('reason');
      $failure = $test->getElementsByTagName('failure');
      $error = $test->getElementsByTagName('error');
      $skip = $test->getElementsByTagName('skipped');

      if ($failure->length > 0 || $error->length > 0) {
        $status = ArcanistUnitTestResult::RESULT_FAIL;
      } elseif ($skip->length > 0) {
        $status = ArcanistUnitTestResult::RESULT_SKIP;
      } else {
        $status = ArcanistUnitTestResult::RESULT_PASS;
      }

      $result = new ArcanistUnitTestResult();
      $result->setName($name);
      $result->setResult($status);
      $result->setDuration(floatval($time));

      $results[] = $result;
    }
    return $results;
  }
}
