// These tests are run with two different test runners which work a bit
// differently. Runners are Testem and Karma. Read more about them in
// CONTRIBUTING.md
// Supporting both has lead to some compromises.

var chai = require('chai');
var chaiStats = require('chai-stats');
chai.use(chaiStats);
var sinon = require('sinon');
var expect = chai.expect;

// https://github.com/mochajs/mocha/wiki/Shared-Behaviours
var shapeTests = require('./shape-behaviour');
var pathTests = require('./path-behaviour');
var ProgressBar = require('../src/main');
var utils = require('../src/utils');

var afterEachCase = function() {
    try {
        this.bar.destroy();
    } catch (e) {
        // Some test cases destroy the bar themselves and calling again
        // throws an error
    }
};

var barOpts = {
    text: { value: 'Test' },
    trailWidth: 1,
    attachment: {foo: 'bar'}
};

describe('Line', function() {
    beforeEach(function() {
        // Append progress bar to body since adding a custom HTML and div
        // with Karma was not that trivial compared to Testem
        barOpts.step = function(state, bar, attachment) {};
        this.bar = new ProgressBar.Line('body', barOpts);
        this.attachment = this.bar._opts.attachment;
        this.step = sinon.spy(this.bar._opts, 'step');

    });

    afterEach(afterEachCase);
    shapeTests();
});

describe('Circle', function() {
    beforeEach(function() {
        barOpts.step = function(state, bar, attachment) {};
        this.bar = new ProgressBar.Circle('body', barOpts);
        this.attachment = this.bar._opts.attachment;
        this.step = sinon.spy(this.bar._opts, 'step');

    });

    afterEach(afterEachCase);
    shapeTests();
});

describe('SemiCircle', function() {
    beforeEach(function() {
        barOpts.step = function(state, bar, attachment) {};
        this.bar = new ProgressBar.SemiCircle('body', barOpts);
        this.attachment = this.bar._opts.attachment;
        this.step = sinon.spy(this.bar._opts, 'step');
    });

    afterEach(afterEachCase);
    shapeTests();
});

describe('Square', function() {
    beforeEach(function() {
        barOpts.step = function(state, bar, attachment) {};
        this.bar = new ProgressBar.Square('body', barOpts);
        this.attachment = this.bar._opts.attachment;
        this.step = sinon.spy(this.bar._opts, 'step');
    });

    afterEach(afterEachCase);
    shapeTests();
});

describe('Path', function() {

    beforeEach(function() {
        var svgView = pathTests.createPath();
        this.svg = svgView.svg;
        this.path = svgView.path;
        this.path.setAttribute('strokeOffset', this.path.getTotalLength());
        pathTests.options.attachment = this.path;

        this.bar = new ProgressBar.Path(this.path, pathTests.options);
        this.attachment = this.bar._opts.attachment;
        this.step = sinon.spy(this.bar._opts, 'step');
    });

    afterEach(function() {
        var container = this.svg.parentNode;
        container.removeChild(this.svg);
        this.svg = null;
        pathTests.options.attachment = null;
        this.path = null;
        this.bar = null;
    });

    pathTests.runTests();
});

describe('utils', function() {
    it('extend without recursive should not merge', function() {
        var first = {
            a: { content: 1 },
            b: 2,
            c: 3,
            d: [1, 2]

        };
        var second = {
            a: { test: 1 },
            b: 4,
            d: [],
            e: 1
        };
        utils.extend(first, second);

        // These should normally override a's attributes
        expect(first.a.content).to.equal(undefined);
        expect(first.b).to.equal(second.b);
        expect(first.d).to.equal(second.d);
        expect(first.e).to.equal(second.e);

        // b.c is undefined so c should not be modified
        expect(first.c).to.equal(first.c);
    });

    it('extend with recursive should merge', function() {
        var first = {
            a: {
                content: 1,
                b: {
                    content: 2
                }
            },
            arr: [1, 2]
        };
        var second = {
            a: {
                test: 1,
                b: {
                    test: 2
                }
            },
            arr: []
        };
        utils.extend(first, second, true);

        // These should normally override a's attributes
        expect(first).to.deep.equal({
            a: {
                content: 1,
                test: 1,
                b: {
                    content: 2,
                    test: 2
                }
            },
            arr: []
        });
    });
});
