Moves the diff-processing functionality of the gr-diff-builder component into a new gr-diff-processor component which exposes a promise-based interface. This is step one of creating an asynchronous (non-blocking) diff rendering system. As much as possible, this change is a transfer of code (with tests) from one component to another, making it easier to verify that functionality has not changed. Cleanup of the code, and refactoring it into a more-testable form will come with later changes. Feature: Issue 3916 Change-Id: I875b03b20bf953b128cbe3c5001ba1f8eba12c61
		
			
				
	
	
		
			300 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!DOCTYPE html>
 | 
						|
<!--
 | 
						|
Copyright (C) 2016 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-builder</title>
 | 
						|
 | 
						|
<script src="../../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
 | 
						|
<script src="../../../bower_components/web-component-tester/browser.js"></script>
 | 
						|
<script src="../gr-diff/gr-diff-line.js"></script>
 | 
						|
<script src="../gr-diff/gr-diff-group.js"></script>
 | 
						|
<script src="gr-diff-builder.js"></script>
 | 
						|
 | 
						|
<link rel="import" href="gr-diff-builder.html">
 | 
						|
 | 
						|
<test-fixture id="basic">
 | 
						|
  <template>
 | 
						|
    <gr-diff-builder>
 | 
						|
      <table id="diffTable"></table>
 | 
						|
    </gr-diff-builder>
 | 
						|
  </template>
 | 
						|
</test-fixture>
 | 
						|
 | 
						|
 | 
						|
<script>
 | 
						|
  suite('gr-diff-builder tests', function() {
 | 
						|
    var builder;
 | 
						|
 | 
						|
    setup(function() {
 | 
						|
      var prefs = {
 | 
						|
        line_length: 10,
 | 
						|
        show_tabs: true,
 | 
						|
        tab_size: 4,
 | 
						|
      };
 | 
						|
      builder = new GrDiffBuilder({content: []}, {left: [], right: []}, prefs);
 | 
						|
    });
 | 
						|
 | 
						|
    test('context control buttons', function() {
 | 
						|
      var section = {};
 | 
						|
      var line = {contextGroup: {lines: []}};
 | 
						|
 | 
						|
      // Create 10 lines.
 | 
						|
      for (var i = 0; i < 10; i++) {
 | 
						|
        line.contextGroup.lines.push('lorem upsum');
 | 
						|
      }
 | 
						|
 | 
						|
      // Does not include +10 buttons when there are fewer than 11 lines.
 | 
						|
      var td = builder._createContextControl(section, line);
 | 
						|
      var buttons = td.querySelectorAll('gr-button.showContext');
 | 
						|
 | 
						|
      assert.equal(buttons.length, 1);
 | 
						|
      assert.equal(buttons[0].textContent, 'Show 10 common lines');
 | 
						|
 | 
						|
      // Add another line.
 | 
						|
      line.contextGroup.lines.push('lorem upsum');
 | 
						|
 | 
						|
      // Includes +10 buttons when there are at least 11 lines.
 | 
						|
      td = builder._createContextControl(section, line);
 | 
						|
      buttons = td.querySelectorAll('gr-button.showContext');
 | 
						|
 | 
						|
      assert.equal(buttons.length, 3);
 | 
						|
      assert.equal(buttons[0].textContent, '+10↑');
 | 
						|
      assert.equal(buttons[1].textContent, 'Show 11 common lines');
 | 
						|
      assert.equal(buttons[2].textContent, '+10↓');
 | 
						|
    });
 | 
						|
 | 
						|
    test('newlines', function() {
 | 
						|
      var text = 'abcdef';
 | 
						|
      assert.equal(builder._addNewlines(text, text), text);
 | 
						|
      text = 'a'.repeat(20);
 | 
						|
      assert.equal(builder._addNewlines(text, text),
 | 
						|
          'a'.repeat(10) +
 | 
						|
          GrDiffBuilder.LINE_FEED_HTML +
 | 
						|
          'a'.repeat(10));
 | 
						|
 | 
						|
      text = '<span class="thumbsup">👍</span>';
 | 
						|
      var html = '<span class="thumbsup">👍</span>';
 | 
						|
      assert.equal(builder._addNewlines(text, html),
 | 
						|
          '<span clas' +
 | 
						|
          GrDiffBuilder.LINE_FEED_HTML +
 | 
						|
          's="thumbsu' +
 | 
						|
          GrDiffBuilder.LINE_FEED_HTML +
 | 
						|
          'p">👍</spa' +
 | 
						|
          GrDiffBuilder.LINE_FEED_HTML +
 | 
						|
          'n>');
 | 
						|
 | 
						|
      text = '01234\t56789';
 | 
						|
      assert.equal(builder._addNewlines(text, text),
 | 
						|
          '01234\t5' +
 | 
						|
          GrDiffBuilder.LINE_FEED_HTML +
 | 
						|
          '6789');
 | 
						|
    });
 | 
						|
 | 
						|
    test('text length with tabs', function() {
 | 
						|
      assert.equal(builder._textLength('12345', 4), 5);
 | 
						|
      assert.equal(builder._textLength('\t\t12', 4), 10);
 | 
						|
    });
 | 
						|
 | 
						|
    test('tab wrapper insertion', function() {
 | 
						|
      var html = 'abc\tdef';
 | 
						|
      var wrapper = builder._getTabWrapper(
 | 
						|
          builder._prefs.tab_size,
 | 
						|
          builder._prefs.show_tabs);
 | 
						|
      assert.ok(wrapper);
 | 
						|
      assert.isAbove(wrapper.length, 0);
 | 
						|
      assert.equal(builder._addTabWrappers(html), 'abc' + wrapper + 'def');
 | 
						|
      assert.throws(builder._getTabWrapper.bind(
 | 
						|
          builder,
 | 
						|
          // using \x3c instead of < in string so gjslint can parse
 | 
						|
          '">\x3cimg src="/" onerror="alert(1);">\x3cspan class="',
 | 
						|
          true));
 | 
						|
    });
 | 
						|
 | 
						|
    test('comments', function() {
 | 
						|
      var line = new GrDiffLine(GrDiffLine.Type.BOTH);
 | 
						|
      line.beforeNumber = 3;
 | 
						|
      line.afterNumber = 5;
 | 
						|
 | 
						|
      var comments = {left: [], right: []};
 | 
						|
      assert.deepEqual(builder._getCommentsForLine(comments, line), []);
 | 
						|
      assert.deepEqual(builder._getCommentsForLine(comments, line,
 | 
						|
          GrDiffBuilder.Side.LEFT), []);
 | 
						|
      assert.deepEqual(builder._getCommentsForLine(comments, line,
 | 
						|
          GrDiffBuilder.Side.RIGHT), []);
 | 
						|
 | 
						|
      comments = {
 | 
						|
        left: [
 | 
						|
          {id: 'l3', line: 3},
 | 
						|
          {id: 'l5', line: 5},
 | 
						|
        ],
 | 
						|
        right: [
 | 
						|
          {id: 'r3', line: 3},
 | 
						|
          {id: 'r5', line: 5},
 | 
						|
        ],
 | 
						|
      };
 | 
						|
      assert.deepEqual(builder._getCommentsForLine(comments, line),
 | 
						|
          [{id: 'l3', line: 3}, {id: 'r5', line: 5}]);
 | 
						|
      assert.deepEqual(builder._getCommentsForLine(comments, line,
 | 
						|
          GrDiffBuilder.Side.LEFT), [{id: 'l3', line: 3}]);
 | 
						|
      assert.deepEqual(builder._getCommentsForLine(comments, line,
 | 
						|
          GrDiffBuilder.Side.RIGHT), [{id: 'r5', line: 5}]);
 | 
						|
    });
 | 
						|
 | 
						|
    test('comment thread creation', function() {
 | 
						|
      builder._comments = {
 | 
						|
        meta: {
 | 
						|
          changeNum: '42',
 | 
						|
          patchRange: {
 | 
						|
            basePatchNum: 'PARENT',
 | 
						|
            patchNum: '3',
 | 
						|
          },
 | 
						|
          path: '/path/to/foo',
 | 
						|
          projectConfig: {foo: 'bar'},
 | 
						|
        },
 | 
						|
        left: [
 | 
						|
          {id: 'l3', line: 3},
 | 
						|
          {id: 'l5', line: 5},
 | 
						|
        ],
 | 
						|
        right: [
 | 
						|
          {id: 'r5', line: 5},
 | 
						|
        ],
 | 
						|
      };
 | 
						|
 | 
						|
      function checkThreadProps(threadEl, patchNum, side, comments) {
 | 
						|
        assert.equal(threadEl.changeNum, '42');
 | 
						|
        assert.equal(threadEl.patchNum, patchNum);
 | 
						|
        assert.equal(threadEl.path, '/path/to/foo');
 | 
						|
        assert.equal(threadEl.side, side);
 | 
						|
        assert.deepEqual(threadEl.projectConfig, {foo: 'bar'});
 | 
						|
        assert.deepEqual(threadEl.comments, comments);
 | 
						|
      }
 | 
						|
 | 
						|
      var line = new GrDiffLine(GrDiffLine.Type.BOTH);
 | 
						|
      line.beforeNumber = 5;
 | 
						|
      line.afterNumber = 5;
 | 
						|
      var threadEl = builder._commentThreadForLine(line);
 | 
						|
      checkThreadProps(threadEl, '3', 'REVISION',
 | 
						|
          [{id: 'l5', line: 5}, {id: 'r5', line: 5}]);
 | 
						|
 | 
						|
      threadEl = builder._commentThreadForLine(line, GrDiffBuilder.Side.RIGHT);
 | 
						|
      checkThreadProps(threadEl, '3', 'REVISION', [{id: 'r5', line: 5}]);
 | 
						|
 | 
						|
      threadEl = builder._commentThreadForLine(line, GrDiffBuilder.Side.LEFT);
 | 
						|
      checkThreadProps(threadEl, '3', 'PARENT', [{id: 'l5', line: 5}]);
 | 
						|
 | 
						|
      builder._comments.meta.patchRange.basePatchNum = '1';
 | 
						|
 | 
						|
      threadEl = builder._commentThreadForLine(line);
 | 
						|
      checkThreadProps(threadEl, '3', 'REVISION',
 | 
						|
          [{id: 'l5', line: 5}, {id: 'r5', line: 5}]);
 | 
						|
 | 
						|
      threadEl = builder._commentThreadForLine(line, GrDiffBuilder.Side.LEFT);
 | 
						|
      checkThreadProps(threadEl, '1', 'REVISION', [{id: 'l5', line: 5}]);
 | 
						|
 | 
						|
      threadEl = builder._commentThreadForLine(line, GrDiffBuilder.Side.RIGHT);
 | 
						|
      checkThreadProps(threadEl, '3', 'REVISION', [{id: 'r5', line: 5}]);
 | 
						|
 | 
						|
      builder._comments.meta.patchRange.basePatchNum = 'PARENT';
 | 
						|
 | 
						|
      line = new GrDiffLine(GrDiffLine.Type.REMOVE);
 | 
						|
      line.beforeNumber = 5;
 | 
						|
      line.afterNumber = 5;
 | 
						|
      threadEl = builder._commentThreadForLine(line);
 | 
						|
      checkThreadProps(threadEl, '3', 'PARENT',
 | 
						|
          [{id: 'l5', line: 5}, {id: 'r5', line: 5}]);
 | 
						|
 | 
						|
      line = new GrDiffLine(GrDiffLine.Type.ADD);
 | 
						|
      line.beforeNumber = 3;
 | 
						|
      line.afterNumber = 5;
 | 
						|
      threadEl = builder._commentThreadForLine(line);
 | 
						|
      checkThreadProps(threadEl, '3', 'REVISION',
 | 
						|
          [{id: 'l3', line: 3}, {id: 'r5', line: 5}]);
 | 
						|
    });
 | 
						|
 | 
						|
    suite('rendering', function() {
 | 
						|
      var content;
 | 
						|
      var outputEl;
 | 
						|
 | 
						|
      setup(function(done) {
 | 
						|
        var prefs = {
 | 
						|
          line_length: 10,
 | 
						|
          show_tabs: true,
 | 
						|
          tab_size: 4,
 | 
						|
          context: -1
 | 
						|
        };
 | 
						|
        content = [
 | 
						|
          {
 | 
						|
            a: ['all work and no play make andybons a dull boy'],
 | 
						|
            b: ['elgoog elgoog elgoog']
 | 
						|
          },
 | 
						|
          {
 | 
						|
            ab: [
 | 
						|
              'Non eram nescius, Brute, cum, quae summis ingeniis ',
 | 
						|
              'exquisitaque doctrina philosophi Graeco sermone tractavissent',
 | 
						|
            ]
 | 
						|
          },
 | 
						|
        ];
 | 
						|
        element = fixture('basic');
 | 
						|
        outputEl = element.queryEffectiveChildren('#diffTable');
 | 
						|
        element.addEventListener('render', function() {
 | 
						|
          done();
 | 
						|
        });
 | 
						|
        sinon.stub(element, '_getDiffBuilder', function() {
 | 
						|
          var builder = new GrDiffBuilder(
 | 
						|
              {content: content}, {left: [], right: []}, prefs, outputEl);
 | 
						|
          builder.buildSectionElement = function(group) {
 | 
						|
            var section = document.createElement('stub');
 | 
						|
            section.textContent = group.lines.reduce(function(acc, line) {
 | 
						|
              return acc + line.text;
 | 
						|
            }, '');
 | 
						|
            return section;
 | 
						|
          };
 | 
						|
          return builder;
 | 
						|
        });
 | 
						|
        element.render({ content: content }, {left: [], right: []}, prefs);
 | 
						|
      });
 | 
						|
 | 
						|
      test('renderSection', function() {
 | 
						|
        var section = outputEl.querySelector('stub:nth-of-type(2)');
 | 
						|
        var prevInnerHTML = section.innerHTML;
 | 
						|
        section.innerHTML = 'wiped';
 | 
						|
        element._builder.renderSection(section);
 | 
						|
        section = outputEl.querySelector('stub:nth-of-type(2)');
 | 
						|
        assert.equal(section.innerHTML, prevInnerHTML);
 | 
						|
      });
 | 
						|
 | 
						|
      test('getSectionsByLineRange one line', function() {
 | 
						|
        var section = outputEl.querySelector('stub:nth-of-type(2)');
 | 
						|
        var sections = element._builder.getSectionsByLineRange(1, 1, 'left');
 | 
						|
        assert.equal(sections.length, 1);
 | 
						|
        assert.strictEqual(sections[0], section);
 | 
						|
      });
 | 
						|
 | 
						|
      test('getSectionsByLineRange over diff', function() {
 | 
						|
        var section = [
 | 
						|
          outputEl.querySelector('stub:nth-of-type(2)'),
 | 
						|
          outputEl.querySelector('stub:nth-of-type(3)'),
 | 
						|
        ];
 | 
						|
        var sections = element._builder.getSectionsByLineRange(1, 2, 'left');
 | 
						|
        assert.equal(sections.length, 2);
 | 
						|
        assert.strictEqual(sections[0], section[0]);
 | 
						|
        assert.strictEqual(sections[1], section[1]);
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
</script>
 |