         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

    assert.strictEqual result.fn, arg


# 3. chain.remove()
describe 'test chain.remove()', ->
  fn1 = ->
  fn2 = ->
  fn3 = ->
  chain = null
  beforeEach -> chain = buildChain() ; chain.add fn1

  it 'should remove fn1 from array', ->
    chain.remove fn1
    assert.equal chain.array.length, 0, 'array should be empty'

  it 'should remove fn1 from array', ->
    chain.add fn2, fn3
    chain.remove fn1
    assert.equal chain.array.length, 2, 'array should be one less: 2'
    assert.strictEqual chain.array[0], fn2, 'first element should be fn2'
    assert.strictEqual chain.array[1], fn3, 'first element should be fn3'

  it 'should remove fn2 from array', ->
    chain.add fn2, fn3
    chain.remove fn2
    assert.equal chain.array.length, 2, 'array should be one less: 2'
    assert.strictEqual chain.array[0], fn1, 'first element should be fn1'
    assert.strictEqual chain.array[1], fn3, 'first element should be fn3'

  it 'should remove fn3 from array', ->
    chain.add fn2, fn3
    chain.remove fn3
    assert.equal chain.array.length, 2, 'array should be one less: 2'
    assert.strictEqual chain.array[0], fn1, 'first element should be fn1'
    assert.strictEqual chain.array[1], fn2, 'first element should be fn2'

# 4. chain.run()
describe 'test running chain', ->
  ran  = (control, context) -> context.ran = true
  stop = (control, context) -> context.stop = true ; control.stop 'testing'

    process.nextTick resume

  chain = null
  beforeEach ->
    chain = buildChain()

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