493 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			493 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | ||
| <!--
 | ||
| Copyright (C) 2015 The Android Open Source Project
 | ||
| 
 | ||
| Licensed under the Apache License, Version 2.0 (the "License");
 | ||
| you may not use this file except in compliance with the License.
 | ||
| You may obtain a copy of the License at
 | ||
| 
 | ||
| http://www.apache.org/licenses/LICENSE-2.0
 | ||
| 
 | ||
| Unless required by applicable law or agreed to in writing, software
 | ||
| distributed under the License is distributed on an "AS IS" BASIS,
 | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||
| See the License for the specific language governing permissions and
 | ||
| limitations under the License.
 | ||
| -->
 | ||
| 
 | ||
| <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 | ||
| <title>gr-diff</title>
 | ||
| 
 | ||
| <script src="../../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
 | ||
| <script src="../../../bower_components/web-component-tester/browser.js"></script>
 | ||
| <script src="../../../test/fake-app.js"></script>
 | ||
| <script src="../../../scripts/util.js"></script>
 | ||
| 
 | ||
| <link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
 | ||
| <link rel="import" href="gr-diff.html">
 | ||
| 
 | ||
| <test-fixture id="basic">
 | ||
|   <template>
 | ||
|     <gr-diff></gr-diff>
 | ||
|   </template>
 | ||
| </test-fixture>
 | ||
| 
 | ||
| <script>
 | ||
|   suite('gr-diff tests', function() {
 | ||
|     var element;
 | ||
|     var server;
 | ||
|     var getDiffStub;
 | ||
|     var getCommentsStub;
 | ||
| 
 | ||
|     setup(function() {
 | ||
|       element = fixture('basic');
 | ||
|       element.changeNum = 42;
 | ||
|       element.path = 'sieve.go';
 | ||
|       element.prefs = {
 | ||
|         context: 10,
 | ||
|         tab_size: 8,
 | ||
|       };
 | ||
| 
 | ||
|       getDiffStub = sinon.stub(element.$.restAPI, 'getDiff', function() {
 | ||
|         return Promise.resolve({
 | ||
|           change_type: 'MODIFIED',
 | ||
|           content: [
 | ||
|             {
 | ||
|               ab: [
 | ||
|                 '<!DOCTYPE html>',
 | ||
|                 '<meta charset="utf-8">',
 | ||
|                 '<title>My great page</title>',
 | ||
|                 '<style>',
 | ||
|                 '  *,',
 | ||
|                 '  *:before,',
 | ||
|                 '  *:after {',
 | ||
|                 '    box-sizing: border-box;',
 | ||
|                 '  }',
 | ||
|                 '</style>',
 | ||
|                 '<header>',
 | ||
|               ]
 | ||
|             },
 | ||
|             {
 | ||
|               a: [
 | ||
|                 '  Welcome ',
 | ||
|                 '  to the wooorld of tomorrow!',
 | ||
|               ],
 | ||
|               b: [
 | ||
|                 '  Hello, world!',
 | ||
|               ],
 | ||
|             },
 | ||
|             {
 | ||
|               ab: [
 | ||
|                 '</header>',
 | ||
|                 '<body>',
 | ||
|                 'Leela: This is the only place the ship can’t hear us, so ',
 | ||
|                 'everyone pretend to shower.',
 | ||
|                 'Fry: Same as every day. Got it.',
 | ||
|               ]
 | ||
|             },
 | ||
|           ]
 | ||
|         });
 | ||
|       });
 | ||
| 
 | ||
|       getCommentsStub = sinon.stub(element.$.restAPI, 'getDiffComments',
 | ||
|         function() {
 | ||
|           return Promise.resolve({
 | ||
|             baseComments: [
 | ||
|               {
 | ||
|                 author: {
 | ||
|                   _account_id: 1000000,
 | ||
|                   name: 'Andrew Bonventre',
 | ||
|                   email: 'andybons@gmail.com',
 | ||
|                 },
 | ||
|                 id: '9af53d3f_5f2b8b82',
 | ||
|                 line: 1,
 | ||
|                 message: 'this isn’t quite right',
 | ||
|                 updated: '2015-12-10 02:50:21.627000000',
 | ||
|               }
 | ||
|             ],
 | ||
|             comments: [
 | ||
|               {
 | ||
|                 author: {
 | ||
|                   _account_id: 1010008,
 | ||
|                   name: 'Dave Borowitz',
 | ||
|                   email: 'dborowitz@google.com',
 | ||
|                 },
 | ||
|                 id: '001a2067_f30f3048',
 | ||
|                 line: 12,
 | ||
|                 message: 'What on earth are you thinking, here?',
 | ||
|                 updated: '2015-12-12 02:51:37.973000000',
 | ||
|               },
 | ||
|               {
 | ||
|                 author: {
 | ||
|                   _account_id: 1000000,
 | ||
|                   name: 'Andrew Bonventre',
 | ||
|                   email: 'andybons@gmail.com',
 | ||
|                 },
 | ||
|                 id: 'a0407443_30dfe8fb',
 | ||
|                 in_reply_to: '001a2067_f30f3048',
 | ||
|                 line: 12,
 | ||
|                 message: '¯\\_(ツ)_/¯',
 | ||
|                 updated: '2015-12-12 18:50:21.627000000',
 | ||
|               },
 | ||
|             ],
 | ||
|           });
 | ||
|         }
 | ||
|       );
 | ||
| 
 | ||
|       server = sinon.fakeServer.create();
 | ||
|       server.respondWith(
 | ||
|         'PUT',
 | ||
|         '/accounts/self/preferences.diff',
 | ||
|         [
 | ||
|           200,
 | ||
|           {'Content-Type': 'application/json'},
 | ||
|           ')]}\'\n' +
 | ||
|           JSON.stringify({context: 25}),
 | ||
|         ]
 | ||
|       );
 | ||
| 
 | ||
|     });
 | ||
| 
 | ||
|     teardown(function() {
 | ||
|       getDiffStub.restore();
 | ||
|       getCommentsStub.restore();
 | ||
|       server.restore();
 | ||
|     });
 | ||
| 
 | ||
|     test('comment rendering', function(done) {
 | ||
|       element.prefs.context = -1;
 | ||
|       element._loggedIn = true;
 | ||
|       element.patchRange = {
 | ||
|         basePatchNum: 1,
 | ||
|         patchNum: 2,
 | ||
|       };
 | ||
| 
 | ||
|       element.reload().then(function() {
 | ||
|         flush(function() {
 | ||
|           var leftThreadEls =
 | ||
|               Polymer.dom(element.$.leftDiff.root).querySelectorAll(
 | ||
|                   'gr-diff-comment-thread');
 | ||
|           assert.equal(leftThreadEls.length, 1);
 | ||
|           assert.equal(leftThreadEls[0].comments.length, 1);
 | ||
| 
 | ||
|           var rightThreadEls =
 | ||
|               Polymer.dom(element.$.rightDiff.root).querySelectorAll(
 | ||
|                   'gr-diff-comment-thread');
 | ||
|           assert.equal(rightThreadEls.length, 1);
 | ||
|           assert.equal(rightThreadEls[0].comments.length, 2);
 | ||
| 
 | ||
|           var index = leftThreadEls[0].getAttribute('data-index');
 | ||
|           var leftFillerEls =
 | ||
|               Polymer.dom(element.$.leftDiff.root).querySelectorAll(
 | ||
|                   '.commentThread.filler[data-index="' + index + '"]');
 | ||
|           assert.equal(leftFillerEls.length, 1);
 | ||
|           var rightFillerEls =
 | ||
|               Polymer.dom(element.$.rightDiff.root).querySelectorAll(
 | ||
|                   '[data-index="' + index + '"]');
 | ||
|           assert.equal(rightFillerEls.length, 2);
 | ||
| 
 | ||
|           for (var i = 0; i < rightFillerEls.length; i++) {
 | ||
|             assert.isTrue(rightFillerEls[i].classList.contains('filler'));
 | ||
|           }
 | ||
|           var originalHeight = rightFillerEls[0].offsetHeight;
 | ||
|           assert.equal(rightFillerEls[1].offsetHeight, originalHeight);
 | ||
|           assert.equal(leftThreadEls[0].offsetHeight, originalHeight);
 | ||
|           assert.equal(leftFillerEls[0].offsetHeight, originalHeight);
 | ||
| 
 | ||
|           // Create a comment on the opposite side of the first comment.
 | ||
|           var rightLineEL = element.$.rightDiff.$$(
 | ||
|                 '.lineNum[data-index="' + (index - 1) + '"]');
 | ||
|           assert.ok(rightLineEL);
 | ||
|           MockInteractions.tap(rightLineEL);
 | ||
|           flush(function() {
 | ||
|             var newThreadEls =
 | ||
|               Polymer.dom(element.$.rightDiff.root).querySelectorAll(
 | ||
|                   '[data-index="' + index + '"]');
 | ||
|             assert.equal(newThreadEls.length, 2);
 | ||
|             for (var i = 0; i < newThreadEls.length; i++) {
 | ||
|               assert.isTrue(
 | ||
|                   newThreadEls[i].classList.contains('commentThread') ||
 | ||
|                   newThreadEls[i].tagName == 'GR-DIFF-COMMENT-THREAD');
 | ||
|             }
 | ||
|             var newHeight = newThreadEls[0].offsetHeight;
 | ||
|             assert.equal(newThreadEls[1].offsetHeight, newHeight);
 | ||
|             assert.equal(leftFillerEls[0].offsetHeight, newHeight);
 | ||
|             assert.equal(leftThreadEls[0].offsetHeight, newHeight);
 | ||
| 
 | ||
|             // The editing mode height of the right comment will be greater than
 | ||
|             // the non-editing mode height of the left comment.
 | ||
|             assert.isAbove(newHeight, originalHeight);
 | ||
| 
 | ||
|             // Discard the right thread and ensure the left comment heights are
 | ||
|             // back to their original values.
 | ||
|             newThreadEls[1].addEventListener('discard', function() {
 | ||
|               rightFillerEls =
 | ||
|                   Polymer.dom(element.$.rightDiff.root).querySelectorAll(
 | ||
|                       '[data-index="' + index + '"]');
 | ||
|               assert.equal(rightFillerEls.length, 2);
 | ||
| 
 | ||
|               for (var i = 0; i < rightFillerEls.length; i++) {
 | ||
|                 assert.isTrue(rightFillerEls[i].classList.contains('filler'));
 | ||
|               }
 | ||
|               var originalHeight = rightFillerEls[0].offsetHeight;
 | ||
|               assert.equal(rightFillerEls[1].offsetHeight, originalHeight);
 | ||
|               assert.equal(leftThreadEls[0].offsetHeight, originalHeight);
 | ||
|               assert.equal(leftFillerEls[0].offsetHeight, originalHeight);
 | ||
|               done();
 | ||
|             });
 | ||
|             var commentEl = newThreadEls[1].$$('gr-diff-comment');
 | ||
|             commentEl.fire('discard', null, {bubbles: false});
 | ||
|           });
 | ||
|         });
 | ||
|       });
 | ||
|       server.respond();
 | ||
|     });
 | ||
| 
 | ||
|     test('intraline normalization', function() {
 | ||
|       // The content and highlights are in the format returned by the Gerrit
 | ||
|       // REST API.
 | ||
|       var content = [
 | ||
|         '      <section class="summary">',
 | ||
|         '        <gr-linked-text content="' +
 | ||
|             '[[_computeCurrentRevisionMessage(change)]]"></gr-linked-text>',
 | ||
|         '      </section>',
 | ||
|       ];
 | ||
|       var highlights = [
 | ||
|         [31, 34], [42, 26]
 | ||
|       ];
 | ||
|       var results = element._normalizeIntralineHighlights(content, highlights);
 | ||
|       assert.deepEqual(results, [
 | ||
|         {
 | ||
|           contentIndex: 0,
 | ||
|           startIndex: 31,
 | ||
|         },
 | ||
|         {
 | ||
|           contentIndex: 1,
 | ||
|           startIndex: 0,
 | ||
|           endIndex: 33,
 | ||
|         },
 | ||
|         {
 | ||
|           contentIndex: 1,
 | ||
|           startIndex: 75,
 | ||
|         },
 | ||
|         {
 | ||
|           contentIndex: 2,
 | ||
|           startIndex: 0,
 | ||
|           endIndex: 6,
 | ||
|         }
 | ||
|       ]);
 | ||
| 
 | ||
|       content = [
 | ||
|         '        this._path = value.path;',
 | ||
|         '',
 | ||
|         '        // When navigating away from the page, there is a possibility that the',
 | ||
|         '        // patch number is no longer a part of the URL (say when navigating to',
 | ||
|         '        // the top-level change info view) and therefore undefined in `params`.',
 | ||
|         '        if (!this._patchRange.patchNum) {',
 | ||
|       ];
 | ||
|       highlights = [
 | ||
|         [14, 17],
 | ||
|         [11, 70],
 | ||
|         [12, 67],
 | ||
|         [12, 67],
 | ||
|         [14, 29],
 | ||
|       ];
 | ||
|       results = element._normalizeIntralineHighlights(content, highlights);
 | ||
|       assert.deepEqual(results, [
 | ||
|         {
 | ||
|           contentIndex: 0,
 | ||
|           startIndex: 14,
 | ||
|           endIndex: 31,
 | ||
|         },
 | ||
|         {
 | ||
|           contentIndex: 2,
 | ||
|           startIndex: 8,
 | ||
|           endIndex: 78,
 | ||
|         },
 | ||
|         {
 | ||
|           contentIndex: 3,
 | ||
|           startIndex: 11,
 | ||
|           endIndex: 78,
 | ||
|         },
 | ||
|         {
 | ||
|           contentIndex: 4,
 | ||
|           startIndex: 11,
 | ||
|           endIndex: 78,
 | ||
|         },
 | ||
|         {
 | ||
|           contentIndex: 5,
 | ||
|           startIndex: 12,
 | ||
|           endIndex: 41,
 | ||
|         }
 | ||
|       ]);
 | ||
|     });
 | ||
| 
 | ||
|     test('context', function() {
 | ||
|       element.prefs.context = 3;
 | ||
|       element._diffResponse = {
 | ||
|         content: [
 | ||
|           {
 | ||
|             ab: [
 | ||
|               '<!DOCTYPE html>',
 | ||
|               '<meta charset="utf-8">',
 | ||
|               '<title>My great page</title>',
 | ||
|               '<style>',
 | ||
|               '  *,',
 | ||
|               '  *:before,',
 | ||
|               '  *:after {',
 | ||
|               '    box-sizing: border-box;',
 | ||
|               '  }',
 | ||
|               '</style>',
 | ||
|               '<header>',
 | ||
|             ]
 | ||
|           },
 | ||
|           {
 | ||
|             a: [
 | ||
|               '  Welcome ',
 | ||
|               '  to the wooorld of tomorrow!',
 | ||
|             ],
 | ||
|             b: [
 | ||
|               '  Hello, world!',
 | ||
|             ],
 | ||
|           },
 | ||
|           {
 | ||
|             ab: [
 | ||
|               '</header>',
 | ||
|               '<body>',
 | ||
|               'Leela: This is the only place the ship can’t hear us, so ',
 | ||
|               'everyone pretend to shower.',
 | ||
|               'Fry: Same as every day. Got it.',
 | ||
|             ]
 | ||
|           },
 | ||
|         ]
 | ||
|       };
 | ||
|       element._processContent();
 | ||
| 
 | ||
|       // First eight lines should be hidden on both sides.
 | ||
|       for (var i = 0; i < 8; i++) {
 | ||
|         assert.isTrue(element._diff.leftSide[i].hidden);
 | ||
|         assert.isTrue(element._diff.rightSide[i].hidden);
 | ||
|       }
 | ||
|       // A context control should be at index 8 on both sides.
 | ||
|       var leftContext = element._diff.leftSide[8];
 | ||
|       var rightContext = element._diff.rightSide[8];
 | ||
|       assert.deepEqual(leftContext, rightContext);
 | ||
|       assert.equal(leftContext.numLines, 8);
 | ||
|       assert.equal(leftContext.start, 0);
 | ||
|       assert.equal(leftContext.end, 8);
 | ||
| 
 | ||
|       // Line indices 9-16 should be shown.
 | ||
|       for (var i = 9; i <= 16; i++) {
 | ||
|         // notOk (falsy) because the `hidden` attribute may not be present.
 | ||
|         assert.notOk(element._diff.leftSide[i].hidden);
 | ||
|         assert.notOk(element._diff.rightSide[i].hidden);
 | ||
|       }
 | ||
| 
 | ||
|       // Lines at indices 17 and 18 should be hidden.
 | ||
|       assert.isTrue(element._diff.leftSide[17].hidden);
 | ||
|       assert.isTrue(element._diff.rightSide[17].hidden);
 | ||
|       assert.isTrue(element._diff.leftSide[18].hidden);
 | ||
|       assert.isTrue(element._diff.rightSide[18].hidden);
 | ||
| 
 | ||
|       // Context control at index 19.
 | ||
|       leftContext = element._diff.leftSide[19];
 | ||
|       rightContext = element._diff.rightSide[19];
 | ||
|       assert.deepEqual(leftContext, rightContext);
 | ||
|       assert.equal(leftContext.numLines, 2);
 | ||
|       assert.equal(leftContext.start, 17);
 | ||
|       assert.equal(leftContext.end, 19);
 | ||
|     });
 | ||
| 
 | ||
|     test('save prefs', function(done) {
 | ||
|       element._loggedIn = false;
 | ||
| 
 | ||
|       element.prefs = {
 | ||
|         tab_size: 4,
 | ||
|         context: 50,
 | ||
|       };
 | ||
|       element.fire('save', {}, {node: element.$$('gr-diff-preferences')});
 | ||
|       assert.isTrue(element._diffPreferencesPromise == null);
 | ||
| 
 | ||
|       element._loggedIn = true;
 | ||
|       element.fire('save', {}, {node: element.$$('gr-diff-preferences')});
 | ||
|       server.respond();
 | ||
| 
 | ||
|       element._diffPreferencesPromise.then(function(req) {
 | ||
|         assert.equal(req.xhr.requestBody, JSON.stringify(element.prefs));
 | ||
|         done();
 | ||
|       });
 | ||
|     });
 | ||
| 
 | ||
|     test('visible line length', function() {
 | ||
|       assert.equal(element._visibleLineLength('A'.repeat(5)), 5);
 | ||
|       assert.equal(
 | ||
|           element._visibleLineLength('A'.repeat(5) + '\t' + 'A'.repeat(5)), 18);
 | ||
|     });
 | ||
| 
 | ||
|     test('break up common diff chunks', function() {
 | ||
|       element._groupedBaseComments = {
 | ||
|         1: {},
 | ||
|       };
 | ||
|       element._groupedComments = {
 | ||
|         10: {},
 | ||
|       };
 | ||
|       var ctx = {
 | ||
|         left: {lineNum: 0},
 | ||
|         right: {lineNum: 0},
 | ||
|       };
 | ||
|       var content = [
 | ||
|         {
 | ||
|           ab: [
 | ||
|             'Copyright (C) 2015 The Android Open Source Project',
 | ||
|             '',
 | ||
|             'Licensed under the Apache License, Version 2.0 (the "License");',
 | ||
|             'you may not use this file except in compliance with the License.',
 | ||
|             'You may obtain a copy of the License at',
 | ||
|             '',
 | ||
|             'http://www.apache.org/licenses/LICENSE-2.0',
 | ||
|             '',
 | ||
|             'Unless required by applicable law or agreed to in writing, ',
 | ||
|             'software distributed under the License is distributed on an ',
 | ||
|             '"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, ',
 | ||
|             'either express or implied. See the License for the specific ',
 | ||
|             'language governing permissions and limitations under the License.',
 | ||
|           ]
 | ||
|         }
 | ||
|       ];
 | ||
|       var result = element._breakUpCommonChunksWithComments(ctx, content);
 | ||
|       assert.deepEqual(result, [
 | ||
|         {
 | ||
|           __noHighlight: true,
 | ||
|           a: ['Copyright (C) 2015 The Android Open Source Project'],
 | ||
|           b: ['Copyright (C) 2015 The Android Open Source Project'],
 | ||
|         },
 | ||
|         {
 | ||
|           ab: [
 | ||
|             '',
 | ||
|             'Licensed under the Apache License, Version 2.0 (the "License");',
 | ||
|             'you may not use this file except in compliance with the License.',
 | ||
|             'You may obtain a copy of the License at',
 | ||
|             '',
 | ||
|             'http://www.apache.org/licenses/LICENSE-2.0',
 | ||
|             '',
 | ||
|             'Unless required by applicable law or agreed to in writing, ',
 | ||
|           ]
 | ||
|         },
 | ||
|         {
 | ||
|           __noHighlight: true,
 | ||
|           a: ['software distributed under the License is distributed on an '],
 | ||
|           b: ['software distributed under the License is distributed on an ']
 | ||
|         },
 | ||
|         {
 | ||
|           ab: [
 | ||
|             '"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, ',
 | ||
|             'either express or implied. See the License for the specific ',
 | ||
|             'language governing permissions and limitations under the License.',
 | ||
|           ]
 | ||
|         }
 | ||
|       ]);
 | ||
|     });
 | ||
|   });
 | ||
| 
 | ||
| </script>
 | 
