Implementation seems ok. Deeper tests to come
This commit is contained in:
parent
35c64be3d7
commit
cbd93f450e
132
packages/xo-collection/collection.async.spec.js
Normal file
132
packages/xo-collection/collection.async.spec.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
|
||||||
|
import Collection, {DuplicateEntry, NoSuchEntry} from './collection'
|
||||||
|
|
||||||
|
import eventToPromise from 'event-to-promise'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
import chai from 'chai'
|
||||||
|
const expect = chai.expect
|
||||||
|
import dirtyChai from 'dirty-chai'
|
||||||
|
chai.use(dirtyChai)
|
||||||
|
|
||||||
|
describe('Collection', function () {
|
||||||
|
beforeEach(function (done) {
|
||||||
|
this.col = new Collection()
|
||||||
|
this.col.add('bar', 0)
|
||||||
|
|
||||||
|
process.nextTick(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#add()', function () {
|
||||||
|
it('adds item to the collection', function () {
|
||||||
|
const spy = sinon.spy()
|
||||||
|
this.col.on('add', spy)
|
||||||
|
|
||||||
|
this.col.add('foo', true)
|
||||||
|
|
||||||
|
expect(this.col.get('foo')).to.equal(true)
|
||||||
|
|
||||||
|
// No sync events.
|
||||||
|
sinon.assert.notCalled(spy)
|
||||||
|
|
||||||
|
// Async event.
|
||||||
|
return eventToPromise(this.col, 'add').then(function (added) {
|
||||||
|
expect(added).to.have.all.keys('foo')
|
||||||
|
expect(added.foo).to.equal(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an exception if the item already exists', function () {
|
||||||
|
expect(() => this.col.add('bar', true)).to.throw(DuplicateEntry)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#update()', function () {
|
||||||
|
it('updates an item of the collection', function () {
|
||||||
|
const spy = sinon.spy()
|
||||||
|
this.col.on('update', spy)
|
||||||
|
|
||||||
|
this.col.update('bar', 1)
|
||||||
|
expect(this.col.get('bar')).to.equal(1) // Will be forgotten by de-duplication
|
||||||
|
this.col.update('bar', 2)
|
||||||
|
expect(this.col.get('bar')).to.equal(2)
|
||||||
|
|
||||||
|
// No sync events.
|
||||||
|
sinon.assert.notCalled(spy)
|
||||||
|
|
||||||
|
// Async event.
|
||||||
|
return eventToPromise(this.col, 'update').then(function (updated) {
|
||||||
|
expect(updated).to.have.all.keys('bar')
|
||||||
|
expect(updated.bar).to.equal(2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an exception if the item does not exist', function () {
|
||||||
|
expect(() => this.col.update('baz', true)).to.throw(NoSuchEntry)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#remove()', function () {
|
||||||
|
it('removes an item of the collection', function () {
|
||||||
|
const spy = sinon.spy()
|
||||||
|
this.col.on('remove', spy)
|
||||||
|
|
||||||
|
this.col.update('bar', 1)
|
||||||
|
expect(this.col.get('bar')).to.equal(1) // Will be forgotten by de-duplication
|
||||||
|
this.col.remove('bar')
|
||||||
|
|
||||||
|
// No sync events.
|
||||||
|
sinon.assert.notCalled(spy)
|
||||||
|
|
||||||
|
// Async event.
|
||||||
|
return eventToPromise(this.col, 'remove').then(function (removed) {
|
||||||
|
expect(removed).to.have.all.keys('bar')
|
||||||
|
expect(removed.bar).to.equal(null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an exception if the item does not exist', function () {
|
||||||
|
expect(() => this.col.remove('baz', true)).to.throw(NoSuchEntry)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#set()', function () {
|
||||||
|
it('adds item if collection has not key', function () {
|
||||||
|
const spy = sinon.spy()
|
||||||
|
this.col.on('add', spy)
|
||||||
|
|
||||||
|
this.col.set('foo', true)
|
||||||
|
|
||||||
|
expect(this.col.get('foo')).to.equal(true)
|
||||||
|
|
||||||
|
// No sync events.
|
||||||
|
sinon.assert.notCalled(spy)
|
||||||
|
|
||||||
|
// Async events.
|
||||||
|
return eventToPromise(this.col, 'add').then(function (added) {
|
||||||
|
expect(added).to.have.all.keys('foo')
|
||||||
|
expect(added.foo).to.equal(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('updates item if collection has key', function () {
|
||||||
|
const spy = sinon.spy()
|
||||||
|
this.col.on('udpate', spy)
|
||||||
|
|
||||||
|
this.col.set('bar', 1)
|
||||||
|
|
||||||
|
expect(this.col.get('bar')).to.equal(1)
|
||||||
|
|
||||||
|
// No sync events.
|
||||||
|
sinon.assert.notCalled(spy)
|
||||||
|
|
||||||
|
// Async events.
|
||||||
|
return eventToPromise(this.col, 'update').then(function (updated) {
|
||||||
|
expect(updated).to.have.all.keys('bar')
|
||||||
|
expect(updated.bar).to.equal(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
@ -1,500 +0,0 @@
|
|||||||
var chai = require('chai');
|
|
||||||
var expect = chai.expect;
|
|
||||||
var dirtyChai = require('dirty-chai');
|
|
||||||
chai.use(dirtyChai);
|
|
||||||
var leche = require('leche');
|
|
||||||
var sinon = require('sinon');
|
|
||||||
|
|
||||||
var Collection = require('./collection');
|
|
||||||
|
|
||||||
describe('collection buffer', function () {
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
var col;
|
|
||||||
|
|
||||||
var addSpy, addCount;
|
|
||||||
var updateSpy, updateCount;
|
|
||||||
var removeSpy, removeCount;
|
|
||||||
var flush;
|
|
||||||
|
|
||||||
before(function () {
|
|
||||||
|
|
||||||
col = new Collection.Collection();
|
|
||||||
|
|
||||||
addSpy = sinon.spy();
|
|
||||||
addCount = 0;
|
|
||||||
updateSpy = sinon.spy();
|
|
||||||
updateCount = 0;
|
|
||||||
removeSpy = sinon.spy();
|
|
||||||
removeCount = 0;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
after(function () {
|
|
||||||
|
|
||||||
col.removeAllListeners();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(/*'force flush', */function () {
|
|
||||||
|
|
||||||
col.removeAllListeners(); // flush may emit events
|
|
||||||
|
|
||||||
try { // In case test cases interrupt before flushing
|
|
||||||
if (flush) {
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
} catch(e) {
|
|
||||||
if (!e instanceof Collection.NotBuffering) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
col.on('add', addSpy);
|
|
||||||
col.on('update', updateSpy);
|
|
||||||
col.on('remove', removeSpy);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection is empty =======================================================
|
|
||||||
|
|
||||||
var data1 = {
|
|
||||||
foo: 1,
|
|
||||||
bar: [1, 2],
|
|
||||||
baz: {a:1, b:2}
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('add', function () {
|
|
||||||
|
|
||||||
|
|
||||||
it('Emits no event when buffered, all data is emitted when flushed', function () {
|
|
||||||
|
|
||||||
flush = col.bufferChanges();
|
|
||||||
|
|
||||||
expect(addSpy.callCount).to.eq(addCount);
|
|
||||||
|
|
||||||
for (var prop in data1) {
|
|
||||||
expect(col.add(prop, data1[prop])).to.eq(col);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(addSpy.callCount).to.eq(addCount);
|
|
||||||
|
|
||||||
flush();
|
|
||||||
addCount++;
|
|
||||||
|
|
||||||
expect(addSpy.callCount).to.eq(addCount);
|
|
||||||
expect(addSpy.calledWith(data1)).to.be.true();
|
|
||||||
|
|
||||||
expect(flush).to.throw(Collection.NotBuffering);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data 1 ================================================
|
|
||||||
|
|
||||||
var data2 = {
|
|
||||||
foo: 3,
|
|
||||||
bar: [3, 4],
|
|
||||||
baz: {c:3, d:4}
|
|
||||||
};
|
|
||||||
|
|
||||||
var removedKeysData2 = {
|
|
||||||
foo: null,
|
|
||||||
bar: null,
|
|
||||||
baz: null
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('update', function () {
|
|
||||||
|
|
||||||
|
|
||||||
it('Emits no event when buffered, all data is emitted when flushed', function () {
|
|
||||||
|
|
||||||
flush = col.bufferChanges();
|
|
||||||
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
|
|
||||||
for (var prop in data2) {
|
|
||||||
expect(col.update(prop, data2[prop])).to.eq(col);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
|
|
||||||
flush();
|
|
||||||
updateCount++;
|
|
||||||
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
expect(updateSpy.calledWith(data2)).to.be.true();
|
|
||||||
|
|
||||||
expect(flush).to.throw(Collection.NotBuffering);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data 2 (update of data 1 keys) ========================
|
|
||||||
|
|
||||||
describe('touch', function () {
|
|
||||||
|
|
||||||
|
|
||||||
it('Marks a key as buffer-updated, and gives the value for object-property modification cases', function () {
|
|
||||||
|
|
||||||
flush = col.bufferChanges();
|
|
||||||
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
|
|
||||||
for (var prop in data2) {
|
|
||||||
expect(col.touch(prop)).to.eq(data2[prop]);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
|
|
||||||
flush();
|
|
||||||
updateCount++;
|
|
||||||
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
expect(updateSpy.calledWith(data2)).to.be.true();
|
|
||||||
|
|
||||||
expect(flush).to.throw(Collection.NotBuffering);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('remove', function () {
|
|
||||||
|
|
||||||
|
|
||||||
it('Emits no event when buffered, removed keys are emitted when flushed', function () {
|
|
||||||
|
|
||||||
flush = col.bufferChanges();
|
|
||||||
|
|
||||||
expect(removeSpy.callCount).to.eq(removeCount);
|
|
||||||
|
|
||||||
for (var prop in data2) {
|
|
||||||
expect(col.remove(prop)).to.eq(col);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(removeSpy.callCount).to.eq(removeCount);
|
|
||||||
|
|
||||||
flush();
|
|
||||||
removeCount++;
|
|
||||||
|
|
||||||
expect(removeSpy.callCount).to.eq(removeCount);
|
|
||||||
expect(removeSpy.calledWith(removedKeysData2)).to.be.true();
|
|
||||||
|
|
||||||
expect(flush).to.throw(Collection.NotBuffering);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection is empty =======================================================
|
|
||||||
|
|
||||||
var dataBefore = { // Will be removed if not re-added (-> udpate)
|
|
||||||
foo: 1,
|
|
||||||
bar: 2,
|
|
||||||
baz: 3
|
|
||||||
};
|
|
||||||
|
|
||||||
// Buffered from now
|
|
||||||
|
|
||||||
var dataToAdd = { // will be out of events if not post-added (-> add)
|
|
||||||
qux: 4,
|
|
||||||
hop: 6
|
|
||||||
};
|
|
||||||
|
|
||||||
var dataToUpdate = {
|
|
||||||
bar: 22,
|
|
||||||
};
|
|
||||||
|
|
||||||
var dataToRemove = {
|
|
||||||
hop: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
// All above will be cleared
|
|
||||||
|
|
||||||
var dataToPostAdd = {
|
|
||||||
baz: 33,
|
|
||||||
hip: 5
|
|
||||||
};
|
|
||||||
|
|
||||||
// flush
|
|
||||||
|
|
||||||
var expectedRemovedData = {
|
|
||||||
foo: null,
|
|
||||||
bar: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
var expectedUpdatedData = {
|
|
||||||
baz: 33
|
|
||||||
};
|
|
||||||
|
|
||||||
var expectedAddedData = {
|
|
||||||
hip:5
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('clear', function () {
|
|
||||||
|
|
||||||
|
|
||||||
it('acts as a multi-remove', function () {
|
|
||||||
|
|
||||||
var prop;
|
|
||||||
|
|
||||||
for (prop in dataBefore) {
|
|
||||||
expect(col.add(prop, dataBefore[prop])).to.eq(col);
|
|
||||||
}
|
|
||||||
|
|
||||||
addCount = addSpy.callCount; // Not buffered, events have been emitted
|
|
||||||
|
|
||||||
flush = col.bufferChanges();
|
|
||||||
|
|
||||||
expect(addSpy.callCount).to.eq(addCount);
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
expect(removeSpy.callCount).to.eq(removeCount);
|
|
||||||
|
|
||||||
for (prop in dataToAdd) {
|
|
||||||
expect(col.add(prop, dataToAdd[prop])).to.eq(col);
|
|
||||||
}
|
|
||||||
for (prop in dataToUpdate) {
|
|
||||||
expect(col.update(prop, dataToUpdate[prop])).to.eq(col);
|
|
||||||
}
|
|
||||||
for (prop in dataToRemove) {
|
|
||||||
expect(col.remove(prop)).to.eq(col);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(col.clear()).to.eq(col);
|
|
||||||
|
|
||||||
for (prop in dataToPostAdd) {
|
|
||||||
expect(col.add(prop, dataToPostAdd[prop])).to.eq(col);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(addSpy.callCount).to.eq(addCount);
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
expect(removeSpy.callCount).to.eq(removeCount);
|
|
||||||
|
|
||||||
flush();
|
|
||||||
|
|
||||||
addCount++;
|
|
||||||
updateCount++;
|
|
||||||
removeCount++;
|
|
||||||
|
|
||||||
expect(addSpy.callCount).to.eq(addCount);
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
expect(removeSpy.callCount).to.eq(removeCount);
|
|
||||||
|
|
||||||
expect(addSpy.calledWith(expectedAddedData)).to.be.true();
|
|
||||||
expect(updateSpy.calledWith(expectedUpdatedData)).to.be.true();
|
|
||||||
expect(removeSpy.calledWith(expectedRemovedData)).to.be.true();
|
|
||||||
|
|
||||||
expect(flush).to.throw(Collection.NotBuffering);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('buffer', function() {
|
|
||||||
|
|
||||||
beforeEach(/*'Init collection before buffering', */function() {
|
|
||||||
|
|
||||||
col.removeAllListeners();
|
|
||||||
|
|
||||||
col.clear();
|
|
||||||
col.add('exist', 0);
|
|
||||||
col.add('disappear', 3);
|
|
||||||
|
|
||||||
col.on('add', addSpy);
|
|
||||||
col.on('update', updateSpy);
|
|
||||||
col.on('remove', removeSpy);
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(
|
|
||||||
{
|
|
||||||
|
|
||||||
'add && update(|set) => add': [
|
|
||||||
[
|
|
||||||
{action: 'add', key: 'new', value:1},
|
|
||||||
{action: 'set', key: 'new', value:1.5},
|
|
||||||
{action: 'update', key: 'new', value:2},
|
|
||||||
],
|
|
||||||
{
|
|
||||||
add: 1,
|
|
||||||
update: 0,
|
|
||||||
remove: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
add: {'new': 2}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
'set(1st == add) && update(|set) => add': [
|
|
||||||
[
|
|
||||||
{action: 'set', key: 'new', value:1},
|
|
||||||
{action: 'update', key: 'new', value:1.5},
|
|
||||||
{action: 'set', key: 'new', value:2},
|
|
||||||
],
|
|
||||||
{
|
|
||||||
add: 1,
|
|
||||||
update: 0,
|
|
||||||
remove: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
add: {'new': 2}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
'update && update => update': [
|
|
||||||
[
|
|
||||||
{action: 'update', key: 'exist', value:1},
|
|
||||||
{action: 'set', key: 'exist', value:1.5},
|
|
||||||
{action: 'update', key: 'exist', value:2},
|
|
||||||
],
|
|
||||||
{
|
|
||||||
add: 0,
|
|
||||||
update: 1,
|
|
||||||
remove: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
update: {'exist': 2}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
'update && remove => remove': [
|
|
||||||
[
|
|
||||||
{action: 'update', key: 'exist', value:1},
|
|
||||||
{action: 'set', key: 'exist', value:1},
|
|
||||||
{action: 'remove', key: 'exist'},
|
|
||||||
],
|
|
||||||
{
|
|
||||||
add: 0,
|
|
||||||
update: 0,
|
|
||||||
remove: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
remove: {'exist': null}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
'add && [update &&] remove => nothing': [
|
|
||||||
[
|
|
||||||
{action: 'add', key: 'new', value:1},
|
|
||||||
{action: 'update', key: 'new', value:2},
|
|
||||||
{action: 'set', key: 'new', value:3},
|
|
||||||
{action: 'remove', key: 'new'},
|
|
||||||
],
|
|
||||||
{
|
|
||||||
add: 0,
|
|
||||||
update: 0,
|
|
||||||
remove: 0
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
],
|
|
||||||
|
|
||||||
'remove && add => update': [
|
|
||||||
[
|
|
||||||
{action: 'remove', key: 'exist'},
|
|
||||||
{action: 'add', key: 'exist', value:0}
|
|
||||||
],
|
|
||||||
{
|
|
||||||
add: 0,
|
|
||||||
update: 1,
|
|
||||||
remove: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
update: {'exist': 0}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
'remove && set => update': [
|
|
||||||
[
|
|
||||||
{action: 'remove', key: 'exist'},
|
|
||||||
{action: 'set', key: 'exist', value:0}
|
|
||||||
],
|
|
||||||
{
|
|
||||||
add: 0,
|
|
||||||
update: 1,
|
|
||||||
remove: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
update: {'exist': 0}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
'every entry is isolated': [
|
|
||||||
[
|
|
||||||
{action: 'update', key: 'disappear', value:22},
|
|
||||||
{action: 'remove', key: 'disappear'},
|
|
||||||
{action: 'add', key: 'new', value:1},
|
|
||||||
{action: 'update', key: 'new', value:222},
|
|
||||||
{action: 'update', key: 'exist', value:1},
|
|
||||||
{action: 'update', key: 'exist', value:2222},
|
|
||||||
{action: 'add', key: 'nothing', value:0},
|
|
||||||
{action: 'update', key: 'nothing', value:1},
|
|
||||||
{action: 'remove', key: 'nothing'},
|
|
||||||
|
|
||||||
],
|
|
||||||
{
|
|
||||||
add: 1,
|
|
||||||
update: 1,
|
|
||||||
remove: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
remove: {'disappear': null},
|
|
||||||
add: {'new': 222},
|
|
||||||
update: {'exist': 2222}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
function (actions, increments, eventArgs) {
|
|
||||||
|
|
||||||
it('Filters side effects forgotten by override', function () {
|
|
||||||
|
|
||||||
expect(addSpy.callCount).to.eq(addCount);
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
expect(removeSpy.callCount).to.eq(removeCount);
|
|
||||||
|
|
||||||
flush = col.bufferChanges();
|
|
||||||
|
|
||||||
actions.forEach(function (action) {
|
|
||||||
expect(
|
|
||||||
col[action.action](action.key, action.value)
|
|
||||||
).to.eq(col);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(addSpy.callCount).to.eq(addCount);
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
expect(removeSpy.callCount).to.eq(removeCount);
|
|
||||||
|
|
||||||
flush();
|
|
||||||
expect(flush).to.throw(Collection.NotBuffering);
|
|
||||||
|
|
||||||
addCount += increments.add;
|
|
||||||
updateCount += increments.update;
|
|
||||||
removeCount += increments.remove;
|
|
||||||
|
|
||||||
expect(addSpy.callCount).to.eq(addCount);
|
|
||||||
expect(updateSpy.callCount).to.eq(updateCount);
|
|
||||||
expect(removeSpy.callCount).to.eq(removeCount);
|
|
||||||
|
|
||||||
if (eventArgs.add) {
|
|
||||||
expect(addSpy.calledWith(eventArgs.add)).to.be.true();
|
|
||||||
}
|
|
||||||
if (eventArgs.update) {
|
|
||||||
expect(updateSpy.calledWith(eventArgs.update)).to.be.true();
|
|
||||||
}
|
|
||||||
if (eventArgs.remove) {
|
|
||||||
expect(removeSpy.calledWith(eventArgs.remove)).to.be.true();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -1,210 +0,0 @@
|
|||||||
var chai = require('chai');
|
|
||||||
var expect = chai.expect;
|
|
||||||
var dirtyChai = require('dirty-chai');
|
|
||||||
chai.use(dirtyChai);
|
|
||||||
var leche = require('leche');
|
|
||||||
var sinon = require('sinon');
|
|
||||||
|
|
||||||
var Collection = require('./collection');
|
|
||||||
|
|
||||||
var col = new Collection.Collection();
|
|
||||||
|
|
||||||
describe('collection events', function () {
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
var data1 = {
|
|
||||||
'primitive value': ['foo1', 1],
|
|
||||||
'array value': ['bar1', [1,2]],
|
|
||||||
'object value': ['baz1', {a:1, b:2}]
|
|
||||||
};
|
|
||||||
|
|
||||||
var addSpy;
|
|
||||||
var updateSpy;
|
|
||||||
var removeSpy;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
|
|
||||||
addSpy = sinon.spy();
|
|
||||||
updateSpy = sinon.spy();
|
|
||||||
removeSpy = sinon.spy();
|
|
||||||
col.on('add', addSpy);
|
|
||||||
col.on('update', updateSpy);
|
|
||||||
col.on('remove', removeSpy);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
|
|
||||||
col.removeAllListeners();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection is empty =======================================================
|
|
||||||
|
|
||||||
describe('add', function () {
|
|
||||||
|
|
||||||
leche.withData(data1, function (key, value) {
|
|
||||||
|
|
||||||
it('Emits an add event transporting the key and value', function () {
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
|
|
||||||
expect(col.add(key, value)).to.eql(col);
|
|
||||||
expect(addSpy.called).to.be.true();
|
|
||||||
expect(addSpy.calledWith({key: value})).to.be.true();
|
|
||||||
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
var updateData1 = {
|
|
||||||
'primitive value': ['foo1', 3],
|
|
||||||
'array value': ['bar1', [3,4]],
|
|
||||||
'object value': ['baz1', {c:2, d:4}]
|
|
||||||
};
|
|
||||||
|
|
||||||
// Collection contains data1 =================================================
|
|
||||||
|
|
||||||
describe('update', function () {
|
|
||||||
|
|
||||||
leche.withData(updateData1, function (key, value) {
|
|
||||||
|
|
||||||
it('Emits an update event transporting the key and value', function () {
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
|
|
||||||
expect(col.update(key, value)).to.eql(col);
|
|
||||||
expect(updateSpy.called).to.be.true();
|
|
||||||
expect(updateSpy.calledWith({key: value})).to.be.true();
|
|
||||||
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
var data2 = {
|
|
||||||
'primitive value': ['foo2', 1],
|
|
||||||
'array value': ['bar2', [1,2]],
|
|
||||||
'object value': ['baz2', {a:1, b:2}]
|
|
||||||
};
|
|
||||||
|
|
||||||
// Collection contains data1 updated =========================================
|
|
||||||
|
|
||||||
describe('set', function () {
|
|
||||||
|
|
||||||
leche.withData(data1, function (key, value) {
|
|
||||||
|
|
||||||
it('Emits an update event for pre-existing keys', function () {
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
|
|
||||||
expect(col.update(key, value)).to.eql(col);
|
|
||||||
expect(updateSpy.called).to.be.true();
|
|
||||||
expect(updateSpy.calledWith({key: value})).to.be.true();
|
|
||||||
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data1 =============================================
|
|
||||||
|
|
||||||
leche.withData(data2, function (key, value) {
|
|
||||||
|
|
||||||
it('Emits an add event for unexisting keys', function () {
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
|
|
||||||
expect(col.add(key, value)).to.eql(col);
|
|
||||||
expect(addSpy.called).to.be.true();
|
|
||||||
expect(addSpy.calledWith({key: value})).to.be.true();
|
|
||||||
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data1 & data 2 ========================================
|
|
||||||
|
|
||||||
describe('remove', function () {
|
|
||||||
|
|
||||||
leche.withData(data1, function (key, value) {
|
|
||||||
|
|
||||||
it('Emits an remove event transporting the key and removed value', function () {
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
|
|
||||||
expect(col.remove(key)).to.eql(col);
|
|
||||||
expect(removeSpy.called).to.be.true();
|
|
||||||
expect(removeSpy.calledWith({key: value})).to.be.true();
|
|
||||||
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data 2 ================================================
|
|
||||||
|
|
||||||
describe('clear', function () {
|
|
||||||
|
|
||||||
var clearedData;
|
|
||||||
|
|
||||||
it('Emits a remove event', function() {
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
|
|
||||||
expect(col.clear()).to.eq(col);
|
|
||||||
expect(removeSpy.calledOnce).to.be.true();
|
|
||||||
|
|
||||||
clearedData = removeSpy.lastCall.args[0];
|
|
||||||
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Emits no event if collection is empty', function() {
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
|
|
||||||
expect(col.clear()).to.eq(col);
|
|
||||||
|
|
||||||
expect(addSpy.called).to.be.false();
|
|
||||||
expect(updateSpy.called).to.be.false();
|
|
||||||
expect(removeSpy.called).to.be.false();
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(data2, function (key, value) {
|
|
||||||
|
|
||||||
it('Emits a remove event with all cleared data', function () {
|
|
||||||
|
|
||||||
expect(clearedData[key]).to.eq(value);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -1,273 +1,197 @@
|
|||||||
import makeError from 'make-error';
|
import events from 'events'
|
||||||
import events from 'events';
|
import makeError from 'make-error'
|
||||||
import _forEach from 'lodash.foreach';
|
|
||||||
|
export const DuplicateEntry = makeError('DuplicateEntry')
|
||||||
const AlreadyBuffering = makeError('AlreadyBuffering');
|
export const BufferAlreadyFlushed = makeError('BufferAlreadyFlushed')
|
||||||
const NotBuffering = makeError('NotBuffering');
|
export const IllegalAdd = makeError('IllegalAdd')
|
||||||
const IllegalAdd = makeError('IllegalAdd');
|
export const NoSuchEntry = makeError('NoSuchEntry')
|
||||||
const DuplicateEntry = makeError('DuplicateEntry');
|
|
||||||
const NoSuchEntry = makeError('NoSuchEntry');
|
export default class Collection extends events.EventEmitter {
|
||||||
|
constructor () {
|
||||||
class Collection extends events.EventEmitter {
|
super()
|
||||||
|
|
||||||
constructor () {
|
this._buffering = 0
|
||||||
|
this._map = {}
|
||||||
super();
|
this._size = 0
|
||||||
|
}
|
||||||
this._map = {};
|
|
||||||
this._buffering = false;
|
bufferChanges () {
|
||||||
this._size = 0;
|
if (this._buffering++ === 0) {
|
||||||
|
this._buffer = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
bufferChanges () {
|
let called = false
|
||||||
|
return () => {
|
||||||
if (this._buffering) {
|
if (called) {
|
||||||
throw new AlreadyBuffering('Already buffering'); // FIXME Really ?...
|
throw new BufferAlreadyFlushed('Buffer flush already requested')
|
||||||
}
|
}
|
||||||
|
called = true
|
||||||
this._buffering = true;
|
|
||||||
this._buffer = {};
|
if (--this._buffering > 0) {
|
||||||
|
return
|
||||||
return () => {
|
}
|
||||||
|
|
||||||
if (!this._buffering) {
|
let data = {
|
||||||
throw new NotBuffering('Nothing to flush'); // FIXME Really ?
|
add: {data: {}},
|
||||||
}
|
remove: {data: {}},
|
||||||
|
update: {data: {}}
|
||||||
this._buffering = false; // FIXME Really ?
|
}
|
||||||
|
|
||||||
let data = {
|
for (let key in this._buffer) {
|
||||||
add: {data: {}},
|
data[this._buffer[key]].data[key] = this.has(key) ?
|
||||||
update: {data: {}},
|
this.get(key) :
|
||||||
remove: {data: {}}
|
null // "remove" case
|
||||||
};
|
data[this._buffer[key]].has = true
|
||||||
|
}
|
||||||
for (let key in this._buffer) {
|
|
||||||
data[this._buffer[key]].data[key] = this.has(key) ?
|
['add', 'update', 'remove'].forEach(action => {
|
||||||
this.get(key) :
|
if (data[action].has) {
|
||||||
null; // 'remove' case
|
this.emit(action, data[action].data)
|
||||||
data[this._buffer[key]].has = true;
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
['add', 'update', 'remove'].forEach(action => {
|
delete this._buffer
|
||||||
if (data[action].has) {
|
}
|
||||||
this.emit(action, data[action].data);
|
}
|
||||||
}
|
|
||||||
});
|
_touch (action, key) {
|
||||||
|
if (this._buffering === 0) {
|
||||||
delete this._buffer;
|
process.nextTick(this.bufferChanges())
|
||||||
|
}
|
||||||
};
|
switch (action) {
|
||||||
|
case 'add':
|
||||||
}
|
this._buffer[key] = this._buffer[key] ? 'update' : 'add'
|
||||||
|
break
|
||||||
_touch (action, key, value) {
|
case 'remove':
|
||||||
|
switch (this._buffer[key]) {
|
||||||
if (this._buffering) {
|
case undefined:
|
||||||
|
case 'update':
|
||||||
switch(action) {
|
this._buffer[key] = 'remove'
|
||||||
|
break
|
||||||
case 'add':
|
case 'add':
|
||||||
this._buffer[key] = this._buffer[key] ? 'update' : 'add';
|
delete this._buffer[key]
|
||||||
break;
|
break
|
||||||
case 'update':
|
}
|
||||||
this._buffer[key] = this._buffer[key] || 'update';
|
break
|
||||||
break;
|
case 'update':
|
||||||
case 'remove':
|
this._buffer[key] = this._buffer[key] || 'update'
|
||||||
switch(this._buffer[key]) {
|
break
|
||||||
case undefined:
|
}
|
||||||
case 'update':
|
}
|
||||||
this._buffer[key] = 'remove';
|
|
||||||
break;
|
getId (item) {
|
||||||
case 'add':
|
return item.id
|
||||||
delete this._buffer[key];
|
}
|
||||||
break;
|
|
||||||
|
has (key) {
|
||||||
}
|
return Object.hasOwnProperty.call(this._map, key)
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
resolveEntry (keyOrObjectWithId, valueIfKey = null) {
|
||||||
|
let value
|
||||||
} else {
|
let key = (undefined !== keyOrObjectWithId) ?
|
||||||
|
this.getId(keyOrObjectWithId) :
|
||||||
this.emit(action, {key: value});
|
undefined
|
||||||
|
|
||||||
}
|
if (undefined === key) {
|
||||||
|
if (arguments.length < 2) {
|
||||||
}
|
throw new IllegalAdd('Missing value, or object value does not provide id/key')
|
||||||
|
} else {
|
||||||
getId (item) {
|
key = keyOrObjectWithId
|
||||||
|
value = valueIfKey
|
||||||
return item.id;
|
}
|
||||||
|
} else {
|
||||||
}
|
value = keyOrObjectWithId
|
||||||
|
}
|
||||||
has (key) {
|
|
||||||
|
return [key, value]
|
||||||
return Object.hasOwnProperty.call(this._map, key);
|
}
|
||||||
|
|
||||||
}
|
_assertHas (key) {
|
||||||
|
if (!this.has(key)) {
|
||||||
resolveEntry (keyOrObjectWithId, valueIfKey = null) {
|
throw new NoSuchEntry('No ' + key + ' entry')
|
||||||
|
}
|
||||||
let value;
|
}
|
||||||
let key = (undefined !== keyOrObjectWithId) ?
|
|
||||||
this.getId(keyOrObjectWithId) :
|
_assertHasNot (key) {
|
||||||
undefined;
|
if (this.has(key)) {
|
||||||
|
throw new DuplicateEntry('Attempt to duplicate ' + key + ' entry')
|
||||||
if (undefined === key) {
|
}
|
||||||
if (arguments.length < 2) {
|
}
|
||||||
throw new IllegalAdd();
|
|
||||||
} else {
|
add (keyOrObjectWithId, valueIfKey = null) {
|
||||||
key = keyOrObjectWithId;
|
const [key, value] = this.resolveEntry.apply(this, arguments)
|
||||||
value = valueIfKey;
|
this._assertHasNot(key)
|
||||||
}
|
|
||||||
} else {
|
this._map[key] = value
|
||||||
value = keyOrObjectWithId;
|
this._size++
|
||||||
}
|
this._touch('add', key)
|
||||||
|
|
||||||
return [key, value];
|
return this
|
||||||
|
}
|
||||||
}
|
|
||||||
|
set (keyOrObjectWithId, valueIfKey = null) {
|
||||||
_assertHas(key) {
|
const [key, value] = this.resolveEntry.apply(this, arguments)
|
||||||
|
|
||||||
if (!this.has(key)) {
|
const action = this.has(key) ? 'update' : 'add'
|
||||||
throw new NoSuchEntry();
|
this._map[key] = value
|
||||||
}
|
if (action === 'add') {
|
||||||
|
this._size++
|
||||||
}
|
}
|
||||||
|
this._touch(action, key)
|
||||||
_assertHasNot(key) {
|
|
||||||
|
return this
|
||||||
if (this.has(key)) {
|
}
|
||||||
throw new DuplicateEntry();
|
|
||||||
}
|
get (key) {
|
||||||
|
this._assertHas(key)
|
||||||
}
|
return this._map[key]
|
||||||
|
}
|
||||||
add (keyOrObjectWithId, valueIfKey = null) {
|
|
||||||
|
update (keyOrObjectWithId, valueIfKey = null) {
|
||||||
const [key, value] = this.resolveEntry.apply(this, arguments);
|
const [key, value] = this.resolveEntry.apply(this, arguments)
|
||||||
|
this._assertHas(key)
|
||||||
this._assertHasNot(key);
|
|
||||||
|
this._map[key] = value
|
||||||
this._map[key] = value;
|
this._touch('update', key)
|
||||||
|
|
||||||
this._size++;
|
return this
|
||||||
this._touch('add', key, value);
|
}
|
||||||
|
|
||||||
return this;
|
touch (keyOrObjectWithId) {
|
||||||
|
const [key] = this.resolveEntry(keyOrObjectWithId, null)
|
||||||
}
|
this._assertHas(key)
|
||||||
|
|
||||||
set (keyOrObjectWithId, valueIfKey = null) {
|
this._touch('update', key)
|
||||||
|
|
||||||
const [key, value] = this.resolveEntry.apply(this, arguments);
|
return this.get(key)
|
||||||
|
}
|
||||||
const action = this.has(key) ? 'update' : 'add';
|
|
||||||
this._map[key] = value;
|
remove (keyOrObjectWithId) {
|
||||||
if ('add' === action) {
|
const [key] = this.resolveEntry(keyOrObjectWithId, null)
|
||||||
this._size++;
|
this._assertHas(key)
|
||||||
}
|
|
||||||
|
delete this._map[key]
|
||||||
this._touch(action, key, value);
|
this._size--
|
||||||
|
this._touch('remove', key)
|
||||||
return this;
|
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
get (key) {
|
clear () {
|
||||||
|
for (let key in this._map) {
|
||||||
this._assertHas(key);
|
delete this._map[key]
|
||||||
|
this._size--
|
||||||
return this._map[key];
|
this._touch('remove', key)
|
||||||
}
|
}
|
||||||
|
return this
|
||||||
update (keyOrObjectWithId, valueIfKey = null) {
|
}
|
||||||
|
|
||||||
const [key, value] = this.resolveEntry.apply(this, arguments);
|
get size () {
|
||||||
|
return this._size
|
||||||
this._assertHas(key);
|
}
|
||||||
|
|
||||||
this._map[key] = value;
|
get all () {
|
||||||
this._touch('update', key, value);
|
return this._map
|
||||||
|
}
|
||||||
return this;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
touch (keyOrObjectWithId) {
|
|
||||||
|
|
||||||
const [key] = this.resolveEntry(keyOrObjectWithId, null);
|
|
||||||
|
|
||||||
this._assertHas(key);
|
|
||||||
|
|
||||||
if (!this._buffering) { // FIXME Really ?
|
|
||||||
// TODO throw something
|
|
||||||
}
|
|
||||||
|
|
||||||
this._touch('update', key);
|
|
||||||
return this.get(key);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
remove (keyOrObjectWithId) {
|
|
||||||
|
|
||||||
const [key] = this.resolveEntry(keyOrObjectWithId, null);
|
|
||||||
|
|
||||||
this._assertHas(key);
|
|
||||||
|
|
||||||
const oldValue = this.get(key);
|
|
||||||
delete this._map[key];
|
|
||||||
this._size--;
|
|
||||||
|
|
||||||
// FIXME do we "emit" null in place of oldValue to harmonize with flush remove events ?
|
|
||||||
this._touch('remove', key, oldValue);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
clear () {
|
|
||||||
|
|
||||||
if (this._size > 0) { // FIXME Really ?
|
|
||||||
if (!this._buffering) {
|
|
||||||
this.emit('remove', this._map);
|
|
||||||
} else {
|
|
||||||
for (let key in this._map) {
|
|
||||||
this._touch('remove', key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._map = {};
|
|
||||||
this._size = 0;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
get size () {
|
|
||||||
|
|
||||||
return this._size;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
get all () {
|
|
||||||
|
|
||||||
return this._map;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
|
||||||
Collection,
|
|
||||||
AlreadyBuffering,
|
|
||||||
NotBuffering,
|
|
||||||
IllegalAdd,
|
|
||||||
DuplicateEntry,
|
|
||||||
NoSuchEntry
|
|
||||||
};
|
|
@ -1,252 +0,0 @@
|
|||||||
var chai = require('chai');
|
|
||||||
var expect = chai.expect;
|
|
||||||
var dirtyChai = require('dirty-chai');
|
|
||||||
chai.use(dirtyChai);
|
|
||||||
var leche = require('leche');
|
|
||||||
|
|
||||||
var Collection = require('./collection');
|
|
||||||
|
|
||||||
var col = new Collection.Collection();
|
|
||||||
|
|
||||||
describe('collection', function () {
|
|
||||||
|
|
||||||
// Collection is empty =======================================================
|
|
||||||
|
|
||||||
var data1 = {
|
|
||||||
'primitive value': ['foo1', 1],
|
|
||||||
'array value': ['bar1', [1,2]],
|
|
||||||
'object value': ['baz1', {a:1, b:2}]
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('add', function () {
|
|
||||||
|
|
||||||
leche.withData(data1, function (key, value) {
|
|
||||||
|
|
||||||
it('Adds a new entry to the collection', function () {
|
|
||||||
expect(col.add(key, value)).to.eql(col);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(data1, function (key, value) {
|
|
||||||
|
|
||||||
it('We cannot add on a pre-existing key', function () {
|
|
||||||
expect(function () {
|
|
||||||
col.add(key, value);
|
|
||||||
}).to.throw(Collection.DuplicateEntry);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data 1 ================================================
|
|
||||||
|
|
||||||
var data2 = {
|
|
||||||
'primitive value': ['foo2', 1],
|
|
||||||
'array value': ['bar2', [1,2]],
|
|
||||||
'object value': ['baz2', {a:1, b:2}]
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('set', function () {
|
|
||||||
|
|
||||||
leche.withData(data2, function (key, value) {
|
|
||||||
|
|
||||||
it('Sets an entry of the collection...', function () {
|
|
||||||
expect(col.set(key, value)).to.eql(col);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(data2, function (key, value) {
|
|
||||||
|
|
||||||
it('...would it already exists or not', function () {
|
|
||||||
expect(col.set(key, value)).to.eql(col);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data 1 & 2 ============================================
|
|
||||||
|
|
||||||
var unexistingData = {
|
|
||||||
'Unexisting key/entry': ['wat', 'any']
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('get', function () {
|
|
||||||
|
|
||||||
leche.withData(data1, function (key, value) {
|
|
||||||
|
|
||||||
it('Returns the value of an entry of the collection...', function () {
|
|
||||||
expect(col.get(key)).to.eql(value);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(data2, function (key, value) {
|
|
||||||
|
|
||||||
it('Returns the value of an entry of the collection...', function () {
|
|
||||||
expect(col.get(key)).to.eql(value);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(unexistingData, function (key) {
|
|
||||||
|
|
||||||
it('...or throws if it does not exist', function () {
|
|
||||||
expect(function () {
|
|
||||||
col.get(key);
|
|
||||||
}).to.throw(Collection.NoSuchEntry);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data 1 & 2 ============================================
|
|
||||||
|
|
||||||
var updateData2 = {
|
|
||||||
'primitive value': ['foo2', 3],
|
|
||||||
'array value': ['bar2', [3,4]],
|
|
||||||
'object value': ['baz2', {c:3, d:4}]
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('update', function () {
|
|
||||||
|
|
||||||
leche.withData(updateData2, function (key, value) {
|
|
||||||
|
|
||||||
it('updates the given entries...', function () {
|
|
||||||
expect(col.update(key, value)).to.eql(col);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(updateData2, function (key, value) {
|
|
||||||
|
|
||||||
it('...so we can see the values we get have changed accordingly', function () {
|
|
||||||
expect(col.get(key)).to.eql(value);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(unexistingData, function (key, value) {
|
|
||||||
|
|
||||||
it('If the entry does not exist, updating throws', function () {
|
|
||||||
expect(function () {
|
|
||||||
col.update(key, value);
|
|
||||||
}).to.throw(Collection.NoSuchEntry);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data 1 & 2 updated ====================================
|
|
||||||
|
|
||||||
describe('remove', function () {
|
|
||||||
|
|
||||||
leche.withData(data2, function (key) {
|
|
||||||
|
|
||||||
it('removes the given entries...', function () {
|
|
||||||
expect(col.remove(key)).to.eql(col);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(data2, function (key) {
|
|
||||||
|
|
||||||
it('...so trying to get them again throws...', function () {
|
|
||||||
expect(function () {
|
|
||||||
col.get(key);
|
|
||||||
}).to.throw(Collection.NoSuchEntry);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(data2, function (key) {
|
|
||||||
|
|
||||||
it('...and trying to remove them again also throws', function () {
|
|
||||||
expect(function () {
|
|
||||||
col.remove(key);
|
|
||||||
}).to.throw(Collection.NoSuchEntry);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data 1 ================================================
|
|
||||||
|
|
||||||
describe('has', function () {
|
|
||||||
|
|
||||||
leche.withData(data1, function (key) {
|
|
||||||
|
|
||||||
it('Tells us if an entry exists...', function () {
|
|
||||||
expect(col.has(key)).to.be.true();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(data2, function (key) {
|
|
||||||
|
|
||||||
it('...or not', function () {
|
|
||||||
expect(col.has(key)).to.be.false();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data 1 ================================================
|
|
||||||
|
|
||||||
describe('size', function () {
|
|
||||||
|
|
||||||
it('Reveals the number of existing entries', function () {
|
|
||||||
expect(col.size).to.eq(Object.keys(data1).length);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data 1 ================================================
|
|
||||||
|
|
||||||
describe('all', function () {
|
|
||||||
|
|
||||||
leche.withData(data1, function (key, value) {
|
|
||||||
|
|
||||||
it('Gives access to the internal collection...', function () {
|
|
||||||
expect(col.all).to.have.ownProperty(key);
|
|
||||||
expect(col.all[key]).to.eq(value);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
leche.withData(data2, function (key) {
|
|
||||||
|
|
||||||
it('Gives access to the internal collection...', function () {
|
|
||||||
expect(col.all).to.not.have.ownProperty(key);
|
|
||||||
expect(col.all[key]).to.eq(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Gives access to the internal collection...', function () {
|
|
||||||
expect(col.size).to.eq(Object.keys(col.all).length);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collection contains data 1 ================================================
|
|
||||||
|
|
||||||
describe('clear', function () {
|
|
||||||
|
|
||||||
it('wipes out all the collection', function () {
|
|
||||||
expect(col.clear()).to.eq(col);
|
|
||||||
|
|
||||||
expect(col.size).to.eq(0);
|
|
||||||
expect(col.all).to.eql({});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -11,6 +11,7 @@
|
|||||||
"babel": "^4.7.16",
|
"babel": "^4.7.16",
|
||||||
"chai": "^2.2.0",
|
"chai": "^2.2.0",
|
||||||
"dirty-chai": "^1.2.0",
|
"dirty-chai": "^1.2.0",
|
||||||
|
"event-to-promise": "^0.3.2",
|
||||||
"leche": "^2.1.1",
|
"leche": "^2.1.1",
|
||||||
"mocha": "^2.2.1",
|
"mocha": "^2.2.1",
|
||||||
"sinon": "^1.14.1"
|
"sinon": "^1.14.1"
|
||||||
|
Loading…
Reference in New Issue
Block a user