Can't add followup comment to a previous comment
[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').innerHTML += 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($(links).attr('href'), 'http://trac.webkit.org/log/trunk/foo/bar/baz.h');
45
46   var links = tracLinks('foo/bar.cpp/qux.mm', '');
47   ASSERT_EQUAL($(links).attr('href'), 'http://trac.webkit.org/log/trunk/foo/bar.cpp/qux.h');
48 }
49
50 function testDraftCommentSaver() {
51   function MockLocalStorage() {
52       this.localStorageStore = {};
53       this.log = [];
54
55       this.getItem = function(key) {
56           this.log.push('getItem:' + key);
57           return this.localStorageStore[key];
58       };
59
60       this.setItem = function(key, value) {
61           // For testing sake, consider having more than 2 items to exceed the storage quota.
62           if (Object.keys(this.localStorageStore).length > 2) {
63               this.log.push('QuotaExceeded on setItem:' + key + ',' + value);
64               throw "QuotaExceeded";
65           }
66           this.log.push('setItem:' + key + ',' + value);
67           this.localStorageStore[key] = value;
68       };
69
70       this.removeItem = function(key) {
71           this.log.push('removeItem:' + key);
72           delete this.localStorageStore[key];
73       };
74
75       this.log_string = function() {
76           return this.log.join('\n');
77       };
78
79       this.key = function(i) {
80           return Object.keys(this.localStorageStore)[i];
81       };
82
83       this.__defineGetter__('length', function() {
84           return Object.keys(this.localStorageStore).length;
85       });
86   }
87
88   function MockDraftCommentSaver(attachment_id, opt_localStorage) {
89       DraftCommentSaver.call(this, attachment_id, opt_localStorage);
90   }
91
92   inherits(MockDraftCommentSaver, DraftCommentSaver)
93
94   MockDraftCommentSaver.prototype._json = function() {
95       return "{MOCK JSON}";
96   }
97
98   MockDraftCommentSaver.prototype._should_remove_comments = function(message) {
99       return false;
100   }
101
102   // Basic setItem.
103   var ls = new MockLocalStorage();
104   new MockDraftCommentSaver('1234', ls).save();
105   ASSERT_EQUAL(ls.log_string(), 'setItem:draft-comments-for-attachment-1234,{MOCK JSON}');
106
107   // Exceed quota, but succeed after erasing old reviews.
108   var ls = new MockLocalStorage();
109   ls.localStorageStore = {
110       'draft-comments-for-attachment-1': '{"born-on": 100, "comments":[]}',
111       'draft-comments-for-attachment-2': '{"born-on": 100, "comments":[]}',
112       'draft-comments-for-attachment-3': '{"born-on": 100, "comments":[]}',
113       'draft-comments-for-attachment-4': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}'
114   };
115   new MockDraftCommentSaver('1234', ls).save();
116   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}');
117
118   // Exceed quota after erasing old reviews and fail after prompt.
119   var ls = new MockLocalStorage();
120   ls.localStorageStore = {
121       'draft-comments-for-attachment-1': '{"born-on": 100, "comments":[]}',
122       'draft-comments-for-attachment-2': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
123       'draft-comments-for-attachment-3': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
124       'draft-comments-for-attachment-4': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}'
125   };
126   var mockDraftSaver = new MockDraftCommentSaver('1234', ls);
127   mockDraftSaver.save();
128   // Second save to ensure that we stop trying to save when we fail the prompt.
129   mockDraftSaver.save();
130   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}');
131
132   // Exceed quota after erasing old reviews, but succeed after prompt.
133   var ls = new MockLocalStorage();
134   ls.localStorageStore = {
135       'draft-comments-for-attachment-1': '{"born-on": 100, "comments":[]}',
136       'draft-comments-for-attachment-2': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
137       'draft-comments-for-attachment-3': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
138       'draft-comments-for-attachment-4': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}'
139   };
140   var mockDraftSaver = new MockDraftCommentSaver('1234', ls);
141   mockDraftSaver._should_remove_comments = function() { return true; };
142   mockDraftSaver.save();
143   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}');
144
145   // Always exceeds quota, even after erasing all review comments. There should be no setItem calls.
146   var ls = new MockLocalStorage();
147   ls.setItem = function() {
148       this.log.push('QuotaExceeded on setItem:' + key + ',' + value);
149       throw "QuotaExceeded"; 
150   }
151   ls.localStorageStore = {
152       'draft-comments-for-attachment-1': '{"born-on": 100, "comments":[]}',
153       'draft-comments-for-attachment-2': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
154       'draft-comments-for-attachment-3': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}',
155       'draft-comments-for-attachment-4': '{"born-on": ' + (Date.now() - 100) + ', "comments":[]}'
156   };
157   var mockDraftSaver = new MockDraftCommentSaver('1234', ls);
158   mockDraftSaver._should_remove_comments = function() { return true; };
159   mockDraftSaver.save();
160   // Second save to ensure that we stop trying to save when we fail the prompt.
161   mockDraftSaver.save();
162   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');
163
164   var ls = new MockLocalStorage();
165   ls.localStorageStore = {
166       'draft-comments-for-attachment-1': '{"born-on": 100, "comments":[]}',
167       '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"}]}'
168   };
169   var comments = new MockDraftCommentSaver('2', ls).saved_comments().comments;
170   ASSERT_EQUAL(comments.length, 2);
171   ASSERT_EQUAL(ls.log_string(), 'getItem:draft-comments-for-attachment-2');
172
173   var ls = new MockLocalStorage();
174   ls.localStorageStore = {
175       'draft-comments-for-attachment-1': 'corrupt comments'
176   };
177   var comments = new MockDraftCommentSaver('1', ls).saved_comments().comments;
178   ASSERT_EQUAL(ls.log_string(), 'getItem:draft-comments-for-attachment-1\nremoveItem:draft-comments-for-attachment-1');
179
180   var ls = new MockLocalStorage();
181   ls.localStorageStore = {
182       'draft-comments-for-attachment-1': '["also corrupt comments"]'
183   };
184   var comments = new MockDraftCommentSaver('1', ls).saved_comments().comments;
185   ASSERT_EQUAL(ls.log_string(), 'getItem:draft-comments-for-attachment-1\nremoveItem:draft-comments-for-attachment-1');
186 }
187
188 function stripBornOn(json) {
189   return json.replace(/\"born\-on\"\:\d+,/, "");
190 }
191
192 function strippedSavedComments() {
193   return stripBornOn(localStorage[g_draftCommentSaver.localStorageKey()]);
194 }
195
196 function syncSlideUp(type, handler) {
197   handler.call(this);
198 }
199
200 function testReaddDiscardedCommentWithPreviousComment() {
201   document.getElementById('diff-content').innerHTML =
202       '<div class="FileDiff">' +
203         '<h1><a href="http://trac.webkit.org/browser/trunk/Source/WebCore/ChangeLog">Source/WebCore/ChangeLog</a></h1>' +
204         '<div class="DiffSection">' +
205           '<div class="DiffBlock">' +
206             '<div class="DiffBlockPart add">' +
207               '<div class="Line LineContainer add">' +
208                 '<span class="from lineNumber">&nbsp;</span><span class="to lineNumber">1</span><span class="text">first diff block first line</span>' +
209               '</div>' +
210               '<div class="Line LineContainer add">' +
211                 '<span class="from lineNumber">&nbsp;</span><span class="to lineNumber">2</span><span class="text"></span>' +
212               '</div>' +
213             '</div>' +
214             '<div class="clear_float"></div>' +
215           '</div>' +
216           '<div class="DiffBlock">' +
217             '<div class="DiffBlockPart shared">' +
218               '<div class="Line LineContainer">' +
219                 '<span class="from lineNumber">1</span><span class="to lineNumber">12</span><span class="text">second diff block first line</span>' +
220               '</div>' +
221               '</div><div class="clear_float">' +
222             '</div>' +
223           '</div>' +
224         '</div>' +
225       '</div>';
226
227   eraseDraftComments();
228   crawlDiff();
229   appendToolbar();
230
231   var line = document.getElementById('line0');
232   var author = "ojan@chromium.org";
233   var comment_text = "This change sux.";
234   addPreviousComment(line, author, comment_text);
235   var previous_comment = document.querySelector('.previousComment');
236   ASSERT("Line with only a previous comment should not have 'data-has-comment' attribute.", !line.getAttribute('data-has-comment'));
237
238   var new_comment = addCommentField(previous_comment);
239   new_comment.find('textarea').val("dummy content");
240   var frozen_comment = acceptComment(new_comment);
241
242   ASSERT_EQUAL(document.querySelectorAll('.comment').length, 1);
243   ASSERT_EQUAL(strippedSavedComments(), '{"comments":[{"start_line_id":"line0","end_line_id":"line0","contents":"dummy content"}],"overall-comments":""}');
244
245   unfreezeComment(frozen_comment);
246   // This is a hack to make slideUp synchronous so that we can keep this test from needing to be async.
247   jQuery.fn.slideUp = syncSlideUp;
248   discardComment(new_comment);
249
250   ASSERT('There should be no draft comments.', !document.querySelector('.comment'));
251   ASSERT_EQUAL(strippedSavedComments(), '{"comments":[],"overall-comments":""}');
252   ASSERT("Line with only a previous comment should not have 'data-has-comment' attribute.", !line.getAttribute('data-has-comment'));
253
254   new_comment = addCommentField(previous_comment);
255   new_comment.find('textarea').val("dummy content");
256   acceptComment(new_comment);
257
258   ASSERT_EQUAL(document.querySelectorAll('.comment').length, 1);
259   ASSERT_EQUAL(strippedSavedComments(), '{"comments":[{"start_line_id":"line0","end_line_id":"line0","contents":"dummy content"}],"overall-comments":""}');
260
261   document.getElementById('diff-content').innerHTML = '';
262 }
263
264 function testSideBySideDiffWithPreviousCommentsOnSharedLine() {
265   document.getElementById('diff-content').innerHTML =
266       '<div class="FileDiff">' +
267         '<h1><a href="http://trac.webkit.org/browser/trunk/Source/WebCore/ChangeLog">Source/WebCore/ChangeLog</a></h1>' +
268         '<div class="DiffSection">' +
269           '<div class="DiffBlock">' +
270             '<div class="DiffBlockPart shared">' +
271               '<div class="Line LineContainer">' +
272               '<span class="from lineNumber">336</span><span class="to lineNumber">338</span><span class="text">    layoutFlexItems(*m_orderIterator, lineContexts);</span>' +
273               '</div>' +
274               '<div class="Line LineContainer">' +
275               '<span class="from lineNumber">337</span><span class="to lineNumber">339</span><span class="text"></span>' +
276               '</div>' +
277               '<div class="Line LineContainer">' +
278               '<span class="from lineNumber">338</span><span class="to lineNumber">340</span><span class="text">    LayoutUnit oldClientAfterEdge = clientLogicalBottom();</span>' +
279               '</div>' +
280             '</div><div class="clear_float">' +
281           '</div>' +
282         '</div>' +
283       '</div>';
284
285   next_line_id = 0;
286   eraseDraftComments();
287   crawlDiff();
288
289   convertAllFileDiffs('sidebyside', $('.FileDiff'));
290
291   displayPreviousComments([{
292     author: 'ojan@chromium.org',
293     file_name: 'Source/WebCore/ChangeLog',
294     line_number: 338,
295     comment_text: 'This change sux.'
296   }]);
297
298   var previous_comment = document.querySelector('.previousComment');
299   ASSERT_EQUAL(previous_comment.getAttribute('data-comment-for'), 'line0');
300
301   var new_comment = addCommentField(previous_comment);
302   ASSERT("New comment should exist and contain a textarea.", new_comment.find('textarea'));
303
304   document.getElementById('diff-content').innerHTML = '';
305 }
306
307 function testIsChangeLog() {
308   ASSERT("Top-level ChangeLog file is a ChangeLog file", isChangeLog("ChangeLog"));
309   ASSERT("Second-level ChangeLog file is a ChangeLog file", isChangeLog("Tools/ChangeLog"));
310   ASSERT("prepare-ChangeLog is not a ChangeLog file", !isChangeLog("Tools/Scripts/prepare-ChangeLog"));
311   ASSERT("ChangeLog-script is not a ChangeLog file", !isChangeLog("Tools/Scripts/ChangeLog-script"));
312 }
313
314 for (var property in window) {
315   if (property.indexOf('test') == 0) {
316     window[property]();
317   }
318 }
319 </script>