summaryrefslogtreecommitdiffstats
path: root/tools/code-coverage/PerTestCoverageUtils.jsm
blob: ed50e1245ec5edf3152b73b4dc51b44408142a46 (plain)
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
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* exported PerTestCoverageUtils */

"use strict";

var EXPORTED_SYMBOLS = ["PerTestCoverageUtils"];

const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");

const env = Cc["@mozilla.org/process/environment;1"].getService(
  Ci.nsIEnvironment
);
// This is the directory where gcov is emitting the gcda files.
const gcovPrefixPath = env.get("GCOV_PREFIX");
// This is the directory where codecoverage.py is expecting to see the gcda files.
const gcovResultsPath = env.get("GCOV_RESULTS_DIR");
// This is the directory where the JS engine is emitting the lcov files.
const jsvmPrefixPath = env.get("JS_CODE_COVERAGE_OUTPUT_DIR");
// This is the directory where codecoverage.py is expecting to see the lcov files.
const jsvmResultsPath = env.get("JSVM_RESULTS_DIR");

const gcovPrefixDir = Cc["@mozilla.org/file/local;1"].createInstance(
  Ci.nsIFile
);
if (gcovPrefixPath) {
  gcovPrefixDir.initWithPath(gcovPrefixPath);
}

let gcovResultsDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
if (gcovResultsPath) {
  gcovResultsDir.initWithPath(gcovResultsPath);
}

const jsvmPrefixDir = Cc["@mozilla.org/file/local;1"].createInstance(
  Ci.nsIFile
);
if (jsvmPrefixPath) {
  jsvmPrefixDir.initWithPath(jsvmPrefixPath);
}

let jsvmResultsDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
if (jsvmResultsPath) {
  jsvmResultsDir.initWithPath(jsvmResultsPath);
}

function awaitPromise(promise) {
  let ret;
  let complete = false;
  let error = null;
  promise
    .catch(e => (error = e))
    .then(v => {
      ret = v;
      complete = true;
    });
  Services.tm.spinEventLoopUntil(() => complete);
  if (error) {
    throw new Error(error);
  }
  return ret;
}

function removeDirectoryContents(dir) {
  let entries = dir.directoryEntries;
  while (entries.hasMoreElements()) {
    entries.nextFile.remove(true);
  }
}

function moveDirectoryContents(src, dst) {
  let entries = src.directoryEntries;
  while (entries.hasMoreElements()) {
    entries.nextFile.moveTo(dst, null);
  }
}

var PerTestCoverageUtils = class PerTestCoverageUtilsClass {
  // Resets the counters to 0.
  static async beforeTest() {
    if (!PerTestCoverageUtils.enabled) {
      return;
    }

    // Flush the counters.
    let codeCoverageService = Cc[
      "@mozilla.org/tools/code-coverage;1"
    ].getService(Ci.nsICodeCoverage);
    await codeCoverageService.flushCounters();

    // Remove coverage files created by the flush, and those that might have been created between the end of a previous test and the beginning of the next one (e.g. some tests can create a new content process for every sub-test).
    removeDirectoryContents(gcovPrefixDir);
    removeDirectoryContents(jsvmPrefixDir);

    // Move coverage files from the GCOV_RESULTS_DIR and JSVM_RESULTS_DIR directories, so we can accumulate the counters.
    moveDirectoryContents(gcovResultsDir, gcovPrefixDir);
    moveDirectoryContents(jsvmResultsDir, jsvmPrefixDir);
  }

  static beforeTestSync() {
    awaitPromise(this.beforeTest());
  }

  // Dumps counters and moves the gcda files in the directory expected by codecoverage.py.
  static async afterTest() {
    if (!PerTestCoverageUtils.enabled) {
      return;
    }

    // Flush the counters.
    let codeCoverageService = Cc[
      "@mozilla.org/tools/code-coverage;1"
    ].getService(Ci.nsICodeCoverage);
    await codeCoverageService.flushCounters();

    // Move the coverage files in GCOV_RESULTS_DIR and JSVM_RESULTS_DIR, so that the execution from now to shutdown (or next test) is not counted.
    moveDirectoryContents(gcovPrefixDir, gcovResultsDir);
    moveDirectoryContents(jsvmPrefixDir, jsvmResultsDir);
  }

  static afterTestSync() {
    awaitPromise(this.afterTest());
  }
};

PerTestCoverageUtils.enabled = !!gcovResultsPath;