Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 #library('dartest'); | |
| 6 | |
| 7 #import('dart:dom'); | |
| 8 #import('../unittest/unittest_dartest.dart'); | |
| 9 | |
| 10 #source('css.dart'); | |
| 11 | |
| 12 /** DARTest provides a library to run tests in the app. */ | |
| 13 class DARTest{ | |
| 14 Map<String, HTMLElement> _inAppElements, _fullAppElements, _appElements; | |
| 15 DOMWindow _runnerWindow; | |
| 16 | |
| 17 DARTest() { | |
| 18 _runnerWindow = window; | |
| 19 dartestLogger = _log; | |
| 20 _inAppElements = new HashMap<String, HTMLElement>(); | |
| 21 _appElements = _inAppElements; | |
| 22 DARTestCss.inject(document, true); | |
| 23 } | |
| 24 | |
| 25 void run() { | |
| 26 _renderMain(); | |
| 27 _createResultsTable(); | |
| 28 } | |
| 29 | |
| 30 void _log(String message) { | |
| 31 _runnerWindow.console.log(message); | |
| 32 } | |
| 33 | |
| 34 void _addChildToElem(String key, HTMLElement child) { | |
| 35 if(_appElements[key] != null) { | |
| 36 _appElements[key].appendChild(child); | |
| 37 } | |
| 38 } | |
| 39 | |
| 40 /** Create the results table after loading tests. */ | |
| 41 void _createResultsTable() { | |
| 42 _log('Creating results table'); | |
| 43 HTMLTableElement table = _runnerWindow.document.createElement('table'); | |
| 44 table.className = 'dt-results'; | |
| 45 HTMLTableSectionElement head = _runnerWindow.document.createElement('thead') ; | |
| 46 head.innerHTML = '<tr><th>ID <th>Description <th>Result'; | |
| 47 table.appendChild(head); | |
| 48 | |
| 49 HTMLTableSectionElement body = _runnerWindow.document.createElement('tbody') ; | |
| 50 body.id = 'dt-results-body'; | |
| 51 tests.forEach((final t) { | |
| 52 HTMLTableRowElement testDetailRow = _runnerWindow.document.createElement(' tr'); | |
| 53 testDetailRow.id = 'dt-test-${t.id}'; | |
| 54 _addTestDetails(t, testDetailRow); | |
| 55 body.appendChild(testDetailRow); | |
| 56 | |
| 57 HTMLTableRowElement testMessageRow = _runnerWindow.document.createElement( 'tr'); | |
| 58 testMessageRow.id = 'dt-detail-${t.id}'; | |
| 59 testMessageRow.className = 'dt-hide'; | |
| 60 body.appendChild(testMessageRow); | |
| 61 }); | |
| 62 | |
| 63 table.appendChild(body); | |
| 64 _addChildToElem('testBody', table); | |
| 65 } | |
| 66 | |
| 67 /** Update the results table for test. */ | |
| 68 void _updateResultsTable(TestCase t, DOMWindow domWin) { | |
| 69 HTMLTableRowElement row = domWin.document.getElementById('dt-test-${t.id}'); | |
| 70 row.className = 'dt-result-row'; | |
| 71 row.innerHTML = ''; // Remove all children as we will re-populate them | |
| 72 _addTestDetails(t, row); | |
| 73 | |
| 74 HTMLTableRowElement details = | |
| 75 domWin.document.getElementById('dt-detail-${t.id}'); | |
| 76 details.appendChild(_getTestStats(t, domWin)); | |
| 77 | |
| 78 row.addEventListener('click', (Event e) { | |
| 79 if(details.className == 'dt-hide') { | |
| 80 details.className = ''; | |
| 81 } else { | |
| 82 details.className = 'dt-hide'; | |
| 83 } | |
| 84 }, true); | |
| 85 } | |
| 86 | |
| 87 /** Escape HTML special chars. */ | |
| 88 String _escape(String str) { | |
| 89 str = str.replaceAll('&','&'); | |
| 90 str = str.replaceAll('<','<'); | |
| 91 str = str.replaceAll('>','>'); | |
| 92 str = str.replaceAll('"','"'); | |
| 93 str = str.replaceAll("'",'''); | |
| 94 str = str.replaceAll('/','/'); | |
| 95 return str; | |
| 96 } | |
| 97 | |
| 98 /** Get test results as table cells. */ | |
| 99 void _addTestDetails(TestCase t, HTMLTableRowElement row) { | |
| 100 | |
|
pdr
2011/12/16 17:00:50
Extra space
shauvik
2011/12/16 17:57:06
Done.
| |
| 101 HTMLTableCellElement testId = _runnerWindow.document.createElement('td'); | |
| 102 testId.textContent = t.id; | |
| 103 row.appendChild(testId); | |
| 104 | |
| 105 HTMLTableCellElement testDesc = _runnerWindow.document.createElement('td'); | |
| 106 testDesc.textContent = t.description; | |
| 107 row.appendChild(testDesc); | |
| 108 | |
| 109 HTMLTableCellElement testResult = _runnerWindow.document.createElement('td') ; | |
| 110 String result = (t.result == null) ? 'none' : _escape(t.result); | |
| 111 testResult.className = 'dt-$result'; | |
| 112 testResult.title = '${_escape(t.message)}'; | |
| 113 testResult.textContent = result.toUpperCase(); | |
| 114 row.appendChild(testResult); | |
| 115 } | |
| 116 | |
| 117 HTMLTableCellElement _getTestStats(TestCase t, DOMWindow domWin) { | |
| 118 HTMLTableCellElement tableCell = domWin.document.createElement('td'); | |
| 119 tableCell.colSpan = 3; | |
| 120 | |
| 121 if(t.message != '') { | |
| 122 HTMLSpanElement messageSpan = domWin.document.createElement('span'); | |
| 123 messageSpan.textContent = t.message; | |
| 124 tableCell.appendChild(messageSpan); | |
| 125 tableCell.appendChild(domWin.document.createElement('br')); | |
| 126 } | |
| 127 if(t.stackTrace != null) { | |
| 128 HTMLPreElement stackTacePre = domWin.document.createElement('pre'); | |
| 129 stackTacePre.textContent = t.stackTrace; | |
| 130 } | |
| 131 | |
| 132 HTMLSpanElement durationSpan = domWin.document.createElement('span'); | |
| 133 durationSpan.textContent = 'took ${_printDuration(t.runningTime)}'; | |
| 134 tableCell.appendChild(durationSpan); | |
| 135 | |
| 136 return tableCell; | |
| 137 } | |
| 138 | |
| 139 /** Update the UI after running test. */ | |
| 140 void _updateDARTestUI(TestCase test) { | |
| 141 _updateResultsTable(test, window); | |
| 142 if(_runnerWindow != window) { | |
| 143 _updateResultsTable(test, _runnerWindow); | |
| 144 } | |
| 145 | |
| 146 if(test.result != null) { | |
| 147 _log(' Result: ${test.result.toUpperCase()} ${test.message}'); | |
| 148 } | |
| 149 if(test.runningTime != null) { | |
| 150 _log(' took ${_printDuration(test.runningTime)}'); | |
| 151 } | |
| 152 _updateStatusProgress(_appElements); | |
| 153 if(_runnerWindow != window) { | |
| 154 _updateStatusProgress(_inAppElements); | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 void _updateStatusProgress(Map<String, HTMLElement> elements) { | |
| 159 // Update progressbar | |
| 160 var pPass = | |
| 161 ((testsRun - testsFailed - testsErrors) / tests.length) * 100; | |
| 162 elements['green'].setAttribute('style', 'width:$pPass%'); | |
| 163 var pFailed = pPass + (testsFailed / tests.length) * 100; | |
| 164 elements['red'].setAttribute('style', 'width:$pFailed%'); | |
| 165 var pErrors = pFailed + (testsErrors / tests.length) * 100; | |
| 166 elements['orange'].setAttribute('style', 'width:$pErrors%'); | |
| 167 | |
| 168 // Update status | |
| 169 elements['testsRunElem'].textContent = testsRun.toString(); | |
| 170 elements['testsFailedElem'].textContent = testsFailed.toString(); | |
| 171 elements['testsErrorsElem'].textContent = testsErrors.toString(); | |
| 172 } | |
| 173 | |
| 174 String _printDuration(Duration timeDuration) { | |
| 175 StringBuffer out = new StringBuffer(); | |
| 176 if(timeDuration.inDays > 0) { | |
| 177 out.add('${timeDuration.inDays} days '); | |
| 178 } | |
| 179 if(timeDuration.inHours > 0) { | |
| 180 out.add('${timeDuration.inHours} hrs '); | |
| 181 } | |
| 182 if(timeDuration.inMinutes > 0) { | |
| 183 out.add('${timeDuration.inMinutes} mins '); | |
| 184 } | |
| 185 if(timeDuration.inSeconds > 0) { | |
| 186 out.add('${timeDuration.inSeconds} s '); | |
| 187 } | |
| 188 if(timeDuration.inMilliseconds > 0 || out.length == 0) { | |
| 189 out.add('${timeDuration.inMilliseconds} ms'); | |
| 190 } | |
| 191 return out.toString(); | |
| 192 } | |
| 193 | |
| 194 /** Populates the floating div with controls and toolbar. */ | |
| 195 HTMLDivElement _renderMain() { | |
| 196 HTMLDivElement containerDiv = _runnerWindow.document.createElement('div'); | |
| 197 containerDiv.className = 'dt-container'; | |
| 198 _appElements['containerDiv'] = containerDiv; | |
| 199 | |
| 200 // Add the test controls | |
| 201 HTMLDivElement mainElem = _runnerWindow.document.createElement('div'); | |
| 202 mainElem.className = 'dt-main'; | |
| 203 _appElements['mainElem'] = mainElem; | |
| 204 | |
| 205 _showTestControls(); | |
| 206 | |
| 207 // Create header to hold window controls | |
| 208 if(_runnerWindow == window) { | |
| 209 HTMLDivElement headDiv = _runnerWindow.document.createElement('div'); | |
| 210 headDiv.className = 'dt-header'; | |
| 211 headDiv.innerHTML = '<b>DARTest: In-App View</b>'; | |
|
pdr
2011/12/16 17:00:50
I think you should use font-weight: bold in your C
| |
| 212 HTMLImageElement close = _runnerWindow.document.createElement('img'); | |
| 213 close.className = 'dt-header-close'; | |
| 214 close.addEventListener('click', (Event) { | |
| 215 containerDiv.className = 'dt-hide'; | |
| 216 }, true); | |
| 217 HTMLImageElement pop = _runnerWindow.document.createElement('img'); | |
| 218 pop.className = 'dt-header-pop'; | |
| 219 pop.addEventListener('click', (Event) => dartestMaximize(), true); | |
| 220 HTMLImageElement minMax = _runnerWindow.document.createElement('img'); | |
| 221 minMax.className = 'dt-header-min'; | |
| 222 minMax.addEventListener('click', (Event) { | |
| 223 if (mainElem.classList.contains('dt-hide')) { | |
| 224 mainElem.classList.remove('dt-hide'); | |
| 225 mainElem.classList.add('dt-show'); | |
| 226 minMax.className = 'dt-header-min'; | |
| 227 } else { | |
| 228 if (mainElem.classList.contains('dt-show')) { | |
| 229 mainElem.classList.remove('dt-show'); | |
| 230 } | |
| 231 mainElem.classList.add('dt-hide'); | |
| 232 minMax.className = 'dt-header-max'; | |
| 233 } | |
| 234 }, true); | |
| 235 headDiv.appendChild(close); | |
| 236 headDiv.appendChild(pop); | |
| 237 headDiv.appendChild(minMax); | |
| 238 | |
| 239 containerDiv.appendChild(headDiv); | |
| 240 } | |
| 241 | |
| 242 HTMLDivElement tabDiv = _runnerWindow.document.createElement('div'); | |
| 243 tabDiv.className = 'dt-tab'; | |
| 244 HTMLUListElement tabList = _runnerWindow.document.createElement('ul'); | |
| 245 HTMLLIElement testingTab = _runnerWindow.document.createElement('li'); | |
| 246 HTMLLIElement coverageTab = _runnerWindow.document.createElement('li'); | |
| 247 testingTab.className = 'dt-tab-selected'; | |
| 248 testingTab.textContent = 'Testing'; | |
| 249 testingTab.addEventListener('click', (Event) { | |
| 250 _showTestControls(); | |
| 251 _changeTabs(testingTab, coverageTab); | |
| 252 }, true); | |
| 253 tabList.appendChild(testingTab); | |
| 254 coverageTab.textContent = 'Coverage'; | |
| 255 coverageTab.addEventListener('click', (Event) { | |
| 256 _showCoverageControls(); | |
| 257 _changeTabs(coverageTab, testingTab); | |
| 258 }, true); | |
| 259 tabList.appendChild(coverageTab); | |
| 260 tabDiv.appendChild(tabList); | |
| 261 containerDiv.appendChild(tabDiv); | |
| 262 | |
| 263 if(_runnerWindow != window) { | |
| 264 HTMLDivElement popIn = _runnerWindow.document.createElement('div'); | |
| 265 popIn.className = 'dt-minimize'; | |
| 266 popIn.innerHTML = 'Pop In ⇲'; | |
| 267 popIn.addEventListener('click', (Event) => dartestMinimize(), true); | |
| 268 containerDiv.appendChild(popIn); | |
| 269 } | |
| 270 | |
| 271 containerDiv.appendChild(mainElem); | |
| 272 _runnerWindow.document.body.appendChild(containerDiv); | |
| 273 } | |
| 274 | |
| 275 void _changeTabs(HTMLLIElement clickedTab, HTMLLIElement oldTab) { | |
| 276 oldTab.className = ''; | |
| 277 clickedTab.className = 'dt-tab-selected'; | |
| 278 } | |
| 279 | |
| 280 void _showTestControls() { | |
| 281 HTMLDivElement testBody = _appElements['testBody']; | |
| 282 if(testBody == null) { | |
| 283 testBody = _runnerWindow.document.createElement('div'); | |
| 284 _appElements['testBody'] = testBody; | |
| 285 | |
| 286 // Create a toolbar to hold action buttons | |
| 287 HTMLDivElement toolDiv = _runnerWindow.document.createElement('div'); | |
| 288 toolDiv.className = 'dt-toolbar'; | |
| 289 HTMLButtonElement runBtn = _runnerWindow.document.createElement('button'); | |
| 290 runBtn.innerHTML = '►'; | |
| 291 runBtn.title = 'Run Tests'; | |
| 292 runBtn.className = 'dt-button dt-run'; | |
| 293 runBtn.addEventListener('click', (Event) { | |
| 294 _log('Running tests'); | |
| 295 updateUI = _updateDARTestUI; | |
| 296 runDartests(); | |
| 297 }, true); | |
| 298 toolDiv.appendChild(runBtn); | |
| 299 HTMLButtonElement exportBtn = | |
| 300 _runnerWindow.document.createElement('button'); | |
| 301 exportBtn.innerHTML = '↷'; | |
| 302 exportBtn.title = 'Export Results'; | |
| 303 exportBtn.className = 'dt-button dt-run'; | |
| 304 exportBtn.addEventListener('click', (Event e) { | |
| 305 _log('Exporting results'); | |
| 306 exportTestResults(); | |
| 307 }, true); | |
| 308 toolDiv.appendChild(exportBtn); | |
| 309 testBody.appendChild(toolDiv); | |
| 310 | |
| 311 // Create a datalist element for showing test status | |
| 312 HTMLDListElement statList = _runnerWindow.document.createElement('dl'); | |
| 313 statList.className = 'dt-status'; | |
| 314 HTMLElement runsDt = _runnerWindow.document.createElement('dt'); | |
| 315 runsDt.textContent = 'Runs:'; | |
| 316 statList.appendChild(runsDt); | |
| 317 HTMLElement testsRunElem = _runnerWindow.document.createElement('dd'); | |
| 318 _appElements['testsRunElem'] = testsRunElem; | |
| 319 testsRunElem.textContent = testsRun.toString(); | |
| 320 statList.appendChild(testsRunElem); | |
| 321 | |
| 322 HTMLElement failDt = _runnerWindow.document.createElement('dt'); | |
| 323 failDt.textContent = 'Failed:'; | |
| 324 statList.appendChild(failDt); | |
| 325 HTMLElement testsFailedElem = _runnerWindow.document.createElement('dd'); | |
| 326 _appElements['testsFailedElem'] = testsFailedElem; | |
| 327 testsFailedElem.textContent = testsFailed.toString(); | |
| 328 statList.appendChild(testsFailedElem); | |
| 329 | |
| 330 HTMLElement errDt = _runnerWindow.document.createElement('dt'); | |
| 331 errDt.textContent = 'Errors:'; | |
| 332 statList.appendChild(errDt); | |
| 333 HTMLElement testsErrorsElem = _runnerWindow.document.createElement('dd'); | |
| 334 _appElements['testsErrorsElem'] = testsErrorsElem; | |
| 335 testsErrorsElem.textContent = testsErrors.toString(); | |
| 336 statList.appendChild(testsErrorsElem); | |
| 337 testBody.appendChild(statList); | |
| 338 | |
| 339 // Create progressbar and add red, green, orange bars | |
| 340 HTMLDivElement progressDiv = _runnerWindow.document.createElement('div'); | |
| 341 progressDiv.className = 'dt-progressbar'; | |
| 342 progressDiv.innerHTML = "<span style='width:100%'></span>"; | |
| 343 | |
| 344 HTMLSpanElement orange = _runnerWindow.document.createElement('span'); | |
| 345 _appElements['orange'] = orange; | |
| 346 orange.className = 'orange'; | |
| 347 progressDiv.appendChild(orange); | |
| 348 | |
| 349 HTMLSpanElement red = _runnerWindow.document.createElement('span'); | |
| 350 _appElements['red'] = red; | |
| 351 red.className = 'red'; | |
| 352 progressDiv.appendChild(red); | |
| 353 | |
| 354 HTMLSpanElement green = _runnerWindow.document.createElement('span'); | |
| 355 _appElements['green'] = green; | |
| 356 green.className = 'green'; | |
| 357 | |
| 358 progressDiv.appendChild(green); | |
| 359 testBody.appendChild(progressDiv); | |
| 360 | |
| 361 HTMLDivElement hiddenElem = _runnerWindow.document.createElement('div'); | |
| 362 hiddenElem.className = 'dt-hide'; | |
| 363 hiddenElem.innerHTML = | |
| 364 "<a id='dt-export' download='test_results.csv' href='#' />"; | |
| 365 testBody.appendChild(hiddenElem); | |
| 366 | |
| 367 _addChildToElem('mainElem', testBody); | |
| 368 } | |
| 369 | |
| 370 // Show hide divs | |
| 371 _show('testBody'); | |
| 372 _hide('coverageBody'); | |
| 373 } | |
| 374 | |
| 375 void _showCoverageControls() { | |
| 376 HTMLDivElement coverageBody = _appElements['coverageBody']; | |
| 377 if(coverageBody == null) { | |
| 378 coverageBody = _runnerWindow.document.createElement('div'); | |
| 379 _appElements['coverageBody'] = coverageBody; | |
| 380 | |
| 381 HTMLPreElement covPreElem = _runnerWindow.document.createElement('pre'); | |
| 382 _appElements['covPreElem'] = covPreElem; | |
| 383 coverageBody.appendChild(covPreElem); | |
| 384 | |
| 385 HTMLTableElement covTable = _runnerWindow.document.createElement('table'); | |
| 386 covTable.className = 'dt-results'; | |
| 387 HTMLTableSectionElement head = | |
| 388 _runnerWindow.document.createElement('thead'); | |
| 389 head.innerHTML = '<tr><th>Unit <th>Function <th>Statement <th>Branch'; | |
| 390 covTable.appendChild(head); | |
| 391 HTMLTableSectionElement covTableBody = | |
| 392 _runnerWindow.document.createElement('tbody'); | |
| 393 _appElements['covTableBody'] = covTableBody; | |
| 394 covTableBody.id = 'dt-results-body'; | |
| 395 covTable.appendChild(covTableBody); | |
|
pdr
2011/12/16 17:00:50
indentation
shauvik
2011/12/16 17:57:06
Done.
| |
| 396 coverageBody.appendChild(covTable); | |
| 397 | |
| 398 _addChildToElem('mainElem', coverageBody); | |
| 399 } | |
| 400 _show('coverageBody'); | |
| 401 _hide('testBody'); | |
| 402 | |
| 403 _appElements['covPreElem'].textContent = getCoverageSummary(); | |
| 404 _appElements['covTableBody'].innerHTML = getCoverageDetails(); | |
| 405 } | |
| 406 | |
| 407 void _show(String toShow) { | |
| 408 HTMLElement show = _appElements[toShow]; | |
| 409 if(show != null) { | |
| 410 if(show.classList.contains('dt-hide')) { | |
| 411 show.classList.remove('dt-hide'); | |
| 412 } | |
| 413 show.classList.add('dt-show'); | |
| 414 } | |
| 415 } | |
| 416 | |
| 417 void _hide(String toHide) { | |
| 418 HTMLElement hide = _appElements[toHide]; | |
| 419 if(hide != null) { | |
| 420 if(hide.classList.contains('dt-show')) { | |
| 421 hide.classList.remove('dt-show'); | |
| 422 } | |
| 423 hide.classList.add('dt-hide'); | |
| 424 } | |
| 425 } | |
| 426 | |
| 427 void dartestMaximize() { | |
| 428 _hide('containerDiv'); | |
| 429 _runnerWindow = window.open('', 'dartest-window', 'width=600,height=750'); | |
|
pdr
2011/12/16 17:00:50
Optional nit: I like moving these kinds of static
shauvik
2011/12/16 17:57:06
Done.
| |
| 430 _runnerWindow.document.title = 'Dartest'; | |
| 431 _fullAppElements = new HashMap<String, HTMLElement>(); | |
| 432 _appElements = _fullAppElements; | |
| 433 DARTestCss.inject(_runnerWindow.document, false); | |
| 434 run(); | |
| 435 if(testsRun > 0) { | |
| 436 populateResults(); | |
| 437 } | |
| 438 } | |
| 439 | |
| 440 void populateResults() { | |
| 441 tests.forEach((final t) => _updateDARTestUI(t)); | |
| 442 } | |
| 443 | |
| 444 void dartestMinimize() { | |
| 445 _runnerWindow.close(); | |
| 446 _runnerWindow = window; | |
| 447 _appElements = _inAppElements; | |
| 448 _show('containerDiv'); | |
| 449 } | |
| 450 | |
| 451 void exportTestResults() { | |
| 452 String csvData = getTestResultsCsv(); | |
| 453 _log(csvData); | |
| 454 HTMLAnchorElement exportLink = | |
| 455 _runnerWindow.document.getElementById('dt-export'); | |
| 456 | |
| 457 /** Bug: Can't instantiate WebKitBlobBuilder | |
| 458 * If this bug is fixed, we can remove the urlencode and lpad function. | |
| 459 WebKitBlobBuilder bb = new WebKitBlobBuilder(); | |
| 460 bb.append(csvData); | |
| 461 Blob blob = bb.getBlob('text/plain;charset=${document.characterSet}'); | |
| 462 exportLink.href = window.webkitURL.createObjectURL(blob); | |
| 463 **/ | |
| 464 | |
| 465 exportLink.href = 'data:text/csv,'+urlencode(csvData); | |
| 466 | |
| 467 MouseEvent ev = document.createEvent("MouseEvents"); | |
| 468 ev.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0 | |
| 469 , false, false, false, false, 0, null); | |
| 470 exportLink.dispatchEvent(ev); | |
| 471 | |
| 472 } | |
| 473 | |
|
pdr
2011/12/16 17:00:50
Make these private and static
shauvik
2011/12/16 17:57:06
Done.
| |
| 474 String urlencode(String s) { | |
| 475 StringBuffer out = new StringBuffer(); | |
| 476 for(int i = 0; i < s.length; i++) { | |
| 477 int cc = s.charCodeAt(i); | |
| 478 if((cc >= 48 && cc <= 57) || (cc >= 65 && cc <= 90) || | |
| 479 (cc >= 97 && cc <= 122)) { | |
| 480 out.add(s[i]); | |
| 481 } else { | |
| 482 out.add('%${lpad(cc.toRadixString(16),2).toUpperCase()}'); | |
| 483 } | |
| 484 } | |
| 485 return out.toString(); | |
| 486 } | |
| 487 | |
| 488 String lpad(String s, int n) { | |
| 489 if(s.length < n) { | |
| 490 for(int i = 0; i < n - s.length; i++) { | |
| 491 s = '0'+s; | |
| 492 } | |
| 493 } | |
| 494 return s; | |
| 495 } | |
| 496 } | |
| OLD | NEW |