1<!DOCTYPE html>
2<!--
3Copyright (c) 2014 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7<link rel="import" href="/tracing/base/guid.html">
8<link rel="import" href="/tracing/base/unittest/constants.html">
9<script>
10'use strict';
11
12tr.exportTo('tr.b.unittest', function() {
13  var TestTypes = tr.b.unittest.TestTypes;
14
15  function TestCase(name, opt_testFn, opt_options) {
16    if (!name)
17      throw new Error('Name must be provided');
18    this.guid_ = tr.b.GUID.allocate();
19    this.suite_ = undefined; // Set by TestSuite.addTest.
20    this.name_ = name;
21
22    if (opt_options)
23      this.options_ = opt_options;
24    else
25      this.options_ = {};
26
27    this.testFn_ = opt_testFn;
28  }
29
30  TestCase.parseFullyQualifiedName = function(fqn) {
31    var i = fqn.lastIndexOf('.');
32    if (i == -1)
33      throw new Error('FullyQualifiedNames must have a period in them');
34    return {
35      suiteName: fqn.substr(0, i),
36      testCaseName: fqn.substr(i + 1)
37    };
38  };
39
40  TestCase.prototype = {
41    __proto__: Object.prototype,
42
43    get guid() {
44      return this.guid_;
45    },
46
47    get suite() {
48      return this.suite_;
49    },
50
51    set suite(suite) {
52      if (this.suite_ !== undefined)
53        throw new Error('Suite can only be assigned once.');
54      this.suite_ = suite;
55    },
56
57    get testType() {
58      return TestTypes.UNITTEST;
59    },
60
61    get name() {
62      return this.name_;
63    },
64
65    get fullyQualifiedName() {
66      return this.suite_.name + '.' + this.name_;
67    },
68
69    get options() {
70      return this.options_;
71    },
72
73    setUp: function() {
74      if (this.options_.setUp)
75        this.options_.setUp.call(this);
76    },
77
78    run: function(htmlHook) {
79      return this.testFn_();
80    },
81
82    tearDown: function() {
83      if (this.options_.tearDown)
84        this.options_.tearDown.call(this);
85    },
86
87    // TODO(nduca): The routing of this is a bit awkward. Probably better
88    // to install a global function.
89    addHTMLOutput: function(element) {
90      tr.b.unittest.addHTMLOutputForCurrentTest(element);
91    }
92  };
93
94  function PerfTestCase(name, testFn, opt_options) {
95    TestCase.call(this, name, testFn, opt_options);
96    this.iterations = this.options.iterations || 10;
97  }
98
99  PerfTestCase.prototype = {
100    __proto__: TestCase.prototype,
101
102    get testType() {
103      return TestTypes.PERFTEST;
104    },
105
106    run: function() {
107      var durations = [];
108      var iterations = this.iterations;
109      for (var i = 0; i < iterations; ++i) {
110        var start = window.performance.now();
111        this.runOneIteration();
112        var duration = window.performance.now() - start;
113        durations.push(duration);
114      }
115
116      var durationStrings = durations.map(function(d) {
117        return d.toFixed(2) + 'ms';
118      });
119      var average = tr.b.Statistics.mean(durations);
120      var min = tr.b.Statistics.min(durations);
121
122      var summaryString = ' [';
123      summaryString += 'min ' + min.toFixed(2) + 'ms, ';
124      summaryString += 'avg ' + average.toFixed(2) + 'ms';
125      summaryString += ']';
126
127      return durationStrings.join(', ') + summaryString;
128    },
129
130    runOneIteration: function() {
131      this.testFn_();
132    }
133  };
134
135  return {
136    TestCase: TestCase,
137    PerfTestCase: PerfTestCase
138  };
139});
140</script>
141