double-linked-list
Version:
A doubly-linked list implementation.
731 lines (650 loc) • 27 kB
JavaScript
var chai = require('chai');
var expect = chai.expect;
var LinkedList = require('../index.js');
describe('testing linked-list', function () {
describe('structure', function () {
it('the first element should be undefined when newly created', function () {
var list = new LinkedList();
expect(list.first()).to.equal(undefined);
});
it('the last element should be undefined when newly created', function () {
var list = new LinkedList();
expect(list.last()).to.equal(undefined);
});
it('the first and last elements should be the same when there is one element in the list', function () {
var list = new LinkedList();
list.push('one');
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('one');
expect(list.last()).to.equal(list.last());
});
it('the first and last elements should be correct when the list consists of multiple elements', function () {
var list = new LinkedList();
list.push('one');
list.push('two');
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('two');
list.push('three');
expect(list.last()).to.equal('three');
});
});
describe('length', function () {
it('should have a length of 0 when newly created', function () {
var list = new LinkedList();
expect(list.length).to.equal(0);
});
it('should have the correct length when items have been added to it', function () {
var list = new LinkedList();
list.push('one');
expect(list.length).to.equal(1);
list.push('two');
expect(list.length).to.equal(2);
list.push('three');
expect(list.length).to.equal(3);
});
it('should have the correct length when adding and removing elements from it', function () {
var list = new LinkedList();
list.push('one');
list.push('two');
expect(list.length).to.equal(2);
list.shift();
expect(list.length).to.equal(1);
list.shift();
expect(list.length).to.equal(0);
});
it('should not have a length below 0 if you try and remove from an empty list', function () {
var list = new LinkedList();
list.shift();
expect(list.length).to.equal(0);
list.pop();
expect(list.length).to.equal(0);
});
});
describe('#push', function () {
it('should change the last element of the list to be the added element', function () {
var list = new LinkedList();
list.push('one');
expect(list.last()).to.equal('one');
list.push('two');
expect(list.last()).to.equal('two');
list.push('three');
expect(list.last()).to.equal('three');
});
it('the first and last elements should be the same when added to an empty list', function () {
var list = new LinkedList();
list.push('one');
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('one');
});
it('the length should increase by 1 when an element is pushed to the list', function () {
var list = new LinkedList();
expect(list.length).to.equal(0);
list.push('one');
expect(list.length).to.equal(1);
list.push('two');
expect(list.length).to.equal(2);
list.push('three');
expect(list.length).to.equal(3);
});
it('should return null if the data passed into it is null', function() {
var list = new LinkedList();
list.push(null);
expect(list.first()).to.equal(null);
});
});
describe('#unShift', function() {
it('should change the first element in the list to be the added element', function() {
var list = new LinkedList();
list.unShift('one');
expect(list.first()).to.equal('one');
list.unShift('two');
expect(list.first()).to.equal('two');
list.unShift('three');
expect(list.first()).to.equal('three');
});
it('the first and last elements should be the same when added to an empty list', function() {
var list = new LinkedList();
list.unShift('one');
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('one');
});
it('the length should increase by 1 when an element is unShifted onto the list', function () {
var list = new LinkedList();
expect(list.length).to.equal(0);
list.unShift('one');
expect(list.length).to.equal(1);
list.unShift('two');
expect(list.length).to.equal(2);
list.unShift('three');
expect(list.length).to.equal(3);
});
it('the list should survive shifting and unShifting in random orders', function() {
var list = new LinkedList();
list.unShift('one');
expect(list.length).to.equal(1);
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('one');
list.unShift('two');
expect(list.length).to.equal(2);
expect(list.first()).to.equal('two');
expect(list.last()).to.equal('one');
list.unShift('three');
expect(list.length).to.equal(3);
expect(list.first()).to.equal('three');
expect(list.last()).to.equal('one');
list.shift();
expect(list.length).to.equal(2);
expect(list.first()).to.equal('two');
expect(list.last()).to.equal('one');
list.shift();
expect(list.length).to.equal(1);
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('one');
list.shift();
expect(list.length).to.equal(0);
expect(list.first()).to.equal(undefined);
expect(list.last()).to.equal(undefined);
list.unShift('four');
list.unShift('five');
expect(list.length).to.equal(2);
expect(list.first()).to.equal('five');
expect(list.last()).to.equal('four');
list.shift();
expect(list.length).to.equal(1);
expect(list.first()).to.equal('four');
expect(list.last()).to.equal('four');
});
it('should return null if the data passed into it is null', function() {
var list = new LinkedList();
list.unShift(null);
expect(list.first()).to.equal(null);
});
});
describe('#shift', function () {
it('after shifting, the second item in the list should become the first', function () {
var list = new LinkedList();
list.push('one');
list.push('two');
list.shift();
expect(list.first()).to.equal('two');
});
it('the list should survive shifting and pushing in random orders', function() {
var list = new LinkedList();
list.push('one');
expect(list.length).to.equal(1);
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('one');
list.push('two');
expect(list.length).to.equal(2);
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('two');
list.push('three');
expect(list.length).to.equal(3);
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('three');
list.shift();
expect(list.length).to.equal(2);
expect(list.first()).to.equal('two');
expect(list.last()).to.equal('three');
list.shift();
expect(list.length).to.equal(1);
expect(list.first()).to.equal('three');
expect(list.last()).to.equal('three');
list.shift();
expect(list.length).to.equal(0);
expect(list.first()).to.equal(undefined);
expect(list.last()).to.equal(undefined);
list.push('four');
list.push('five');
expect(list.length).to.equal(2);
expect(list.first()).to.equal('four');
expect(list.last()).to.equal('five');
list.shift();
expect(list.length).to.equal(1);
expect(list.first()).to.equal('five');
expect(list.last()).to.equal('five');
});
it('should return the removed element data', function () {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
expect(list.shift()).to.equal('one');
});
it('should return undefined when removing from an empty list', function () {
var list = new LinkedList();
expect(list.shift()).to.equal(undefined);
});
it('should have a length of one less after shifting', function () {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
expect(list.length).to.equal(3);
list.shift();
expect(list.length).to.equal(2);
list.shift();
expect(list.length).to.equal(1);
list.shift();
expect(list.length).to.equal(0);
});
it('should return the actual reference to the object that was passed into the list', function() {
var list = new LinkedList();
var string = 'one';
list.push(string);
expect(list.shift()).to.equal(string);
list = new LinkedList();
var obj = {foo: 'bar'};
list.push(obj);
expect(list.shift()).to.equal(obj);
});
});
describe('#pop', function () {
it('after popping, the second last item in the list should become the last', function () {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
list.push('four');
list.pop();
expect(list.last()).to.equal('three');
});
it('should survive popping and adding in random orders', function() {
var list = new LinkedList();
list.push('one');
expect(list.length).to.equal(1);
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('one');
list.push('two');
expect(list.length).to.equal(2);
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('two');
list.push('three');
expect(list.length).to.equal(3);
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('three');
list.pop();
expect(list.length).to.equal(2);
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('two');
list.pop();
expect(list.length).to.equal(1);
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('one');
list.pop();
expect(list.length).to.equal(0);
expect(list.first()).to.equal(undefined);
expect(list.last()).to.equal(undefined);
list.push('four');
list.push('five');
expect(list.length).to.equal(2);
expect(list.first()).to.equal('four');
expect(list.last()).to.equal('five');
list.pop();
expect(list.length).to.equal(1);
expect(list.first()).to.equal('four');
expect(list.last()).to.equal('four');
});
it('should return the removed element data', function () {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
expect(list.pop()).to.equal('three');
});
it('should return undefined when removing from an empty list', function () {
var list = new LinkedList();
expect(list.pop()).to.equal(undefined);
});
it('should have a length of one less after popping', function () {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
expect(list.length).to.equal(3);
list.pop();
expect(list.length).to.equal(2);
list.pop();
expect(list.length).to.equal(1);
list.pop();
expect(list.length).to.equal(0);
});
it('should return the actual reference to the object that was passed into the list', function() {
var list = new LinkedList();
var string = 'one';
list.push(string);
expect(list.pop()).to.equal(string);
list = new LinkedList();
var obj = {foo: 'bar'};
list.push(obj);
expect(list.pop()).to.equal(obj);
});
});
describe('#get', function () {
it('should return the correct item at the given index', function () {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
list.push('four');
expect(list.get(0)).to.equal('one');
expect(list.get(1)).to.equal('two');
expect(list.get(2)).to.equal('three');
expect(list.get(3)).to.equal('four');
});
it('should return undefined if a negative index is given', function() {
var list = new LinkedList();
list.push('one');
expect(list.get(-1)).to.equal(undefined);
expect(list.get(-10)).to.equal(undefined);
expect(list.get(-0.1)).to.equal(undefined);
expect(list.get(-100)).to.equal(undefined);
});
it('should return undefined if used on an empty list', function() {
var list = new LinkedList();
expect(list.get(0)).to.equal(undefined);
});
it('should return undefined if a decimal index is given', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
list.push('four');
list.push('five');
expect(list.get(0.1)).to.equal(undefined);
expect(list.get(1.5)).to.equal(undefined);
expect(list.get(3.99999)).to.equal(undefined);
});
it('should return undefined if too great an index is given', function() {
var list = new LinkedList();
expect(list.get(0)).to.equal(undefined);
list.push('one');
expect(list.get(5)).to.equal(undefined);
expect(list.get(100)).to.equal(undefined);
expect(list.get(list.length)).to.equal(undefined);
expect(list.get(list.length + 0.1)).to.equal(undefined);
});
it('should return the actual reference to the object that was passed into the list', function() {
var list = new LinkedList();
var string = 'one';
list.push(string);
expect(list.get(0)).to.equal(string);
list = new LinkedList();
var obj = {foo: 'bar'};
list.push(obj);
expect(list.get(0)).to.equal(obj);
});
it('when items in front are removed, the correct index of an item should change', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
list.push('four');
expect(list.get(3)).to.equal('four');
list.shift();
expect(list.get(2)).to.equal('four');
list.shift();
expect(list.get(1)).to.equal('four');
list.shift();
expect(list.get(0)).to.equal('four');
});
it('the item at index 0 should be the first item in the list', function() {
var list = new LinkedList();
list.push('one');
expect(list.get(0)).to.equal(list.first());
});
it('the item at index list.length-1 should be the last item in the list', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
expect(list.get(list.length - 1)).to.equal(list.last());
});
it('should return the correct item on a large list', function() {
var list = new LinkedList();
list.push('hello');
list.push('hello');
list.push('hello');
list.push('hello');
list.push('four'); // i = 4
list.push('hello');
list.push('hello');
list.push('seven'); // i = 7
list.push('eight'); // i = 8
list.push('nine'); // i = 9
list.push('hello');
list.push('hello');
list.push('hello');
list.push('thirteen'); // 13
list.push('hello');
list.push('hello'); // list.length === 16
expect(list.get(4)).to.equal('four');
expect(list.get(13)).to.equal('thirteen');
expect(list.get(7)).to.equal('seven');
expect(list.get(8)).to.equal('eight');
expect(list.get(9)).to.equal('nine');
list.push('hello'); // list.length === 17
expect(list.get(7)).to.equal('seven');
expect(list.get(8)).to.equal('eight');
expect(list.get(9)).to.equal('nine');
});
});
describe('#add', function() {
it('should place the item in the correct position', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
list.push('four');
list.push('five');
list.add(1, 'new1');
expect(list.get(1)).to.equal('new1');
list.add(3, 'new3');
expect(list.get(3)).to.equal('new3');
list.add(4, 'new4');
expect(list.get(4)).to.equal('new4');
});
it('adding to index 0 should make the item the first in the list', function() {
var list = new LinkedList();
list.push('one');
list.add(0, 'new1');
expect(list.first()).to.equal('new1');
});
it('adding to an index of less than 0 should make the item the first in the list', function() {
var list = new LinkedList();
list.push('one');
list.add(-1, 'new1');
expect(list.first()).to.equal('new1');
list.add(-5, 'new2');
expect(list.first()).to.equal('new2');
list.add(-100, 'new3');
expect(list.first()).to.equal('new3');
});
it('adding to index list.length should make the item the last in the list', function() {
var list = new LinkedList();
list.push('one');
list.add(list.length, 'new1');
expect(list.last()).to.equal('new1');
});
it('adding to a decimal index should do nothing', function() {
var list = new LinkedList();
list.push('one');
list.add(1.1, 'new1');
list.add(0.1, 'new1');
list.add(-5.7, 'new1');
expect(list.length).to.equal(1);
expect(list.first()).to.equal('one');
expect(list.last()).to.equal('one');
});
it('adding to an index larger than the length of the list should add to the end', function() {
var list = new LinkedList();
list.push('one');
list.add(list.length + 1, 'new1');
expect(list.last()).to.equal('new1');
list.add(10, 'new2');
expect(list.last()).to.equal('new2');
list.add(100, 'new3');
expect(list.last()).to.equal('new3');
});
it('should move the other items in the list correctly', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
list.add(1, 'hello');
expect(list.get(0)).to.equal('one');
expect(list.get(1)).to.equal('hello');
expect(list.get(2)).to.equal('two');
expect(list.get(3)).to.equal('three');
});
it('should increase the length by one', function() {
var list = new LinkedList();
list.add(0, 'one');
list.add(0, 'two');
list.add(0, 'three');
expect(list.length).to.equal(3);
});
});
describe('#remove', function() {
it('should remove the correct item', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
list.push('four');
list.push('five');
expect(list.remove(4)).to.equal('five');
expect(list.remove(3)).to.equal('four');
expect(list.remove(2)).to.equal('three');
expect(list.remove(1)).to.equal('two');
expect(list.remove(0)).to.equal('one');
});
it('should move the positions of the items after it', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
list.push('four');
list.push('five');
list.remove(1);
expect(list.get(0)).to.equal('one');
expect(list.get(1)).to.equal('three');
expect(list.get(2)).to.equal('four');
});
it('removing from index 0 should change the first item in the list', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
list.remove(0);
expect(list.first()).to.equal('two');
});
it('removing from index list.length should change the last item in the list', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
list.remove(list.length - 1);
expect(list.last()).to.equal('two');
});
it('should decrease the length by one', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
expect(list.length).to.equal(3);
list.remove(2);
expect(list.length).to.equal(2);
list.remove(1);
expect(list.length).to.equal(1);
list.remove(0);
expect(list.length).to.equal(0);
});
it('should return undefined if removing from the empty list', function() {
var list = new LinkedList();
expect(list.remove(0)).to.equal(undefined);
});
it('should return undefined if removing from a non existent index in the list', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
expect(list.remove(3)).to.equal(undefined);
expect(list.remove(-1)).to.equal(undefined);
expect(list.remove(100)).to.equal(undefined);
});
it('should return undefined if removing from a decimal index', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
expect(list.remove(0.1)).to.equal(undefined);
expect(list.remove(1.4)).to.equal(undefined);
expect(list.remove(-1.1)).to.equal(undefined);
expect(list.remove(3.00000001)).to.equal(undefined);
expect(list.remove(2.99999999)).to.equal(undefined);
});
it('should return the actual reference to the object that was passed into the list', function() {
var list = new LinkedList();
var string = 'one';
list.push(string);
expect(list.remove(0)).to.equal(string);
list = new LinkedList();
var obj = {foo: 'bar'};
list.push(obj);
expect(list.remove(0)).to.equal(obj);
});
});
describe('#toString', function() {
it('should return the list in a nice format', function() {
var list = new LinkedList();
list.push('one');
list.push('two');
list.push('three');
expect(list.toString()).to.equal("one, two, three");
});
it('should return an object in a readable format', function() {
var list = new LinkedList();
list.push({
one: "2"
});
list.push({
two: "2"
});
expect(list.toString()).to.equal('{"one":"2"}, {"two":"2"}');
});
it('should return the empty string if the list is empty', function() {
var list = new LinkedList();
expect(list.toString()).to.equal("");
});
});
describe('time testing to see how it handles large lists', function() {
var iterations = 100000;
it('testing the LinkedList', function() {
var startTime = new Date();
var list = new LinkedList();
for(var i = 0; i < iterations; i++) {
list.push('item');
}
for(i = 0; i < iterations; i++) {
list.shift();
}
var endTime = new Date();
var time = endTime.getTime() - startTime.getTime();
console.log("linked list time: %sms", time);
});
it('testing the js array', function() {
var startTime = new Date();
var list = [];
for(var i = 0; i < iterations; i++) {
list.push('item');
}
for(i = 0; i < iterations; i++) {
list.shift();
}
var endTime = new Date();
var time = endTime.getTime() - startTime.getTime();
console.log("js array time: %sms", time);
});
});
});