diff --git a/README.md b/README.md index 276409c..48835fc 100644 --- a/README.md +++ b/README.md @@ -111,14 +111,7 @@ If you were to track all instances of an entity on each update the write penalty ###Data shape This is not currently designed to work with cyclical data. It is best for non-cyclical objects received from the server in the form of json (or other non-cyclical fomats). -If a strong need arises for managing cyclical structures this might be an option for future development. - -###Release Notes -5.1.0 -* remove thread api, time travel works on main thread only to prevent mixing data from different cache nodes -* ```getCurrentIndex()``` change to ```index()``` with dual nature to get or set the current index. -* add ```node()``` api in order to locate cache nodes by their id -Replaces the threading option in a much simpler and intuitive manner since threads are only a way of jumping around in time on the cache. +It might happen later if there's a need. ###Documentation * [Immutable data](https://maierson.gitbooks.io/one/content/immutable_data.html) @@ -127,5 +120,6 @@ Replaces the threading option in a much simpler and intuitive manner since threa * [Get](https://maierson.gitbooks.io/one/content/get.html) * [Evict](https://maierson.gitbooks.io/one/content/evict.html) * [Time travel](https://maierson.gitbooks.io/one/content/time_travel.html) +* [Release Notes](https://maierson.gitbooks.io/one/content/release_notes.html) diff --git a/package.json b/package.json index 82c2097..746dd97 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "one", - "version": "5.1.0", + "version": "5.1.1", "description": "Browser application cache. It guarantees entity uniqueness across the entire cache.", "main": "lib/index.js", "scripts": { diff --git a/src/cache.js b/src/cache.js index 4d90986..20bb100 100644 --- a/src/cache.js +++ b/src/cache.js @@ -474,16 +474,20 @@ function getCache(debugParam = false) { // at this point all items are added into the flush map - update their pointers if applicable flushMap.forEach((item, key) => { if (key !== UPDATED_KEY) { + // do not modify flush map on its own iteration but ok to pass along for reference let refsFrom = item[REF_FROM]; + // parentUid = uid of the item being targeted for ref update (ie the ref's parent) for (let parentUid in refsFrom) { if (refsFrom.hasOwnProperty(parentUid)) { + let paths = refsFrom[parentUid]; let parentItem = flushMap.get(parentUid); if (!parentItem) { parentItem = getLiveItem(parentUid); } + /* only update if dirty - no need to iterate all paths - just check the first one - if dirty then the parent entity needs to be cloned and updated anyways so pass in the ref entity when cloning - it will be updated wherever it is encountered during cloning */ @@ -492,10 +496,11 @@ function getCache(debugParam = false) { let targetRef = opath.get(parentItem[ENTITY], firstPath); // check for dirty let dirty = (targetRef && targetRef !== item[ENTITY]); + if (dirty === true) { parentItem = ensureItem(parentItem[ENTITY], flushMap); // the entity is still frozen here - clone it to update and freeze it deeply - parentItem[ENTITY] = deepClone(parentItem[ENTITY], item[ENTITY], true, true); + parentItem[ENTITY] = deepClone(parentItem[ENTITY], item[ENTITY], true); } } } diff --git a/src/utils/clone.js b/src/utils/clone.js index 70c1d0b..70ca4fd 100644 --- a/src/utils/clone.js +++ b/src/utils/clone.js @@ -38,7 +38,7 @@ export function isEmpty(value) { * @param force * @returns {*} */ -export function deepClone(obj, uidReference, freeze = true, force = false) { +export function deepClone(obj, uidReference, freeze = true) { if (!obj || (!isObject(obj) && !isArray(obj))) { return obj; } @@ -59,7 +59,7 @@ export function deepClone(obj, uidReference, freeze = true, force = false) { let value = result[propName]; if (value) { if (isArray(value)) { - result[propName] = deepCloneArray(value, uidReference, force); + result[propName] = deepCloneArray(value, uidReference, freeze); } else if (isDate(value)) { let date = new Date(value.getTime()); if (freeze === true) { @@ -80,7 +80,7 @@ export function deepClone(obj, uidReference, freeze = true, force = false) { //result[propName] = deepClone(value); } } else { - result[propName] = deepClone(value, uidReference, freeze, force); + result[propName] = deepClone(value, uidReference, freeze); } } } @@ -92,16 +92,19 @@ export function deepClone(obj, uidReference, freeze = true, force = false) { return result; } -function deepCloneArray(arr, uidReference, force) { +function deepCloneArray(arr, uidReference, freeze) { return arr.map(item => { if (isArray(item)) { - return deepCloneArray(item, uidReference, force); + return deepCloneArray(item, uidReference, freeze); } else if (isObject(item)) { // *** keep items inside clones as we're not editing them = must getEdit on item - if (hasUid(item) && force === false) { + if (hasUid(item)) { + if(uidReference && (item[config.prop.uidName] === uidReference[config.prop.uidName])){ + return uidReference; + } return item; } else { - return deepClone(item, uidReference, force); + return deepClone(item, uidReference, freeze); } } else { return item; diff --git a/test/cache-test.js b/test/io-test.js similarity index 80% rename from test/cache-test.js rename to test/io-test.js index e43de5e..93058ec 100644 --- a/test/cache-test.js +++ b/test/io-test.js @@ -13,7 +13,7 @@ import {deepClone, isArray} from '../src/utils/clone'; import * as path from "../src/utils/path"; import {describe, it} from 'mocha/lib/mocha.js'; -describe("One", function () { +describe("IO", function () { "use strict"; @@ -134,6 +134,55 @@ describe("One", function () { expect(One.length()).to.equal(1); }); + it("updates parent when inner uid ref changed but keeps other children references unchanged", function () { + let item1 = {uid: 1}; + let item2 = {uid: 2}; + let item3 = { + uid : 3, + item1: item1, + item2: item2 + }; + One.put(item3); + + let item4 = {uid:4}; + One.put(item4); + let edit1 = One.getEdit(1); + edit1.item = item4; + One.put(edit1); + + let result = One.get(3); + expect(item2 === result.item2).to.be.true; + let result2 = One.get(2); + expect(item2 === result2).to.be.true; + }); + + + it("updates parent when inner uid ref changed " + + "but keeps other children references unchanged in ARRAY", function () { + let item = {uid:"item"}; + let item1 = {uid: 1}; + let item2 = {uid: 2}; + let item3 = { + uid : 3, + item : item, + children: [item1,item2] + }; + One.put(item3); + + let item4 = {uid:4}; + One.put(item4); + let edit1 = One.getEdit(1); + edit1.item = item4; + One.put(edit1); + + let itemResult = One.get("item"); + expect(item === itemResult).to.be.true; + let result = One.get(3); + expect(item2 === result.children[1]).to.be.true; + let result2 = One.get(2); + expect(item2 === result2).to.be.true; + }); + it("puts top array even if it contains no uid items", function () { let firstItem = {uid: "first"}; let item1 = {uid: 1, item: firstItem}; @@ -326,7 +375,7 @@ describe("One", function () { let item2 = {uid: 2, item: item1}; One.put(item2); - let state = One.undo(); + let state = One.undo(); expect(state.success).to.be.true; expect(state.hasPrev).to.be.false; expect(state.hasNext).to.be.true; @@ -369,29 +418,6 @@ describe("One", function () { expect(hasThree).to.be.true; }); - it("updates entity in other reference pointer on same entity", function () { - let item1 = {uid: 1, val: "one"}; - // test object ref AND array at the same time - let item2 = { - uid : 2, - item : item1, - items : [item1], - otherItem: item1 - }; - One.put(item2); - - let editable2 = One.getEdit(2); - editable2.otherItem = { - uid: 1, - val: "two" - }; - One.put(editable2); - - let result = One.get(item2); - expect(result.item.val).to.equal("two"); - expect(result.items[0].val).to.equal("two"); - }); - it("puts array of entities in one cache update", function () { let arr = [{uid: 1}, {uid: 2}, {uid: 3}]; One.put(arr); @@ -586,6 +612,7 @@ describe("One", function () { // change item 1 and make sure it modified in item2 on current state but not previous item1 = One.getEdit(item1); item1.text = "text"; + One.put(item1); let result = One.get(2); @@ -854,150 +881,6 @@ describe("One", function () { }); }); - describe("pointer management", function () { - it("updates pointers correctly when putting via an entity reference", function () { - let item1 = {uid: 1}; - let item2 = { - uid : 2, - item: item1 - }; - One.put([item2]); - item1 = One.getEdit(1); - item1.text = "test"; - One.put(item1); - expect(One.size()).to.equal(2); - expect(One.length()).to.equal(2); - let result = One.get(2); - expect(result.item.text).to.equal("test"); - }); - - it("updates pointers deeply when putting via an entity reference", function () { - let item1 = {uid: 1}; - let item2 = { - uid : 2, - item: item1 - } - let item3 = { - uid : 3, - item: item2 - } - One.put(item3); - let cached2 = One.get(2); - let cached3 = One.get(3); - item1 = One.getEdit(1); - item1.text = "test"; - One.put(item1); - let result2 = One.get(2); - expect(cached2 === result2).to.be.false; - expect(result2.item.text).to.equal("test"); - let result3 = One.get(3); - expect(cached3 === result3).to.be.false; - expect(result3.item.item.text).to.equal("test"); - }); - - it("updates pointers deeply when nested inside non uid objects", function () { - let item1 = {uid: 1}; - let item2 = { - uid : 2, - item: { - item: item1 - } - } - One.put(item2); - item1 = One.getEdit(1); - item1.text = "test"; - One.put(item1); - - let result2 = One.get(item2); - - expect(result2 === item2).to.be.false; - expect(result2.item === item2.item).to.be.false; - expect(result2.item.item.text).to.equal("test"); - - // compare to the previous instance of item1 - One.undo(); - let result1 = One.get(1); - expect(result2.item.item === result1).to.be.false; - }); - - it("updates pointers when nested inside arrays", function () { - let item1 = {uid: 1}; - let item2 = { - uid : 2, - items: [item1] - } - One.put(item2); - item1 = One.getEdit(1); - item1.text = "test"; - One.put(item1); - - ; - - let result2 = One.get(2); - expect(result2.items[0].text).to.equal("test"); - - }); - - it("updates pointers deeply when nested inside arrays", function () { - let item1 = {uid: 1}; - let item2 = { - uid : 2, - items: [ - [item1] - ] - }; - One.put(item2); - item1 = One.getEdit(item1); - item1.text = "test"; - One.put(item1); - ; - let result = One.get(2); - expect(result.items[0][0].text).to.equal("test"); - One.undo(); - let result1 = One.get(1); - expect(result.items[0][0] === result1).to.be.false; - }); - - it("updates multiple pointer references", function () { - let item1 = {uid: 1}; - let item2 = { - uid : 2, - item: item1 - }; - let item3 = { - uid : 3, - items: [item1] - }; - One.put([item2, item3, item3]); - - item1 = One.getEdit(item1); - expect(Object.isFrozen(item1)).to.be.false; - let item4 = { - uid: 4 - }; - item1.item = item4; - expect(item1.item).to.not.be.undefined; - One.put(item1); - - // check updates to the parent enitities - let result2 = One.get(2); - expect(result2.item.item.uid).to.equal(4); - let result3 = One.get(3); - expect(result3.items[0].item.uid).to.equal(4); - - item4 = One.getEdit(4); - item4.text = "standard"; - One.put(item4); - - result2 = One.get(2); - result3 = One.get(3); - expect(result2.item.item.text).to.equal("standard"); - expect(result3.items[0].item.text).to.equal("standard"); - let result1 = One.get(1); - expect(result1.item.text).to.equal("standard"); - }) - }); - describe("get", function () { it("gets an entire array by uid", function () { let item1 = {uid: 1}; @@ -1213,35 +1096,6 @@ describe("One", function () { expect(One.refTo(2)["1"]).to.be.undefined; }); - it("updates pointers array when putting through another entity", function () { - let item1 = {uid: 1}; - let item = { - uid : 2, - item: item1 - }; - One.put(item); //1 - let item3 = { - uid : 3, - item: item1 - }; - One.put(item3); //2 - One.evict(item);//3 - expect(One.length()).to.equal(3); - expect(One.size()).to.equal(2); // item1, item3 - expect(One.contains(item1)).to.be.true; - expect(One.contains(item3)).to.be.true; - - One.evict(1); - - expect(One.length()).to.equal(4); - expect(One.size()).to.equal(1); - expect(One.contains(item3)).to.be.true; - expect(One.contains(item1)).to.be.false; - - let result = One.get(3); - expect(result.item).to.be.undefined; - }); - it("removes entity if is last reference when putting entity with removed reference", function () { let item1 = {uid: 1}; let item3 = { @@ -1365,22 +1219,6 @@ describe("One", function () { expect(items.length).to.equal(2); }); - it("keeps previous version pointers when it updates the new ones", function () { - let item1 = {uid: 1}; - One.put(item1); - let item = { - uid : 2, - item: item1 - } - One.put(item); - let resultOne = One.get(1); - // rewind one and check again - One.undo(); - expect(One.contains(2)).to.be.false; - let resultTwo = One.get(1); - expect(resultOne === resultTwo).to.be.true; - }) - it("creates new entity when updating through a referenced entity", function () { let item1 = {uid: 1}; One.put(item1); @@ -1425,57 +1263,6 @@ describe("One", function () { expect(One.get(3)).to.be.undefined; }) - it("leaves previous pointer set intact when entity is evicted on current state", function () { - let item1 = {uid: 1}; - let item2 = {uid: 2, item: item1}; - One.put(item2); - - let item3 = {uid: 3, item: item1}; - One.put(item3); - - One.evict(1); - expect(One.length()).to.equal(3); - expect(One.size()).to.equal(2); - expect(One.get(1)).to.be.undefined; - expect(One.get(2)).to.not.be.undefined; - expect(One.get(3)).to.not.be.undefined; - - One.undo(); - expect(One.get(1)).to.not.be.undefined; - - // verify pointers - One.evict(item2); - expect(One.length()).to.equal(3); - expect(One.size()).to.equal(2); - expect(One.get(1)).to.not.be.undefined; - expect(One.get(2)).to.be.undefined; - expect(One.get(3)).to.not.be.undefined; - - One.evict(item3); - expect(One.length()).to.equal(4); - expect(One.size()).to.equal(0); - }) - - it("removes with pointers inside array", function () { - let item1 = {uid: 1}; - let item2 = {uid: 2, items: [item1]}; - let item3 = {uid: 3}; - One.put(item2); - One.put(item3); - One.evict(item2); - expect(One.length()).to.equal(3); - expect(One.size()).to.equal(1); - }); - - it("removes with pointers deeply nested inside objects", function () { - let item1 = {uid: 1}; - let item2 = {uid: 2, item: {nested: item1}}; - One.put(item2); - One.evict(item2); - expect(One.length()).to.equal(2); - expect(One.size()).to.equal(0); - }); - it("removes the referenced property from the pulled item " + "if its corresponding uid value has been evicted", function () { // this is ONLY when a reference is evicted directly (item is deleted), if it is the child of an evicted @@ -1543,94 +1330,6 @@ describe("One", function () { // One.print(); }); }); - - describe("clear", function () { - it("clears the cache", function () { - let item1 = {uid: 1}; - let item2 = {uid: 2}; - let item3 = { - uid : 3, - item: item1 - }; - One.put(item3); - One.put(item2); - One.reset(); - expect(One.size()).to.equal(0); - expect(One.length()).to.equal(0); - }) - }); - - describe("config", function () { - it("sets the config correctly", function () { - expect(config.prop.uidName).to.equal("uid"); - expect(config.prop.maxHistoryStates).to.equal(1000); - - let newConfig = { - uidName : "uniqueId", - maxHistoryStates: 20 - }; - One.config(newConfig); - expect(config.prop.maxHistoryStates).to.equal(20); - expect(config.prop.uidName).to.equal("uniqueId"); - }); - - it("fails to set config if there are items in the cache", function () { - let a = {uid: 1}; - One.put(a); - let config = { - uidName: "uuid" - } - expect(() => { - One.config(config) - }).to.throw(Error); - }); - - it("it configures a cleared cache", function () { - let a = {uid: 1}; - One.put(a); - One.reset(); - let conf = { - uidName: "uniqueId" - }; - One.config(conf); - expect(config.prop.uidName).to.equal("uniqueId"); - }); - - //it("maintains the correct number of configured history states", function () { - // expect(0, "Not impletmented").to.equal(1); - //}); - }); - - describe("print", function () { - it("prints", function () { - let item = {uid:1}; - let item2 = { - uid:2, - child: item - }; - One.put(item2); - expect(One.get(1)).to.not.be.undefined; - expect(One.print()).to.be.undefined; - }); - - it("prints empty", function(){ - expect(() => {One.print()}).to.not.throw(Error); - }) - }); - - describe("dirty", function () { - it("reads non uid item as dirty", function () { - expect(One.isDirty({})).to.be.true; - expect(One.isDirty({}, 1)).to.be.true; - }) - - }) - - describe("uid", function () { - it("creates uid", function () { - expect(One.uuid()).to.not.be.undefined; - }) - }) }); diff --git a/test/notify-test.js b/test/notify-test.js index 351b63b..651f01e 100644 --- a/test/notify-test.js +++ b/test/notify-test.js @@ -89,7 +89,7 @@ describe("Notify", function () { One.evict(2); expect(listener1).to.have.been.calledTwice; expect(listener2).to.have.been.calledOnce; - }); + }) it("notifies when changing the index", function () { One.put({uid: 1}); diff --git a/test/queue-test.js b/test/queue-test.js index 8508a38..4e52cec 100644 --- a/test/queue-test.js +++ b/test/queue-test.js @@ -404,6 +404,16 @@ describe("Queue", function () { expect(One.pending().queue).to.equal(0); let result = One.get(1); expect(item1 === result).to.be.true; + }); + + it("clears the queue on commit", function () { + One.queue({uid: 1}); + One.queue({uid: 2}); + One.commit(); + expect(One.getQueued(1)).to.be.undefined; + expect(One.getQueued(2)).to.be.undefined; + expect(One.get(1)).to.not.be.undefined; + expect(One.get(2)).to.not.be.undefined; }) }); diff --git a/test/ref-test.js b/test/ref-test.js new file mode 100644 index 0000000..833529b --- /dev/null +++ b/test/ref-test.js @@ -0,0 +1,301 @@ +/** + * Created by maierdesign on 12/20/15. + */ +import { + expect, + sinon, + print, + contains +} from './test_helper'; +import createCache from '../src/cache'; +import * as config from '../src/utils/config'; +import {deepClone, isArray} from '../src/utils/clone'; +import * as path from "../src/utils/path"; +import {describe, it} from 'mocha/lib/mocha.js'; + +describe("References", function () { + + "use strict"; + + let One; + + function printCache() { + print(One, "CACHE"); + } + + beforeEach(function () { + One = createCache(true); + // reset config before each call + One.config({ + uidName : "uid", + maxHistoryStates: 1000 + }) + }); + + afterEach(function () { + One.reset(); + }); + + it("updates pointers correctly when putting via an entity reference", function () { + let item1 = {uid: 1}; + let item2 = { + uid : 2, + item: item1 + }; + One.put([item2]); + item1 = One.getEdit(1); + item1.text = "test"; + One.put(item1); + expect(One.size()).to.equal(2); + expect(One.length()).to.equal(2); + let result = One.get(2); + expect(result.item.text).to.equal("test"); + }); + + it("updates pointers deeply when putting via an entity reference", function () { + let item1 = {uid: 1}; + let item2 = { + uid : 2, + item: item1 + } + let item3 = { + uid : 3, + item: item2 + } + One.put(item3); + let cached2 = One.get(2); + let cached3 = One.get(3); + item1 = One.getEdit(1); + item1.text = "test"; + One.put(item1); + let result2 = One.get(2); + expect(cached2 === result2).to.be.false; + expect(result2.item.text).to.equal("test"); + let result3 = One.get(3); + expect(cached3 === result3).to.be.false; + expect(result3.item.item.text).to.equal("test"); + }); + + it("updates pointers deeply when nested inside non uid objects", function () { + let item1 = {uid: 1}; + let item2 = { + uid : 2, + item: { + item: item1 + } + } + One.put(item2); + item1 = One.getEdit(1); + item1.text = "test"; + One.put(item1); + + let result2 = One.get(item2); + + expect(result2 === item2).to.be.false; + expect(result2.item === item2.item).to.be.false; + expect(result2.item.item.text).to.equal("test"); + + // compare to the previous instance of item1 + One.undo(); + let result1 = One.get(1); + expect(result2.item.item === result1).to.be.false; + }); + + it("updates pointers when nested inside arrays", function () { + let item1 = {uid: 1}; + let item2 = { + uid : 2, + items: [item1] + } + One.put(item2); + item1 = One.getEdit(1); + item1.text = "test"; + One.put(item1); + + ; + + let result2 = One.get(2); + expect(result2.items[0].text).to.equal("test"); + + }); + + it("updates pointers deeply when nested inside arrays", function () { + let item1 = {uid: 1}; + let item2 = { + uid : 2, + items: [ + [item1] + ] + }; + One.put(item2); + item1 = One.getEdit(item1); + item1.text = "test"; + One.put(item1); + ; + let result = One.get(2); + expect(result.items[0][0].text).to.equal("test"); + One.undo(); + let result1 = One.get(1); + expect(result.items[0][0] === result1).to.be.false; + }); + + it("keeps previous version pointers when it updates the new ones", function () { + let item1 = {uid: 1}; + One.put(item1); + let item = { + uid : 2, + item: item1 + }; + One.put(item); + let resultOne = One.get(1); + // rewind one and check again + One.undo(); + expect(One.contains(2)).to.be.false; + let resultTwo = One.get(1); + expect(resultOne === resultTwo).to.be.true; + }); + + it("leaves previous pointer set intact when entity is evicted on current state", function () { + let item1 = {uid: 1}; + let item2 = {uid: 2, item: item1}; + One.put(item2); + + let item3 = {uid: 3, item: item1}; + One.put(item3); + + One.evict(1); + expect(One.length()).to.equal(3); + expect(One.size()).to.equal(2); + expect(One.get(1)).to.be.undefined; + expect(One.get(2)).to.not.be.undefined; + expect(One.get(3)).to.not.be.undefined; + + One.undo(); + expect(One.get(1)).to.not.be.undefined; + + // verify pointers + One.evict(item2); + expect(One.length()).to.equal(3); + expect(One.size()).to.equal(2); + expect(One.get(1)).to.not.be.undefined; + expect(One.get(2)).to.be.undefined; + expect(One.get(3)).to.not.be.undefined; + + One.evict(item3); + expect(One.length()).to.equal(4); + expect(One.size()).to.equal(0); + }); + + it("updates entity in other reference pointer on same entity", function () { + let item1 = {uid: 1, val: "one"}; + // test object ref AND array at the same time + let item2 = { + uid : 2, + item : item1, + items : [item1], + otherItem: item1 + }; + One.put(item2); + + let editable2 = One.getEdit(2); + editable2.otherItem = { + uid: 1, + val: "two" + }; + One.put(editable2); + + let result = One.get(item2); + expect(result.item.val).to.equal("two"); + expect(result.items[0].val).to.equal("two"); + }); + + it("updates pointers array when putting through another entity", function () { + let item1 = {uid: 1}; + let item = { + uid : 2, + item: item1 + }; + One.put(item); //1 + let item3 = { + uid : 3, + item: item1 + }; + One.put(item3); //2 + One.evict(item);//3 + expect(One.length()).to.equal(3); + expect(One.size()).to.equal(2); // item1, item3 + expect(One.contains(item1)).to.be.true; + expect(One.contains(item3)).to.be.true; + + One.evict(1); + + expect(One.length()).to.equal(4); + expect(One.size()).to.equal(1); + expect(One.contains(item3)).to.be.true; + expect(One.contains(item1)).to.be.false; + + let result = One.get(3); + expect(result.item).to.be.undefined; + }); + + it("removes with pointers inside array", function () { + let item1 = {uid: 1}; + let item2 = {uid: 2, items: [item1]}; + let item3 = {uid: 3}; + One.put(item2); + One.put(item3); + One.evict(item2); + expect(One.length()).to.equal(3); + expect(One.size()).to.equal(1); + }); + + it("removes with pointers deeply nested inside objects", function () { + let item1 = {uid: 1}; + let item2 = {uid: 2, item: {nested: item1}}; + One.put(item2); + One.evict(item2); + expect(One.length()).to.equal(2); + expect(One.size()).to.equal(0); + }); + + it("updates multiple pointer references", function () { + let item1 = {uid: 1}; + let item2 = { + uid : 2, + item: item1 + }; + let item3 = { + uid : 3, + items: [item1] + }; + One.put([item2, item3, item3]); + + item1 = One.getEdit(item1); + expect(Object.isFrozen(item1)).to.be.false; + let item4 = { + uid: 4 + }; + item1.item = item4; + expect(item1.item).to.not.be.undefined; + One.put(item1); + + // check updates to the parent enitities + let result2 = One.get(2); + expect(result2.item.item.uid).to.equal(4); + let result3 = One.get(3); + expect(result3.items[0].item.uid).to.equal(4); + + item4 = One.getEdit(4); + item4.text = "standard"; + One.put(item4); + + result2 = One.get(2); + result3 = One.get(3); + expect(result2.item.item.text).to.equal("standard"); + expect(result3.items[0].item.text).to.equal("standard"); + let result1 = One.get(1); + expect(result1.item.text).to.equal("standard"); + }) +}); + + diff --git a/test/utils-test.js b/test/utils-test.js index 10b4517..c3c99c1 100644 --- a/test/utils-test.js +++ b/test/utils-test.js @@ -9,6 +9,8 @@ import { print, contains } from './test_helper'; +import createCache from '../src/cache'; +import * as config from '../src/utils/config'; import deepFreeze from '../src/utils/deepFreeze' import {deepClone, isArray, hasUid} from '../src/utils/clone'; import {describe, it} from 'mocha/lib/mocha.js'; @@ -17,12 +19,19 @@ describe("Utils", function () { "use strict"; - beforeEach(function () { + let One; + beforeEach(function () { + One = createCache(true); + // reset config before each call + One.config({ + uidName : "uid", + maxHistoryStates: 1000 + }) }); afterEach(function () { - + One.reset(); }); function getTestObj() { @@ -124,9 +133,17 @@ describe("Utils", function () { expect(result.arr[3][1].date.getTime()).to.equal(date.getTime()); }); + it("returns the object when cloning with replace of itself", function(){ + let item1 = {uid:1}; + let result = deepClone(item1, item1, false); + expect(item1 === result).to.be.true; + }); + it("should replace item not freeze", function () { let obj = getTestObj(); + expect(Object.isFrozen(obj.c)).to.be.false; let result = deepClone(obj, {uid: 1, text: "test"}, false); + expect(result.c).to.not.be.undefined; expect(Object.isFrozen(result.c)).to.be.false; expect(result.c.text).to.equal("test"); @@ -137,6 +154,96 @@ describe("Utils", function () { expect(hasUid({})).to.be.false; }) }); + + describe("clear", function () { + it("clears the cache", function () { + let item1 = {uid: 1}; + let item2 = {uid: 2}; + let item3 = { + uid : 3, + item: item1 + }; + One.put(item3); + One.put(item2); + One.reset(); + expect(One.size()).to.equal(0); + expect(One.length()).to.equal(0); + }) + }); + + describe("config", function () { + it("sets the config correctly", function () { + expect(config.prop.uidName).to.equal("uid"); + expect(config.prop.maxHistoryStates).to.equal(1000); + + let newConfig = { + uidName : "uniqueId", + maxHistoryStates: 20 + }; + One.config(newConfig); + expect(config.prop.maxHistoryStates).to.equal(20); + expect(config.prop.uidName).to.equal("uniqueId"); + }); + + it("fails to set config if there are items in the cache", function () { + let a = {uid: 1}; + One.put(a); + let config = { + uidName: "uuid" + } + expect(() => { + One.config(config) + }).to.throw(Error); + }); + + it("it configures a cleared cache", function () { + let a = {uid: 1}; + One.put(a); + One.reset(); + let conf = { + uidName: "uniqueId" + }; + One.config(conf); + expect(config.prop.uidName).to.equal("uniqueId"); + }); + + //it("maintains the correct number of configured history states", function () { + // expect(0, "Not impletmented").to.equal(1); + //}); + }); + + describe("print", function () { + it("prints", function () { + let item = {uid: 1}; + let item2 = { + uid : 2, + child: item + }; + One.put(item2); + expect(One.get(1)).to.not.be.undefined; + expect(One.print()).to.be.undefined; + }); + + it("prints empty", function () { + expect(() => { + One.print() + }).to.not.throw(Error); + }) + }); + + describe("dirty", function () { + it("reads non uid item as dirty", function () { + expect(One.isDirty({})).to.be.true; + expect(One.isDirty({}, 1)).to.be.true; + }) + + }) + + describe("uid", function () { + it("creates uid", function () { + expect(One.uuid()).to.not.be.undefined; + }) + }) });