function UnitTestReporter(env, filter, activeSuite) {
        var self = this;

        this.activeSuite = activeSuite;

        this.runInfo = {
            app: brackets.metadata.name,
            version: brackets.metadata.version,
            platform: brackets.platform
        };
        BuildInfoUtils.getBracketsSHA().done(function (branch, sha) {
            self.runInfo.branch = branch;
            self.runInfo.sha = sha;
        });

        // _topLevelFilter is applied first - selects Performance vs. Unit test suites
        this._topLevelFilter = filter;

        // Jasmine's runner uses the specFilter to choose which tests to run.
        // If you selected an option other than "All" this will be a subset of all tests loaded.
        env.specFilter = this._createSpecFilter(this.activeSuite);

        this.suites = {};
        this.passed = false;

        this.totalSpecCount = 0;
        this.totalPassedCount = 0;
        this.totalFailedCount = 0;
        env.currentRunner().topLevelSuites().forEach(function (suite) {
            var specCount = self._countSpecs(suite, filter);
            self.suites[suite.getFullName()] = {
                id: suite.id,
                name: suite.getFullName(),
                specCount: specCount,
                passedCount: 0,
                failedCount: 0,
                specs: []
            };
            self.totalSpecCount += specCount;
        });

        this.sortedNames = Object.keys(this.suites).sort(function (a, b) {
            a = a.toLowerCase();
            b = b.toLowerCase();
            if (a < b) {
                return -1;
            } else if (a > b) {
                return 1;
            }
            return 0;
        });

        this.activeSpecCount = 0;
        this.activeSpecCompleteCount = 0;

        env.currentRunner().specs().forEach(function (spec, index) {
            if (env.specFilter(spec)) {
                self.activeSpecCount++;
            }
        });
    }
@constructor
Creates a UnitTestReporter object. This has a number public properties:

suites - an object with entries for each top-level suite; each value is an object containing:
   name - the full name of the suite
   specCount - number of specs in the suite and its descendants
   passedCount - number of passed specs in the suite and its descendants
   failedCount - number of failed specs in the suite and its descendants
   specs - an array of results for each spec; each result is an object containing:
       name - the full name of the spec
       passed - true if the spec passed, false otherwise
       messages - if defined, an array of message objects for the failed spec
       perf - if defined, the performance record for the spec

passed - true if all specs passed, false otherwise
sortedNames - a sorted list of suite names (including all the keys in the suites object except All).
activeSuite - the suite currently selected in the URL params, "all" if all are being run, and null if no tests are being run.
activeSpecCount - the number of specs that will actually be run given the current filter
activeSpecCompleteCount - the number of specs that have been run so far
totalSpecCount - the total number of specs (ignoring filter)
totalPassedCount - the total number of specs passed across all suites
totalFailedCount - the total number of specs failed across all suites

runInfo - an object containing info about the current run:
    app - name of the app
    version - version number
    branch - branch the current build is running on
    sha - sha of the current build
    platform - platform of the current run
    startTime - time the run was started
    endTime - time the run finished

@param {!Object} env The Jasmine environment we're running in.
@param {Function} filter The filter being used to determine whether a given spec is run or not.
@param {string} activeSuite The suite currently selected in the URL params, or null if all are being run.