text: define(["helper/Test", "Tone/core/Timeline"], function(Test, Timeline){
  
  	describe("Timeline", function(){
  
  		it("can be created and disposed", function(){
  			var sched = new Timeline();
  			sched.dispose();
  			Test.wasDisposed(sched);
  		});
  
  		it("accepts events into the timeline", function(){
  			var sched = new Timeline();
  			sched.add({
  				"state" : "A",
  				"time" : 0
  			});
  			sched.add({
  				"state" : "B",
  				"time" : 1
  			});
  			sched.add({
  				"state" : "C",
  				"time" : 2
  			});
  			sched.dispose();
  		});
  
  		it("can insert events in the timeline in the right order", function(){
  			var sched = new Timeline();
  			sched.add({
  				"time" : 0
  			});
  			sched.add({
  				"time" : 2
  			});
  			sched.add({
  				"time" : 1
  			});
  			expect(sched._timeline[0].time).to.equal(0);
  			expect(sched._timeline[1].time).to.equal(1);
  			expect(sched._timeline[2].time).to.equal(2);
  			sched.dispose();
  		});
  
  		it("can get the length of the timeline", function(){
  			var sched = new Timeline();
  			expect(sched.length).to.equal(0);
  			sched.add({
  				"time" : 0
  			});
  			expect(sched.length).to.equal(1);
  			sched.dispose();
  		});
  
  		it("throws an error if no time is provided in object", function(){
  			var sched = new Timeline();
  			expect(function(){
  				sched.add({
  					"no_time" : 0
  				});
  			}).to.throw(Error);
  			sched.dispose();
  		});
  
  		it("can remove items from the timeline", function(){
  			var sched = new Timeline();
  			var obj = { "time" : 0 };
  			sched.add(obj);
  			sched.add({
  				"time" : 2
  			});
  			expect(sched.length).to.equal(2);
  			sched.remove(obj);
  			expect(sched.length).to.equal(1);
  			sched.dispose();
  		});
  
  		it("has no effect to remove an object which is not there", function(){
  			var sched = new Timeline();
  			sched.add({
  				"time" : 2
  			});
  			sched.remove({});
  			expect(sched.length).to.equal(1);
  			sched.forEach(function(event){
  				sched.remove({});
  			});
  			expect(sched.length).to.equal(1);
  			sched.dispose();
  		});
  
  		it("can search for events in the timeline by time", function(){
  			var sched = new Timeline();
  			sched.add({
  				"time" : 0
  			});
  			sched.add({
  				"time" : 2
  			});
  			sched.add({
  				"time" : 1
  			});
  			expect(sched._search(0)).to.equal(0);
  			expect(sched._search(0.01)).to.equal(0);
  			expect(sched._search(1)).to.equal(1);
  			expect(sched._search(1.01)).to.equal(1);
  			expect(sched._search(2)).to.equal(2);
  			expect(sched._search(20000)).to.equal(2);
  			expect(sched._search(-1)).to.equal(-1);
  			sched.dispose();
  		});
  
  		it("can get a previous event", function(){
  			var sched = new Timeline();
  			var event0 = {
  				"time" : 0
  			};
  			var event1 = {
  				"time" : 1
  			};
  			sched.add(event0);
  			sched.add(event1);
  			expect(sched.previousEvent(event1)).to.equal(event0);
  			expect(sched.previousEvent(event0)).to.equal(null);
  			sched.dispose();
  		});
  
  		it("can get the scheduled event at the given time", function(){
  			var sched = new Timeline();
  			sched.add({
  				"state" : "A",
  				"time" : 2
  			});
  			sched.add({
  				"state" : "C",
  				"time" : 9.4
  			});
  			sched.add({
  				"state" : "B",
  				"time" : 6
  			});
  			expect(sched.get(0)).is.null;
  			expect(sched.get(2).state).is.equal("A");
  			expect(sched.get(5.9).state).is.equal("A");
  			expect(sched.get(6.1).state).is.equal("B");
  			expect(sched.get(12).state).is.equal("C");
  			sched.dispose();
  		});
  
  		it("puts the second scheduled event after if two events are scheduled at the same time", function(){
  			var sched = new Timeline();
  			sched.add({
  				"name" : "A",
  				"time" : 0
  			});
  			sched.add({
  				"name" : "B",
  				"time" : 0
  			});
  			expect(sched.get(0).name).is.equal("B");
  			sched.add({
  				"name" : "C",
  				"time" : 0
  			});
  			expect(sched.get(0).name).is.equal("C");
  			sched.dispose();
  		});
  
  		it("can the next event after the given time", function(){
  			var sched = new Timeline();
  			expect(sched.getAfter(0)).is.null;
  			sched.add({
  				"state" : "A",
  				"time" : 0.1
  			});
  			sched.add({
  				"state" : "B",
  				"time" : 1.1
  			});
  			sched.add({
  				"state" : "C",
  				"time" : 2.1
  			});
  			expect(sched.getAfter(0).state).is.equal("A");
  			expect(sched.getAfter(1).state).is.equal("B");
  			expect(sched.getAfter(3)).is.null;
  			sched.dispose();
  		});
  
  		it("can the event before the event before the given time", function(){
  			var sched = new Timeline();
  			expect(sched.getBefore(0)).is.null;
  			sched.add({
  				"state" : "A",
  				"time" : 0.1
  			});
  			sched.add({
  				"state" : "B",
  				"time" : 1.1
  			});
  			sched.add({
  				"state" : "C",
  				"time" : 2.1
  			});
  			expect(sched.getBefore(0)).is.null;
  			expect(sched.getBefore(1.1).state).is.equal("A");
  			expect(sched.getBefore(2.1).state).is.equal("B");
  			expect(sched.getBefore(3).state).is.equal("C");
  			sched.dispose();
  		});
  
  		it("can cancel an item", function(){
  			var sched = new Timeline();
  			sched.add({ "time" : 3 });
  			sched.add({ "time" : 5 });
  			sched.add({ "time" : 4 });
  			sched.add({ "time" : 8 });
  			sched.add({ "time" : 5 });
  			expect(sched.length).to.equal(5);
  			sched.cancel(10);
  			expect(sched.length).to.equal(5);
  			sched.cancel(5);
  			expect(sched.length).to.equal(2);
  			sched.cancel(3);
  			expect(sched.length).to.equal(0);
  			sched.dispose();
  		});
  
  		it("can cancel items after the given time", function(){
  			var sched = new Timeline();
  			for (var i = 0; i < 100; i++){
  				sched.add({ "time" : 100 - i });
  			}
  			sched.cancel(10);
  			expect(sched.length).to.equal(9);
  			sched.cancel(5);
  			expect(sched.length).to.equal(4);
  			sched.cancel(0);
  			expect(sched.length).to.equal(0);
  			sched.dispose();
  		});
  
  		it("can cancel items before the given time", function(){
  			var sched = new Timeline();
  			for (var i = 0; i < 100; i++){
  				sched.add({ "time" : i });
  			}
  			sched.cancelBefore(9);
  			expect(sched.length).to.equal(90);
  			sched.cancelBefore(10.1);
  			expect(sched.length).to.equal(89);
  			sched.cancelBefore(100);
  			expect(sched.length).to.equal(0);
  			sched.dispose();
  		});
  
  		it("has no problem with many items", function(){
  			var sched = new Timeline();
  			for (var i = 0; i < 10000; i++){
  				sched.add({
  					"time" : i
  				});
  			}
  			for (var j = 0; j < 10000; j++){
  				expect(sched.get(j).time).to.equal(j);
  			}
  			sched.dispose();
  		});
  
  		it("can constrain the length of the timeline", function(){
  			var sched = new Timeline(4);
  			for (var i = 0; i < 10000; i++){
  				sched.add({
  					"time" : i
  				});
  			}
  			expect(sched.length).to.equal(4);
  			sched.dispose();
  		});
  
  		it("can peek and shift off the first element", function(){
  			var timeline = new Timeline();
  			timeline.add({
  				"time" : 0,
  				"value" : "a"
  			});
  			timeline.add({
  				"time" : 1,
  				"value" : "b"
  			});
  			timeline.add({
  				"time" : 2,
  				"value" : "c"
  			});
  			expect(timeline.length).to.equal(3);
  			expect(timeline.peek().value).to.equal("a");
  			expect(timeline.length).to.equal(3);
  			expect(timeline.shift().value).to.equal("a");
  			expect(timeline.length).to.equal(2);
  			expect(timeline.peek().value).to.equal("b");
  			expect(timeline.shift().value).to.equal("b");
  			expect(timeline.length).to.equal(1);
  			timeline.dispose();
  		});
  
  		context("Iterators", function(){
  
  			it("forEach is invoked with the timeline as the context", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0 });
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				sched.forEach(function(){
  					expect(this).to.equal(sched);
  				});
  				sched.dispose();
  			});
  
  			it("forEachBefore is invoked with the timeline as the context", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0 });
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				sched.forEachBefore(0.5, function(){
  					expect(this).to.equal(sched);
  				});
  				sched.dispose();
  			});
  
  			it("forEachAfter is invoked with the timeline as the context", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0 });
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				sched.forEachAfter(0.5, function(){
  					expect(this).to.equal(sched);
  				});
  				sched.dispose();
  			});
  
  			it("forEachFrom is invoked with the timeline as the context", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0 });
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				sched.forEachFrom(0.5, function(){
  					expect(this).to.equal(sched);
  				});
  				sched.dispose();
  			});
  
  			it("forEachAtTime is invoked with the timeline as the context", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0 });
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				sched.forEachAtTime(0.5, function(){
  					expect(this).to.equal(sched);
  				});
  				sched.dispose();
  			});
  
  			it("iterates over all items and returns and item", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0 });
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				var count = 0;
  				sched.forEach(function(event){
  					expect(event).to.be.an.object;
  					count++;
  				});
  				expect(count).to.equal(5);
  				sched.dispose();
  			});
  
  			it("iterates over all items before the given time", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0 });
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				var count = 0;
  				sched.forEachBefore(0.3, function(event){
  					expect(event).to.be.an.object;
  					expect(event.time).to.be.at.most(0.3);
  					count++;
  				});
  				expect(count).to.equal(4);
  				sched.dispose();
  			});
  
  			it("handles time ranges before the available objects", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				var count = 0;
  				sched.forEachBefore(0, function(){
  					count++;
  				});
  				expect(count).to.equal(0);
  				sched.dispose();
  			});
  
  			it("iterates over all items after the given time", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0 });
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				var count = 0;
  				sched.forEachAfter(0.1, function(event){
  					expect(event).to.be.an.object;
  					expect(event.time).to.be.above(0.1);
  					count++;
  				});
  				expect(count).to.equal(3);
  				sched.dispose();
  			});
  
  			it("handles time ranges after the available objects", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				var count = 0;
  				sched.forEachAfter(0.5, function(){
  					count++;
  				});
  				expect(count).to.equal(0);
  				sched.dispose();
  			});
  
  			it("handles time ranges before the first object", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				var count = 0;
  				sched.forEachAfter(-Infinity, function(){
  					count++;
  				});
  				expect(count).to.equal(4);
  				sched.dispose();
  			});
  
  			it("can iterate after inclusive of the item at the given time", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				var count = 0;
  				sched.forEachFrom(0.2, function(){
  					count++;
  				});
  				expect(count).to.equal(4);
  				count = 0;
  				sched.forEachFrom(0.21, function(){
  					count++;
  				});
  				expect(count).to.equal(2);
  				count = 0;
  				sched.forEachFrom(0, function(){
  					count++;
  				});
  				expect(count).to.equal(5);
  				sched.dispose();
  			});
  
  			it("iterates over all items at the given time", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0 });
  				sched.add({ "time" : 0 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.4 });
  				var count = 0;
  				sched.forEachAtTime(0.1, function(event){
  					count++;
  				});
  				expect(count).to.equal(0);
  				//and with an actual time
  				sched.forEachAtTime(0.2, function(event){
  					expect(event.time).to.equal(0.2);
  					count++;
  				});
  				expect(count).to.equal(2);
  				sched.dispose();
  			});
  
  			it("can remove items during iterations", function(){
  				var sched = new Timeline();
  				for (var i = 0; i < 1000; i++){
  					sched.add({ "time" : i });
  				}
  				sched.forEach(function(event){
  					sched.remove(event);
  				});
  				expect(sched.length).to.equal(0);
  				sched.dispose();
  			});
  
  			it("can add items during iteration", function(){
  				var sched = new Timeline();
  				for (var i = 0; i < 1000; i++){
  					sched.add({ "time" : i });
  				}
  				var added = false;
  				sched.forEach(function(event){
  					if (!added){
  						added = true;
  						sched.add({
  							"time" : 10,
  							"added" : true,
  						});
  					}
  				});
  				expect(sched.length).to.equal(1001);
  				sched.dispose();
  			});
  
  			it("can iterate between a time range", function(){
  				var sched = new Timeline();
  				sched.add({ "time" : 0.1 });
  				sched.add({ "time" : 0.2 });
  				sched.add({ "time" : 0.3 });
  				sched.add({ "time" : 0.4 });
  				var count = 0;
  				sched.forEachBetween(0.2, 0.4, function(event){
  					count++;
  					expect(event.time).to.be.within(0.2, 0.3);
  				});
  				expect(count).to.equal(2);
  				count = 0;
  				sched.forEachBetween(0.21, 0.4, function(event){
  					count++;
  					expect(event.time).to.be.within(0.21, 0.3);
  				});
  				expect(count).to.equal(1);
  				count = 0;
  				sched.forEachBetween(0.21, 0.39, function(event){
  					count++;
  					expect(event.time).to.be.within(0.21, 0.39);
  				});
  				expect(count).to.equal(1);
  				count = 0;
  				sched.forEachBetween(0, 0.11, function(event){
  					count++;
  					expect(event.time).to.be.within(0, 0.11);
  				});
  				expect(count).to.equal(1);
  				count = 0;
  				sched.forEachBetween(0, 0.09, function(event){
  					count++;
  					expect(event.time).to.be.within(0, 0.09);
  				});
  				expect(count).to.equal(0);
  				count = 0;
  				sched.forEachBetween(0.41, 0.5, function(event){
  					count++;
  					expect(event.time).to.be.within(0.41, 0.5);
  				});
  				expect(count).to.equal(0);
  				sched.dispose();
  			});
  
  		});
  	});
  });
  