suite "Array", ()->
	test "Can bind an array property using 'array:' descriptor and update subscribers when calling the .push, .pop, .shift, .unshift, .splice, .reverse, and .sort methods", ()->
		mutations = 0
		SimplyBind('array:list').of(objectA).to('prop4').of(objectB).and.to ()-> mutations++

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



	test "If the array binding receives an update of another array, it will discard the previous array and make the new array 'live'", ()->
		invokeCount = 0
		originalArray = objectA.list
		SimplyBind('array:list').of(objectA).to('prop4').of(objectB).and.to ()-> invokeCount++

		expect(objectB.prop4).to.equal(originalArray)
		expect(invokeCount).to.equal 1
		objectB.prop4 = 'reset'
		
		originalArray.sort()
		expect(objectB.prop4).to.equal(originalArray)
		expect(invokeCount).to.equal 2
		
		objectA.list = [1,2,3,4,5,6,7]
		newArray = objectA.list
		expect(objectB.prop4).to.equal(newArray)
		expect(invokeCount).to.equal 3
		
		originalArray.sort()
		expect(objectB.prop4).to.equal(newArray)
		expect(invokeCount).to.equal 3
		
		newArray.sort()
		expect(objectB.prop4).to.equal(newArray)
		expect(invokeCount).to.equal 4

		newArray.push 8
		originalArray.push 8
		expect(objectB.prop4).to.equal(newArray)
		expect(invokeCount).to.equal 5
		
		newArray.shift()
		originalArray.shift()
		expect(objectB.prop4).to.equal(newArray)
		expect(invokeCount).to.equal 6
		
		newArray.unshift 1
		originalArray.unshift 1
		expect(objectB.prop4).to.equal(newArray)
		expect(invokeCount).to.equal 7
		
		newArray.pop()
		originalArray.pop()
		expect(objectB.prop4).to.equal(newArray)
		expect(invokeCount).to.equal 8
		
		newArray.splice 0, 5
		originalArray.splice 0, 5
		expect(objectB.prop4).to.equal(newArray)
		expect(invokeCount).to.equal 9
		
		restartSandbox()



	test "If the array binding receives an update of another array, it will clone the new array and set it as the binding's value", ()->
		invokeCount = 0
		originalArray = objectA.list
		newArray = [1,2,3,4]
		SimplyBind('array:list').of(objectA).to ()-> invokeCount++

		expect(objectA.list).to.equal(originalArray)
		expect(invokeCount).to.equal(1)

		originalArray.sort()
		expect(objectA.list).to.equal(originalArray)
		expect(invokeCount).to.equal(2)


		objectA.list = newArray
		expect(objectA.list).not.to.equal(originalArray)
		expect(objectA.list).not.to.equal(newArray)
		expect(objectA.list).not.to.eql(originalArray)
		expect(Object.values objectA.list).to.eql(newArray)
		expect(invokeCount).to.equal(3)
		
		originalArray.sort()
		expect(objectA.list).not.to.equal(originalArray)
		expect(objectA.list).not.to.equal(newArray)
		expect(objectA.list).not.to.eql(originalArray)
		expect(Object.values objectA.list).to.eql(newArray)
		expect(invokeCount).to.equal(3)
		
		newArray.sort()
		expect(objectA.list).not.to.equal(originalArray)
		expect(objectA.list).not.to.equal(newArray)
		expect(objectA.list).not.to.eql(originalArray)
		expect(Object.values objectA.list).to.eql(newArray)
		expect(invokeCount).to.equal(3)
		
		objectA.list.sort()
		expect(objectA.list).not.to.equal(originalArray)
		expect(objectA.list).not.to.equal(newArray)
		expect(objectA.list).not.to.eql(originalArray)
		expect(Object.values objectA.list).to.eql(newArray)
		expect(invokeCount).to.equal(4)
		restartSandbox()



	test "Will update subscribers with a clone when options.sendArrayCopies is on", ()->
		receivedValues = copies:{current:null, prev:null}, noCopies:{current:null, prev:null}
		
		SimplyBind('array:list').of(objectA).to (currentArray, prevArray)->
			receivedValues.noCopies.current = currentArray
			receivedValues.noCopies.prev = prevArray
		

		expect(receivedValues.noCopies.current).to.equal(objectA.list)
		expect(receivedValues.noCopies.prev).to.be.undefined

		objectA.list.sort()
		expect(receivedValues.noCopies.current).to.be.instanceOf(Array)
		expect(receivedValues.noCopies.current).to.equal(objectA.list)
		expect(receivedValues.noCopies.prev).to.equal(objectA.list)
		
		
		SimplyBind('array:list', sendArrayCopies:true).of(objectB).to (currentArray, prevArray)->
			receivedValues.copies.current = currentArray
			receivedValues.copies.prev = prevArray
		
		prevCurrent = receivedValues.copies.current
		expect(receivedValues.copies.current).to.be.instanceOf(Array)
		expect(receivedValues.copies.current).to.eql(Object.values objectA.list)
		expect(receivedValues.copies.current).not.to.equal(objectA.list)
		expect(receivedValues.copies.prev).to.be.undefined

		objectB.list.sort()
		expect(receivedValues.copies.current).to.eql(Object.values objectA.list)
		expect(receivedValues.copies.current).not.to.equal(objectA.list)
		expect(receivedValues.copies.current).not.to.equal(prevCurrent)
		expect(receivedValues.copies.prev).to.equal(prevCurrent)

		restartSandbox()



	test "If an array binding receives a value that isn't an array it'll be normalized to an array", ()->
		invokeCount = 0
		SimplyBind('array:list').of(objectA).to ()-> invokeCount++

		expect(objectA.list).to.be.instanceOf Array
		expect(objectA.list.length).to.equal 10
		expect(invokeCount).to.equal 1

		objectA.list = 'value'
		expect(objectA.list).to.be.instanceOf Array
		expect(objectA.list.length).to.equal 1
		expect(objectA.list[0]).to.equal 'value'
		expect(invokeCount).to.equal 2

		objectA.list = [1,2,3]
		expect(objectA.list).to.be.instanceOf Array
		expect(objectA.list.length).to.equal 3
		expect(Object.values objectA.list).to.eql [1,2,3]
		expect(invokeCount).to.equal 3
		restartSandbox()


	test "Using array: descriptors for non-array properties will cause the binding to be a regular ObjectProp binding", ()->
		interfaces = {}
		obj = 
			list: [0,1,2,3]
			object: {}
			arrayLike: arguments
			number: 5
			string: '5'
			undefined: undefined
			null: null
		
		expect(()->
			interfaces.list = SimplyBind('array:list').of(obj)
			interfaces.object = SimplyBind('array:object').of(obj)
			interfaces.arrayLike = SimplyBind('array:arrayLike').of(obj)
			interfaces.number = SimplyBind('array:number').of(obj)
			interfaces.string = SimplyBind('array:string').of(obj)
			interfaces.undefined = SimplyBind('array:undefined').of(obj)
			interfaces.null = SimplyBind('array:null').of(obj)
		).not.to.throw()

		expect(interfaces.list._.type).to.equal 'Array'
		expect(interfaces.object._.type, 'object').to.equal 'ObjectProp'
		expect(interfaces.arrayLike._.type, 'arrayLike').to.equal 'ObjectProp'
		expect(interfaces.number._.type, 'number').to.equal 'ObjectProp'
		expect(interfaces.string._.type, 'string').to.equal 'ObjectProp'
		expect(interfaces.undefined._.type, 'undefined').to.equal 'ObjectProp'
		expect(interfaces.null._.type, 'null').to.equal 'ObjectProp'


	test "Creating an Array binding and an ObjectProp binding on the same property should work as expected", ()->
		countA = array:0, object:0
		countB = array:0, object:0
		lastA = array:null, object:null
		lastB = array:null, object:null
		baseArray = [0,1,2,3,4,5,6,7,8,9]

		SimplyBind('array:list').of(objectA).to ()-> countA.array++; lastA.array = arguments[0]
		SimplyBind('list').of(objectA).to ()-> countA.object++; lastA.object = arguments[0]
		
		SimplyBind('list').of(objectB).to ()-> countB.object++; lastB.object = arguments[0]
		SimplyBind('array:list').of(objectB).to ()-> countB.array++; lastB.array = arguments[0]

		expect(countA.array, 'countA.array 1').to.equal 1
		expect(countA.object, 'countA.object 1').to.equal 1
		expect(countB.array, 'countB.array 1').to.equal 1
		expect(countB.object, 'countB.object 1').to.equal 1
		expect(lastA.array, 'lastA.array 1').to.eql baseArray
		expect(lastA.object, 'lastA.object 1').to.eql baseArray
		expect(lastB.array, 'lastB.array 1').to.eql baseArray
		expect(lastB.object, 'lastB.object 1').to.eql baseArray
		expect(objectA.list, 'objectA.list 1').to.eql baseArray
		expect(objectB.list, 'objectB.list 1').to.eql baseArray

		baseP1 = baseArray.concat(10)
		objectA.list.push(10)
		objectB.list.push(10)
		expect(countA.array, 'countA.array 2').to.equal 2
		expect(countA.object, 'countA.object 2').to.equal 1
		expect(countB.array, 'countB.array 2').to.equal 2
		expect(countB.object, 'countB.object 2').to.equal 1
		expect(lastA.array, 'lastA.array 2').to.eql baseP1
		expect(lastA.object, 'lastA.object 2').to.eql baseP1
		expect(lastB.array, 'lastB.array 2').to.eql baseP1
		expect(lastB.object, 'lastB.object 2').to.eql baseP1
		expect(objectA.list, 'objectA.list 2').to.eql baseP1
		expect(objectB.list, 'objectB.list 2').to.eql baseP1

		baseP2 = baseP1.concat(11)
		objectA.list = baseP2.slice()
		objectB.list = baseP2.slice()
		expect(countA.array, 'countA.array 3').to.equal 3
		expect(countA.object, 'countA.object 3').to.equal 2
		expect(countB.array, 'countB.array 3').to.equal 3
		expect(countB.object, 'countB.object 3').to.equal 2
		expect(lastA.array, 'lastA.array 3').to.eql baseP2
		expect(lastA.object, 'lastA.object 3').to.eql baseP2
		expect(lastB.array, 'lastB.array 3').to.eql baseP2
		expect(lastB.object, 'lastB.object 3').to.eql baseP2
		expect(objectA.list, 'objectA.list 3').to.eql baseP2
		expect(objectB.list, 'objectB.list 3').to.eql baseP2



















