| OLD | NEW |
| (Empty) |
| 1 library dromaeo_test; | |
| 2 | |
| 3 import 'dart:html'; | |
| 4 import 'dart:async'; | |
| 5 import "dart:convert"; | |
| 6 import 'dart:math' as Math; | |
| 7 import 'Suites.dart'; | |
| 8 | |
| 9 main() { | |
| 10 new Dromaeo().run(); | |
| 11 } | |
| 12 | |
| 13 class SuiteController { | |
| 14 final SuiteDescription _suiteDescription; | |
| 15 final IFrameElement _suiteIframe; | |
| 16 | |
| 17 DivElement _element; | |
| 18 double _meanProduct; | |
| 19 int _nTests; | |
| 20 | |
| 21 SuiteController(this._suiteDescription, this._suiteIframe) | |
| 22 : _meanProduct = 1.0, | |
| 23 _nTests = 0 { | |
| 24 _make(); | |
| 25 _init(); | |
| 26 } | |
| 27 | |
| 28 start() { | |
| 29 _suiteIframe.contentWindow.postMessage('start', '*'); | |
| 30 } | |
| 31 | |
| 32 update(String testName, num mean, num error, double percent) { | |
| 33 _meanProduct *= mean; | |
| 34 _nTests++; | |
| 35 | |
| 36 final meanAsString = mean.toStringAsFixed(2); | |
| 37 final errorAsString = error.toStringAsFixed(2); | |
| 38 final Element progressDisplay = _element.nextNode.nextNode; | |
| 39 progressDisplay.innerHtml = | |
| 40 '${progressDisplay.innerHtml}<li><b>${testName}:</b>' | |
| 41 '${meanAsString}<small> runs/s ±${errorAsString}%<small></li>'; | |
| 42 _updateTestPos(percent); | |
| 43 } | |
| 44 | |
| 45 _make() { | |
| 46 _element = _createDiv('test'); | |
| 47 // TODO(antonm): add an onclick functionality. | |
| 48 _updateTestPos(); | |
| 49 } | |
| 50 | |
| 51 _updateTestPos([double percent = 1.0]) { | |
| 52 String suiteName = _suiteDescription.name; | |
| 53 final done = percent >= 100.0; | |
| 54 String info = ''; | |
| 55 if (done) { | |
| 56 final parent = _element.parent; | |
| 57 parent.attributes['class'] = '${parent.attributes["class"]} done'; | |
| 58 final mean = Math.pow(_meanProduct, 1.0 / _nTests).toStringAsFixed(2); | |
| 59 info = '<span>${mean} runs/s</span>'; | |
| 60 } | |
| 61 _element.innerHtml = | |
| 62 '<b>${suiteName}:</b>' | |
| 63 '<div class="bar"><div style="width:${percent}%;">${info}</div></div>'; | |
| 64 } | |
| 65 | |
| 66 _init() { | |
| 67 final div = _createDiv('result-item'); | |
| 68 div.nodes.add(_element); | |
| 69 final description = _suiteDescription.description; | |
| 70 final originUrl = _suiteDescription.origin.url; | |
| 71 final testUrl = '${_suiteDescription.file}'; | |
| 72 div.innerHtml = | |
| 73 '${div.innerHtml}<p>${description}<br/><a href="${originUrl}">Origin</a' | |
| 74 '>, <a href="${testUrl}">Source</a>' | |
| 75 '<ol class="results"></ol>'; | |
| 76 // Reread the element, as the previous wrapper get disconnected thanks | |
| 77 // to .innerHtml update above. | |
| 78 _element = div.nodes[0]; | |
| 79 | |
| 80 document.querySelector('#main').nodes.add(div); | |
| 81 } | |
| 82 | |
| 83 DivElement _createDiv(String clazz) { | |
| 84 final div = new DivElement(); | |
| 85 div.attributes['class'] = clazz; | |
| 86 return div; | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 class Dromaeo { | |
| 91 final List<SuiteController> _suiteControllers; | |
| 92 Function _handler; | |
| 93 | |
| 94 Dromaeo() | |
| 95 : _suiteControllers = new List<SuiteController>() | |
| 96 { | |
| 97 _handler = _createHandler(); | |
| 98 window.onMessage.listen( | |
| 99 (MessageEvent event) { | |
| 100 try { | |
| 101 final response = JSON.decode(event.data); | |
| 102 _handler = _handler(response['command'], response['data']); | |
| 103 } catch (e, stacktrace) { | |
| 104 if (!(e is FormatException && | |
| 105 (event.data.toString().startsWith('unittest') || | |
| 106 event.data.toString().startsWith('dart')))) { | |
| 107 // Hack because unittest also uses post messages to communicate. | |
| 108 // So the fact that the event.data is not proper json is not | |
| 109 // always an error. | |
| 110 print('Exception: ${e}: ${stacktrace}'); | |
| 111 print(event.data); | |
| 112 } | |
| 113 } | |
| 114 }); | |
| 115 } | |
| 116 | |
| 117 run() { | |
| 118 // TODO(vsm): Initial page should not run. For now, run all | |
| 119 // tests by default. | |
| 120 var tags = window.location.search; | |
| 121 if (tags.length > 1) { | |
| 122 tags = tags.substring(1); | |
| 123 } else if (window.navigator.userAgent.contains('(Dart)')) { | |
| 124 // TODO(vsm): Update when we change Dart VM detection. | |
| 125 tags = 'js|dart&html'; | |
| 126 } else { | |
| 127 tags = 'js|dart2js&html'; | |
| 128 } | |
| 129 | |
| 130 // TODO(antonm): create Re-run tests href. | |
| 131 final Element suiteNameElement = _byId('overview').nodes[0]; | |
| 132 final category = Suites.getCategory(tags); | |
| 133 if (category != null) { | |
| 134 suiteNameElement.innerHtml = category; | |
| 135 } | |
| 136 _css(_byId('tests'), 'display', 'none'); | |
| 137 for (SuiteDescription suite in Suites.getSuites(tags)) { | |
| 138 final iframe = new IFrameElement(); | |
| 139 _css(iframe, 'height', '1px'); | |
| 140 _css(iframe, 'width', '1px'); | |
| 141 iframe.src = '${suite.file}'; | |
| 142 document.body.nodes.add(iframe); | |
| 143 | |
| 144 _suiteControllers.add(new SuiteController(suite, iframe)); | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 static const double _SECS_PER_TEST = 5.0; | |
| 149 | |
| 150 Function _createHandler() { | |
| 151 int suitesLoaded = 0; | |
| 152 int totalTests = 0; | |
| 153 int currentSuite; | |
| 154 double totalTimeSecs, estimatedTimeSecs; | |
| 155 | |
| 156 // TODO(jat): Remove void type below. Bug 5269037. | |
| 157 void _updateTime() { | |
| 158 final mins = (estimatedTimeSecs / 60).floor(); | |
| 159 final secs = (estimatedTimeSecs - mins * 60).round(); | |
| 160 final secsAsString = '${(secs < 10 ? "0" : "")}$secs'; | |
| 161 _byId('left').innerHtml = '${mins}:${secsAsString}'; | |
| 162 | |
| 163 final elapsed = totalTimeSecs - estimatedTimeSecs; | |
| 164 final percent = (100 * elapsed / totalTimeSecs).toStringAsFixed(2); | |
| 165 _css(_byId('timebar'), 'width', '${percent}%'); | |
| 166 } | |
| 167 | |
| 168 Function loading, running, done; | |
| 169 | |
| 170 loading = (String command, var data) { | |
| 171 assert(command == 'inited'); | |
| 172 suitesLoaded++; | |
| 173 totalTests += data['nTests']; | |
| 174 if (suitesLoaded == _suitesTotal) { | |
| 175 totalTimeSecs = estimatedTimeSecs = _SECS_PER_TEST * totalTests; | |
| 176 _updateTime(); | |
| 177 currentSuite = 0; | |
| 178 _suiteControllers[currentSuite].start(); | |
| 179 return running; | |
| 180 } | |
| 181 | |
| 182 return loading; | |
| 183 }; | |
| 184 | |
| 185 running = (String command, var data) { | |
| 186 switch (command) { | |
| 187 case 'result': | |
| 188 final testName = data['testName']; | |
| 189 final mean = data['mean']; | |
| 190 final error = data['error']; | |
| 191 final percent = data['percent']; | |
| 192 _suiteControllers[currentSuite].update(testName, mean, error, percent)
; | |
| 193 estimatedTimeSecs -= _SECS_PER_TEST; | |
| 194 _updateTime(); | |
| 195 return running; | |
| 196 | |
| 197 case 'over': | |
| 198 currentSuite++; | |
| 199 if (currentSuite < _suitesTotal) { | |
| 200 _suiteControllers[currentSuite].start(); | |
| 201 return running; | |
| 202 } | |
| 203 document.body.attributes['class'] = 'alldone'; | |
| 204 return done; | |
| 205 | |
| 206 default: | |
| 207 throw 'Unknown command ${command} [${data}]'; | |
| 208 } | |
| 209 }; | |
| 210 | |
| 211 done = (String command, var data) { | |
| 212 }; | |
| 213 | |
| 214 return loading; | |
| 215 } | |
| 216 | |
| 217 _css(Element element, String property, String value) { | |
| 218 // TODO(antonm): remove the last argument when CallWithDefaultValue | |
| 219 // is implemented. | |
| 220 element.style.setProperty(property, value, ''); | |
| 221 } | |
| 222 | |
| 223 Element _byId(String id) { | |
| 224 return document.querySelector('#$id'); | |
| 225 } | |
| 226 | |
| 227 int get _suitesTotal { | |
| 228 return _suiteControllers.length; | |
| 229 } | |
| 230 } | |
| OLD | NEW |