/* global describe, it */

// Dependencies
var Examine = require('../index')
var async = require('async')
var chai = require('chai')
var AssertionError = chai.AssertionError

// Build a examine
var examine = new Examine()
var expect = examine.expect

// Helper to test throws
function testThrow (fn, cb) {
  try {
    fn()
  } catch(err) {
    if (!(err instanceof AssertionError)) {
      return cb(new Error('error is not from AssertionError, could be syntax error'))
    }

    if (!(/prefix testing/.test(err.message))) {
      return cb(new Error('error message wasn\'t passed properly'))
    }

    return cb()
  }

  return cb(new Error('didn\'t thrown an error'))
}

function testChain (apiChain) {
  if (typeof apiChain === 'undefined') {
    throw new Error('Invalid expect chain')
  }
}

describe('examine.expect # full API test', function () {
  describe('expect chains', function () {
    // Expect chains:
    var chains = [
      'to',
      'be',
      'been',
      'is',
      'that',
      'which',
      'and',
      'has',
      'have',
      'with',
      'at',
      'of',
      'same'
    ]

    var s = 'hey'

    // Generate tests for all chains
    // lazy way ftw!
    chains.forEach(function (describeChain) {
      describe('expect.' + describeChain, function () {
        it('should not true an error', function () {
          chains.forEach(function (chain) {
            testChain(expect(s)[describeChain][chain])
          })
        })
      })
    })
  })

  describe('expect.not', function () {
    var foo = 'foo'
    var bar = 'bar'
    var goodFn = function () { return 'happy!' }
    var badFn = function () { throw new Error('bad function!') }
    var obj = { foo: 'baz' }

    it('should assert successfuly', function () {
      expect(foo).to.not.equal('bar')
      expect(goodFn).to.not.throw(Error)
      expect(obj).to.have.property('foo')
        .and.not.equal('bar')
    })

    it('should throw an error', function (next) {
      // Tests that should fail
      var tests = {
        '1': function () {
          expect(bar, 'prefix testing').to.not.equal('bar')
        },
        '2': function () {
          expect(badFn, 'prefix testing').to.not.throw(Error)
        },
        '3': function () {
          expect(obj, 'prefix testing').to.have.property('foo')
            .and.not.equal('baz')
        }
      }

      // Run failing tests
      return async.waterfall([
        testThrow.bind(null, tests['1']),
        testThrow.bind(null, tests['2']),
        testThrow.bind(null, tests['3'])
      ], next)
    })
  })
})

@@ -289,16 +289,25 @@
 tThrow (
+msgFlag, 
 fn, cb) 
@@ -308,16 +308,108 @@
 , cb) %7B%0A
+  if (typeof msgFlag === 'function') %7B%0A    cb = fn%0A    fn = msgFlag%0A    msgFlag = true%0A  %7D%0A%0A
   try %7B%0A
@@ -567,24 +567,45 @@
 r'))%0A    %7D%0A%0A
+    if (msgFlag) %7B%0A  
     if (!(/p
@@ -637,24 +637,26 @@
 essage))) %7B%0A
+  
       return
@@ -707,24 +707,32 @@
 properly'))%0A
+      %7D%0A
     %7D%0A%0A    r
@@ -2490,24 +2490,1100 @@
  %7D%0A      %7D%0A%0A
+      // Run failing tests%0A      return async.waterfall(%5B%0A        testThrow.bind(null, tests%5B'1'%5D),%0A        testThrow.bind(null, tests%5B'2'%5D),%0A        testThrow.bind(null, tests%5B'3'%5D)%0A      %5D, next)%0A    %7D)%0A  %7D)%0A%0A  describe('expect.deep', function () %7B%0A    var barObj = %7B bar: 'baz' %7D%0A    var fooObj = %7B foo: 'foz' %7D%0A    var veryDeepObj = %7B%0A      foo: %7B%0A        bar: %7B%0A          baz: 'quux'%0A        %7D%0A      %7D%0A    %7D%0A%0A    it('should assert successfuly', function () %7B%0A      expect(barObj).to.deep.equal(%7B bar: 'baz' %7D)%0A      expect(veryDeepObj).to.have.deep.property('foo.bar.baz', 'quux')%0A    %7D)%0A%0A    it('should throw an error', function (next) %7B%0A      // Tests that should fail%0A      var tests = %7B%0A        '1': function () %7B%0A          expect(fooObj, 'prefix testing').to.deep.equal(%7B bar: 'baz' %7D)%0A        %7D,%0A        '2': function () %7B%0A          expect(veryDeepObj, 'prefix testing').to.have.deep.property('foo.bar.baz', 'nop')%0A        %7D,%0A        '3': function () %7B%0A          expect(veryDeepObj, 'prefix testing').to.have.deep.property('foo.bar.nop', 'quux')%0A        %7D%0A      %7D%0A%0A
       // Run

add expect.deep