~ubuntu-branches/ubuntu/wily/phabricator/wily

« back to all changes in this revision

Viewing changes to src/unit/engine/PytestTestEngine.php

  • Committer: Package Import Robot
  • Author(s): Richard Sellam
  • Date: 2014-11-01 23:20:06 UTC
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: package-import@ubuntu.com-20141101232006-mvlnp0cil67tsboe
Tags: upstream-0~git20141101/arcanist
Import upstream version 0~git20141101, component arcanist

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
/**
 
4
 * Very basic 'py.test' unit test engine wrapper.
 
5
 */
 
6
final class PytestTestEngine extends ArcanistUnitTestEngine {
 
7
 
 
8
  public function run() {
 
9
    $working_copy = $this->getWorkingCopy();
 
10
    $this->project_root = $working_copy->getProjectRoot();
 
11
 
 
12
    $junit_tmp = new TempFile();
 
13
    $cover_tmp = new TempFile();
 
14
 
 
15
    $future = $this->buildTestFuture($junit_tmp, $cover_tmp);
 
16
    $future->resolvex();
 
17
 
 
18
    $future = new ExecFuture('coverage xml -o %s', $cover_tmp);
 
19
    $future->setCWD($this->project_root);
 
20
    $future->resolvex();
 
21
 
 
22
    return $this->parseTestResults($junit_tmp, $cover_tmp);
 
23
  }
 
24
 
 
25
  public function buildTestFuture($junit_tmp, $cover_tmp) {
 
26
    $paths = $this->getPaths();
 
27
 
 
28
    $cmd_line = csprintf('py.test --junit-xml=%s', $junit_tmp);
 
29
 
 
30
    if ($this->getEnableCoverage() !== false) {
 
31
      $cmd_line = csprintf(
 
32
        'coverage run --source %s -m %C',
 
33
        $this->project_root,
 
34
        $cmd_line);
 
35
    }
 
36
 
 
37
    return new ExecFuture('%C', $cmd_line);
 
38
  }
 
39
 
 
40
  public function parseTestResults($junit_tmp, $cover_tmp) {
 
41
    $parser = new ArcanistXUnitTestResultParser();
 
42
    $results = $parser->parseTestResults(
 
43
      Filesystem::readFile($junit_tmp));
 
44
 
 
45
    if ($this->getEnableCoverage() !== false) {
 
46
      $coverage_report = $this->readCoverage($cover_tmp);
 
47
      foreach ($results as $result) {
 
48
          $result->setCoverage($coverage_report);
 
49
      }
 
50
    }
 
51
 
 
52
    return $results;
 
53
  }
 
54
 
 
55
  public function readCoverage($path) {
 
56
    $coverage_data = Filesystem::readFile($path);
 
57
    if (empty($coverage_data)) {
 
58
       return array();
 
59
    }
 
60
 
 
61
    $coverage_dom = new DOMDocument();
 
62
    $coverage_dom->loadXML($coverage_data);
 
63
 
 
64
    $paths = $this->getPaths();
 
65
    $reports = array();
 
66
    $classes = $coverage_dom->getElementsByTagName('class');
 
67
 
 
68
    foreach ($classes as $class) {
 
69
      // filename is actually python module path with ".py" at the end,
 
70
      // e.g.: tornado.web.py
 
71
      $relative_path = explode('.', $class->getAttribute('filename'));
 
72
      array_pop($relative_path);
 
73
      $relative_path = implode('/', $relative_path);
 
74
 
 
75
      // first we check if the path is a directory (a Python package), if it is
 
76
      // set relative and absolute paths to have __init__.py at the end.
 
77
      $absolute_path = Filesystem::resolvePath($relative_path);
 
78
      if (is_dir($absolute_path)) {
 
79
        $relative_path .= '/__init__.py';
 
80
        $absolute_path .= '/__init__.py';
 
81
      }
 
82
 
 
83
      // then we check if the path with ".py" at the end is file (a Python
 
84
      // submodule), if it is - set relative and absolute paths to have
 
85
      // ".py" at the end.
 
86
      if (is_file($absolute_path.'.py')) {
 
87
        $relative_path .= '.py';
 
88
        $absolute_path .= '.py';
 
89
      }
 
90
 
 
91
      if (!file_exists($absolute_path)) {
 
92
        continue;
 
93
      }
 
94
 
 
95
      if (!in_array($relative_path, $paths)) {
 
96
        continue;
 
97
      }
 
98
 
 
99
      // get total line count in file
 
100
      $line_count = count(file($absolute_path));
 
101
 
 
102
      $coverage = '';
 
103
      $start_line = 1;
 
104
      $lines = $class->getElementsByTagName('line');
 
105
      for ($ii = 0; $ii < $lines->length; $ii++) {
 
106
        $line = $lines->item($ii);
 
107
 
 
108
        $next_line = intval($line->getAttribute('number'));
 
109
        for ($start_line; $start_line < $next_line; $start_line++) {
 
110
            $coverage .= 'N';
 
111
        }
 
112
 
 
113
        if (intval($line->getAttribute('hits')) == 0) {
 
114
            $coverage .= 'U';
 
115
        }
 
116
        else if (intval($line->getAttribute('hits')) > 0) {
 
117
            $coverage .= 'C';
 
118
        }
 
119
 
 
120
        $start_line++;
 
121
      }
 
122
 
 
123
      if ($start_line < $line_count) {
 
124
        foreach (range($start_line, $line_count) as $line_num) {
 
125
          $coverage .= 'N';
 
126
        }
 
127
      }
 
128
 
 
129
      $reports[$relative_path] = $coverage;
 
130
    }
 
131
 
 
132
    return $reports;
 
133
  }
 
134
 
 
135
}