'use strict';

var copyProps = require('..');
var chai = require('chai');
var expect = chai.expect;

/* eslint max-statements: "off", brace-style: "off" */

describe('Arguments', function() {

  describe('When arguments is src and dest', function() {

    it('Should succeed when src and dst is normal', function(done) {
      var src = { a: 1, b: 2 };
      var dst = { a: 9, c: 3 };
      expect(copyProps(src, dst)).to.deep.equal({ a: 1, b: 2, c: 3 });
      done();
    });

    it('Should not change dst when src is not an plain object',
    function(done) {
      var dst = { a: 9, c: 3 };
      expect(copyProps(undefined, dst)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(null, dst)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(true, dst)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(false, dst)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(0, dst)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(123, dst)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps('', dst)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps('A', dst)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps([], dst)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps([1,2,3], dst)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(new Date(0), dst)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(function() {}, dst)).to.deep.equal({ a: 9, c: 3 });
      done();
    });

    it('Should return copy of src when dst is not a plain object',
    function(done) {
      var src = { a: 9, c: 3 };
      expect(copyProps(src, undefined)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(src, null)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(src, true)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(src, false)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(src, 0)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(src, 123)).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(src, '')).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(src, 'A')).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(src, [])).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(src, [1,2,3])).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(src, new Date(0))).to.deep.equal({ a: 9, c: 3 });
      expect(copyProps(src, function() {})).to.deep.equal({ a: 9, c: 3 });
      done();
    });

  });

  describe('When arguments is src, dst, fromto/converter/reverse', function() {

    it('Should succeed when 3rd arg is a plain object', function(done) {
      var src = { a: 1, b: { c: 2 } };
      var dst = { A: 10, B: { D: 20 } };
      var fromto = { a: 'A', 'b.c': 'B.C' };
      var expected = { A: 1, B: { C: 2, D: 20 } };
      expect(copyProps(src, dst, fromto)).to.deep.equal(expected);
      done();
    });

    it('Should only pass fromto properties of which value is a string',
    function(done) {
      var src = { a: 1, b: 2 };
      var dst = { A: 10, true: 20 };
      var fromto = { a: 'A', b: true };
      var expected = { A: 1, true: 20 };
      expect(copyProps(src, dst, fromto)).to.deep.equal(expected);
      done();
    });

    it('Should succeed when 3rd arg is an array', function(done) {
      var src = { a: 1, b: { c: 2 } };
      var dst = { a: 10, b: { d: 20 } };
      var fromto = ['a', 'b.c'];
      var expected = { a: 1, b: { c: 2, d: 20 } };
      expect(copyProps(src, dst, fromto)).to.deep.equal(expected);
      done();
    });

    it('Should only pas frommto elements which is a string', function(done) {
      var src = { a: 1, 123: 99 };
      var dst = { a: 10, 123: 8 };
      var fromto = ['a', 123];
      var expected = { a: 1, 123: 8 };
      expect(copyProps(src, dst, fromto)).to.deep.equal(expected);
      done();
    });

    it('Should succeed when 3rd arg is a function', function(done) {
      var src = { a: 1, b: { c: 2 } };
      var dst = { a: 10, b: { d: 20 } };
      var converter = function(srcInfo) { return srcInfo.value * 2; };
      var expected = { a: 2, b: { c: 4, d: 20 } };
      expect(copyProps(src, dst, converter)).to.deep.equal(expected);
      done();
    });

    it('Should succeed when 3rd arg is a boolean', function(done) {
      var src = { a: 1, b: { c: 2 } };
      var dst = { a: 10, b: { d: 20 } };
      var expected = { a: 10, b: { c: 2, d: 20 } };
      expect(copyProps(src, dst, true)).to.deep.equal(expected);
      done();
    });

    it('Should ignore 3rd arg when it is other type', function(done) {
      var src = { a: 1, b: { c: 2 } };
      var dst = { a: 10, b: { d: 20 } };
      var expected = { a: 1, b: { c: 2, d: 20 } };
      expect(copyProps(src, dst, undefined)).to.deep.equal(expected);
      expect(copyProps(src, dst, null)).to.deep.equal(expected);
      expect(copyProps(src, dst, 0)).to.deep.equal(expected);
      expect(copyProps(src, dst, 123)).to.deep.equal(expected);
      expect(copyProps(src, dst, '')).to.deep.equal(expected);
      expect(copyProps(src, dst, 'ABC')).to.deep.equal(expected);
      expect(copyProps(src, dst, new Date(0))).to.deep.equal(expected);
      done();
    });

  });

  describe('When arguments is src, dst, fromto, converter/reverse',
  function() {

    it('Should succeed when 4th arg is a function', function(done) {
      var src = { a: 1, b: { c: 2 } };
      var dst = { A: 10, B: { D: 20 } };
      var fromto = { a: 'A', 'b.c': 'B.C' };
      var expected = { A: 2, B: { C: 4, D: 20 } };
      expect(copyProps(src, dst, fromto, function(srcInfo) {
        return srcInfo.value * 2;
      })).to.deep.equal(expected);
      done();
    });

    it('Should succeed when 4th arg is a boolean', function(done) {
      var src = { a: 1, b: { c: 2 } };
      var dst = { A: 10, B: { D: 20 } };
      var fromto = { a: 'A', 'b.c': 'B.C', 'b.d': 'B.D' };
      var expected = { a: 10, b: { c: 2, d: 20 } };
      expect(copyProps(src, dst, fromto, true)).to.deep.equal(expected);
      done();
    });

    it('Should ignore 4th arg when it is other type', function(done) {
      var src = { a: 1, b: { c: 2 } };
      var dst = { A: 10, B: { D: 20 } };
      var map = { a: 'A', 'b.c': 'B.C' };
      var expected = { A: 1, B: { C: 2, D: 20 } };
      expect(copyProps(src, dst, map, undefined)).to.deep.equal(expected);
      expect(copyProps(src, dst, map, null)).to.deep.equal(expected);
      expect(copyProps(src, dst, map, 0)).to.deep.equal(expected);
      expect(copyProps(src, dst, map, 123)).to.deep.equal(expected);
      expect(copyProps(src, dst, map, '')).to.deep.equal(expected);
      expect(copyProps(src, dst, map, 'ABC')).to.deep.equal(expected);
      expect(copyProps(src, dst, map, [1,2])).to.deep.equal(expected);
      expect(copyProps(src, dst, map, { a:1, b:2 })).to.deep.equal(expected);
      expect(copyProps(src, dst, map, new Date())).to.deep.equal(expected);
      done();
    });

  });

  describe('When arguments is src, dst, fromto, converter, reverse',
  function() {

    it('Should succeed when 5th arg is a boolean', function(done) {
      var src = { a: 1, b: { c: 2 } };
      var dst = { A: 10, B: { D: 20 } };
      var fromto = { a: 'A', 'b.c': 'B.C', 'b.d': 'B.D' };
      var converter = function(srcInfo) { return srcInfo.value * 2; };
      var expected = { a: 20, b: { c: 2, d: 40 } };
      expect(copyProps(src, dst, fromto, converter, true))
        .to.deep.equal(expected);
      done();
    });

    it('Should ignore 5th arg when it is other type', function(done) {
      var src = { a: 1, b: { c: 2 } };
      var dst = { A: 10, B: { D: 20 } };
      var fromto = { a: 'A', 'b.c': 'B.C', 'b.d': 'B.D' };
      var converter = function(srcInfo) { return srcInfo.value * 2; };
      var expected = { A: 2, B: { C: 4, D: 20 } };
      expect(copyProps(src, dst, fromto, converter, undefined))
        .to.deep.equal(expected);
      expect(copyProps(src, dst, fromto, converter, null))
        .to.deep.equal(expected);
      expect(copyProps(src, dst, fromto, converter, 0))
        .to.deep.equal(expected);
      expect(copyProps(src, dst, fromto, converter, 123))
        .to.deep.equal(expected);
      expect(copyProps(src, dst, fromto, converter, ''))
        .to.deep.equal(expected);
      expect(copyProps(src, dst, fromto, converter, 'ABC'))
        .to.deep.equal(expected);
      expect(copyProps(src, dst, fromto, converter, [1,2]))
        .to.deep.equal(expected);
      expect(copyProps(src, dst, fromto, converter, { a:1, b: 2 }))
        .to.deep.equal(expected);
      expect(copyProps(src, dst, fromto, converter, new Date()))
        .to.deep.equal(expected);
      expect(copyProps(src, dst, fromto, converter, function() {}))
        .to.deep.equal(expected);
      done();
    });

  });

});

