1// Copyright 2006 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12// implied. See the License for the specific language governing
13// permissions and limitations under the License.
14/**
15 * @pageoverview Some logic for the jstemplates test pages.
16 *
17 * @author Steffen Meschkat (mesch@google.com)
18 */
19
20
21function elem(id) {
22  return document.getElementById(id);
23}
24
25/**
26 * Are we actively profiling JstProcessor?
27 * @type boolean
28 */
29var profiling = false;
30
31logHtml = function(html) {
32  elem('log').innerHTML += html + '<br/>';
33};
34
35
36/**
37 * Initializer for interactive test: copies the value from the actual
38 * template HTML into a text area to make the HTML source visible.
39 */
40function jsinit() {
41  elem('template').value = elem('tc').innerHTML;
42}
43
44
45/**
46 * Interactive test.
47 *
48 * @param {boolean} reprocess If true, reprocesses the output of the
49 * previous invocation.
50 */
51function jstest(reprocess) {
52  var jstext = elem('js').value;
53  var input = jsEval(jstext);
54  var t;
55  if (reprocess) {
56    t = elem('out');
57  } else {
58    elem('tc').innerHTML = elem('template').value;
59    t = jstGetTemplate('t');
60    elem('out').innerHTML = '';
61    elem('out').appendChild(t);
62  }
63  if (profiling) Profiler.reset();
64  jstProcess(new JsEvalContext(input), t);
65  if (profiling) Profiler.dump();
66  elem('html').value = elem('out').innerHTML;
67}
68
69
70/**
71 * Performance test: jst initial processing.
72 *
73 * @param {Object} data Test data to apply the template to.
74 */
75function perf1(data) {
76  elem('out').innerHTML = '';
77  var t = jstGetTemplate('t1');
78  elem('out').appendChild(t);
79  if (profiling) Profiler.reset();
80  jstProcess(new JsEvalContext(data), t);
81  if (profiling) Profiler.dump();
82}
83
84
85/**
86 * Performance test: jst reprocessing or previous processing output.
87 *
88 * @param {Object} data Test data to apply the template to.
89 */
90function perf1a(data) {
91  if (profiling) Profiler.reset();
92  jstProcess(new JsEvalContext(data), elemOrDie('out'));
93  if (profiling) Profiler.dump();
94}
95
96
97/**
98 * Performance test: jst initial processing, with display:none during
99 * processing.
100 *
101 * @param {Object} data Test data to apply the template to.
102 */
103function perf1b(data) {
104  var o = elem('out');
105  o.innerHTML = '';
106  var t = jstGetTemplate('t1');
107  o.appendChild(t);
108  displayNone(o);
109  if (profiling) Profiler.reset();
110  jstProcess(new JsEvalContext(data), t);
111  if (profiling) Profiler.dump();
112  displayDefault(o);
113}
114
115
116/**
117 * Performance test: create output procedurally as string and assign
118 * to innerHTML.
119 *
120 * @param {Object} data Test data to apply the template to.
121 */
122function perf2(data) {
123  var t = [];
124  t.push("<table><tr><th>item</th><th>label</th><th>address</th></tr>");
125  for (var i = 0; i < data.entries.length; ++i) {
126    var e = data.entries[i];
127    t.push("<tr><td>" + i + "</td><td>" + e.label + "</td><td>" +
128           e.address + "</td></tr>");
129  }
130  t.push("</table>");
131  elem("out").innerHTML = t.join('');
132}
133
134
135/**
136 * A test runner for a test. Does the timing. @constructor
137 *
138 * @param {number} times number of iterations the test is executed.
139 * @param {Function} test The test to execute.
140 * @param {Function} result Function will be called with the execution
141 * time as argument.
142 */
143function TestRun(times, test, result) {
144  this.count_ = 0;
145  this.times_ = times;
146  this.test_ = test;
147  this.result_ = result;
148  this.start_ = (new Date).valueOf();
149  this.run_();
150}
151
152
153/**
154 * Executes the test run.
155 */
156TestRun.prototype.run_ = function() {
157  if (this.count_ < this.times_) {
158    this.test_(this.count_);
159    this.count_ += 1;
160    objectSetTimeout(this, this.run_, 0);
161  } else {
162    this.stop_ = (new Date).valueOf();
163    this.result_(this.stop_ - this.start_);
164  }
165};
166
167
168/**
169 * Creates a testrun function for test count invocations of function
170 * f, whose runtime will be output to the element with is given in
171 * result.
172 *
173 * @param {Object} data The test data object.
174 * @param {Function} f
175 * @param {number} count
176 * @param {string} result
177*/
178function createTestRun(count, test) {
179  var data = {
180    entries: []
181  };
182  for (var i = 0; i < count; ++i) {
183    data.entries.push({ label: "label" + i, address: "address" + i });
184  }
185  // This function is passed to the TimeoutSequence, and receives the
186  // TimeoutSequence as argument on invocation.
187  return function(s) {
188    new TestRun(1, function(i) {
189      window[test](data);
190    }, function(time) {
191      elem(test + '-' + count).innerHTML = time + 'ms';
192      s.run();
193    });
194  };
195}
196
197/**
198 * Runs all tests the given number of times. Invoked from the HTML page.
199 *
200 * @param {number} count
201 */
202function jsperf(count) {
203  elemOrDie('log').innerHTML = '';
204  profiling = !!elemOrDie('profile').checked;
205  if (profiling && !JstProcessor.profiling_) {
206    JstProcessor.profiling_ = true;
207    Profiler.monitorAll(proto(JstProcessor), false);
208  }
209
210  var s = new TimeoutSequence(null, null, true);
211
212  s.add(createTestRun(count, "perf1"));
213  s.add(createTestRun(count, "perf1b"));
214  s.add(createTestRun(count, "perf1a"));
215  s.add(createTestRun(count, "perf2"));
216
217  s.run();
218}
219
220function run(test, count) {
221  var data = {
222    entries: []
223  };
224  for (var i = 0; i < count; ++i) {
225    data.entries.push({ label: "label" + i, address: "address" + i });
226  }
227  new TestRun(1, function() {
228    window[test](data);
229  }, function(time) {
230    elem(test + '-' + count).innerHTML = time + 'ms';
231  });
232}
233