// DecentCMS (c) 2014 Bertrand Le Roy, under MIT. See LICENSE.txt for licensing details.
'use strict';
var expect = require('chai').expect;
var flasync = require('../lib/flasync');

describe('Flasync Fluent Async API helper', function() {
  // Build an API using the library
  var Api = function Api(output) {
    var self = this;
    this.output = output || [];
    flasync(this);
    // It has one synchronous method
    this.writeSync = this.asyncify(
      this._writeSync = function(text) {

      this.output.push(text);
      return this;
    });
    // And one asynchronous method
    this.write = this.async(function(text, next) {
      process.nextTick(function () {
        self._writeSync(text);
        next();
      });
      return this;
    });
  };

  it('behaves as a synchronous API as long as only synchronous methods are called', function() {
    var api = new Api();

    api
      .writeSync('foo')
      .writeSync('bar')
      .writeSync('baz');

    expect(api.output).to.deep.equal(['foo', 'bar', 'baz']);
  });

  it('preserves call order even for synchronous methods called after an asynchronous one', function(done) {
    var api = new Api();

    api
      .writeSync('foo')
      .write('bar')
      .writeSync('baz')
      .then(function() {
        expect(api.output).to.deep.equal(['foo', 'bar', 'baz']);
        done();
      });
  });

  it('executes asynchronous continuations in order', function(done) {
    var api = new Api();

    api
      .write('foo')
      .then(function(next) {
        api.output.push('bar');
        next();
      })
      .then(function(next) {
        api.output.push('baz');
        next();
      })
      .then(function() {
        expect(api.output).to.deep.equal(['foo', 'bar', 'baz']);
        done();
      });
  });

  it('can nest async calls', function(done) {
    var api = new Api();

    api
      .write('foo')
      .then(function(next) {
        api
          .writeSync('bar')
          .write('baz')
          .then(function() {
            expect(api.output).to.deep.equal(['foo', 'bar', 'baz']);
            done();
          });
        next();
      });
  });

  it('can handle exceptions and suspend execution', function(done) {
    var api = new Api();
    var hit = false;

    api
      .onError(function(err) {
        expect(hit).to.be.false;
        done();
      })
      .then(function(next) {
        throw new Error('oops');
      })
      .then(function(next) {
        hit = true;
      });
  });

  it('lets exceptions through if no error handler is defined', function() {
    var api = new Api();

    expect(function() {
      api
        .then(function(next) {
          throw new Error('oops');
        })
    })
      .to.throw('oops');
  });
});
@@ -558,20 +558,16 @@
  // And 
-one 
 asynchro
@@ -569,32 +569,33 @@
 nchronous method
+s
 %0A    this.write 
@@ -607,16 +607,37 @@
 s.async(
+%0A      this._write = 
 function
@@ -764,24 +764,24 @@
 n this;%0A
-
     %7D);%0A
   %7D;%0A%0A  
@@ -772,16 +772,210 @@
     %7D);%0A
+    // An async method that calls another%0A    this.writeToken = this.async(%0A      this._writeToken = function(text, next) %7B%0A%0A      self._write('%5B' + text + '%5D', next);%0A      return this;%0A    %7D)%0A
   %7D;%0A%0A  
@@ -2955,12 +2955,354 @@
 );%0A  %7D);
+%0A%0A  it('lets asynchronous methods call other asynchronous methods', function(done) %7B%0A    var api = new Api();%0A%0A    api%0A      .write('foo')%0A      .writeToken('bar')%0A      .writeToken('baz')%0A      .write('done')%0A      .then(function() %7B%0A        expect(api.output).to.deep.equal(%5B'foo', '%5Bbar%5D', '%5Bbaz%5D', 'done'%5D);%0A        done();%0A      %7D)%0A  %7D);
 %0A%7D);

Test async methods calling each other.