   fn1 = ->
   fn2 = ->
   fn3 = ->
-  beforeEach -> chain = buildChain()
+  beforeEach ->
+    chain = buildChain()
 
   it 'should add single fn to array', ->
     chain.add fn1

    process.nextTick resume

  chain = null
  beforeEach -> chain = buildChain()

  it 'should catch thrown errors', ->
    chain.add -> throw new Error 'my bad'

        assert.equal result?.context?.paused, false, 'should have called last fn and set paused=false'
        assert.deepEqual syncResult?.paused, reason:'testing', index:0, fn:pause
        done()




# 6. disable
# - chain.disable()
# - chain.disable('reason')
#
# - chain.disable(index)
# - chain.disable(index, 'reason')
#
# - chain.disable('someid')
# - chain.disable('someid', 'reason')
#
# - chain.disable(someFn)
# - chain.disable(someFn, 'reason')
#
# - control.disable()
# - control.disable('reason')
#
# - select(fn).disable()        - single
# - select(fn).disable(reason)  - single
#
# - select(fn).disable()        - duo
# - select(fn).disable(reason)  - duo


describe 'test disable', ->

  fn1 = ->
  fn1.options = id:'fn1'
  fn2 = ->
  fn2.options = id:'fn2'
  fn3 = ->
  fn3.options = id:'fn3'

  chain = null

  beforeEach ->
    chain = buildChain()

  it 'should disable the chain with a default reason', ->

    called = []
    caller1 = -> called.push 1
    caller1.options = id:'caller1'
    caller2 = -> called.push 2
    caller2.options = id:'caller2'
    caller3 = -> called.push 3
    caller3.options = id:'caller3'
    chain.add caller1, caller2, caller3

    results1 = chain.run()
    results2 = chain.disable()
    results3 = chain.run()

    assert results1.result, 'first run should succeed'
    assert results2.result, 'disable should succeed'
    assert results2.reason, 'disable reason should default to true'
    assert.equal results3.result, false, 'second run should fail due to being disabled'
    assert.equal results3.reason, 'chain disabled'
    assert.equal results3.disabled, true
    assert.equal called.length, 3, 'chain should be called only once (for 3 functions)'
    assert.deepEqual called, [ 1, 2, 3]

  it 'should disable the chain with a specified reason', ->

    reason = 'the reason'
    called = []
    caller1 = -> called.push 1
    caller1.options = id:'caller1'
    caller2 = -> called.push 2
    caller2.options = id:'caller2'
    caller3 = -> called.push 3
    caller3.options = id:'caller3'
    chain.add caller1, caller2, caller3

    results1 = chain.run()
    results2 = chain.disable reason
    results3 = chain.run()

    assert results1.result, 'first run should succeed'
    assert results2.result, 'disable should succeed'
    assert results2.reason, 'disable reason should default to true'
    assert.equal results3.result, false, 'second run should fail due to being disabled'
    assert.equal results3.reason, 'chain disabled'
    assert.equal results3.disabled, reason
    assert.equal called.length, 3, 'chain should be called only once (for 3 functions)'
    assert.deepEqual called, [ 1, 2, 3]


  it 'should disable the function by index with default reason', ->

    called = []
    caller = -> called.push true
    chain.add fn1, caller, fn3

    results1 = chain.run()
    results2 = chain.disable 1
    results3 = chain.run()

    assert results1.result, 'first run should succeed'
    assert results2.result, 'disable should succeed'
    assert results2.reason, 'disable reason should default to true'
    assert results3.result, 'second run should succeed'
    assert.equal called.length, 1, 'should be called only once'

  it 'should disable the function by index with specific reason', ->
    reason = 'the reason'
    called = []
    caller = -> called.push true
    chain.add fn1, caller, fn3

    results1 = chain.run()
    results2 = chain.disable 1, reason
    results3 = chain.run()

    assert results1.result, 'first run should succeed'
    assert results2.result, 'disable should succeed'
    assert.equal results2.reason, reason
    assert results3.result, 'second run should succeed'
    assert.equal called.length, 1, 'should be called only once'


  # NOTE: you can't use default reason with an id.

  it 'should disable the function by id with specific reason', ->
    reason = 'the reason'
    called = []
    caller = -> called.push true
    caller.options = id:'caller'
    chain.add fn1, caller, fn3

    results1 = chain.run()
    results2 = chain.disable 'caller', reason
    results3 = chain.run()

    assert results1.result, 'first run should succeed'
    assert results2.result, 'disable should succeed'
    assert.equal results2.reason, reason
    assert results3.result, 'second run should succeed'
    assert.equal called.length, 1, 'should be called only once'


  it 'should disable the function by function with default reason', ->

    called = []
    caller = -> called.push true
    chain.add fn1, caller, fn3

    results1 = chain.run()
    results2 = chain.disable caller
    results3 = chain.run()

    assert results1.result, 'first run should succeed'
    assert results2.result, 'disable should succeed'
    assert results2.reason, 'disable reason should default to true'
    assert results3.result, 'second run should succeed'
    assert.equal called.length, 1, 'should be called only once'

  it 'should disable the function by function with specific reason', ->
    reason = 'the reason'
    called = []
    caller = -> called.push true
    chain.add fn1, caller, fn3

    results1 = chain.run()
    results2 = chain.disable caller, reason
    results3 = chain.run()

    assert results1.result, 'first run should succeed'
    assert results2.result, 'disable should succeed'
    assert.equal results2.reason, reason
    assert results3.result, 'second run should succeed'
    assert.equal called.length, 1, 'should be called only once'


  it 'should disable via control with default reason', ->
    disabler = (control) -> control.disable()
    chain.add fn1, disabler, fn3
    assert.equal chain.array.length, 3, 'should start with 3 functions'
    chain.run()
    assert.equal chain.array.length, 3, 'should still have 3 functions'
    assert.equal chain.array[1].options.disabled, true

  it 'should disable via control with specific reason', ->
    reason = 'the reason'
    disabler = (control) -> control.disable reason
    chain.add fn1, disabler, fn3
    assert.equal chain.array.length, 3, 'should start with 3 functions'
    chain.run()
    assert.equal chain.array.length, 3, 'should still have 3 functions'
    assert.equal chain.array[1].options.disabled, reason


  it 'should select() a function and disable with default reason', ->
    target = ->
    selector = (fn, index) -> (fn is target and index is 1)
    chain.add fn1, target, fn3
    assert.equal chain.array.length, 3, 'should start with 3 functions'
    chain.select(selector).disable()
    assert.equal chain.array.length, 3, 'should still have 3 functions'
    assert.equal target.options.disabled, true
    assert.equal chain.array[1].options.disabled, true

  it 'should select() a function and disable with specific reason', ->
    reason = 'the reason'
    target = ->
    selector = (fn, index) -> (fn is target and index is 1)
    chain.add fn1, target, fn3
    assert.equal chain.array.length, 3, 'should start with 3 functions'
    chain.select(selector).disable reason
    assert.equal chain.array.length, 3, 'should still have 3 functions'
    assert.equal target.options.disabled, reason
    assert.equal chain.array[1].options.disabled, reason


  it 'should select() two functions and disable with default reason', ->
    reason = true
    target1 = ->
    target2 = ->
    selector = (fn, index) ->
      (fn is target1 and index is 1) or (fn is target2 and index is 2)
    chain.add fn1, target1, target2, fn3
    assert.equal chain.array.length, 4, 'should start with 3 functions'
    chain.select(selector).disable()
    assert.equal chain.array.length, 4, 'should still have 3 functions'
    assert.equal target1.options.disabled, reason
    assert.equal target2.options.disabled, reason
    assert.equal chain.array[1].options.disabled, reason
    assert.equal chain.array[2].options.disabled, reason

  it 'should select() two functions and disable with specific reason', ->
    reason = 'the reason'
    target1 = ->
    target2 = ->
    selector = (fn, index) ->
      (fn is target1 and index is 1) or (fn is target2 and index is 2)
    chain.add fn1, target1, target2, fn3
    assert.equal chain.array.length, 4, 'should start with 3 functions'
    chain.select(selector).disable reason
    assert.equal chain.array.length, 4, 'should still have 3 functions'
    assert.equal target1.options.disabled, reason
    assert.equal target2.options.disabled, reason
    assert.equal chain.array[1].options.disabled, reason
    assert.equal chain.array[2].options.disabled, reason




# 7. enable
# - chain.enable()
# - chain.enable(index)
# - chain.enable('someid')
# - chain.enable(someFn)
# - select(fn).enable()        - single
# - select(fn).enable()        - duo

describe 'test enable', ->

  fn1 = ->
  fn1.options = id:'fn1'
  fn2 = ->
  fn2.options = id:'fn2'
  fn3 = ->
  fn3.options = id:'fn3'

  chain = null

  beforeEach ->
    chain = buildChain()

  it 'should have false result if chain is already enabled', ->

    results = chain.enable()

    assert.equal results.result, false, 'should fail because it\'s already enabled'
    assert.equal results.reason, 'chain not disabled'

  it 'should enable the chain', ->

    called = []
    caller1 = -> called.push 1
    caller1.options = id:'caller1'
    caller2 = -> called.push 2
    caller2.options = id:'caller2'
    caller3 = -> called.push 3
    caller3.options = id:'caller3'
    chain.add caller1, caller2, caller3

    chain._disabled = true
    results1 = chain.run()
    results2 = chain.enable()
    results3 = chain.run()

    assert.equal results1.result, false, 'first run should fail because it\'s disabled'
    assert results2.result, 'enable should succeed'
    assert results3.result, 'second run should succeed due to being enabled'
    assert.equal results3.disabled, undefined
    assert.equal called.length, 3, 'chain should be called only once (for 3 functions)'
    assert.deepEqual called, [ 1, 2, 3]


  it 'should have false result if function is already enabled', ->

    chain.add fn1
    results = chain.enable 0

    assert.equal results.result, false, 'should fail because it\'s already enabled'
    assert.equal results.reason, 'function not disabled'

  it 'should enable the function by index', ->

    called = []
    caller = -> called.push true
    caller.options = disabled:true
    chain.add fn1, caller, fn3

    results1 = chain.run()
    results2 = chain.enable 1
    results3 = chain.run()

    assert results1.result, 'first run should succeed'
    assert results2.result, 'enable should succeed'
    assert results3.result, 'second run should succeed'
    assert.equal called.length, 1, 'should be called only once'
    assert.equal caller.options.disabled, undefined, 'should delete the `disabled` marker'


  it 'should enable the function by id', ->
    called = []
    caller = -> called.push true
    caller.options = disabled:true, id:'caller'
    chain.add fn1, caller, fn3

    results1 = chain.run()
    results2 = chain.enable 'caller'
    results3 = chain.run()

    assert results1.result, 'first run should succeed'
    assert results2.result, 'enable should succeed'
    assert results3.result, 'second run should succeed'
    assert.equal called.length, 1, 'should be called only once'
    assert.equal caller.options.disabled, undefined, 'should delete the `disabled` marker'
    assert.equal caller.options.id, 'caller', 'should still have the id in options'


  it 'should enable the function by function', ->

    called = []
    caller = -> called.push true
    caller.options = disabled:true
    chain.add fn1, caller, fn3

    results1 = chain.run()
    results2 = chain.enable caller
    results3 = chain.run()

    assert results1.result, 'first run should succeed'
    assert results2.result, 'enable should succeed'
    assert results3.result, 'second run should succeed'
    assert.equal called.length, 1, 'should be called only once'
    assert.equal caller.options.disabled, undefined, 'should delete the `disabled` marker'



  it 'should select() a function and enable', ->
    
    target = ->
    target.options = disabled:true
    selector = (fn, index) -> (fn is target and index is 1)
    chain.add fn1, target, fn3
    assert.equal chain.array.length, 3, 'should start with 3 functions'
    chain.select(selector).enable()
    assert.equal chain.array.length, 3, 'should still have 3 functions'
    assert.equal target.options.disabled, undefined
    assert.equal chain.array[1].options.disabled, undefined


  it 'should select() two functions and enable', ->

    target1 = ->
    target1.options = disabled:true
    target2 = ->
    target2.options = disabled:true
    selector = (fn, index) ->
      (fn is target1 and index is 1) or (fn is target2 and index is 2)
    chain.add fn1, target1, target2, fn3
    assert.equal chain.array.length, 4, 'should start with 3 functions'
    chain.select(selector).enable()
    assert.equal chain.array.length, 4, 'should still have 3 functions'
    assert.equal target1.options.disabled, undefined
    assert.equal target2.options.disabled, undefined
    assert.equal chain.array[1].options.disabled, undefined
    assert.equal chain.array[2].options.disabled, undefined




  # TODO: Move these to testing for .select(...).remove()
  # it 'should remove zero functions with falsey selector', ->
  #   chain.array = [ fn1, fn2, fn3 ]
  #   result = chain.clear -> false
  #   assert.equal chain.array.length, 3, 'array should be unchanged'
  #   assert.strictEqual result.removed.length, 0
  #
  # it 'should remove all functions from with truthy selector', ->
  #   chain.array = [ fn1, fn2, fn3 ]
  #   result = chain.clear -> true
  #   assert.equal chain.array.length, 0, 'array should be empty'
  #   assert.strictEqual result.removed.length, 3
  #   assert.strictEqual result.removed?[0], fn1
  #   assert.strictEqual result.removed?[1], fn2
  #   assert.strictEqual result.removed?[2], fn3
  #
  #
  # it 'should remove function from chain by id selector', ->
  #   chain.array = [ fn1, fn2, fn3 ]
  #   result = chain.clear (fn) -> fn?.options?.id is 'fn2'
  #   assert.equal chain.array.length, 2, 'array should be one less'
  #   assert.strictEqual result.removed.length, 1, 'should remove one function'
  #   assert.strictEqual result.removed?[0], fn2
  #
  # it 'should remove functions from chain by two-id selector', ->
  #   chain.array = [ fn1, fn2, fn3, (->) ]
  #   result = chain.clear (fn) -> fn?.options?.id is 'fn2' or fn?.options?.id is 'fn3'
  #   assert.equal chain.array.length, 2, 'array should be two less'
  #   assert.strictEqual result.removed.length, 2, 'should remove two functions'
  #   assert.strictEqual result.removed?[0], fn2
  #   assert.strictEqual result.removed?[1], fn3
