var expect = require('chai').expect
  , Encoder = require('../..').Encoder;

describe('jsr-resp (encoder):', function() {

  it('should throw error on invalid type (undefined)', function(done) {
    var enc = new Encoder();
    function fn() {
      enc.value(undefined);
    }
    expect(fn).throws(Error);
    expect(fn).throws(/invalid encoder type/);
    expect(fn).throws(/undefined/);
    done();
  });

  it('should throw error on invalid type (object)', function(done) {
    var enc = new Encoder();
    function fn() {
      enc.value({});
    }
    expect(fn).throws(Error);
    expect(fn).throws(/invalid encoder type/);
    expect(fn).throws(/object/);
    done();
  });

  it('should encode null', function(done) {
    var enc = new Encoder()
      , value = ['get', null]
      , expected;
    expected = '*2\r\n$3\r\nget\r\n$-1\r\n';
    expect(enc.encode(value).toString()).to.eql(expected);
    done();
  });

  it('should encode bulk string', function(done) {
    var k = 'mock-key'
      , v = 'mock-value'
      , enc = new Encoder()
      , value = ['set', k, v]
      , expected;

    expected = '*3\r\n$3\r\nset\r\n$8\r\nmock-key\r\n$10\r\nmock-value\r\n';
    expect(enc.encode(value).toString()).to.eql(expected);
    done();
  });

  it('should encode multi-byte string', function(done) {
    var k = 'mock-key'
      , v = '\u00ff'
      , enc = new Encoder()
      , value = ['set', k, v]
      , expected;

    expected = '*3\r\n$3\r\nset\r\n$8\r\nmock-key\r\n$2\r\nÿ\r\n';
    expect(enc.encode(value).toString()).to.eql(expected);
    done();
  });


  it('should encode simple string', function(done) {
    var enc = new Encoder()
      , value = new String('mock-simple-string')
      , expected;

    //console.dir(enc.value(value, null, true) + '');
    expected = '+mock-simple-string\r\n';
    expect(enc.value(value).toString()).to.eql(expected);
    done();
  });

  it('should encode integer argument', function(done) {
    var k = 'mock-key'
      , v = 1
      , enc = new Encoder()
      , value = ['incrby', k, v]
      , expected;

    expected = '*3\r\n$6\r\nincrby\r\n$8\r\nmock-key\r\n:1\r\n';
    expect(enc.encode(value).toString()).to.eql(expected);
    done();
  });

  it('should encode boolean as integer', function(done) {
    var k = 'mock-key'
      , v = false
      , enc = new Encoder()
      , value = ['incrby', k, v]
      , expected;
    expected = '*3\r\n$6\r\nincrby\r\n$8\r\nmock-key\r\n:0\r\n';
    expect(enc.encode(value).toString()).to.eql(expected);
    done();
  });

  it('should encode float argument as string', function(done) {
    var k = 'mock-key'
      , v = 3.14
      , enc = new Encoder()
      , value = ['set', k, v]
      , expected;

    expected = '*3\r\n$3\r\nset\r\n$8\r\nmock-key\r\n$4\r\n3.14\r\n';
    expect(enc.encode(value).toString()).to.eql(expected);
    done();
  });

  it('should encode array argument', function(done) {
    var k = 'mock-key'
      , v = [1,2,3]
      , enc = new Encoder()
      , value = ['set', k, v]
      , expected;

    expected = '*3\r\n$3\r\nset\r\n$8\r\nmock-key\r\n*3\r\n:1\r\n:2\r\n:3\r\n';
    expect(enc.encode(value).toString()).to.eql(expected);
    done();
  });

  it('should encode nested array argument', function(done) {
    var k = 'mock-key'
      , v = [[1,2,3], ['foo', 'bar']]
      , enc = new Encoder()
      , value = ['set', k, v]
      , expected;

    expected = '*3\r\n$3\r\nset\r\n$8\r\nmock-key\r\n'
    expected += '*2\r\n*3\r\n:1\r\n:2\r\n:3\r\n*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n';
    expect(enc.encode(value).toString()).to.eql(expected);
    done();
  });

  it('should encode error as simple string', function(done) {
    var encoder = new Encoder()
      , err = new Error('mock error message')
      , expected;
    expected = '-mock error message\r\n';
    expect(encoder.value(err).toString()).to.eql(expected);
    done();
  });

  it('should encode array of arrays', function(done) {
    var k1 = 'mock-key-1'
      , v1 = 1
      , k2 = 'mock-key-2'
      , v2 = 2
      , enc = new Encoder()
      , value = [['set', k1, v1], ['set', k2, v2]]
      , expected;

    expected = '*2\r\n*3\r\n$3\r\nset\r\n$10\r\nmock-key-1\r\n:1\r\n'
    expected += '*3\r\n$3\r\nset\r\n$10\r\nmock-key-2\r\n:2\r\n';

    expect(enc.pack(value).toString()).to.eql(expected);
    done();
  });

});
