mocha.setup('bdd')
expect = chai.expect
should = chai.should()

describe "SimplyBind", ()->
	before ()->
		startSandbox()
		window.server = sinon.fakeServer.create()
		server.respondWith '/local', ''
		server.respondWith '/get/some/data.json', [
			200
			{ 'Content-Type': 'application/json' }
			JSON.stringify('prop': 'externalValues': 'it works :)')
		]
		server.respondWith '/get/some/data2.json', [
			200
			{ 'Content-Type': 'application/json' }
			JSON.stringify('prop': 'externalValues': 'it works :)')
		]
		server.respondWith '/get/nonexistent', ''
		server.respondWith '/set/some/data.json', [
			200
			{ 'Content-Type': 'application/json' }
			JSON.stringify('prop': 'externalValues': 'it works too :)')
		]
		server.respondWith '/set/some/data2.json', [
			200
			{ 'Content-Type': 'application/json' }
			JSON.stringify('prop': 'externalValues': 'it works too :)')
		]
		server.autoRespond = true
		server.autoRespondAfter = 0


	it "should return an options list when calling SimplyBind.options", ()->
		options = SimplyBind.options
		expect(options.silent).not.to.be.undefined
		expect(options.placeholderStart).not.to.be.undefined
		expect(options.placeholderEnd).not.to.be.undefined
		expect(options.liveProps).not.to.be.undefined
		expect(options.ignoreCase).not.to.be.undefined
		expect(options.dispatchEvents).not.to.be.undefined
		expect(options.updateEvenIfUndefined).not.to.be.undefined
		expect(options.updateEvenIfSame).not.to.be.undefined
		expect(options.mutateInherited).not.to.be.undefined
		expect(options.mutateArrayMethods).not.to.be.undefined
		expect(options.invokeOnBind).not.to.be.undefined



	it "should set a new value for a single option when calling SimplyBind.setOption()", ()->
		expect(SimplyBind.options.silent).to.equal false
		SimplyBind.setOption 'silent', true
		expect(SimplyBind.options.silent).to.equal true
		SimplyBind.setOption 'silent', false



	it "should set new values for a all the options passed when calling SimplyBind.setOptions()", ()->
		expect(SimplyBind.options.silent).to.equal false
		expect(SimplyBind.options.liveProps).to.equal true
		
		SimplyBind.setOptions
			'silent': true
			'liveProps': false
		
		expect(SimplyBind.options.silent).to.equal true
		expect(SimplyBind.options.liveProps).to.equal false
		
		SimplyBind.setOptions
			'silent': false
			'liveProps': true
		SimplyBind.setOptions {}
		
		expect(SimplyBind.options.silent).to.equal false
		expect(SimplyBind.options.liveProps).to.equal true



	it "should not add non-existing options when they are added via .setOptions", ()->
		SimplyBind.setOptions
			placeholderStart: '{{'
			placeholderEnd: '}}'
			youtube: 'yea!'
		
		expect(SimplyBind.options.placeholderStart).to.equal '{{'
		expect(SimplyBind.options.placeholderEnd).to.equal '}}'
		expect(SimplyBind.options.youtube).to.be.undefined



	it 'should apply input-simplybind polyfill', (done)->
		$inputA.one 'input-simplybind', ()->
			expect(true).to.equal true
			done()

		$inputA.trigger 'input-simplybind'



	it "should only accept a param value with the constructor of String, Number, Function, or SimplyBounded", ()->
		symbol = ()->
			SimplyBind Symbol('5')




		expect(symbol).to.throw()



	it "should only accept a param value with the constructor of String or SimplyBounded that isn't empty", ()->
		emptyString = ()-> SimplyBind ''
		numberZero = ()-> SimplyBind 0

		expect(emptyString).to.throw()
		expect(numberZero).not.to.throw()



	it "should not accept null subjects in .of()", ()->
		fn = ()-> SimplyBind('prop').of null
		
		expect(fn).to.throw()



	it "should not accept undefined subjects in .of()", ()->
		fn = ()-> SimplyBind('prop').of undefined
		
		expect(fn).to.throw()



	it "should not accept string, number, or boolean subjects in .of()", ()->
		fn = ()-> SimplyBind('prop').of 'string'
		fn2 = ()-> SimplyBind('prop').of 3
		fn3 = ()-> SimplyBind('prop').of true

		expect(fn).to.throw()
		expect(fn2).to.throw()
		expect(fn3).to.throw()



	it "should not accept non-object subjects in .of()", ()->
		fn = ()-> SimplyBind('prop').of Symbol('test')
		
		expect(fn).to.throw()



	it "should throw a warning when binding a property of a jQuery element with multiple els", ()->
		origLog = console.log
		console.log = chai.spy()
		
		SimplyBind('value').of $('input[type="text"]')

		expect(console.log).to.have.been.called()
		console.log = origLog



	it "should throw a warning when binding a property of an empty NodeList/HTMLCollection", ()->
		origLog = console.log
		console.log = chai.spy()
		
		SimplyBind('value').of document.querySelectorAll('nonexistent')
		expect(console.log).to.have.been.called()
		
		SimplyBind('value').of document.getElementsByTagName('nonexistent')
		expect(console.log).to.have.been.called()
		
		console.log = origLog



	it "should throw a warning when binding a property of an empty jQuery element", ()->
		origLog = console.log
		console.log = chai.spy()
		
		SimplyBind('value').of $('input[type="nonexistent"]')
		expect(console.log).to.have.been.called()
		
		console.log = origLog



	it "should throw a warning when creating a binding with a non-function object using the .transform or .transformAll method.", ()->
		origLog = console.log
		console.log = chai.spy()
	
		SimplyBind('prop1').of(objectA).to('prop1').of(objectB).transform []
		expect(console.log).to.have.been.called()
	
		SimplyBind('prop1').of(objectA).to('prop1').of(objectB).transformAll []
		expect(console.log).to.have.been.called()
	
		console.log = origLog
		restartSandbox()



	it "should\'t throw warnings if errors are suppressed, but should throw errors regardless", ()->
		emptyString = ()->
			SimplyBind ''

		SimplyBind.setOption 'silent', true
		
		origLog = console.log
		console.log = chai.spy()
		
		SimplyBind('value').of $('input[type="text"]')
		expect(console.log).not.to.have.been.called()
		expect(emptyString).to.throw()
		console.log = origLog
		
		SimplyBind.setOption 'silent', false






describe "Bound Object", ()->
	before ()->
		restartSandbox()



	it "should have the proper methods depending on its stage", ()->
		bound = ()-> SimplyBind '1'

		expect(()-> bound().of objectA).not.to.throw()
		expect(()-> bound().ofEvent objectA).not.to.throw()
		expect(()-> bound().ofExternal '/local').not.to.throw()
		expect(()-> bound().to 'prop2').to.throw()
		expect(()-> bound().toExternal '/local').to.throw()
		expect(()-> bound().and 'prop2').to.throw()
		expect(()-> bound().set 'value').to.throw()
		expect(()-> bound().get()).to.throw()
		expect(()-> bound().transform ()->).to.throw()
		expect(()-> bound().transformAll ()->).to.throw()
		expect(()-> bound().bothWays()).to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
		expect(()-> bound().unBind()).to.throw()
		expect(()-> bound().chainTo ()->).to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').to.throw()
		expect(()-> bound().removeEvent 'a').to.throw()

		bound = ()->
			SimplyBind('1').of objectA

		expect(()-> bound().of objectA).to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').not.to.throw()
		expect(()-> bound().toExternal '/local').not.to.throw()
		expect(()-> bound().and 'prop2').to.throw()
		expect(()-> bound().set 'value').not.to.throw()
		expect(()-> bound().get()).not.to.throw()
		expect(()-> bound().transform ()->).to.throw()
		expect(()-> bound().transformAll ()->).to.throw()
		expect(()-> bound().bothWays()).to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
		expect(()-> bound().unBind()).to.throw()
		expect(()-> bound().chainTo ()->).to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').to.throw()
		expect(()-> bound().removeEvent 'a').to.throw()

		bound = ()->
			SimplyBind('1').ofEvent 'click'

		expect(()-> bound().of objectA).not.to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').to.throw()
		expect(()-> bound().toExternal '/local').to.throw()
		expect(()-> bound().and 'prop2').to.throw()
		expect(()-> bound().set 'value').to.throw()
		expect(()-> bound().get()).to.throw()
		expect(()-> bound().transform ()->).to.throw()
		expect(()-> bound().transformAll ()->).to.throw()
		expect(()-> bound().bothWays()).to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
		expect(()-> bound().unBind()).to.throw()
		expect(()-> bound().chainTo ()->).to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').to.throw()
		expect(()-> bound().removeEvent 'a').to.throw()

		bound = ()->
			SimplyBind('1').ofEvent('click').of inputA

		expect(()-> bound().of objectA).to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').not.to.throw()
		expect(()-> bound().toExternal '/local').not.to.throw()
		expect(()-> bound().and 'prop2').to.throw()
		expect(()-> bound().set 'value').not.to.throw()
		expect(()-> bound().get()).not.to.throw()
		expect(()-> bound().transform ()->).to.throw()
		expect(()-> bound().transformAll ()->).to.throw()
		expect(()-> bound().bothWays()).to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
		expect(()-> bound().unBind()).to.throw()
		expect(()-> bound().chainTo ()->).to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').to.throw()
		expect(()-> bound().removeEvent 'a').to.throw()

		bound = ()->
			SimplyBind('1').of(objectA).to 'prop1'

		expect(()-> bound().of objectA).not.to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').to.throw()
		expect(()-> bound().toExternal '/local').to.throw()
		expect(()-> bound().and 'prop2').to.throw()
		expect(()-> bound().set 'value').to.throw()
		expect(()-> bound().get()).to.throw()
		expect(()-> bound().transform ()->).to.throw()
		expect(()-> bound().transformAll ()->).to.throw()
		expect(()-> bound().bothWays()).to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
		expect(()-> bound().unBind()).to.throw()
		expect(()-> bound().chainTo ()->).to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').to.throw()
		expect(()-> bound().removeEvent 'a').to.throw()

		bound = ()->
			SimplyBind('1').of(objectA).to('prop1').of objectB

		expect(()-> bound().of objectA).to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').to.throw()
		expect(()-> bound().toExternal '/local').to.throw()
		expect(()-> bound().and 'prop2').not.to.throw()
		expect(()-> bound().set 'value').not.to.throw()
		expect(()-> bound().get()).not.to.throw()
		expect(()-> bound().transform ()->).not.to.throw()
		expect(()-> bound().transformAll ()->).not.to.throw()
		expect(()-> bound().bothWays()).not.to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
		expect(()-> bound().unBind()).not.to.throw()
		expect(()-> bound().chainTo ()->).not.to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
		expect(()-> bound().removeEvent 'a').not.to.throw()

		bound = ()->
			SimplyBind('1').of(objectA).to('prop1').of(objectB).and 'prop2'

		expect(()-> bound().of objectA).not.to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').to.throw()
		expect(()-> bound().toExternal '/local').to.throw()
		expect(()-> bound().and 'prop2').to.throw()
		expect(()-> bound().set 'value').to.throw()
		expect(()-> bound().get()).to.throw()
		expect(()-> bound().transform ()->).to.throw()
		expect(()-> bound().transformAll ()->).to.throw()
		expect(()-> bound().bothWays()).to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
		expect(()-> bound().unBind()).to.throw()
		expect(()-> bound().chainTo ()->).to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').to.throw()
		expect(()-> bound().removeEvent 'a').to.throw()

		bound = ()->
			SimplyBind('1').of(objectA).to('prop1').of(objectB).and('prop2').of objectB

		expect(()-> bound().of objectA).to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').to.throw()
		expect(()-> bound().toExternal '/local').to.throw()
		expect(()-> bound().and 'prop2').not.to.throw()
		expect(()-> bound().set 'value').not.to.throw()
		expect(()-> bound().get()).not.to.throw()
		expect(()-> bound().transform ()->).not.to.throw()
		expect(()-> bound().transformAll ()->).not.to.throw()
		expect(()-> bound().bothWays()).not.to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
		expect(()-> bound().unBind()).not.to.throw()
		expect(()-> bound().chainTo ()->).not.to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
		expect(()-> bound().removeEvent 'a').not.to.throw()

		bound = ()->
			SimplyBind('1').of(objectA).to('prop1').of(objectB).bothWays()

		expect(()-> bound().of objectA).to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').to.throw()
		expect(()-> bound().toExternal '/local').to.throw()
		expect(()-> bound().and 'prop2').not.to.throw()
		expect(()-> bound().set 'value').not.to.throw()
		expect(()-> bound().get()).not.to.throw()
		expect(()-> bound().transform ()->).not.to.throw()
		expect(()-> bound().transformAll ()->).not.to.throw()
		expect(()-> bound().bothWays()).not.to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
		expect(()-> bound().unBind()).not.to.throw()
		expect(()-> bound().chainTo ()->).not.to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
		expect(()-> bound().removeEvent 'a').not.to.throw()

		bound = ()->
			SimplyBind('1').of(objectA).to('prop1').of(objectB).transform ()->

		expect(()-> bound().of objectA).to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').to.throw()
		expect(()-> bound().toExternal '/local').to.throw()
		expect(()-> bound().and 'prop2').not.to.throw()
		expect(()-> bound().set 'value').not.to.throw()
		expect(()-> bound().get()).not.to.throw()
		expect(()-> bound().transform ()->).to.throw()
		expect(()-> bound().transformAll ()->).to.throw()
		expect(()-> bound().bothWays()).not.to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
		expect(()-> bound().unBind()).not.to.throw()
		expect(()-> bound().chainTo ()->).not.to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
		expect(()-> bound().removeEvent 'a').not.to.throw()

		bound = ()->
			SimplyBind('1').of(objectA).to('prop1').of(objectB).transformAll ()->

		expect(()-> bound().of objectA).to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').to.throw()
		expect(()-> bound().toExternal '/local').to.throw()
		expect(()-> bound().and 'prop2').to.throw()
		expect(()-> bound().set 'value').not.to.throw()
		expect(()-> bound().get()).not.to.throw()
		expect(()-> bound().transform ()->).to.throw()
		expect(()-> bound().transformAll ()->).to.throw()
		expect(()-> bound().bothWays()).to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
		expect(()-> bound().unBind()).not.to.throw()
		expect(()-> bound().chainTo ()->).not.to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
		expect(()-> bound().removeEvent 'a').not.to.throw()

		bound = ()->
			SimplyBind('1').of(objectA).to('prop1').of(objectB).transform(()->
			).and ()->

		expect(()-> bound().of objectA).to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').to.throw()
		expect(()-> bound().toExternal '/local').to.throw()
		expect(()-> bound().and 'prop2').not.to.throw()
		expect(()-> bound().set 'value').not.to.throw()
		expect(()-> bound().get()).not.to.throw()
		expect(()-> bound().transform ()->).not.to.throw()
		expect(()-> bound().transformAll ()->).not.to.throw()
		expect(()-> bound().bothWays()).not.to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
		expect(()-> bound().unBind()).not.to.throw()
		expect(()-> bound().chainTo ()->).not.to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
		expect(()-> bound().removeEvent 'a').not.to.throw()

		bound = ()->
			SimplyBind('1').of(objectA).to('prop1').of(objectB).transform(()->
			).and(()->
			).chainTo ()->

		expect(()-> bound().of objectA).to.throw()
		expect(()-> bound().ofEvent objectA).to.throw()
		expect(()-> bound().ofExternal '/local').to.throw()
		expect(()-> bound().to 'prop2').to.throw()
		expect(()-> bound().toExternal '/local').to.throw()
		expect(()-> bound().and 'prop2').not.to.throw()
		expect(()-> bound().set 'value').not.to.throw()
		expect(()-> bound().get()).not.to.throw()
		expect(()-> bound().transform ()->).not.to.throw()
		expect(()-> bound().transformAll ()->).not.to.throw()
		expect(()-> bound().bothWays()).not.to.throw()
		expect(()-> bound().stopPolling()).to.throw()
		expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
		expect(()-> bound().unBind()).not.to.throw()
		expect(()-> bound().chainTo ()->).not.to.throw()
		expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
		expect(()-> bound().removeEvent 'a').not.to.throw()



	it "should have the correct public properties", ()->
		bound = SimplyBind('prop1').of(objectA).to('prop2').of(objectB)
		expect(bound.ID).not.to.be.undefined
		expect(typeof bound.has).to.equal 'object'
		expect(bound.has.initBind).not.to.be.undefined
		expect(bound.has.tf).not.to.be.undefined
		expect(bound.has.massTf).not.to.be.undefined
		expect(bound.has.event).not.to.be.undefined
		expect(bound.has.interval).not.to.be.undefined
		expect(bound.value).not.to.be.undefined
		expect(bound.stage).not.to.be.undefined
		expect(bound.original).not.to.be.undefined
		expect(bound.dependents).not.to.be.undefined
		expect(bound._).not.to.be.undefined



	it "should return the same SimplyBounded object from cache if in it", ()->
		bound1 = SimplyBind('prop1').of(objectA).to('prop1').of(objectB)
		bound2 = SimplyBind('prop1').of(objectA).to('prop1').of(objectB)
		expect(bound1.ID).to.equal bound2.ID



	it "should accept number attributes", ()->
		tempObject = 
			'1': 'text'
			'2': 'shmext'
	
		SimplyBind(1).of(tempObject).to(2).of tempObject
	
		expect(tempObject[1]).to.equal 'text'
		expect(tempObject[2]).to.equal 'text'



	it "should create the passed property on the parent object if undefined", ()->
		bound = SimplyBind('prop20').of(objectA).to('prop20').of(objectB)
		expect(objectA.prop20).not.to.be.undefined
		expect(objectB.prop20).not.to.be.undefined
		expect(objectA.prop20).to.be.null
		expect(objectB.prop20).to.be.null
		

		bound.set 'new value'
		expect(objectA.prop20).to.equal 'new value'
		expect(objectB.prop20).to.equal 'new value'



	it "should return the appropriate values when using .value prop and .get() method", ()->
		tempObject = 
			'a': 'with'
			'b': 'text {{verb}} a placeholder'
	
		SimplyBind('a').of(tempObject).to('b.verb').of tempObject
	

		bound = SimplyBind('b.verb').of(tempObject)
		expect(tempObject.b).to.equal 'text with a placeholder'
		expect(bound.value).to.equal 'text with a placeholder'
		expect(bound.get()).to.equal 'with'
		

		tempObject.a = 'without'
		expect(tempObject.b).to.equal 'text without a placeholder'
		expect(bound.value).to.equal 'text without a placeholder'
		expect(bound.get()).to.equal 'without'






describe "Data Binding", ()->
	before ()->
		restartSandbox()



	describe "Misc.", ()->
		it "can make inherited properties live properties if so set in options, otherwise it shouldn\'t", ()->
			testArray = []
			
			SimplyBind.setOption 'mutateInherited', true
			Array::inherited = 'Hello :)'
			
			SimplyBind('inherited').of(testArray).to('prop1').of objectB
			
			testArray.inherited = 'inherited live prop change :)'
			expect(objectB.prop1).to.equal 'inherited live prop change :)'
			delete Array::inherited
			


			SimplyBind.setOption 'mutateInherited', false
			Array::inherited2 = 'Hello :)'
			
			SimplyBind('inherited2').of(testArray).to('prop2').of objectB
			
			testArray.inherited2 = 'inherited prop shouldn\'t change'
			expect(objectB.prop2).not.to.equal 'inherited prop shouldn\'t change'
			delete Array::inherited2
			

			SimplyBind.setOption 'mutateInherited', false






		it "should invoke the original descriptor\'s setter and getter on a live property (if exists)", ()->
			prop7 = 'hey!'
			invokeCountGet = 0
			invokeCountSet = 0
			
			Object.defineProperty objectA, 'prop7',
				enumerable: true
				configurable: true
				get: ()->
					invokeCountGet++
					prop7
				set: (val)->
					invokeCountSet++
					prop7 = val



			expect(objectA.prop7).to.equal 'hey!'
			expect(invokeCountGet).to.equal 1
			expect(invokeCountSet).to.equal 0
	
			SimplyBind('prop7').of(objectA).to('prop3').of objectB
		
			objectA.prop7 = 'hello!'
			expect(invokeCountGet).to.equal 2
			expect(invokeCountSet).to.equal 1
			expect(objectA.prop7).to.equal 'hello!'
		
			objectA.prop7 = 'hi!'
			expect(invokeCountGet).to.equal 3
			expect(invokeCountSet).to.equal 2



		it "shouldn\'t change anything if passed a null/undefined value to .to()", ()->
			restartSandbox()

			bound = SimplyBind('prop1').of(objectA).to(null)
			expect(bound.stage).to.equal 1
			
			bound = SimplyBind('prop1').of(objectA).to(undefined)
			expect(bound.stage).to.equal 1
			
			if typeof Symbol != 'undefined'
				symbol = ()-> SimplyBind('prop1').of(objectA).to Symbol('whatever')
				expect(symbol).to.throw()



		it "shouldn\'t change anything if passed a null/undefined value to .and()", ()->
			restartSandbox()
			
			bound = SimplyBind('prop1').of(objectA).to(()->).and(null)
			expect(bound.stage).to.equal 3
			
			bound = SimplyBind('prop1').of(objectA).to(()->).and(undefined)
			expect(bound.stage).to.equal 3



		it "can accept a SimplyBounded object as an argument for .of()", ()->
			bound = SimplyBind('prop3').of(objectA).to('prop3').of(objectB)
			
			bound.set 'standard'
			expect(objectA.prop3).to.equal 'standard'
			expect(objectB.prop3).to.equal 'standard'
			
			bound2 = SimplyBind('prop4').of(bound).to('prop4').of(objectB)
			
			bound2.set 'ofBounded'
			expect(objectA.prop4).to.equal 'ofBounded'
			expect(objectB.prop4).to.equal 'ofBounded'



		it "should update values and dependents even if it\'s unchanged, if set the updateEvenIfSame option to true", ()->
			invokeCount = 0
			objectA.prop6 = 'start'
			objectB.prop6 = ''
			
			binding = SimplyBind('prop6').of(objectA).to('prop6').of(objectB).transform (value)-> invokeCount++; return value
			expect(objectB.prop6).to.equal 'start'
			expect(invokeCount).to.equal 1
			
			objectA.prop6 = 'shouldn\'t update'
			expect(objectB.prop6).to.equal 'shouldn\'t update'
			expect(invokeCount).to.equal 2
			
			objectA.prop6 = 'shouldn\'t update'
			expect(objectB.prop6).to.equal 'shouldn\'t update'
			expect(invokeCount).to.equal 2
			
			objectA.prop6 = 'shouldn\'t update'
			objectA.prop6 = 'shouldn\'t update'
			objectA.prop6 = 'shouldn\'t update'
			objectA.prop6 = 'shouldn\'t update'
			expect(invokeCount).to.equal 2
		


			binding.setOption 'updateEvenIfSame', true
			
			objectA.prop6 = 'should update'
			expect(objectB.prop6).to.equal 'should update'
			expect(invokeCount).to.equal 3
		
			objectA.prop6 = 'should update'
			objectA.prop6 = 'should update'
			objectA.prop6 = 'should update'
			objectA.prop6 = 'should update'
			expect(invokeCount).to.equal 7
			

			binding.setOption 'updateEvenIfSame', false
			
			objectA.prop6 = 'shouldn\'t update'
			expect(objectB.prop6).to.equal 'shouldn\'t update'
			expect(invokeCount).to.equal 8
			
			objectA.prop6 = 'shouldn\'t update'
			objectA.prop6 = 'shouldn\'t update'
			objectA.prop6 = 'shouldn\'t update'
			objectA.prop6 = 'shouldn\'t update'
			expect(invokeCount).to.equal 8



		it "can handle complex chainings using the .chainTo() method", ()->
			outerstate = 
				'first': null
				'second': null
				'third': null
		
			objectA.prop1 = 'Hello World'
			SimplyBind('prop1').of(objectA)
				.to('prop1').of(objectB)
				.and('prop2').of(objectA)
				.and (val)-> outerstate.first = val
					.transformAll (val)-> val.toUpperCase()
				
				.chainTo('prop2').of(objectB)
					.and('prop3').of(objectA)
						.transform (val)-> val.toLowerCase()
				
						.chainTo('prop3').of(objectB)
							.and('prop4').of(objectA)
							.and (val)-> outerstate.second = val
				
							.chainTo('prop4').of(objectB)
								.and (val)-> outerstate.third = val.slice(0, 5)



			expect(outerstate.first).to.equal 'HELLO WORLD'
			expect(outerstate.second).to.equal 'hello world'
			expect(outerstate.third).to.equal 'hello'
			expect(objectA.prop1).to.equal 'Hello World'
			expect(objectA.prop2).to.equal 'HELLO WORLD'
			expect(objectB.prop1).to.equal 'HELLO WORLD'
			expect(objectB.prop2).to.equal 'HELLO WORLD'
			expect(objectA.prop3).to.equal 'hello world'
			expect(objectB.prop3).to.equal 'hello world'
			expect(objectA.prop4).to.equal 'hello world'
			expect(objectB.prop4).to.equal 'hello world'



		it "should update dependents even if the new value is undefined, if so set in the options", ()->
			restartSandbox()
		
			binding = SimplyBind('prop1').of(objectA).to('prop1').of(objectB)
			objectA.prop1 = 10
			expect(objectB.prop1).to.equal 10
			
			objectA.prop1 = window.nonexistent # undefined value
			expect(objectB.prop1).to.equal 10
			

			binding.setOption 'updateEvenIfUndefined', true
		

			objectA.prop1 = 20
			expect(objectB.prop1).to.equal 20
			
			objectA.prop1 = window.nonexistent # undefined value
			expect(objectB.prop1).to.be.undefined
			

			binding.setOption 'updateEvenIfUndefined', false




		it "dependents should update their subdependents when being updated by an independent, even if these dependents are not liveProps", ()->
			objectA.prop2 = 0.8
			
			SimplyBind('prop2').of(objectA)
				.to('opacity').of regA.style
			
			SimplyBind('opacity').of(regA.style)
				.to('font-size').of(regA.style)
					.transform (opacity)-> opacity * 20 + 'px'
				.and('font-size').of(regB.style)
					.transform (opacity)-> opacity * 40 + 'px'
			

			expect(regA.style.opacity.toString()).to.equal '0.8'
			expect(regA.style['font-size']).to.equal '16px'
			expect(regB.style['font-size']).to.equal '32px'
			

			objectA.prop2 = 0.5
			expect(regA.style.opacity.toString()).to.equal '0.5'
			expect(regA.style['font-size']).to.equal '10px'
			expect(regB.style['font-size']).to.equal '20px'




		describe "Polling values in an interval", ()->
			it 'can manually poll the subject at a given interval via the .pollEvery method', (done)->
				shouldFinish = false
				lastValue = undefined
				bound = undefined
				arr = []

				fn = (length)->
					if shouldFinish
						expect(length).to.equal 2
						bound.stopPolling()
						done()
					else
						lastValue = length



				bound = SimplyBind('length').of(arr).to(fn)
				expect(lastValue).to.equal 0
				arr.push 'some value'
				arr.push 'and another'
				expect(lastValue).to.equal 0
				arr = []
				bound = SimplyBind('length').of(arr).to(fn).pollEvery(5)
				
				setTimeout ()->
					shouldFinish = true
					expect(lastValue).to.equal 0
					arr.push 'some value'
					arr.push 'and another'
					expect(lastValue).to.equal 0
				, 8



			it 'can manually poll the subject at a given interval via the .pollEvery method, even if it\'s an Attr type', (done)->
				shouldFinish = false
				lastValue = undefined
				bound = undefined
				h1 = regAH1

				fn = (value)->
					if shouldFinish
						expect(value).to.equal 'and another'
						bound.stopPolling()
						done()
					else
						lastValue = value




				bound = SimplyBind('attr:data-attr').of(h1).to(fn).pollEvery(5)
				bound.set 'initial value'
				setTimeout ()->
					shouldFinish = true
					expect(lastValue).to.equal 'initial value'
					h1.setAttribute 'data-attr', 'some value'
					h1.setAttribute 'data-attr', 'and another'
					expect(lastValue).to.equal 'initial value'
				, 8




			it 'can manually poll the subject and invoke it if it\'s a function at a given interval via the .pollEvery method', (done)->
				shouldFinish = false
				timesCalled = 0
				bound = undefined

				sourceFn = ()-> timesCalled++

				fn = (length)->
					if shouldFinish
						expect(timesCalled).to.equal 9
						bound.stopPolling()
						done()
					else
						if timesCalled > 5
							shouldFinish = true


				bound = SimplyBind(sourceFn).to(fn).pollEvery(5)
				expect(timesCalled).to.equal 1









	describe "Objects (Standard)", ()->
		it "supports live properties", ()->
			restartSandbox()
		
			SimplyBind('prop1').of(objectA).to('prop1').of objectB
		
			objectA.prop1 = 'live prop change :)'
			expect(objectB.prop1).to.equal 'live prop change :)'



		it "should avoid infinite loops", ()->
			SimplyBind('prop1').of(objectA).to('prop1').of(objectB).bothWays()
			SimplyBind('prop1').of(objectB).to('prop1').of(objectC).bothWays()
			SimplyBind('prop1').of(objectC).to('prop1').of(objectA).bothWays()
			
			objectA.prop1 = 'objectA'
			expect(objectB.prop1).to.equal 'objectA'
			expect(objectC.prop1).to.equal 'objectA'
			
			objectB.prop1 = 'objectB'
			expect(objectA.prop1).to.equal 'objectB'
			expect(objectC.prop1).to.equal 'objectB'



		it "can bind an object\'s property to another\'s", ()->
			restartSandbox()
			bound = SimplyBind('prop1').of(objectA).to('prop1').of(objectB)
			
			bound.set 'changed'
			expect(objectB.prop1).to.equal 'changed'



		it "can bind an functions\' property to another\'s", ()->
			fn = ()->
			fn.prop = 'some value'
			bound = SimplyBind('prop').of(fn).to('prop1').of(objectB)

			bound.set 'changed'
			expect(objectB.prop1).to.equal 'changed'



		it "can match case in property names (unless told otherwise via options.ignoreCase)", ()->
			restartSandbox()
			bound = SimplyBind('PrOp1').of(objectA).to('prOP1').of(objectB)
			bound.set 'not changed'
			
			expect(objectB.prop1).not.to.equal 'not changed'
			

			SimplyBind.setOption 'ignoreCase', true
			
			bound = SimplyBind('PrOp2').of(objectA).to('prOP2').of(objectB)
			bound.set 'changed'
			expect(objectB.prop2).to.equal 'changed'
			
			SimplyBind.setOption 'ignoreCase', false



		it "can bind even if the value is falsy", ()->
			restartSandbox()
			bound = SimplyBind('prop1').of(objectA).to('prop1').of(objectB)
			
			bound.set ''
			expect(objectB.prop1).to.equal ''
			
			bound.set 0
			expect(objectB.prop1).to.equal 0
			
			bound.set false
			expect(objectB.prop1).to.equal false
			
			bound.set undefined
			expect(objectB.prop1).to.equal false



		it "can bind an object\'s property to multiple other properties", ()->
			restartSandbox()
			SimplyBind('prop1').of(objectA)
				.to('prop1').of(objectB)
				.and('prop2').of(objectB)
				.and('prop3').of(objectB)
				.and('prop4').of(objectB)
		
			objectA.prop1 = 'all at once'
			expect(objectB.prop1).to.equal 'all at once'
			expect(objectB.prop2).to.equal 'all at once'
			expect(objectB.prop3).to.equal 'all at once'
			expect(objectB.prop4).to.equal 'all at once'



		it "can bind two objects\' properties both ways", ()->
			restartSandbox()
			SimplyBind('prop2').of(objectA).to('prop2').of(objectB).bothWays()
			
			objectA.prop2 = 'changed from objectA'
			expect(objectB.prop2).to.equal 'changed from objectA'
			
			objectB.prop2 = 'changed from objectB'
			expect(objectA.prop2).to.equal 'changed from objectB'



		it "can bind multiple bindings and apply the .bothWays() method only to the last binding.", ()->
			restartSandbox()
			SimplyBind('prop1').of(objectA).to('prop1').of(objectB).bothWays().and('prop2').of(objectB).and('prop3').of(objectB).bothWays().and('prop4').of objectB
			
			objectA.prop1 = 'all at once'
			expect(objectB.prop1).to.equal 'all at once'
			expect(objectB.prop2).to.equal 'all at once'
			expect(objectB.prop3).to.equal 'all at once'
			expect(objectB.prop4).to.equal 'all at once'
			
			objectB.prop1 = 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
			expect(objectA.prop1).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
			expect(objectB.prop2).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
			expect(objectB.prop3).to.equal 'all at once'
			expect(objectB.prop4).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
		
			objectB.prop3 = 'just a few'
			expect(objectA.prop1).to.equal 'just a few'
			expect(objectB.prop1).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
			expect(objectB.prop2).to.equal 'just a few'
			expect(objectB.prop4).to.equal 'just a few'



		it "can unbind all bindings", ()->
			restartSandbox()
			modified = false
			bound = SimplyBind('prop1').of(objectA)
				.to('prop1').of(objectB).bothWays()
				.and('prop2').of(objectB).bothWays()
				.and('prop1').of(objectC).bothWays()
				.and('prop2').of(objectC).bothWays()
				.and('value').of(textarea).bothWays()
				.and ()-> modified = true

			expect(objectB.prop1).to.equal 'some string'
			expect(objectB.prop2).to.equal 'some string'
			expect(objectC.prop1).to.equal 'some string'
			expect(objectC.prop2).to.equal 'some string'
			expect(textarea.value).to.equal 'some string'
			expect(modified).to.equal true
		
			modified = false
		
			bound.unBind()
			objectA.prop1 = 'should change'
			expect(modified).to.equal false
			expect(objectB.prop1).to.equal 'should change'
			expect(objectB.prop2).to.equal 'should change'
			expect(objectC.prop1).to.equal 'should change'
			expect(objectC.prop2).to.equal 'should change'
			expect(textarea.value).to.equal 'should change'
		

			SimplyBind.unBindAll objectA
			objectA.prop1 = 'shouldn\'t change'
			expect(objectB.prop1).to.equal 'should change'
			expect(objectB.prop2).to.equal 'should change'
			expect(objectC.prop1).to.equal 'should change'
			expect(objectC.prop2).to.equal 'should change'
			expect(textarea.value).to.equal 'should change'



		describe "Placeholders", ()->
			it "can bind an object\'s property to another\'s with a placeholder", ()->
				restartSandbox()
				objectB.prop1 = 'The size of this shirt is {{size}}, man!'
				bound = SimplyBind('prop1').of(objectA).to('prop1.size').of(objectB)
				bound.set 'Medium'
				expect(objectB.prop1).to.equal 'The size of this shirt is Medium, man!'



			it "shouldn\'t perform any changes if trying to update a placeholder that doesn\'t exist", ()->
				restartSandbox()
				objectB.prop1 = 'The size of this shirt is _____, man!'
				bound = SimplyBind('prop1').of(objectA).to('prop1.size').of(objectB)
				bound.set 'Medium'
				expect(objectB.prop1).to.equal 'The size of this shirt is _____, man!'



			it "can bind even if the value is not a string", ()->
				restartSandbox()
				objectB.prop1 = 'The size of this shirt is {{size}}, man!'
				bound = SimplyBind('prop1').of(objectA).to('prop1.size').of(objectB)
				bound.set false
				expect(objectB.prop1).to.equal 'The size of this shirt is false, man!'
				bound.set null
				expect(objectB.prop1).to.equal 'The size of this shirt is null, man!'
				bound.set {}
				expect(objectB.prop1).to.equal 'The size of this shirt is [object Object], man!'



			it "can bind even when the selector has extra dot-notations", ()->
				restartSandbox()
				objectB.prop1 = 'The size of this shirt is {{size.tedious}}, man!'
				bound = SimplyBind('prop1').of(objectA).to('prop1.size.tedious').of(objectB)
				bound.set 'Medium'
				expect(objectB.prop1).to.equal 'The size of this shirt is Medium, man!'



			it "can bind with a custom placeholder", ()->
				restartSandbox()
				SimplyBind.setOption 'placeholderStart', '^^'
				SimplyBind.setOption 'placeholderEnd', '$$'
				$inputA.val 'The size of this shirt is ^^size$$, man!'
				bound = SimplyBind('prop1').of(objectA).to('value.size').of(inputA)
				bound.set 'XXS'
				expect($inputA.val()).to.equal 'The size of this shirt is XXS, man!'
				SimplyBind.setOption 'placeholderStart', '{{'
				SimplyBind.setOption 'placeholderEnd', '}}'



			it "can bind multiple values to a string that has multiple placeholders", ()->
				restartSandbox()
				objectA.prop1 = 'The following text is {{verb}} {{nounOne}} and {{nounTwo}}'
				sampleObject = 
					'verb': 'not'
					'nounOne': 'small'
					'nounTwo': 'pretty'
			
				SimplyBind('verb').of(sampleObject).to('prop1.verb').of objectA
				SimplyBind('nounOne').of(sampleObject).to('prop1.nounOne').of objectA
				SimplyBind('nounTwo').of(sampleObject).to('prop1.nounTwo').of objectA
				expect(objectA.prop1).to.equal 'The following text is not small and pretty'
			
				sampleObject.verb = 'very'
				sampleObject.nounOne = 'big'
				sampleObject.nounTwo = 'ugly'
				expect(objectA.prop1).to.equal 'The following text is very big and ugly'
			
				sampleObject.verb = 'not'
				sampleObject.nounOne = 'small'
				sampleObject.nounTwo = 'pretty'
				expect(objectA.prop1).to.equal 'The following text is not small and pretty'



			it "can bind multiple values to a string that has multiple placeholders + transforms", ()->
				restartSandbox()
				objectA.prop1 = 'The following text is {{verbOne}} ({{verbTwo}}) {{nounOne}} and {{nounTwo}}'
				caseMethod = 'toUpperCase'
				sampleObject =
					'verb': 'not'
					'nounOne': 'small'
					'nounTwo': 'pretty'
			
				SimplyBind('verb').of(sampleObject)
					.to('prop1.verbOne').of(objectA).transform (value)-> value[caseMethod]()
				SimplyBind('verb').of(sampleObject)
					.to('prop1.verbTwo').of(objectA).transform (value)-> value.toLowerCase()
				SimplyBind('nounOne').of(sampleObject)
					.to('prop1.nounOne').of(objectA).transform (value)-> value[caseMethod]()
				SimplyBind('nounTwo').of(sampleObject)
					.to('prop1.nounTwo').of(objectA).transform (value)-> value[caseMethod]()
				
				expect(objectA.prop1).to.equal 'The following text is NOT (not) SMALL and PRETTY'
				sampleObject.verb = 'Very'
				sampleObject.nounOne = 'Big'
				sampleObject.nounTwo = 'Ugly'
				expect(objectA.prop1).to.equal 'The following text is VERY (very) BIG and UGLY'
			
				caseMethod = 'toLowerCase'
				sampleObject.verb = 'Not'
				sampleObject.nounOne = 'Small'
				sampleObject.nounTwo = 'Pretty'
				expect(objectA.prop1).to.equal 'The following text is not (not) small and pretty'






		describe "Transforms", ()->
			it "can bind an object\'s property to another\'s with a transform", ()->
				objectA.prop2 = 'current'
				bound = SimplyBind('prop2').of(objectA).to('prop2').of(objectB).transform((newValue, currentValue)->
					newValue+'+'+currentValue
				)
				expect(objectB.prop2).to.equal 'current+current'
				objectA.prop2 = 'new'
				expect(objectB.prop2).to.equal 'new+current+current'
				objectA.prop2 = 'new'
				expect(objectB.prop2).to.equal 'new+current+current'
				objectA.prop2 = 'newer'
				expect(objectB.prop2).to.equal 'newer+new+current+current'
			


			it "can bind an object\'s property to another\'s with a promise transform that resolves async", (done)->
				restartSandbox()
				objectA.prop2 = 'current'
				bound = SimplyBind('prop2', {'promiseTransforms':true}).of(objectA)
							.to('prop2').of(objectB)
								.transform (newValue, currentValue)-> new Promise (resolve)-> resolve(newValue+'+'+currentValue)

				setTimeout ()->
					expect(objectB.prop2).to.equal 'current+current'
					objectA.prop2 = 'new'
					
					setTimeout ()->
						expect(objectB.prop2).to.equal 'new+current+current'
						done()
					, 0
				, 0



			it "can bind with a transform both ways", ()->
				restartSandbox()
				objectA.prop2 = 'current'
				bound = SimplyBind('prop2').of(objectA).to('prop2').of(objectB).transform((newValue, currentValue)->
					newValue+'+'+currentValue
				).bothWays()
				expect(objectB.prop2).to.equal 'current+current'
				objectA.prop2 = 'new'
				expect(objectB.prop2).to.equal 'new+current+current'
				objectA.prop2 = 'new'
				expect(objectB.prop2).to.equal 'new+current+current'
				objectB.prop2 = 'new'
				expect(objectA.prop2).to.equal 'new+new'
				objectB.prop2 = 'newer'
				expect(objectA.prop2).to.equal 'newer+new+new'



			it "can bind with multiple transforms in a single chain", ()->
				restartSandbox()
				objectA.prop1 = 'CuRRent'
				SimplyBind('prop1').of(objectA).to('prop1').of(objectB).and('prop2').of(objectB).transform((value)->
					value.toUpperCase()
				).and('prop3').of(objectB).transform((value)->
					value.toLowerCase()
				).and('prop4').of(objectB).transform (value)->
					value.slice 0, 4
				expect(objectA.prop1).to.equal 'CuRRent'
				expect(objectB.prop1).to.equal 'CuRRent'
				expect(objectB.prop2).to.equal 'CURRENT'
				expect(objectB.prop3).to.equal 'current'
				expect(objectB.prop4).to.equal 'CuRR'



			it "can apply a single transform to all bindings in a chain", ()->
				restartSandbox()
				SimplyBind('prop1').of(objectA).to('prop1').of(objectB).and('prop2').of(objectB).transformAll (value)->
					value.toUpperCase()
				SimplyBind('prop1').of(objectA).to('prop3').of(objectB).and('prop4').of objectB
				objectA.prop1 = 'all at once'
				expect(objectB.prop1).to.equal 'ALL AT ONCE'
				expect(objectB.prop2).to.equal 'ALL AT ONCE'
				expect(objectB.prop3).to.equal 'all at once'
				expect(objectB.prop4).to.equal 'all at once'









	describe "Arrays", ()->
		describe "As property value", ()->
			it "supports live properties", ()->
				restartSandbox()
				SimplyBind(0).of(arrayA).to(0).of arrayB
				arrayA[0] = 'live prop change :)'
				expect(arrayB[0]).to.equal 'live prop change :)'



			it "should avoid infinite loops", ()->
				restartSandbox()
				# ==== Standard objects =================================================================================
				SimplyBind(0).of(arrayA).to(0).of(arrayB).bothWays()
				SimplyBind(0).of(arrayB).to(0).of(arrayC).bothWays()
				SimplyBind(0).of(arrayC).to(0).of(arrayA).bothWays()
				arrayA[0] = 'arrayA'
				expect(arrayB[0]).to.equal 'arrayA'
				expect(arrayC[0]).to.equal 'arrayA'
				arrayB[0] = 'arrayB'
				expect(arrayA[0]).to.equal 'arrayB'
				expect(arrayC[0]).to.equal 'arrayB'



			it "can bind an array\'s property to another\'s", ()->
				restartSandbox()
				bound = SimplyBind(0).of(arrayA).to(0).of(arrayB)
				bound.set 'changed'
				expect(arrayB[0]).to.equal 'changed'



			it "can bind an object\'s property to another\'s even if the value is falsy", ()->
				restartSandbox()
				bound = SimplyBind(1).of(arrayA).to(1).of(arrayB)
				bound.set ''
				expect(arrayB[1]).to.equal ''
				bound.set 0
				expect(arrayB[1]).to.equal 0
				bound.set false
				expect(arrayB[1]).to.equal false
				bound.set undefined
				expect(arrayB[1]).to.equal false



			it "can bind an object\'s property to multiple other properties", ()->
				restartSandbox()
				SimplyBind(0).of(arrayA).to(0).of(arrayB).and(1).of(arrayB).and(2).of(arrayB).and(3).of arrayB
				arrayA[0] = 'all at once'
				expect(arrayB[0]).to.equal 'all at once'
				expect(arrayB[1]).to.equal 'all at once'
				expect(arrayB[2]).to.equal 'all at once'
				expect(arrayB[3]).to.equal 'all at once'



			it "can unbind all bindings", ()->
				restartSandbox()
				arrayA[0] = 'some string'
				modified = false
				bound = SimplyBind(0).of(arrayA).to('prop1').of(objectB).bothWays().and('prop2').of(objectB).bothWays().and('prop1').of(objectC).bothWays().and('prop2').of(objectC).bothWays().and('value').of(textarea).bothWays().and(()->
					modified = true



				)
				expect(objectB.prop1).to.equal 'some string'
				expect(objectB.prop2).to.equal 'some string'
				expect(objectC.prop1).to.equal 'some string'
				expect(objectC.prop2).to.equal 'some string'
				expect(textarea.value).to.equal 'some string'
				expect(modified).to.equal true
				modified = false
				bound.unBind()
				arrayA[0] = 'should change'
				expect(modified).to.equal false
				expect(objectB.prop1).to.equal 'should change'
				expect(objectB.prop2).to.equal 'should change'
				expect(objectC.prop1).to.equal 'should change'
				expect(objectC.prop2).to.equal 'should change'
				expect(textarea.value).to.equal 'should change'
				SimplyBind.unBindAll arrayA
				arrayA[0] = 'shouldn\'t change'
				expect(objectB.prop1).to.equal 'should change'
				expect(objectB.prop2).to.equal 'should change'
				expect(objectC.prop1).to.equal 'should change'
				expect(objectC.prop2).to.equal 'should change'
				expect(textarea.value).to.equal 'should change'






		describe "As direct array", ()->
			# it("should avoid infinite loops", function(){
			# 	restartSandbox();
			# 	SimplyBind(0).of(arrayA).to(0).of(arrayB).bothWays();
			# 	SimplyBind(0).of(arrayB).to(0).of(arrayC).bothWays();
			# 	SimplyBind(0).of(arrayC).to(0).of(arrayA).bothWays();
			# 	arrayA[0] = 'arrayA';
			# 	expect(arrayB[0]).to.be('arrayA');
			# 	expect(arrayC[0]).to.be('arrayA');
			# 	arrayB[0] = 'arrayB';
			# 	expect(arrayA[0]).to.be('arrayB');
			# 	expect(arrayC[0]).to.be('arrayB');
			# });
			it "can bind an array to anything and update dependents even when calling the .push, .pop, .shift, .unshift, .splice, .reverse, and .sort methods", ()->
				sampleArray = [1,2,3,4,5,6,7,8,9,10]
				mutations = 0
				SimplyBind(sampleArray).to('prop4').of(objectB).and ()-> mutations++

				expect(objectB.prop4.length).to.equal 10
				expect(mutations).to.equal 1
				sampleArray.push 11
				expect(objectB.prop4.length).to.equal 11
				expect(mutations).to.equal 2
				sampleArray.shift()
				sampleArray.shift()
				expect(objectB.prop4.length).to.equal 9
				expect(mutations).to.equal 4
				sampleArray.unshift 2
				sampleArray.unshift 1
				expect(objectB.prop4.length).to.equal 11
				expect(mutations).to.equal 6
				sampleArray.pop()
				sampleArray.pop()
				expect(objectB.prop4.length).to.equal 9
				expect(mutations).to.equal 8
				sampleArray.splice 0, 5
				expect(objectB.prop4.length).to.equal 4
				expect(mutations).to.equal 9
				sampleArray.reverse()
				expect(objectB.prop4.length).to.equal 4
				expect(mutations).to.equal 10
				sampleArray.sort()
				expect(objectB.prop4.length).to.equal 4
				expect(mutations).to.equal 11
				sampleArray.sort ()->
					1
				expect(objectB.prop4.length).to.equal 4
				expect(mutations).to.equal 12



			it "it\'s impossible to replace the array object in an array binding.", ()->
				sampleArray = [1,2,3,4,5,6,7,8,9,10]
				mutations = 0
				SimplyBind(sampleArray).to('prop4').of(objectB).and ()-> mutations++

				expect(objectB.prop4.length).to.equal 10
				expect(mutations).to.equal 1
				SimplyBind(sampleArray).set [1,2,3,4,5,6,7,8,9,10]
				# Replace array. If it were to replace it, the mutations count will increase by one.
				SimplyBind(sampleArray).set [1,2,3,4,5,6,7,8,9,10]
				SimplyBind(sampleArray).set [1,2,3,4,5,6,7,8,9,10]
				sampleArray.push 11
				expect(objectB.prop4.length).to.equal 11
				expect(mutations).to.equal 2
				sampleArray.shift()
				sampleArray.shift()
				expect(objectB.prop4.length).to.equal 9
				expect(mutations).to.equal 4
				sampleArray.unshift 2
				sampleArray.unshift 1
				expect(objectB.prop4.length).to.equal 11
				expect(mutations).to.equal 6
				sampleArray.pop()
				sampleArray.pop()
				expect(objectB.prop4.length).to.equal 9
				expect(mutations).to.equal 8
				sampleArray.splice 0, 5
				expect(objectB.prop4.length).to.equal 4
				expect(mutations).to.equal 9



			it "will update dependents when its children get modified if specified via the trackArrayChildren option", ()->
				sampleArray = [1,2,3,4,5,6,7,8,9,10]
				sampleArray2 = [1,2,3,4,5,6,7,8,9,10]
				mutations = 0
				SimplyBind(sampleArray).to('prop5').of(objectA).and ()-> mutations++

				expect(objectA.prop5).to.equal sampleArray
				sampleArray[0] = 100
				sampleArray[1] = 200
				sampleArray[2] = 300
				expect(objectA.prop5[0]).to.equal 100
				expect(objectA.prop5[1]).to.equal 200
				expect(objectA.prop5[2]).to.equal 300
				expect(mutations).to.equal 1
				mutations = 0
				SimplyBind(sampleArray2, 'trackArrayChildren': true).to('prop6').of(objectA).and ()-> mutations++

				expect(objectA.prop6).to.equal sampleArray2
				sampleArray2[0] = 100
				sampleArray2[1] = 200
				sampleArray2[2] = 300
				expect(objectA.prop6[0]).to.equal 100
				expect(objectA.prop6[1]).to.equal 200
				expect(objectA.prop6[2]).to.equal 300
				expect(mutations).to.equal 4



			it "will update dependents even when there is a sepearate binding on a reference of the same array", ()->
				sampleArrayA = [1,2,3,4,5,6,7,8,9,10]
				sampleArrayB = sampleArrayA
				sampleArrayC = null
				mutationsA = 0
				mutationsB = 0
				mutationsC = 0
				SimplyBind(sampleArrayA)
					.to('prop6').of(objectA)
					.and ()-> mutationsA++
				
				SimplyBind(sampleArrayB)
					.to('prop6').of(objectB)
					.and (arr)-> sampleArrayC = arr unless sampleArrayC
					.and ()-> mutationsB++

				SimplyBind(sampleArrayC)
					.to('prop6').of(objectC)
					.and ()-> mutationsC++

				expect(sampleArrayA).to.equal sampleArrayB
				expect(mutationsA).to.equal 1
				expect(mutationsB).to.equal 1
				expect(mutationsC).to.equal 1
				sampleArrayA.push 11
				sampleArrayA.push 12
				sampleArrayB.push 13
				sampleArrayB.push 14
				sampleArrayC.push 15
				sampleArrayC.push 16
				expect(mutationsA).to.equal 7
				expect(mutationsB).to.equal 7
				expect(mutationsC).to.equal 7



			it "can unbind all bindings", ()->
				restartSandbox()
				arrayA[0] = 'some string'
				modified = false
				bound = SimplyBind(0).of(arrayA).to('prop1').of(objectB).bothWays().and('prop2').of(objectB).bothWays().and('prop1').of(objectC).bothWays().and('prop2').of(objectC).bothWays().and('value').of(textarea).bothWays().and(()->
					modified = true



				)
				expect(objectB.prop1).to.equal 'some string'
				expect(objectB.prop2).to.equal 'some string'
				expect(objectC.prop1).to.equal 'some string'
				expect(objectC.prop2).to.equal 'some string'
				expect(textarea.value).to.equal 'some string'
				expect(modified).to.equal true
				modified = false
				bound.unBind()
				arrayA[0] = 'should change'
				expect(modified).to.equal false
				expect(objectB.prop1).to.equal 'should change'
				expect(objectB.prop2).to.equal 'should change'
				expect(objectC.prop1).to.equal 'should change'
				expect(objectC.prop2).to.equal 'should change'
				expect(textarea.value).to.equal 'should change'
				SimplyBind.unBindAll arrayA
				arrayA[0] = 'shouldn\'t change'
				expect(objectB.prop1).to.equal 'should change'
				expect(objectB.prop2).to.equal 'should change'
				expect(objectC.prop1).to.equal 'should change'
				expect(objectC.prop2).to.equal 'should change'
				expect(textarea.value).to.equal 'should change'









	describe "DOM field values", ()->
		it "should avoid infinite loops", ()->
			restartSandbox()
			SimplyBind('value').of(inputA).to('value').of(inputB).bothWays()
			SimplyBind('value').of(inputB).to('value').of(inputC).bothWays()
			SimplyBind('value').of(inputC).to('value').of(inputA).bothWays()
			$inputA.val('input1')[0].dispatchEvent new Event('change')
			expect($inputB.val()).to.equal 'input1'
			expect($inputC.val()).to.equal 'input1'
			$inputB.val('input2')[0].dispatchEvent new Event('change')
			expect($inputA.val()).to.equal 'input2'
			expect($inputC.val()).to.equal 'input2'



		it "can update an field\'s value through its bound instance", ()->
			bound = SimplyBind('value').of(inputA).to('prop2').of(objectA)
			bound.set 'changed from bound instance'
			expect(objectA.prop2).to.equal 'changed from bound instance'



		it "can bind an field\'s value to an object\'s property", ()->
			SimplyBind('value').of(inputA).to('prop4').of objectA
			$inputA.val('changed')[0].dispatchEvent new Event('change')
			expect(objectA.prop4).to.equal 'changed'



		it "can bind two fields\' values both ways", ()->
			restartSandbox()
			SimplyBind('value').of(inputA).to('value').of(inputB).bothWays()
			$inputA.val('changed from input1')[0].dispatchEvent new Event('change')
			expect($inputB.val()).to.equal 'changed from input1'
			$inputB.val('changed from input2')[0].dispatchEvent new Event('change')
			expect($inputA.val()).to.equal 'changed from input2'



		it "can bind two fields\' values both ways", ()->
			restartSandbox()
			SimplyBind('value').of(textarea).to('value').of(inputB).bothWays()
			$textarea.val('changed from input1')[0].dispatchEvent new Event('change')
			expect($inputB.val()).to.equal 'changed from input1'
			$inputB.val('changed from input2')[0].dispatchEvent new Event('change')
			expect($textarea.val()).to.equal 'changed from input2'



		it "can bind a select field\'s value both ways", ()->
			SimplyBind('value').of($('#select')[0]).to('prop3').of(objectB).bothWays()
			objectB.prop3 = 'valid'
			expect($('#select').val()).to.equal 'valid'
			$('#select').val('valid2')[0].dispatchEvent new Event('change')
			expect(objectB.prop3).to.equal 'valid2'



		it "can bind a radio field\'s value both ways", ()->
			SimplyBind('value').of($('#radio').children()).to('prop3').of(objectB).bothWays()
			objectB.prop3 = 'changed from objectB'
			expect($('input:checked').length).to.equal 0
			objectB.prop3 = 'radio2'
			expect($('input:checked').val()).to.equal 'radio2'
			$('#radio1').click()[0].dispatchEvent new Event('change')
			expect(objectB.prop3).to.equal 'radio1'



		it "can bind a checkbox field\'s value both ways", ()->
			$('#checkbox1').prop 'checked', true
			SimplyBind('value').of($('#checkbox').children()).to('prop3').of(objectB).bothWays()
			objectB.prop3 = 'changed from objectB'
			expect($('input:checked').length).to.equal 0
			objectB.prop3 = 'checkbox2'
			expect($('input:checked').val()).to.equal 'checkbox2'
			$('#checkbox1').click()[0].dispatchEvent new Event('change')
			expect(objectB.prop3).to.equal 'checkbox1'



		it "can bind a field\'s value when the field passed is a jQuery Object", ()->
			SimplyBind('prop3').of(objectA).to('value').of $inputB
			objectA.prop3 = 'changed from jQuery'
			expect($inputB.val()).to.equal 'changed from jQuery'



		it "can bind a select field\'s value field passed is a jQuery Object", ()->
			restartSandbox()
			SimplyBind('prop3').of(objectB).to('value').of $('#select')
			objectB.prop3 = 'valid'
			expect($('#select').val()).to.equal 'valid'



		it 'should dispatch change events if so told/set', (done)->
			restartSandbox()
			SimplyBind.setOption 'dispatchEvents', true
			SimplyBind('prop4').of(objectA).to('value').of $('#select')
			SimplyBind('value').of($('#textarea')).to('prop4').of objectA
			$('#select')[0].addEventListener 'change', ((event)->
				expect(event.target.value).to.equal 'valid'
				done()



			), false
			$('#textarea').val('valid')[0].dispatchEvent new Event('change')
			SimplyBind.setOption 'dispatchEvents', false



		it "can unbind all bindings", ()->
			restartSandbox()
			$inputA.val('some string')[0].dispatchEvent new Event('change')
			modified = false
			bound = SimplyBind('value').of(inputA).to('prop1').of(objectB).bothWays().and('prop2').of(objectB).bothWays().and('prop1').of(objectC).bothWays().and('prop2').of(objectC).bothWays().and('value').of(textarea).bothWays().and(()->
				modified = true



			)
			expect(objectB.prop1).to.equal 'some string'
			expect(objectB.prop2).to.equal 'some string'
			expect(objectC.prop1).to.equal 'some string'
			expect(objectC.prop2).to.equal 'some string'
			expect(textarea.value).to.equal 'some string'
			expect(modified).to.equal true
			modified = false
			bound.unBind()
			$inputA.val('should change')[0].dispatchEvent new Event('change')
			expect(modified).to.equal false
			expect(objectB.prop1).to.equal 'should change'
			expect(objectB.prop2).to.equal 'should change'
			expect(objectC.prop1).to.equal 'should change'
			expect(objectC.prop2).to.equal 'should change'
			expect(textarea.value).to.equal 'should change'
			SimplyBind.unBindAll inputA
			$inputA.val('should change')[0].dispatchEvent new Event('shouldn\'t change')
			expect(objectB.prop1).to.equal 'should change'
			expect(objectB.prop2).to.equal 'should change'
			expect(objectC.prop1).to.equal 'should change'
			expect(objectC.prop2).to.equal 'should change'
			expect(textarea.value).to.equal 'should change'



		describe "Placeholders", ()->
			it "can bind a field\'s value with a placeholder", ()->
				restartSandbox()
				inputB.value = 'The size of this shirt is {{size}}, man!'
				bound = SimplyBind('value').of(inputA).to('value.size').of(inputB)
				bound.set 'Medium'
				expect(inputB.value).to.equal 'The size of this shirt is Medium, man!'



			it "shouldn\'t perform any changes if trying to update a placeholder that doesn\'t exist", ()->
				restartSandbox()
				inputB.value = 'The size of this shirt is _____, man!'
				bound = SimplyBind('value').of(inputA).to('value.size').of(inputB)
				bound.set 'Medium'
				expect(inputB.value).to.equal 'The size of this shirt is _____, man!'



			it "can bind even if the value is not a string", ()->
				restartSandbox()
				inputB.value = 'The size of this shirt is {{size}}, man!'
				bound = SimplyBind('value').of(inputA).to('value.size').of(inputB)
				bound.set false
				expect(inputB.value).to.equal 'The size of this shirt is false, man!'
				bound.set null
				expect(inputB.value).to.equal 'The size of this shirt is null, man!'
				bound.set {}
				expect(inputB.value).to.equal 'The size of this shirt is [object Object], man!'



			it "can bind even when the selector has extra dot-notations", ()->
				restartSandbox()
				inputB.value = 'The size of this shirt is {{size.tedious}}, man!'
				bound = SimplyBind('value').of(inputA).to('value.size.tedious').of(inputB)
				bound.set 'Medium'
				expect(inputB.value).to.equal 'The size of this shirt is Medium, man!'



			it "can bind with a custom placeholder", ()->
				restartSandbox()
				SimplyBind.setOption 'placeholderStart', '^^'
				SimplyBind.setOption 'placeholderEnd', '$$'
				$inputB.val 'The size of this shirt is ^^size$$, man!'
				bound = SimplyBind('value').of(inputA).to('value.size').of(inputB)
				bound.set 'XXS'
				expect($inputB.val()).to.equal 'The size of this shirt is XXS, man!'
				SimplyBind.setOption 'placeholderStart', '{{'
				SimplyBind.setOption 'placeholderEnd', '}}'






		describe "Transforms", ()->
			it "can bind an object\'s property to another\'s with a transform", ()->
				restartSandbox()
				inputA.value = 'current'
				SimplyBind('value').of(inputA).to('value').of(inputB).transform (newValue, currentValue)->
					newValue+'+'+currentValue
				expect(inputB.value).to.equal 'current+current'
				$inputA.val('new')[0].dispatchEvent new Event('change')
				expect(inputB.value).to.equal 'new+current+current'
				$inputA.val('new')[0].dispatchEvent new Event('change')
				expect(inputB.value).to.equal 'new+current+current'
				$inputA.val('newer')[0].dispatchEvent new Event('change')
				expect(inputB.value).to.equal 'newer+new+current+current'



			it "can bind with a transform both ways", ()->
				restartSandbox()
				inputA.value = 'current'
				SimplyBind('value').of(inputA).to('value').of(inputB).transform((newValue, currentValue)->
					newValue+'+'+currentValue
				).bothWays()
				expect(inputB.value).to.equal 'current+current'
				$inputA.val('new')[0].dispatchEvent new Event('change')
				expect(inputB.value).to.equal 'new+current+current'
				$inputA.val('new')[0].dispatchEvent new Event('change')
				expect(inputB.value).to.equal 'new+current+current'
				$inputB.val('new')[0].dispatchEvent new Event('change')
				expect(inputA.value).to.equal 'new+new'
				$inputB.val('newer')[0].dispatchEvent new Event('change')
				expect(inputA.value).to.equal 'newer+new+new'



			it "can bind with multiple transforms in a single chain", ()->
				restartSandbox()
				inputA.value = 'CuRRent'
				SimplyBind('value').of(inputA).to('value').of(inputB).transform((value)->
					value.toUpperCase()
				).and('value').of(textarea).transform((value)->
					value.toLowerCase()
				).and('value').of(inputC).transform (value)->
					value.slice 0, 4
				expect(inputA.value).to.equal 'CuRRent'
				expect(inputB.value).to.equal 'CURRENT'
				expect(textarea.value).to.equal 'current'
				expect(inputC.value).to.equal 'CuRR'



			it "can apply a single transform to all bindings in a chain", ()->
				restartSandbox()
				SimplyBind('value').of(inputA).to('value').of(inputB).and('value').of(inputC).transformAll (value)->
					value.toUpperCase()
				SimplyBind('value').of(inputA).to('value').of textarea
				$inputA.val('all at once')[0].dispatchEvent new Event('change')
				expect(inputB.value).to.equal 'ALL AT ONCE'
				expect(inputC.value).to.equal 'ALL AT ONCE'
				expect(textarea.value).to.equal 'all at once'









	describe "DOM textContent", ()->
		it "can bind a DOM el\'s textContent property to another\'s", ()->
			restartSandbox()
			bound = SimplyBind('textContent').of(regAH1Span).to('prop1').of(objectB)
			bound.set 'changed'
			expect(objectB.prop1).to.equal 'changed'



		it "can bind an object to a DOM el\'s textContent", ()->
			bound = SimplyBind('prop4').of(objectA).to('textContent').of(regA)
			bound.set 'complete rewrite'
			expect(regA.textContent).to.equal 'complete rewrite'
			expect($regAH1.width()).to.equal 0
			expect($regAH1Span.width()).to.equal 0
			bound.set 'complete rewrite 2'
			expect(regA.textContent).to.equal 'complete rewrite 2'
			expect($regAH1.width()).to.equal 0
			expect($regAH1Span.width()).to.equal 0



		it "can bind an input element\'s value to a DOM el\'s textContent", ()->
			restartSandbox()
			SimplyBind.setOption 'placeholderStart', '{{'
			SimplyBind.setOption 'placeholderEnd', '}}'
			bound = SimplyBind('value').of($inputA).to('textContent.verb').of(regA)
			$inputA.val('very')[0].dispatchEvent new Event('change')
			expect(regA.textContent).to.equal 'The following text is very big and ugly'
			expect($regAH1.width()).not.to.equal 0
			expect($regAH1Span.width()).not.to.equal 0
			$inputA.val('not')[0].dispatchEvent new Event('change')
			expect(regA.textContent).to.equal 'The following text is not big and ugly'
			expect($regAH1.width()).not.to.equal 0
			expect($regAH1Span.width()).not.to.equal 0



		it "should update the values of properties that are inherited from their prototype", ()->
			h1 = regAH1
			sampleObject = 'size': '18px'
			expect(h1.title).to.equal ''
			SimplyBind('size').of(sampleObject).to('title').of h1
			expect(h1.title).to.equal '18px'
			sampleObject.size = '26px'
			expect(h1.title).to.equal '26px'



		it "can match case in property names (unless told otherwise via options.ignoreCase)", ()->
			restartSandbox()
			bound = SimplyBind('TeXtCONtent').of(regA).to('prOP1').of(objectB).bothWays()
			bound.set 'not changed'
			expect(objectB.prop1).not.to.equal 'not changed'
			objectB.prOP1 = 'changed attr'
			expect(regA.textContent).not.to.equal 'changed attr'
			expect(regA.TeXtCONtent).to.equal 'changed attr'
			SimplyBind.setOption 'ignoreCase', true
			regA.textContent = '...'
			bound = SimplyBind('TeXtCONtent').of(regA).to('prOP2').of(objectB).bothWays()
			bound.set 'changed'
			expect(objectB.prop2).to.equal 'changed'
			objectB.prop2 = 'should change'
			expect(regA.textContent).to.equal 'should change'
			SimplyBind.setOption 'ignoreCase', false



		it "can bind even if the value is falsy", ()->
			restartSandbox()
			bound = SimplyBind('textContent').of(regA).to('prop1').of(objectB)
			bound.set ''
			expect(objectB.prop1).to.equal ''
			bound.set 0
			expect(objectB.prop1).to.equal 0
			bound.set false
			expect(objectB.prop1).to.equal false
			bound.set undefined
			expect(objectB.prop1).to.equal false



		it "can bind an object\'s property to multiple other properties", ()->
			restartSandbox()
			bound = SimplyBind('textContent').of(regAH1).to('prop1').of(objectB).and('prop2').of(objectB).and('prop3').of(objectB).and('prop4').of(objectB)
			bound.set 'all at once'
			expect(objectB.prop1).to.equal 'all at once'
			expect(objectB.prop2).to.equal 'all at once'
			expect(objectB.prop3).to.equal 'all at once'
			expect(objectB.prop4).to.equal 'all at once'



		it "can bind two DOM els\' textContents both ways", ()->
			restartSandbox()
			SimplyBind('textContent').of(regA).to('textContent').of(regB).bothWays()
			SimplyBind('textContent').of(regA).set 'changed from regA'
			expect(regB.textContent).to.equal 'changed from regA'
			SimplyBind('textContent').of(regB).set 'changed from regB'
			expect(regA.textContent).to.equal 'changed from regB'



		it "can bind multiple bindings and apply the .bothWays() method only to the last binding.", ()->
			restartSandbox()
			SimplyBind('textContent').of(regA).to('prop1').of(objectB).bothWays().and('prop2').of(objectB).and('prop3').of(objectB).bothWays().and('prop4').of objectB
			SimplyBind('textContent').of(regA).set 'all at once'
			expect(objectB.prop1).to.equal 'all at once'
			expect(objectB.prop2).to.equal 'all at once'
			expect(objectB.prop3).to.equal 'all at once'
			expect(objectB.prop4).to.equal 'all at once'
			objectB.prop1 = 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
			expect(regA.textContent).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
			expect(objectB.prop2).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
			expect(objectB.prop3).to.equal 'all at once'
			expect(objectB.prop4).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
			objectB.prop3 = 'just a few'
			expect(regA.textContent).to.equal 'just a few'
			expect(objectB.prop1).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
			expect(objectB.prop2).to.equal 'just a few'
			expect(objectB.prop4).to.equal 'just a few'



		it "can unbind all bindings", ()->
			restartSandbox()
			regA.textContent = 'some string'
			modified = false
			bound = SimplyBind('textContent').of(regA).to('prop1').of(objectB).bothWays().and('prop2').of(objectB).bothWays().and('prop1').of(objectC).bothWays().and('prop2').of(objectC).bothWays().and('value').of(textarea).bothWays().and(()->
				modified = true



			)
			expect(objectB.prop1).to.equal 'some string'
			expect(objectB.prop2).to.equal 'some string'
			expect(objectC.prop1).to.equal 'some string'
			expect(objectC.prop2).to.equal 'some string'
			expect(textarea.value).to.equal 'some string'
			expect(modified).to.equal true
			modified = false
			bound.unBind()
			SimplyBind('textContent').of(regA).set 'should change'
			expect(modified).to.equal false
			expect(objectB.prop1).to.equal 'should change'
			expect(objectB.prop2).to.equal 'should change'
			expect(objectC.prop1).to.equal 'should change'
			expect(objectC.prop2).to.equal 'should change'
			expect(textarea.value).to.equal 'should change'
			SimplyBind.unBindAll regA
			SimplyBind('textContent').of(regA).set 'shouldn\'t change'
			expect(objectB.prop1).to.equal 'should change'
			expect(objectB.prop2).to.equal 'should change'
			expect(objectC.prop1).to.equal 'should change'
			expect(objectC.prop2).to.equal 'should change'
			expect(textarea.value).to.equal 'should change'



		describe "Placeholders", ()->
			it "can bind an object to a DOM el\'s textContent with a placeholder", ()->
				restartSandbox()
				bound = SimplyBind('prop4').of(objectA).to('textContent.verb').of(regA)
				bound.set 'very'
				expect(regA.textContent).to.equal 'The following text is very big and ugly'
				expect($regAH1.width()).not.to.equal 0
				expect($regAH1Span.width()).not.to.equal 0
				bound.set 'not'
				expect(regA.textContent).to.equal 'The following text is not big and ugly'
				expect($regAH1.width()).not.to.equal 0
				expect($regAH1Span.width()).not.to.equal 0



			it "can bind an input element\'s value to a DOM el\'s textContent with multiple placeholders", ()->
				restartSandbox()
				bound = SimplyBind('value').of($inputA).to('textContent.verb').of(regB)
				bound = SimplyBind('value').of($inputB).to('textContent.nounOne').of(regB)
				bound = SimplyBind('value').of($inputC).to('textContent.nounTwo').of(regB)
				$inputA.val('very')[0].dispatchEvent new Event('change')
				$inputB.val('big')[0].dispatchEvent new Event('change')
				$inputC.val('ugly')[0].dispatchEvent new Event('change')
				expect(regB.textContent).to.equal 'The following text is very big and ugly'
				expect($regBH1.width()).not.to.equal 0
				expect($regBH1Span.width()).not.to.equal 0
				$inputA.val('not')[0].dispatchEvent new Event('change')
				$inputB.val('small')[0].dispatchEvent new Event('change')
				$inputC.val('pretty')[0].dispatchEvent new Event('change')
				expect(regB.textContent).to.equal 'The following text is not small and pretty'
				expect($regBH1.width()).not.to.equal 0
				expect($regBH1Span.width()).not.to.equal 0



			it "can bind an input element\'s value to a DOM el\'s textContent with duplicate placeholders", ()->
				restartSandbox()
				bound = SimplyBind('value').of($inputA).to('textContent.word').of(regC)
				$inputA.val('slang')[0].dispatchEvent new Event('change')
				expect(regC.textContent).to.equal 'The following text should have this: slang, slang twice'
				expect($regCH1.width()).not.to.equal 0
				expect($regCH1Span.width()).not.to.equal 0
				$inputA.val('bird')[0].dispatchEvent new Event('change')
				expect(regC.textContent).to.equal 'The following text should have this: bird, bird twice'
				expect($regCH1.width()).not.to.equal 0
				expect($regCH1Span.width()).not.to.equal 0






		describe "Transforms", ()->
			it "can bind an object\'s property to a DOM el\'s textContent with a transform", ()->
				restartSandbox()
				objectA.prop2 = 'current'
				bound = SimplyBind('prop2').of(objectA).to('textContent').of(regA).transform((newValue, currentValue)->
					newValue+'+'+currentValue
				)
				expect(regA.textContent).to.equal 'current+current'
				objectA.prop2 = 'new'
				expect(regA.textContent).to.equal 'new+current+current'
				objectA.prop2 = 'new'
				expect(regA.textContent).to.equal 'new+current+current'
				objectA.prop2 = 'newer'
				expect(regA.textContent).to.equal 'newer+new+current+current'



			it "can NOT bind with a transform both ways", ()->
				restartSandbox()
				objectA.prop2 = 'current'
				bound = SimplyBind('prop2').of(objectA).to('textContent').of(regA).transform((newValue, currentValue)->
					newValue+'+'+currentValue
				).bothWays()
				expect(regA.textContent).to.equal 'current+current'
				objectA.prop2 = 'new'
				expect(regA.textContent).to.equal 'new+current+current'
				objectA.prop2 = 'new'
				expect(regA.textContent).to.equal 'new+current+current'
				regA.textContent = 'new'
				expect(objectA.prop2).to.equal 'new'
				regA.textContent = 'newer'
				expect(objectA.prop2).to.equal 'new'



			it "can bind with multiple transforms in a single chain", ()->
				restartSandbox()
				objectA.prop1 = 'CuRRent'
				SimplyBind('prop1').of(objectA).to('textContent').of(regA).and('textContent').of(regB).transform((value)->
					value.toUpperCase()
				).and('textContent').of(regC).transform (value)->
					value.toLowerCase()
				expect(objectA.prop1).to.equal 'CuRRent'
				expect(regA.textContent).to.equal 'CuRRent'
				expect(regB.textContent).to.equal 'CURRENT'
				expect(regC.textContent).to.equal 'current'



			it "can apply a single transform to all bindings in a chain", ()->
				restartSandbox()
				SimplyBind('prop1').of(objectA).to('textContent').of(regA).and('textContent').of(regB).transformAll (value)->
					value.toUpperCase()
				SimplyBind('prop1').of(objectA).to('textContent').of regC
				objectA.prop1 = 'all at once'
				expect(regA.textContent).to.equal 'ALL AT ONCE'
				expect(regB.textContent).to.equal 'ALL AT ONCE'
				expect(regC.textContent).to.equal 'all at once'









	describe "DOM attributes/properties", ()->
		it "can bind an object\'s property to a DOM el\'s attribute", ()->
			bound = SimplyBind('prop3').of(objectA).to('attr:data-attr').of($('#domObject')[0])
			bound.set 'changed'
			expect($('#domObject').attr('data-attr')).to.equal 'changed'



		it "cannot bind a DOM el\'s attribute to an object\'s property", ()->
			bound = SimplyBind('attr:data-attr').of($('#domObject')[0]).to('prop4').of(objectA)
			bound.set 'should change'
			expect(objectA.prop4).to.equal 'should change'
			$('#domObject')[0].setAttribute 'data-attr', 'should not change'
			expect(objectA.prop4).not.to.equal 'should not change'



		it "cannot bind an object\'s property to a DOM el\'s attribute both ways", ()->
			bound = SimplyBind('prop1').of(objectB).to('attr:data-attr').of($('#domObject')[0]).bothWays()
			objectB.prop1 = 'changed from objectB.prop1'
			expect($('#domObject').attr('data-attr')).to.equal 'changed from objectB.prop1'
			$('#domObject').attr 'data-attr', 'changed from attribute'
			expect(objectB.prop1).not.to.equal 'changed from attribute'



		it "should be able to bind any DOM el\'s property instead of the el\'s attribute if no descriptor (\'attr:*\') is specified in the selector", ()->
			restartSandbox()
			SimplyBind('prop1').of(objectA).to('attr:innerHTML').of($('#reg'))
			SimplyBind('prop1').of(objectA).to('attr:className').of($('#reg'))
			SimplyBind('prop2').of(objectA).to('innerHTML').of($regB)
			SimplyBind('prop3').of(objectA).to('className').of($regC)
			objectA.prop1 = 'should update/set the attribute, not the property.'
			expect(regA.getAttribute('innerHTML')).to.equal 'should update/set the attribute, not the property.'
			expect(regA.getAttribute('className')).to.equal 'should update/set the attribute, not the property.'
			expect(regA.getAttribute('class')).not.to.equal 'should update/set the attribute, not the property.'
			expect(regA.className).not.to.equal 'should update/set the attribute, not the property.'
			expect(regA.innerHTML).not.to.equal 'should update/set the attribute, not the property.'
			objectA.prop2 = 'should update/set the property, not the attribute.'
			expect(regB.innerHTML).to.equal 'should update/set the property, not the attribute.'
			expect(regB.getAttribute('innerHTML')).to.equal null
			objectA.prop3 = 'should update/set the property, not the attribute.'
			expect(regC.className).to.equal 'should update/set the property, not the attribute.'
			expect(regC.getAttribute('class')).to.equal 'should update/set the property, not the attribute.'
			expect(regC.getAttribute('className')).to.equal null
			# Check placeholder support
			regB.innerHTML = 'make sure to {{verb}} for placeholder support'
			SimplyBind('prop4').of(objectA).to('prop:innerHTML.verb').of regB
			objectA.prop4 = 'check'
			expect(regB.innerHTML).to.equal 'make sure to check for placeholder support'
			# Check that nothing breaks when overriding inherited props
			restartSandbox()
			SimplyBind.setOption 'mutateInherited', true
			regB.innerHTML = 'make sure to {{verb}} for placeholder support'
			SimplyBind('prop4').of(objectA).to('prop:innerHTML.verb').of regB
			objectA.prop4 = 'check'
			expect(regB.innerHTML).to.equal 'make sure to check for placeholder support'
			SimplyBind.setOption 'mutateInherited', false



		describe "Placeholders", ()->
			it "can bind an object to a DOM el\'s attribute with a placeholder", ()->
				restartSandbox()
				regA.setAttribute 'someAttr', regA.textContent
				bound = SimplyBind('prop4').of(objectA).to('attr:someAttr.verb').of(regA)
				bound.set 'very'
				expect(regA.getAttribute('someAttr')).to.equal 'The following text is very big and ugly'
				expect($regAH1.width()).not.to.equal 0
				expect($regAH1Span.width()).not.to.equal 0
				bound.set 'not'
				expect(regA.getAttribute('someAttr')).to.equal 'The following text is not big and ugly'
				expect($regAH1.width()).not.to.equal 0
				expect($regAH1Span.width()).not.to.equal 0



			it "can bind an input element\'s value to a DOM el\'s attribute with multiple placeholders", ()->
				restartSandbox()
				regB.setAttribute 'class', regB.textContent
				SimplyBind('value').of($inputA).to('attr:class.verb').of regB
				SimplyBind('value').of($inputB).to('attr:class.nounOne').of regB
				SimplyBind('value').of($inputC).to('attr:class.nounTwo').of regB
				$inputA.val('very')[0].dispatchEvent new Event('change')
				$inputB.val('big')[0].dispatchEvent new Event('change')
				$inputC.val('ugly')[0].dispatchEvent new Event('change')
				expect(regB.getAttribute('class')).to.equal 'The following text is very big and ugly'
				expect($regBH1.width()).not.to.equal 0
				expect($regBH1Span.width()).not.to.equal 0
				$inputA.val('not')[0].dispatchEvent new Event('change')
				$inputB.val('small')[0].dispatchEvent new Event('change')
				$inputC.val('pretty')[0].dispatchEvent new Event('change')
				expect(regB.getAttribute('class')).to.equal 'The following text is not small and pretty'
				expect($regBH1.width()).not.to.equal 0
				expect($regBH1Span.width()).not.to.equal 0



			it "can bind an input element\'s value to a DOM el\'s attribute with duplicate placeholders", ()->
				restartSandbox()
				regA.setAttribute 'someAttr', regA.textContent
				regB.setAttribute 'someAttr', regB.textContent
				regC.setAttribute 'someAttr', regC.textContent
				bound = SimplyBind('value').of($inputA).to('attr:someAttr.word').of(regC)
				$inputA.val('slang')[0].dispatchEvent new Event('change')
				expect(regC.getAttribute('someAttr')).to.equal 'The following text should have this: slang, slang twice'
				expect($regCH1.width()).not.to.equal 0
				expect($regCH1Span.width()).not.to.equal 0
				$inputA.val('bird')[0].dispatchEvent new Event('change')
				expect(regC.getAttribute('someAttr')).to.equal 'The following text should have this: bird, bird twice'
				expect($regCH1.width()).not.to.equal 0
				expect($regCH1Span.width()).not.to.equal 0






		describe "Transforms", ()->
			it "can bind an object\'s property to a DOM el\'s attribute with a transform", ()->
				restartSandbox()
				objectA.prop2 = 'current'
				bound = SimplyBind('prop2').of(objectA).to('attr:someAttr').of(regA).transform((newValue, currentValue)->
					newValue+'+'+currentValue
				)
				expect(regA.getAttribute('someAttr')).to.equal 'current+current'
				objectA.prop2 = 'new'
				expect(regA.getAttribute('someAttr')).to.equal 'new+current+current'
				objectA.prop2 = 'new'
				expect(regA.getAttribute('someAttr')).to.equal 'new+current+current'
				objectA.prop2 = 'newer'
				expect(regA.getAttribute('someAttr')).to.equal 'newer+new+current+current'



			it "can NOT bind with a transform both ways", ()->
				restartSandbox()
				objectA.prop2 = 'current'
				bound = SimplyBind('prop2').of(objectA).to('attr:someAttr').of(regA).transform((newValue, currentValue)->
					newValue+'+'+currentValue
				).bothWays()
				expect(regA.getAttribute('someAttr')).to.equal 'current+current'
				objectA.prop2 = 'new'
				expect(regA.getAttribute('someAttr')).to.equal 'new+current+current'
				objectA.prop2 = 'new'
				expect(regA.getAttribute('someAttr')).to.equal 'new+current+current'
				regA.setAttribute 'someAttr', 'new'
				expect(objectA.prop2).to.equal 'new'
				regA.setAttribute 'someAttr', 'newer'
				expect(objectA.prop2).to.equal 'new'



			it "can bind with multiple transforms in a single chain", ()->
				restartSandbox()
				objectA.prop1 = 'CuRRent'
				SimplyBind('prop1').of(objectA).to('attr:someAttr').of(regA).and('attr:someAttr').of(regB).transform((value)->
					value.toUpperCase()
				).and('attr:someAttr').of(regC).transform (value)->
					value.toLowerCase()
				expect(objectA.prop1).to.equal 'CuRRent'
				expect(regA.getAttribute('someAttr')).to.equal 'CuRRent'
				expect(regB.getAttribute('someAttr')).to.equal 'CURRENT'
				expect(regC.getAttribute('someAttr')).to.equal 'current'



			it "can apply a single transform to all bindings in a chain", ()->
				restartSandbox()
				SimplyBind('prop1').of(objectA).to('attr:someAttr').of(regA).and('attr:someAttr').of(regB).transformAll (value)->
					value.toUpperCase()
				SimplyBind('prop1').of(objectA).to('attr:someAttr').of regC
				objectA.prop1 = 'all at once'
				expect(regA.getAttribute('someAttr')).to.equal 'ALL AT ONCE'
				expect(regB.getAttribute('someAttr')).to.equal 'ALL AT ONCE'
				expect(regC.getAttribute('someAttr')).to.equal 'all at once'









	describe "Functions", ()->
		it "can bind an object\'s property to a function", ()->

			tempFunc = (value)->
				console.log value
				expect(value).to.equal objectB.prop2




			SimplyBind('prop2').of(objectB).to tempFunc
			objectB.prop2 = 'string'



		it "can bind a function\'s return value to an object\'s property", ()->

			fn = (value)->
				value or 'from function'

			bound = SimplyBind(fn).to('prop4').of(objectB)
			SimplyBind(fn).to('prop4').of objectB
			expect(objectB.prop4).to.equal 'from function'
			bound.set 'from function, but set later'
			expect(objectB.prop4).to.equal 'from function, but set later'



		it 'should update the bound function immediatly after binding to it', (done)->
			objectA.prop5 = 'correct'
			unCalledFn = chai.spy()
						
			binding = SimplyBind('prop5', {'invokeOnBind':false}).of(objectA).to unCalledFn
			expect(unCalledFn).not.to.have.been.called()
			
			binding.setOption 'invokeOnBind', true
			SimplyBind('prop5').of(objectA).to (value)->
				expect(value).to.equal 'correct'
				done()






		it "should not invoke the function if its passed as a proxy (and option is set to not invoke on bind)", ()->
			restartSandbox()
			mutated = false
			objectA.prop5 = 'correct'

			SimplyBind('prop5', {'invokeOnBind':false}).of(objectA).to ()->
				mutated = true

			expect(mutated).to.equal false



		it "should not invoke the proxied function even if it has a transform", ()->
			restartSandbox()
			mutated = false
			objectA.prop5 = 'correct'
			
			SimplyBind('prop5', {'invokeOnBind':false}).of(objectA)
				.to ()-> mutated = true
					.transform (val)-> val
			
			expect(mutated).to.equal false



		it "should pass to params to the receiving function\'s args, the first is the new value from the binding, and the other is the old value", ()->
			sampleObject = 'prop': 10
			outerstate = 
				newValue: null
				oldValue: null

			fn = (newValue, oldValue)->
				outerstate.newValue = newValue
				outerstate.oldValue = oldValue




			SimplyBind('prop').of(sampleObject).to fn
			expect(outerstate.newValue).to.equal 10
			expect(outerstate.oldValue).to.be.undefined
			sampleObject.prop = 20
			expect(outerstate.newValue).to.equal 20
			expect(outerstate.oldValue).to.equal 10






	describe "Events", ()->
		describe "updateDepsOnEvent", ()->
			it "should be able to poll (and update if changed) property values on events, and then unbind event listeners on demand", ()->
				restartSandbox()
				h1 = regAH1
				bound = SimplyBind('attr:data-attr').of(h1).to('prop1').of(objectA).updateDepsOnEvent('click')
				bound.set 'one'
				expect(objectA.prop1).to.equal 'one'
				h1.setAttribute 'data-attr', 'two'
				expect(objectA.prop1).to.equal 'one'
				h1.dispatchEvent new Event('click')
				expect(objectA.prop1).to.equal 'two'
				bound.removeEvent 'click'
				h1.setAttribute 'data-attr', 'three'
				expect(objectA.prop1).to.equal 'two'
				h1.dispatchEvent new Event('click')
				expect(objectA.prop1).to.equal 'two'



			it "should be able to bind/unbind with custom events", ()->
				restartSandbox()
				h1 = regAH1
				bound = undefined

				h1.customAdd = ()->
					h1.addEventListener.apply h1, arguments




				h1.customRemove = ()->
					h1.removeEventListener.apply h1, arguments




				bound = SimplyBind('attr:data-attr').of(h1).to('prop1').of(objectA).updateDepsOnEvent('click', 'customAdd')
				bound.set 'one'
				expect(objectA.prop1).to.equal 'one'
				h1.setAttribute 'data-attr', 'two'
				expect(objectA.prop1).to.equal 'one'
				h1.dispatchEvent new Event('click')
				expect(objectA.prop1).to.equal 'two'
				bound.removeEvent 'click', 'customRemove'
				h1.setAttribute 'data-attr', 'three'
				expect(objectA.prop1).to.equal 'two'
				h1.dispatchEvent new Event('click')
				expect(objectA.prop1).to.equal 'two'



			it "should do nothing when trying to remove an event that wasn\'t registered or when trying to add an event that was already registered", ()->
				h2 = regBH1
				bound = SimplyBind('attr:data-attr').of(h2).to('prop1').of(objectA).updateDepsOnEvent('click')
				expect(bound._.attachedEvents.length).to.equal 1
				bound = SimplyBind('attr:data-attr').of(h2).to('prop1').of(objectA).updateDepsOnEvent('click')
				bound = SimplyBind('attr:data-attr').of(h2).to('prop1').of(objectA).updateDepsOnEvent('change')
				expect(bound._.attachedEvents.length).to.equal 2
				bound.removeEvent 'clicker'
				expect(bound._.attachedEvents.length).to.equal 2
				bound.removeEvent 'click'
				expect(bound._.attachedEvents.length).to.equal 1
				bound.removeEvent 'change'
				expect(bound._.attachedEvents.length).to.equal 0



			it "should resort back to the default event methods if the supplied custom methods don\'t exist", ()->
				restartSandbox()
				h1 = regAH1
				bound = undefined
				bound = SimplyBind('attr:data-attr').of(h1).to('prop1').of(objectA).updateDepsOnEvent('click', 'customAdd')
				bound.set 'one'
				expect(objectA.prop1).to.equal 'one'
				h1.setAttribute 'data-attr', 'two'
				expect(objectA.prop1).to.equal 'one'
				h1.dispatchEvent new Event('click')
				expect(objectA.prop1).to.equal 'two'
				bound.removeEvent 'click', 'customRemove'
				h1.setAttribute 'data-attr', 'three'
				expect(objectA.prop1).to.equal 'two'
				h1.dispatchEvent new Event('click')
				expect(objectA.prop1).to.equal 'two'



			it "should use jQuery\'s .on and .off methods on DOM elements if so indicated", ()->
				restartSandbox()
				$h1 = $regAH1
				bound = undefined
				bound = SimplyBind('attr:data-attr').of($h1).to('prop1').of(objectA).updateDepsOnEvent('customevent', 'on')
				bound.set 'one'
				expect(objectA.prop1).to.equal 'one'
				$h1.attr 'data-attr', 'two'
				expect(objectA.prop1).to.equal 'one'
				$h1.trigger 'customevent'
				expect(objectA.prop1).to.equal 'two'
				bound.removeEvent 'customevent', 'off'
				$h1.attr 'data-attr', 'three'
				expect(objectA.prop1).to.equal 'two'
				$h1.trigger 'customevent'
				expect(objectA.prop1).to.equal 'two'



			it "should return unchanged if passed an event name that is not a string (or is an empty string)", ()->
				expect(SimplyBind(0).ofEvent(null).ID).to.equal null
				expect(SimplyBind(0).ofEvent('').ID).to.equal null



			it "should throw an error if passed a non-number argument selector", ()->
				origLog = console.log

				okArgNum = ()->
					SimplyBind('15').ofEvent 'booyah'




				okArgNum = ()->
					SimplyBind(' 1aos95').ofEvent 'booyah'




				console.log = chai.spy()
				SimplyBind('value').ofEvent 'booyah'
				expect(console.log).to.have.been.called()
				console.log = origLog
				expect(okArgNum).not.to.throw()
				expect(okArgNum).not.to.throw()






		describe "Event Binding", ()->
			it "should be able to bind specific arguments from an event emitter", ()->
				input = $inputA
				emptyObj = {}
				sampleObject = 'holder': emptyObj
				SimplyBind(0).ofEvent('focus').of(input[0]).to('holder').of sampleObject
				expect(sampleObject.holder).to.equal emptyObj
				input[0].dispatchEvent new Event('focus')
				expect(sampleObject.holder.target).to.equal input[0]



			it "can bind with a transform", ()->
				restartSandbox()
				input = $inputA
				emptyObj = {}
				sampleObject = 'holder': emptyObj
				SimplyBind(0).ofEvent('focus').of(input[0]).to('holder').of(sampleObject).transform (event)->
					event.target
				expect(sampleObject.holder).to.equal emptyObj
				input[0].dispatchEvent new Event('focus')
				expect(sampleObject.holder).to.equal input[0]



			it "can using a custom event listener function", ()->
				restartSandbox()
				input = $inputA
				emptyObj = {}
				sampleObject = 'holder': emptyObj
				SimplyBind(0).ofEvent('somethingCustom').of(input[0]).to('holder').of sampleObject
				expect(sampleObject.holder).to.equal emptyObj
				input[0].dispatchEvent new CustomEvent('somethingCustom')
				expect(sampleObject.holder.target).to.equal input[0]



			it 'can bing a value to an event (trigger an event on value change)', (done)->
				emitCount = 0
				regA.addEventListener 'click', (()->
					if emitCount == 3
						done()
					else
						emitCount++



				), false
				SimplyBind('prop1').of(objectA).toEvent('click').of regA
				expect(emitCount).to.equal 1
				objectA.prop1 = 'whatever'
				expect(emitCount).to.equal 2
				objectA.prop1 = 'whatever again'
				expect(emitCount).to.equal 3
				objectA.prop1 = 'last time'



			it "can trigger an event both ways using custom methods", ()->
				restartSandbox()
				emitCount = 0
				receiveCount = 0
				$regA.on 'click', ()->
					emitCount++



				SimplyBind('prop2').of(objectA).toEvent('click', 'trigger', 'on').of($regA).bothWays ()->
					++receiveCount
				expect(emitCount).to.equal 1
				expect(receiveCount).to.equal 0
				objectA.prop2 = 'whatever'
				expect(emitCount).to.equal 2
				$regA.trigger 'click'
				expect(receiveCount).to.equal 1
				expect(objectA.prop2).to.equal 1
				expect(emitCount).to.equal 3
				objectA.prop2 = 'whatever again'
				expect(emitCount).to.equal 4
				$regA.trigger 'click'
				expect(receiveCount).to.equal 2
				expect(objectA.prop2).to.equal 2









	describe "Ajax", ()->
		it 'should be able to bind an external JSON object via AJAX', (done)->
			sampleObject = 'fetched': {}
			expect(sampleObject.fetched.externalValues).to.be.undefined
			SimplyBind('prop').ofExternal('/get/some/data.json').to('fetched').of sampleObject
			setTimeout (()->
				expect(sampleObject.fetched.externalValues).not.to.be.undefined
				expect(sampleObject.fetched.externalValues).to.equal 'it works :)'
				done()



			), 10



		it 'can use custom options for the Ajax request', (done)->
			sampleObject = 'fetched': {}
			expect(sampleObject.fetched.externalValues).to.be.undefined
			SimplyBind('prop').ofExternal('/get/some/data.json',
				'method': 'post'
				'data': 'just a string'
				'headers': 'Content-Type': 'application/json').to('fetched').of sampleObject
			setTimeout (()->
				expect(sampleObject.fetched.externalValues).not.to.be.undefined
				expect(sampleObject.fetched.externalValues).to.equal 'it works :)'
				done()



			), 10



		it 'can continually send the request at a set interval', (done)->
			sampleObject = 'fetched': {}
			count = 0
			bound = undefined

			stopPolling = ()->
				if bound._.pollInterval
					bound.stopPolling()




			expect(sampleObject.fetched.externalValues).to.be.undefined
			bound = SimplyBind('prop').ofExternal('/get/some/data.json').to('fetched').of(sampleObject).transform((val)->
				if count > 4
					expect(sampleObject.fetched.externalValues).not.to.be.undefined
					expect(sampleObject.fetched.externalValues).to.equal 'it works :)'
					done()
					stopPolling()
				else
					count++
				val
			).pollEvery(15)



		it 'should use the entire object of the response if using \'*\' as the selector', (done)->
			sampleObject = 'fetched': {}
			expect(sampleObject.fetched.externalValues).to.be.undefined
			window.bound = SimplyBind('*').ofExternal('/get/some/data.json').to('fetched').of(sampleObject).pollEvery(5)
			setTimeout (()->
				expect(sampleObject.fetched.prop).not.to.be.undefined
				expect(typeof sampleObject.fetched.prop).to.equal 'object'
				expect(sampleObject.fetched.prop.externalValues).to.equal 'it works :)'
				done()



			), 10



		it 'should be able to bind an external JSON object via AJAX', (done)->
			sampleObject = 'fetched': {}
			expect(sampleObject.fetched.externalValues).to.be.undefined
			SimplyBind('prop').ofExternal('/get/nonexistent').to('prop9').of objectA
			setTimeout (()->
				expect(objectA.prop9).not.to.be.undefined
				expect(objectA.prop9).to.equal ''
				done()



			), 10



		it "should return unchanged if passed a non-string location or an empty string", ()->
			shouldntThrow = ()->
				SimplyBind('*').ofExternal('').ofExternal '/get/some/data.json'
			expect(shouldntThrow).not.to.throw()

			shouldntThrow = ()->
				SimplyBind('*').ofExternal(null).ofExternal '/get/some/data.json'
			expect(shouldntThrow).not.to.throw()

			shouldntThrow = ()->
				SimplyBind('*').ofExternal(true).ofExternal '/get/some/data.json'
			expect(shouldntThrow).not.to.throw()



		it "should return unchanged if passed a non-object for the options argument", ()->
			shouldntThrow = ()->
				SimplyBind('*').ofExternal('/get/some/data.json', ()->).ofExternal('/get/some/data.json')
			expect(shouldntThrow).not.to.throw()

			shouldntThrow = ()->
				SimplyBind('*').ofExternal('/get/some/data.json', true).ofExternal '/get/some/data.json'
			expect(shouldntThrow).not.to.throw()




		it 'should be able to bind anything to an external JSON object via AJAX', (done)->
			sampleObject = 'fetched': {}
			expect(sampleObject.fetched.externalValues).to.be.undefined
			objectA.prop1 = 'someprop': 'somevalue'
			SimplyBind('prop1').of(objectA).toExternal('/set/some/data.json').chainTo('fetched').of sampleObject
			
			setTimeout ()->
				expect(sampleObject.fetched.prop).not.to.be.undefined
				expect(sampleObject.fetched.prop.externalValues).to.equal 'it works too :)'
				done()
			, 10



		it 'should be able to bind an externam JSON object to an external JSON object via AJAX', (done)->
			sampleObject = 'fetched': {}
			expect(sampleObject.fetched.externalValues).to.be.undefined
			objectA.prop1 = 'someprop': 'somevalue'
			SimplyBind('*').ofExternal('/get/some/data2.json').toExternal('/set/some/data2.json').chainTo (obj)->
				expect(typeof obj).to.equal 'object'
				expect(obj.prop).not.to.be.undefined
				done()






		it "should return unchanged if passed a non-string location or an empty string", ()->
			shouldntThrow = ()->
				SimplyBind('prop1').of(objectA).toExternal('').toExternal '/get/some/data.json'
			expect(shouldntThrow).not.to.throw()



			shouldntThrow = ()->
				SimplyBind('prop1').of(objectA).toExternal(null).toExternal '/get/some/data.json'
			expect(shouldntThrow).not.to.throw()



			shouldntThrow = ()->
				SimplyBind('prop1').of(objectA).toExternal(true).toExternal '/get/some/data.json'
			expect(shouldntThrow).not.to.throw()





		it "should return unchanged if passed a non-object for the options argument", ()->
			shouldntThrow = ()-> SimplyBind('prop1').of(objectA).toExternal '/get/some/data.json', ()->
			expect(shouldntThrow).not.to.throw()


			shouldntThrow = ()-> SimplyBind('prop1').of(objectA).toExternal '/get/some/data.json', null
			expect(shouldntThrow).not.to.throw()


			shouldntThrow = ()-> SimplyBind('prop1').of(objectA).toExternal '/get/some/data.json', true
			expect(shouldntThrow).not.to.throw()









describe "Data Unbinding", ()->
	before ()->
		restartSandbox()



	it "should be able to unbind object one way", ()->
		bound = SimplyBind('prop1').of(objectA).to('prop1').of(objectB)
		objectA.prop1 = 'should change'
		expect(objectB.prop1).to.equal 'should change'
		bound.unBind true
		objectA.prop1 = 'should not change'
		expect(objectB.prop1).not.to.equal 'should not change'



	it "should be able to unbind objects both ways", ()->
		restartSandbox()
		bound = SimplyBind('prop1').of(objectA).to('prop1').of(objectB).bothWays()
		objectA.prop1 = 'should change'
		expect(objectB.prop1).to.equal 'should change'
		objectB.prop1 = 'should also change'
		expect(objectA.prop1).to.equal 'should also change'
		bound.unBind()
		objectA.prop1 = 'should not change'
		expect(objectB.prop1).not.to.equal 'should not change'
		objectB.prop1 = 'but this should'
		expect(objectA.prop1).to.equal 'but this should'
		restartSandbox()
		bound = SimplyBind('prop1').of(objectA).to('prop1').of(objectB).bothWays()
		bound.unBind true
		objectA.prop1 = 'should not change'
		expect(objectB.prop1).not.to.equal 'should not change'
		objectB.prop1 = 'should also not change'
		expect(objectA.prop1).not.to.equal 'should also not change'



	it "should be able to unbind functions", ()->
		restartSandbox()
		guineaPig = ''
		bound = SimplyBind('prop1').of(objectA).to((newValue)->
			guineaPig = newValue



		)
		objectA.prop1 = 'should change'
		expect(guineaPig).to.equal 'should change'
		bound.unBind()
		objectA.prop1 = 'should not change'
		expect(guineaPig).not.to.equal 'should not change'



	it "should be able to unbind input values one way (jQuery objects)", ()->
		restartSandbox()
		bound = SimplyBind('value').of($inputA).to('value').of($inputB)
		$inputA.val('should change')[0].dispatchEvent new Event('change')
		expect($inputB.val()).to.equal 'should change'
		bound.unBind()
		$inputA.val('should not change')[0].dispatchEvent new Event('change')
		expect($inputB.val()).not.to.equal 'should not change'



	it "should be able to unbind input values both ways", ()->
		restartSandbox()
		bound = SimplyBind('value').of(inputA).to('value').of(inputB).bothWays()
		$inputA.val('should change')[0].dispatchEvent new Event('change')
		expect($inputB.val()).to.equal 'should change'
		$inputB.val('should also change')[0].dispatchEvent new Event('change')
		expect($inputA.val()).to.equal 'should also change'
		bound.unBind()
		$inputA.val('should not change')[0].dispatchEvent new Event('change')
		expect($inputB.val()).not.to.equal 'should not change'
		$inputB.val('but this should')[0].dispatchEvent new Event('change')
		expect($inputA.val()).to.equal 'but this should'
		restartSandbox()
		bound = SimplyBind('value').of(inputA).to('value').of(inputB).bothWays()
		bound.unBind true
		$inputA.val('should not change')[0].dispatchEvent new Event('change')
		expect($inputB.val()).not.to.equal 'should not change'
		$inputB.val('should also not change')[0].dispatchEvent new Event('change')
		expect($inputA.val()).not.to.equal 'should also not change'



	it "should be able to unbind all bindings of an object one way", ()->
		restartSandbox()
		objectC = 'prop1': 'blank'
		SimplyBind('prop1').of(objectA).to('prop1').of(objectB).bothWays()
		SimplyBind('prop1').of(objectA).to('prop1').of(objectC).bothWays()
		SimplyBind('prop1').of(objectA).to('value').of($('input[type="text"]')).bothWays()
		SimplyBind.unBindAll objectA
		objectA.prop1 = 'should not change'
		expect(objectB.prop1).not.to.equal 'should not change'
		expect(objectC.prop1).not.to.equal 'should not change'
		expect($('input[type="text"]').val()).not.to.equal 'should not change'
		objectB.prop1 = 'but this should'
		expect(objectA.prop1).to.equal 'but this should'
		expect(objectC.prop1).not.to.equal 'but this should'
		expect($('input[type="text"]').val()).not.to.equal 'but this should'
		objectC.prop1 = 'and this also should'
		expect(objectA.prop1).to.equal 'and this also should'
		expect(objectB.prop1).not.to.equal 'and this also should'
		expect($('input[type="text"]').val()).not.to.equal 'and this also should'



	it "should be able to unbind all bindings of an input one way (jQuery object)", ()->
		restartSandbox()
		bound = SimplyBind('value').of($inputA).to('value').of($inputB)
		$inputA.val('should change')[0].dispatchEvent new Event('change')
		expect($inputB.val()).to.equal 'should change'
		SimplyBind.unBindAll $inputA.add($inputB)
		$inputA.val('should not change')[0].dispatchEvent new Event('change')
		expect($inputB.val()).not.to.equal 'should not change'



	it "should be able to unbind all bindings of an radio/checkbox one way (jQuery object)", ()->
		restartSandbox()
		bound = SimplyBind('value').of($('input[type="radio"]')).to('prop1').of(objectA)
		$('input[type="radio"]')[0].dispatchEvent new Event('change')
		expect(objectA.prop1).to.equal 'radio1'
		SimplyBind.unBindAll $('input[type="radio"]')
		$('input[type="radio"]')[1].dispatchEvent new Event('change')
		expect(objectA.prop1).not.to.equal 'radio2'



	it "should be able to unbind all bindings of an object both ways", ()->
		restartSandbox()
		objectC = 'prop1': 'blank'
		SimplyBind('prop1').of(objectA).to('prop1').of(objectB).bothWays()
		SimplyBind('prop1').of(objectA).to('prop1').of(objectC).bothWays()
		SimplyBind.unBindAll objectA, true
		objectA.prop1 = 'should not change'
		expect(objectB.prop1).not.to.equal 'should not change'
		expect(objectC.prop1).not.to.equal 'should not change'
		objectB.prop1 = 'and this should not'
		expect(objectA.prop1).not.to.equal 'and this should not'
		expect(objectC.prop1).not.to.equal 'and this should not'
		objectC.prop1 = 'and this should not either'
		expect(objectA.prop1).not.to.equal 'and this should not either'
		expect(objectB.prop1).not.to.equal 'and this should not either'



	it "should be able to unbind all bindings of an input value one way", ()->
		restartSandbox()
		SimplyBind('value').of(inputA).to('value').of(inputB).bothWays()
		SimplyBind('value').of(inputA).to('value').of(inputC).bothWays()
		SimplyBind.unBindAll inputA
		$inputA.val('should not change')[0].dispatchEvent new Event('change')
		expect($inputB.val()).not.to.equal 'should not change'
		expect($inputC.val()).not.to.equal 'should not change'
		$inputB.val('but this should')[0].dispatchEvent new Event('change')
		expect($inputA.val()).to.equal 'but this should'
		expect($inputC.val()).not.to.equal 'but this should'
		$inputC.val('and this also should')[0].dispatchEvent new Event('change')
		expect($inputA.val()).to.equal 'and this also should'
		expect($inputB.val()).not.to.equal 'and this also should'



	it "should be able to unbind all bindings of an input value both ways", ()->
		restartSandbox()
		SimplyBind('value').of(inputA).to('value').of(inputB).bothWays()
		SimplyBind('value').of(inputA).to('value').of(inputC).bothWays()
		SimplyBind.unBindAll inputA, true
		$inputA.val('should not change')[0].dispatchEvent new Event('change')
		expect($inputB.val()).not.to.equal 'should not change'
		expect($inputC.val()).not.to.equal 'should not change'
		$inputB.val('and this should not')[0].dispatchEvent new Event('change')
		expect($inputA.val()).not.to.equal 'and this should not'
		expect($inputC.val()).not.to.equal 'and this should not'
		$inputC.val('and this should not either')[0].dispatchEvent new Event('change')
		expect($inputA.val()).not.to.equal 'and this should not either'
		expect($inputB.val()).not.to.equal 'and this should not either'



	it "should be able to unbind all bindings of an DOM element attribute both ways", ()->
		restartSandbox()
		SimplyBind('value').of(inputA).to('className').of(regAH1).bothWays()
		SimplyBind('value').of(inputA).to('className').of(regAH1Span).bothWays()
		SimplyBind.unBindAll inputA, true
		SimplyBind.unBindAll regAH1, true
		$inputA.val('should not change')[0].dispatchEvent new Event('change')
		expect($regAH1.attr('class')).not.to.equal 'should not change'
		expect($regAH1Span.attr('class')).not.to.equal 'should not change'
		$regAH1.attr 'class', 'and this should not'
		expect($inputA.val()).not.to.equal 'and this should not'
		expect($regAH1Span.attr('class')).not.to.equal 'and this should not'
		$regAH1Span.attr 'class', 'and this should not either'
		expect($inputA.val()).not.to.equal 'and this should not either'
		expect($regAH1.attr('class')).not.to.equal 'and this should not either'



	it "should not unbind anything if argument passed isn\'t an object or if it isn\'t binded", ()->

		uselessUnbind = ()->
			SimplyBind.unBindAll 'nonbinded': 'object'
			SimplyBind.unBindAll 'string'
			SimplyBind('prop1').of(objectA).to ()->
			SimplyBind.unBindAll objectA
			SimplyBind.unBindAll objectA




		expect(uselessUnbind).not.to.throw()



mocha.run()