REGRESSION: code-review-tests.html fails with error "Received an error at line 214"
[WebKit-https.git] / Websites / bugs.webkit.org / code-review-test.html
1 <div>Tests for some of the easily unittestable parts of code-review.js. You should see a series of "PASS" lines.</div>
2 <div>FIXME: Run these as part of the layout test suite?</div>
3
4 <script>
5 CODE_REVIEW_UNITTEST = true;
6
7 window.onerror = function(errorMsg, url, lineNumber) {
8   log('FAIL: Received an error at line ' + lineNumber);
9   return false;
10 }
11 </script>
12 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> 
13 <script src="code-review.js"></script>
14 <pre id="output"></pre>
15 <div id="diff-content"></div>
16 <script>
17 function inherits(childConstructor, parentConstructor) {
18   function tempConstructor() {};
19   tempConstructor.prototype = parentConstructor.prototype;
20   childConstructor.prototype = new tempConstructor();
21   childConstructor.prototype.constructor = childConstructor;
22 }
23
24 function log(msg) {
25     document.getElementById('output').textContent += msg + '\n\n';
26 }
27
28 function ASSERT(msg, assertion) {
29     if (assertion)
30         log('PASS');
31     else
32         log('FAIL: ' + msg);
33 }
34
35 function ASSERT_EQUAL(actual, expected) {
36     if (actual == expected)
37         log('PASS');
38     else
39         log('FAIL:\ngot:\n' + actual + '\nexpected:\n' + expected + '');
40 }
41
42 function testTracLinks() {
43   var links = tracLinks('foo/bar/baz.cpp', '');
44   ASSERT_EQUAL($('<div>').append(links).html(),
45     '<a target="_blank" href="http://trac.webkit.org/log/trunk/foo/bar/baz.h">header</a>' +
46     '<a target="_blank" href="http://trac.webkit.org/browser/trunk/foo/bar/baz.cpp?annotate=blame">annotate</a>' +
47     '<a target="_blank" href="http://trac.webkit.org/log/trunk/foo/bar/baz.cpp">revision log</a>');
48
49   var links = tracLinks('foo/bar.cpp/qux.mm', '');
50   ASSERT_EQUAL($('<div>').append(links).html(),
51     '<a target="_blank" href="http://trac.webkit.org/log/trunk/foo/bar.cpp/qux.h">header</a>' +
52     '<a target="_blank" href="http://trac.webkit.org/browser/trunk/foo/bar.cpp/qux.mm?annotate=blame">annotate</a>' +
53     '<a target="_blank" href="http://trac.webkit.org/log/trunk/foo/bar.cpp/qux.mm">revision log</a>');
54
55   var links = tracLinks('foo/bar.h', '');
56   ASSERT_EQUAL($('<div>').append(links).html(),
57     '<a target="_blank" href="http://trac.webkit.org/browser/trunk/foo/bar.h?annotate=blame">annotate</a>' +
58     '<a target="_blank" href="http://trac.webkit.org/log/trunk/foo/bar.h">revision log</a>');
59
60   var links = tracLinks('foo/bar.gypi', '');
61   ASSERT_EQUAL($('<div>').append(links).html(),
62     '<a target="_blank" href="http://trac.webkit.org/browser/trunk/foo/bar.gypi?annotate=blame">annotate</a>' +
63     '<a target="_blank" href="http://trac.webkit.org/log/trunk/foo/bar.gypi">revision log</a>');
64
65   var links = tracLinks('foo/ChangeLog', '');
66   ASSERT_EQUAL($('<div>').append(links).html(),
67     '<a target="_blank" href="http://trac.webkit.org/browser/trunk/foo/ChangeLog?annotate=blame">annotate</a>' +
68     '<a target="_blank" href="http://trac.webkit.org/log/trunk/foo/ChangeLog">revision log</a>');
69 }
70
71 function testDraftCommentSaver() {
72   function MockLocalStorage() {
73       this.localStorageStore = {};
74       this.log = [];
75
76       this.getItem = function(key) {
77           this.log.push('getItem:' + key);
78           return this.localStorageStore[key];
79       };
80
81       this.setItem = function(key, value) {
82           // For testing sake, consider having more than 2 items to exceed the storage quota.
83           if (Object.keys(this.localStorageStore).length > 2) {
84               this.log.push('QuotaExceeded on setItem:' + key + ',' + value);
85               throw "QuotaExceeded";
86           }
87           this.log.push('setItem:' + key + ',' + value);
88           this.localStorageStore[key] = value;
89       };
90
91       this.removeItem = function(key) {
92           this.log.push('removeItem:' + key);
93           delete this.localStorageStore[key];
94       };
95
96       this.log_string = function() {
97           return this.log.join('\n');
98       };
99
100       this.key = function(i) {
101           return Object.keys(this.localStorageStore)[i];
102       };
103
104       this.__defineGetter__('length', function() {
105           return Object.keys(this.localStorageStore).length;
106       });
107   }
108
109   function MockDraftCommentSaver(attachment_id, opt_localStorage) {
110       DraftCommentSaver.call(this, attachment_id, opt_localStorage);
111   }
112
113   inherits(MockDraftCommentSaver, DraftCommentSaver)
114
115   MockDraftCommentSaver.prototype._json = function() {
116       return "{MOCK JSON}";
117   }
118
119   MockDraftCommentSaver.prototype._should_remove_comments = function(message) {
120       return false;
121   }
122
123   // Basic setItem.
124   var ls = new MockLocalStorage();
125   new MockDraftCommentSaver('1234', ls).save();
126   ASSERT_EQUAL(ls.log_string(), 'setItem:draft-comments-for-attachment-1234,{MOCK JSON}');
127
128   // Exceed quota, but succeed after erasing old reviews.
129   var ls = new MockLocalStorage();
130   ls.localStorageStore = {
131       'draft-comments-for-attachment-1': '{"born-on": 100, "comments":[]}',
132       'draft-comments-for-attachment-2': '{"born-on": 100, "comments":[]}',
133       'draft-comments-for-attachment-3': '{"born-on": 100, "comments":[]}',
134       'draft-comments-for-attachment-4': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}'
135   };
136   new MockDraftCommentSaver('1234', ls).save();
137   ASSERT_EQUAL(ls.log_string(), 'QuotaExceeded on setItem:draft-comments-for-attachment-1234,{MOCK JSON}\ngetItem:draft-comments-for-attachment-1\ngetItem:draft-comments-for-attachment-2\ngetItem:draft-comments-for-attachment-3\ngetItem:draft-comments-for-attachment-4\nremoveItem:draft-comments-for-attachment-1\nremoveItem:draft-comments-for-attachment-2\nremoveItem:draft-comments-for-attachment-3\nsetItem:draft-comments-for-attachment-1234,{MOCK JSON}');
138
139   // Exceed quota after erasing old reviews and fail after prompt.
140   var ls = new MockLocalStorage();
141   ls.localStorageStore = {
142       'draft-comments-for-attachment-1': '{"born-on": 100, "comments":[]}',
143       'draft-comments-for-attachment-2': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
144       'draft-comments-for-attachment-3': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
145       'draft-comments-for-attachment-4': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}'
146   };
147   var mockDraftSaver = new MockDraftCommentSaver('1234', ls);
148   mockDraftSaver.save();
149   // Second save to ensure that we stop trying to save when we fail the prompt.
150   mockDraftSaver.save();
151   ASSERT_EQUAL(ls.log_string(), 'QuotaExceeded on setItem:draft-comments-for-attachment-1234,{MOCK JSON}\ngetItem:draft-comments-for-attachment-1\ngetItem:draft-comments-for-attachment-2\ngetItem:draft-comments-for-attachment-3\ngetItem:draft-comments-for-attachment-4\nremoveItem:draft-comments-for-attachment-1\nQuotaExceeded on setItem:draft-comments-for-attachment-1234,{MOCK JSON}');
152
153   // Exceed quota after erasing old reviews, but succeed after prompt.
154   var ls = new MockLocalStorage();
155   ls.localStorageStore = {
156       'draft-comments-for-attachment-1': '{"born-on": 100, "comments":[]}',
157       'draft-comments-for-attachment-2': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
158       'draft-comments-for-attachment-3': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
159       'draft-comments-for-attachment-4': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}'
160   };
161   var mockDraftSaver = new MockDraftCommentSaver('1234', ls);
162   mockDraftSaver._should_remove_comments = function() { return true; };
163   mockDraftSaver.save();
164   ASSERT_EQUAL(ls.log_string(), 'QuotaExceeded on setItem:draft-comments-for-attachment-1234,{MOCK JSON}\ngetItem:draft-comments-for-attachment-1\ngetItem:draft-comments-for-attachment-2\ngetItem:draft-comments-for-attachment-3\ngetItem:draft-comments-for-attachment-4\nremoveItem:draft-comments-for-attachment-1\nQuotaExceeded on setItem:draft-comments-for-attachment-1234,{MOCK JSON}\nremoveItem:draft-comments-for-attachment-2\nremoveItem:draft-comments-for-attachment-3\nremoveItem:draft-comments-for-attachment-4\nsetItem:draft-comments-for-attachment-1234,{MOCK JSON}');
165
166   // Always exceeds quota, even after erasing all review comments. There should be no setItem calls.
167   var ls = new MockLocalStorage();
168   ls.setItem = function() {
169       this.log.push('QuotaExceeded on setItem:' + key + ',' + value);
170       throw "QuotaExceeded"; 
171   }
172   ls.localStorageStore = {
173       'draft-comments-for-attachment-1': '{"born-on": 100, "comments":[]}',
174       'draft-comments-for-attachment-2': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
175       'draft-comments-for-attachment-3': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
176       'draft-comments-for-attachment-4': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}'
177   };
178   var mockDraftSaver = new MockDraftCommentSaver('1234', ls);
179   mockDraftSaver._should_remove_comments = function() { return true; };
180   mockDraftSaver.save();
181   // Second save to ensure that we stop trying to save when we fail the prompt.
182   mockDraftSaver.save();
183   ASSERT_EQUAL(ls.log_string(), 'getItem:draft-comments-for-attachment-1\ngetItem:draft-comments-for-attachment-2\ngetItem:draft-comments-for-attachment-3\ngetItem:draft-comments-for-attachment-4\nremoveItem:draft-comments-for-attachment-1\nremoveItem:draft-comments-for-attachment-2\nremoveItem:draft-comments-for-attachment-3\nremoveItem:draft-comments-for-attachment-4');
184
185   var ls = new MockLocalStorage();
186   ls.localStorageStore = {
187       'draft-comments-for-attachment-1': '{"born-on": 100, "comments":[]}',
188       'draft-comments-for-attachment-2': '{"born-on": 100, "comments":[{"start_line_id": 1, "end_line_id": 2, "contents": "DUMMY CONTENTS"}, {"start_line_id": 3, "end_line_id": 4, "contents": "DUMMY CONTENTS 2"}]}'
189   };
190   var comments = new MockDraftCommentSaver('2', ls).saved_comments().comments;
191   ASSERT_EQUAL(comments.length, 2);
192   ASSERT_EQUAL(ls.log_string(), 'getItem:draft-comments-for-attachment-2');
193
194   var ls = new MockLocalStorage();
195   ls.localStorageStore = {
196       'draft-comments-for-attachment-1': 'corrupt comments'
197   };
198   var comments = new MockDraftCommentSaver('1', ls).saved_comments().comments;
199   ASSERT_EQUAL(ls.log_string(), 'getItem:draft-comments-for-attachment-1\nremoveItem:draft-comments-for-attachment-1');
200
201   var ls = new MockLocalStorage();
202   ls.localStorageStore = {
203       'draft-comments-for-attachment-1': '["also corrupt comments"]'
204   };
205   var comments = new MockDraftCommentSaver('1', ls).saved_comments().comments;
206   ASSERT_EQUAL(ls.log_string(), 'getItem:draft-comments-for-attachment-1\nremoveItem:draft-comments-for-attachment-1');
207 }
208
209 function stripBornOn(json) {
210   return json.replace(/\"born\-on\"\:\d+,/, "");
211 }
212
213 function strippedSavedComments() {
214   return stripBornOn(localStorage[g_draftCommentSaver.localStorageKey()]);
215 }
216
217 function syncSlideUp(type, handler) {
218   handler.call(this);
219 }
220
221 function testReadDiscardedCommentWithPreviousComment() {
222   document.getElementById('diff-content').innerHTML =
223       '<div class="FileDiff">' +
224         '<h1><a href="http://trac.webkit.org/browser/trunk/Source/WebCore/ChangeLog">Source/WebCore/ChangeLog</a></h1>' +
225         '<div class="DiffSection">' +
226           '<div class="DiffBlock">' +
227             '<div class="DiffBlockPart add">' +
228               '<div class="Line LineContainer add">' +
229                 '<span class="from lineNumber">&nbsp;</span><span class="to lineNumber">1</span><span class="text">first diff block first line</span>' +
230               '</div>' +
231               '<div class="Line LineContainer add">' +
232                 '<span class="from lineNumber">&nbsp;</span><span class="to lineNumber">2</span><span class="text"></span>' +
233               '</div>' +
234             '</div>' +
235             '<div class="clear_float"></div>' +
236           '</div>' +
237           '<div class="DiffBlock">' +
238             '<div class="DiffBlockPart shared">' +
239               '<div class="Line LineContainer">' +
240                 '<span class="from lineNumber">1</span><span class="to lineNumber">12</span><span class="text">second diff block first line</span>' +
241               '</div>' +
242               '</div><div class="clear_float">' +
243             '</div>' +
244           '</div>' +
245         '</div>' +
246       '</div>';
247
248   eraseDraftComments();
249   crawlDiff();
250
251   var line = document.getElementById('line0');
252   var author = "ojan@chromium.org";
253   var comment_text = "This change sux.";
254   addPreviousComment(line, author, comment_text);
255   var previous_comment = document.querySelector('.previousComment');
256   ASSERT("Line with only a previous comment should not have 'data-has-comment' attribute.", !line.getAttribute('data-has-comment'));
257
258   var new_comment = addCommentField(previous_comment);
259   new_comment.find('textarea').val("dummy content");
260   var frozen_comment = acceptComment(new_comment);
261
262   ASSERT_EQUAL(document.querySelectorAll('.comment').length, 1);
263   ASSERT_EQUAL(strippedSavedComments(), '{"comments":[{"start_line_id":"line0","end_line_id":"line0","contents":"dummy content"}],"overall-comments":""}');
264
265   unfreezeComment(frozen_comment);
266   // This is a hack to make slideUp synchronous so that we can keep this test from needing to be async.
267   jQuery.fn.slideUp = syncSlideUp;
268   discardComment(new_comment);
269
270   ASSERT('There should be no draft comments.', !document.querySelector('.comment'));
271   ASSERT_EQUAL(strippedSavedComments(), '{"comments":[],"overall-comments":""}');
272   ASSERT("Line with only a previous comment should not have 'data-has-comment' attribute.", !line.getAttribute('data-has-comment'));
273
274   new_comment = addCommentField(previous_comment);
275   new_comment.find('textarea').val("dummy content");
276   acceptComment(new_comment);
277
278   ASSERT_EQUAL(document.querySelectorAll('.comment').length, 1);
279   ASSERT_EQUAL(strippedSavedComments(), '{"comments":[{"start_line_id":"line0","end_line_id":"line0","contents":"dummy content"}],"overall-comments":""}');
280
281   document.getElementById('diff-content').innerHTML = '';
282 }
283
284 function testSideBySideDiffWithPreviousCommentsOnSharedLine() {
285   document.getElementById('diff-content').innerHTML =
286       '<div class="FileDiff">' +
287         '<h1><a href="http://trac.webkit.org/browser/trunk/Source/WebCore/ChangeLog">Source/WebCore/ChangeLog</a></h1>' +
288         '<div class="DiffSection">' +
289           '<div class="DiffBlock">' +
290             '<div class="DiffBlockPart shared">' +
291               '<div class="Line LineContainer">' +
292               '<span class="from lineNumber">336</span><span class="to lineNumber">338</span><span class="text">    layoutFlexItems(*m_orderIterator, lineContexts);</span>' +
293               '</div>' +
294               '<div class="Line LineContainer">' +
295               '<span class="from lineNumber">337</span><span class="to lineNumber">339</span><span class="text"></span>' +
296               '</div>' +
297               '<div class="Line LineContainer">' +
298               '<span class="from lineNumber">338</span><span class="to lineNumber">340</span><span class="text">    LayoutUnit oldClientAfterEdge = clientLogicalBottom();</span>' +
299               '</div>' +
300             '</div><div class="clear_float">' +
301           '</div>' +
302         '</div>' +
303       '</div>';
304
305   eraseDraftComments();
306   crawlDiff();
307
308   convertAllFileDiffs('sidebyside', $('.FileDiff'));
309
310   displayPreviousComments([{
311     author: 'ojan@chromium.org',
312     file_name: 'Source/WebCore/ChangeLog',
313     line_number: 338,
314     comment_text: 'This change sux.'
315   }]);
316
317   var previous_comment = document.querySelector('.previousComment');
318   ASSERT_EQUAL(previous_comment.getAttribute('data-comment-for'), 'line0');
319
320   var new_comment = addCommentField(previous_comment);
321   ASSERT("New comment should exist and contain a textarea.", new_comment.find('textarea'));
322
323   document.getElementById('diff-content').innerHTML = '';
324 }
325
326 function testSanitizeFragmentForCopy() {
327   var fragment = document.createElement('div');
328   fragment.innerHTML = '<div class="FileDiff">' +
329       '<h1><a href="http://trac.webkit.org/browser/trunk/Source/WebCore/ChangeLog">Source/WebCore/ChangeLog</a></h1>' +
330       '<div class="FileDiffLinkContainer LinkContainer" style="opacity: 0;"><a href="javascript:" class="unify-link cremed" style="display: inline;">unified</a></div>' +
331       '<div class="DiffSection">' +
332         '<div class="DiffBlock">' +
333           '<div class="DiffBlockPart shared">' +
334             '<div class="Line LineContainer">' +
335               '<span class="from lineNumber">336</span><span class="to lineNumber">338</span><span class="text">    layoutFlexItems(*m_orderIterator, lineContexts);</span>' +
336             '</div>' +
337             '<div class="Line LineContainer">' +
338               '<span class="from lineNumber">337</span><span class="to lineNumber">339</span><span class="text"></span>' +
339             '</div>' +
340             '<div class="Line LineContainer">' +
341               '<span class="from lineNumber">338</span><span class="to lineNumber">340</span><span class="text">    LayoutUnit oldClientAfterEdge = clientLogicalBottom();</span>' +
342             '</div>' +
343           '</div><div class="clear_float"></div>' +
344         '</div>' +
345       '</div>' +
346     '</div>';
347
348   var expectedWithLineNumbers = '<div class="FileDiff">' +
349       '<h1><a href="http://trac.webkit.org/browser/trunk/Source/WebCore/ChangeLog">Source/WebCore/ChangeLog</a></h1>' +
350       '<div class="DiffSection">' +
351         '<div class="DiffBlock">' +
352           '<div class="DiffBlockPart shared">' +
353             '<div class="Line LineContainer">' +
354               '<span class="from lineNumber">336</span><span class="to lineNumber">338</span><span class="text">    layoutFlexItems(*m_orderIterator, lineContexts);</span>' +
355             '</div>' +
356             '<div class="Line LineContainer">' +
357               '<span class="from lineNumber">337</span><span class="to lineNumber">339</span><span class="text"><br></span>' +
358             '</div>' +
359             '<div class="Line LineContainer">' +
360               '<span class="from lineNumber">338</span><span class="to lineNumber">340</span><span class="text">    LayoutUnit oldClientAfterEdge = clientLogicalBottom();</span>' +
361             '</div>' +
362           '</div><div class="clear_float"></div>' +
363         '</div>' +
364       '</div>' +
365     '</div>';
366
367   var fragmentCopy = fragment.cloneNode(true);
368   sanitizeFragmentForCopy(fragmentCopy, false);
369   ASSERT_EQUAL(fragmentCopy.innerHTML, expectedWithLineNumbers);
370
371   var expectedWithOutLineNumbers = '<div class="FileDiff">' +
372       '<h1><a href="http://trac.webkit.org/browser/trunk/Source/WebCore/ChangeLog">Source/WebCore/ChangeLog</a></h1>' +
373       '<div class="DiffSection">' +
374         '<div class="DiffBlock">' +
375           '<div class="DiffBlockPart shared">' +
376             '<div class="Line LineContainer">' +
377               '<span class="text">    layoutFlexItems(*m_orderIterator, lineContexts);</span>' +
378             '</div>' +
379             '<div class="Line LineContainer">' +
380               '<span class="text"><br></span>' +
381             '</div>' +
382             '<div class="Line LineContainer">' +
383               '<span class="text">    LayoutUnit oldClientAfterEdge = clientLogicalBottom();</span>' +
384             '</div>' +
385           '</div><div class="clear_float"></div>' +
386         '</div>' +
387       '</div>' +
388     '</div>';
389
390   var fragmentCopy = fragment.cloneNode(true);
391   sanitizeFragmentForCopy(fragmentCopy, true);
392   ASSERT_EQUAL(fragmentCopy.innerHTML, expectedWithOutLineNumbers);
393 }
394
395 function testIsChangeLog() {
396   ASSERT("Top-level ChangeLog file is a ChangeLog file", isChangeLog("ChangeLog"));
397   ASSERT("Second-level ChangeLog file is a ChangeLog file", isChangeLog("Tools/ChangeLog"));
398   ASSERT("prepare-ChangeLog is not a ChangeLog file", !isChangeLog("Tools/Scripts/prepare-ChangeLog"));
399   ASSERT("ChangeLog-script is not a ChangeLog file", !isChangeLog("Tools/Scripts/ChangeLog-script"));
400 }
401
402 function testSaveCommentsWithMissingLineIds() {
403   document.getElementById('diff-content').innerHTML =
404       '<div class="FileDiff">' +
405         '<h1><a href="http://trac.webkit.org/browser/trunk/Source/WebCore/ChangeLog">Source/WebCore/dummy.txt</a></h1>' +
406         '<div class="DiffSection">' +
407           '<div class="DiffBlock">' +
408             '<div class="DiffBlockPart shared">' +
409               '<div class="Line LineContainer">' +
410               '<span class="from lineNumber">6</span><span class="to lineNumber">8</span><span class="text">a</span>' +
411               '</div>' +
412               '<div class="Line LineContainer">' +
413               '<span class="from lineNumber">7</span><span class="to lineNumber">9</span><span class="text">b</span>' +
414               '</div>' +
415               '<div class="Line LineContainer">' +
416               '<span class="from lineNumber">8</span><span class="to lineNumber">10</span><span class="text">c</span>' +
417               '</div>' +
418             '</div><div class="clear_float">' +
419           '</div>' +
420         '</div>' +
421         '<div class="DiffSection">' +
422           '<div class="Line LineContainer context">' +
423             '<span class="from lineNumber">@</span><span class="to lineNumber">@</span><span class="text">static void willRemoveChildren(ContainerNode* container)</span>' +
424           '</div>' +
425           '<div class="DiffBlock">' +
426             '<div class="DiffBlockPart shared">' +
427             '<div class="Line LineContainer">' +
428               '<span class="from lineNumber">15</span><span class="to lineNumber">17</span><span class="text">d</span>' +
429             '</div>' +
430           '</div><div class="clear_float"></div></div>' +
431         '</div>' +
432       '</div>';
433
434   var file_name = "Source/WebCore/dummy.txt";
435   var file_contents = [];
436   for (var i = 0; i < 20; i++)
437     file_contents[i] = i;
438   setFileContents(file_name, file_contents, file_contents);
439
440   eraseDraftComments();
441   crawlDiff();
442
443   var new_comment = addCommentFor($('#line4'));
444   new_comment.find('textarea').val("dummy content");
445   acceptComment(new_comment);
446
447   $('.ExpandLink')[0].click();
448
449   // Strip the link to the context since that points to window.location.
450   ASSERT_EQUAL(serializedComments().replace(/View in context.*code-review-test.html/, ''),
451     '\n\n' +
452     '> Source/WebCore/dummy.txt:17\n\n\n' +
453     'dummy content');
454   document.getElementById('diff-content').innerHTML = '';
455 }
456
457
458 var tests_to_run = [
459     window.testTracLinks,
460     window.testDraftCommentSaver,
461     window.testReadDiscardedCommentWithPreviousComment,
462     window.testSideBySideDiffWithPreviousCommentsOnSharedLine,
463     window.testSanitizeFragmentForCopy,
464     window.testIsChangeLog,
465     window.testSaveCommentsWithMissingLineIds,
466 ];
467
468 appendToolbar();
469 for (var i = 0; i < tests_to_run.length; ++i)
470     tests_to_run[i]();
471 </script>