<!--
Copyright (C) 2018 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>resemble-diff-mode</title>

<link rel="import" href="../node_modules/polymer/polymer.html">
<link rel="import" href="../node_modules/@polymer/test-fixture/test-fixture.html">
<link rel="import" href="../node_modules/iron-test-helpers/iron-test-helpers.html">
<link rel="import" href="./gr-resemble-diff-mode.html">

<script>void(0);</script>

<script src="../node_modules/webcomponents.js/webcomponents-lite.min.js"></script>
<script src="../node_modules/web-component-tester/browser.js"></script>
<script src="../node_modules/@polymer/sinonjs/sinon.js"></script>

<test-fixture id="basicFixture">
  <template>
    <gr-resemble-diff-mode>
    </gr-resemble-diff-mode>
  </template>
</test-fixture>

<script>
  suite('gr-resemble-diff-mode tests', () => {
    let element;
    let sandbox;

    setup(() => {
      sandbox = sinon.sandbox.create();
      element = fixture('basicFixture');
    });

    teardown(() => { sandbox.restore(); })

    test('test initialization', () => {
      assert.notEqual(element, null);
      assert.equal(element.baseImage, null);
      assert.equal(element.revisionImage, null);
    });

    test('_setImageDiffSrc', () => {
      const img = element.$.imageDiff;
      const src = 'data:image/png;base64,SGVsbG8=';
      assert.notOk(img.getAttribute('src'));
      element._setImageDiffSrc(src);
      assert.equal(img.getAttribute('src'), src);
    });

    test('_maybeIgnoreColors', () => {
      const dummyProcess = {
        ignoreColors: sandbox.stub(),
        ignoreNothing: sandbox.stub(),
      };
      element._maybeIgnoreColors(dummyProcess, false);
      assert.isFalse(dummyProcess.ignoreColors.called);
      assert.isTrue(dummyProcess.ignoreNothing.called);
      element._maybeIgnoreColors(dummyProcess, true);
      assert.isTrue(dummyProcess.ignoreColors.called);
    });

    test('_handleIgnoreColorsToggle', () => {
      sandbox.stub(element, 'reload');
      element._ignoreColors = false;
      assert.isFalse(element.$.ignoreColorsToggle.checked);
      MockInteractions.tap(element.$.ignoreColorsToggle);
      flushAsynchronousOperations();

      assert.isTrue(element._ignoreColors);
      assert.isTrue(element.reload.called);
    });

    test('calls reload', () => {
      sandbox.stub(element, 'reload');
      element.baseImage = {};
      assert.equal(element.reload.callCount, 0);
      element.revisionImage = {};
      assert.equal(element.reload.callCount, 1);
      MockInteractions.tap(element.$.ignoreColorsToggle);
      assert.equal(element.reload.callCount, 2);
    });
  });
</script>