From 4f245fb42898c73bc5d107222946601b34efaf73 Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Tue, 24 Sep 2013 00:25:42 -0600 Subject: [PATCH 1/8] Added BinaryHeap class. --- demo/demo.js | 2 +- src/angular-cache.js | 177 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 176 insertions(+), 3 deletions(-) diff --git a/demo/demo.js b/demo/demo.js index 2285775..25fcea6 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -141,7 +141,7 @@ app.service('DemoService', function ($log, $angularCacheFactory) { storageMode: 'localStorage', deleteOnExpire: 'none' }), - $angularCacheFactory('maxAgeCache', { + $angularCacheFactory('passiveDeleteCache', { maxAge: 12000, deleteOnExpire: 'passive', onExpire: function (key, value, done) { diff --git a/src/angular-cache.js b/src/angular-cache.js index 8cd5bfe..195cfd9 100644 --- a/src/angular-cache.js +++ b/src/angular-cache.js @@ -11,6 +11,173 @@ (function (window, angular, undefined) { 'use strict'; + angular.module('jmdobry.binary-heap', []); + + /** + * @class BinaryHeapProvider + * @desc Provider for the BinaryHeap. + */ + function BinaryHeapProvider() { + this.$get = function () { + /** + * @class BinaryHeap + * @desc BinaryHeap implementation of a priority queue. + * @param {Function} weightFunc Function that determines how each node should be weighted. + */ + function BinaryHeap(weightFunc) { + this.heap = []; + this.weightFunc = weightFunc; + } + + /** + * @method BinaryHeap.push + * @desc Push an element into the binary heap. + * @param {*} node The element to push into the binary heap. + * @public + */ + BinaryHeap.prototype.push = function (node) { + this.heap.push(node); + this.bubbleUp(this.heap.length - 1); + }; + + /** + * @method BinaryHeap.peek + * @desc Return, but do not remove, the minimum element in the binary heap. + * @returns {*} + * @public + */ + BinaryHeap.prototype.peek = function () { + return this.heap[0]; + }; + + /** + * @method BinaryHeap.pop + * @desc Remove and return the minimum element in the binary heap. + * @returns {*} + * @public + */ + BinaryHeap.prototype.pop = function () { + var front = this.heap[0], + end = this.heap.pop(); + if (this.heap.length > 0) { + this.heap[0] = end; + this.sinkDown(0); + } + return front; + }; + + /** + * @method BinaryHeap.remove + * @desc Remove the first node in the priority queue that satisfies angular.equals comparison with + * the given node. + * @param {*} node The node to remove. + * @returns {*} The removed node. + * @public + */ + BinaryHeap.prototype.remove = function (node) { + var length = this.heap.length; + for (var i = 0; i < length; i++) { + if (angular.equals(this.heap[i], node)) { + var removed = this.heap[i], + end = this.heap.pop(); + if (i !== length - 1) { + this.heap[i] = end; + this.bubbleUp(i); + this.sinkDown(i); + } + return removed; + } + } + return null; + }; + + /** + * @method BinaryHeap.size + * @desc Return the size of the priority queue. + * @returns {Number} The size of the priority queue. + * @public + */ + BinaryHeap.prototype.size = function () { + return this.heap.length; + }; + + /** + * @method BinaryHeap.bubbleUp + * @param {Number} n The index of the element to bubble up. + * @ignore + */ + BinaryHeap.prototype.bubbleUp = function (n) { + // Fetch the element that has to be moved. + var element = this.heap[n], + weight = this.weightFunc(element); + // When at 0, an element can not go up any further. + while (n > 0) { + // Compute the parent element's index, and fetch it. + var parentN = Math.floor((n + 1) / 2) - 1, + parent = this.heap[parentN]; + // If the parent has a lesser weight, things are in order and we + // are done. + if (weight >= this.weightFunc(parent)) { + break; + } else { + this.heap[parentN] = element; + this.heap[n] = parent; + n = parentN; + } + } + }; + + /** + * @method BinaryHeap.sinkDown + * @param {Number} n The index of the element to sink down. + * @ignore + */ + BinaryHeap.prototype.sinkDown = function (n) { + var length = this.heap.length, + node = this.heap[n], + nodeWeight = this.weightFunc(node); + + while (true) { + // Compute the indices of the child nodes. + var child2N = (n + 1) * 2, child1N = child2N - 1; + // This is used to store the new position of the node, + // if any. + var swap = null; + // If the first child exists (is inside the array)... + if (child1N < length) { + // Look it up and compute its score. + var child1 = this.heap[child1N], + child1Weight = this.weightFunc(child1); + // If the score is less than our node's, we need to swap. + if (child1Weight < nodeWeight) { + swap = child1N; + } + } + // Do the same checks for the other child. + if (child2N < length) { + var child2 = this.heap[child2N], + child2Weight = this.weightFunc(child2); + if (child2Weight < (swap === null ? nodeWeight : child1Weight)) { + swap = child2N; + } + } + + if (swap === null) { + break; + } else { + this.heap[n] = this.heap[swap]; + this.heap[swap] = node; + n = swap; + } + } + }; + + return BinaryHeap; + }; + } + + angular.module('jmdobry.binary-heap').provider('BinaryHeap', BinaryHeapProvider); + /** * @module angular-cache * @desc Provides an $AngularCacheFactoryProvider, which gives you the ability to use an @@ -18,7 +185,7 @@ * the same abilities as the cache objects that come with Angular, except with some added * functionality. */ - angular.module('jmdobry.angular-cache', ['ng']); + angular.module('jmdobry.angular-cache', ['ng', 'jmdobry.binary-heap']); /** * @class $AngularCacheFactoryProvider @@ -137,7 +304,7 @@ /** * @ignore */ - this.$get = ['$timeout', '$window', function ($timeout, $window) { + this.$get = ['$timeout', '$window', 'BinaryHeap', function ($timeout, $window, BinaryHeap) { var caches = {}; /** @@ -185,6 +352,9 @@ config = angular.extend({}, { id: cacheId }), data = {}, lruHash = {}, + heap = new BinaryHeap(function (x) { + return x.expires; + }), freshEnd = null, staleEnd = null, prefix = 'angular-cache.caches.' + cacheId, @@ -209,6 +379,7 @@ if (data[key]) { value = data[key].value; } + heap.remove(data[key]); self.remove(key); if (config.onExpire) { config.onExpire(key, value); @@ -587,6 +758,8 @@ if (data[key] || config.maxAge) { if ((data[key].deleteOnExpire === 'aggressive' || config.deleteOnExpire === 'aggressive') && (data[key].maxAge || config.maxAge)) { + data[key].expires = data[key].timestamp + (data[key].maxAge || config.maxAge); + heap.push(data[key]); _setTimeoutToRemove(key, data[key].maxAge || config.maxAge); } } From 5b545c469c6dee73bdb2b08798d87c54042c9040 Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Tue, 24 Sep 2013 13:19:31 -0600 Subject: [PATCH 2/8] Finished AngularCache.put() using new BinaryHeaps. #28 --- src/angular-cache.js | 207 +++++++++++++++---------------------------- 1 file changed, 71 insertions(+), 136 deletions(-) diff --git a/src/angular-cache.js b/src/angular-cache.js index 195cfd9..f610076 100644 --- a/src/angular-cache.js +++ b/src/angular-cache.js @@ -23,10 +23,12 @@ * @class BinaryHeap * @desc BinaryHeap implementation of a priority queue. * @param {Function} weightFunc Function that determines how each node should be weighted. + * @param {Boolean} reverse Whether to reverse the ordering of the binary heap. */ - function BinaryHeap(weightFunc) { + function BinaryHeap(weightFunc, reverse) { this.heap = []; this.weightFunc = weightFunc; + this.reverse = reverse; } /** @@ -51,12 +53,12 @@ }; /** - * @method BinaryHeap.pop + * @method BinaryHeap.removeMin * @desc Remove and return the minimum element in the binary heap. * @returns {*} * @public */ - BinaryHeap.prototype.pop = function () { + BinaryHeap.prototype.removeMin = function () { var front = this.heap[0], end = this.heap.pop(); if (this.heap.length > 0) { @@ -107,7 +109,6 @@ * @ignore */ BinaryHeap.prototype.bubbleUp = function (n) { - // Fetch the element that has to be moved. var element = this.heap[n], weight = this.weightFunc(element); // When at 0, an element can not go up any further. @@ -138,14 +139,10 @@ nodeWeight = this.weightFunc(node); while (true) { - // Compute the indices of the child nodes. - var child2N = (n + 1) * 2, child1N = child2N - 1; - // This is used to store the new position of the node, - // if any. + var child2N = (n + 1) * 2, + child1N = child2N - 1; var swap = null; - // If the first child exists (is inside the array)... if (child1N < length) { - // Look it up and compute its score. var child1 = this.heap[child1N], child1Weight = this.weightFunc(child1); // If the score is less than our node's, we need to swap. @@ -352,9 +349,12 @@ config = angular.extend({}, { id: cacheId }), data = {}, lruHash = {}, - heap = new BinaryHeap(function (x) { + expiresHeap = new BinaryHeap(function (x) { return x.expires; }), + lruHeap = new BinaryHeap(function (x) { + return x.accessed; + }), freshEnd = null, staleEnd = null, prefix = 'angular-cache.caches.' + cacheId, @@ -379,7 +379,7 @@ if (data[key]) { value = data[key].value; } - heap.remove(data[key]); + expiresHeap.remove(data[key]); self.remove(key); if (config.onExpire) { config.onExpire(key, value); @@ -611,47 +611,6 @@ cacheDirty = true; } - /** - * @method refresh - * @desc Makes the `entry` the freshEnd of the LRU linked list. - * @param {Object} entry - * @private - * @ignore - */ - function _refresh(entry) { - if (entry !== freshEnd) { - if (!staleEnd) { - staleEnd = entry; - } else if (staleEnd === entry) { - staleEnd = entry.n; - } - - _link(entry.n, entry.p); - _link(entry, freshEnd); - freshEnd = entry; - freshEnd.n = null; - } - } - - /** - * @method link - * @desc Bidirectionally links two entries of the LRU linked list - * @param {Object} nextEntry - * @param {Object} prevEntry - * @private - * @ignore - */ - function _link(nextEntry, prevEntry) { - if (nextEntry !== prevEntry) { - if (nextEntry) { - nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify - } - if (prevEntry) { - prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify - } - } - } - /** * @method _loadCacheConfig * @desc If storageMode is set, attempt to load previous cache configuration from localStorage. @@ -706,68 +665,62 @@ * @desc Add a key-value pair with timestamp to the cache. * @param {String} key The identifier for the item to add to the cache. * @param {*} value The value of the item to add to the cache. - * @param {Object} [options] {{ maxAge: {Number}, aggressiveDelete: {Boolean}, timestamp: {Number} }} + * @param {Object} [options] {{ maxAge: {Number}, deleteOnExpire: {String} }} * @returns {*} value The value of the item added to the cache. * @privileged */ this.put = function (key, value, options) { - if (!angular.isString(key)) { - throw new Error('AngularCache.put(): key: must be a string!'); - } - if (options && options.maxAge) { + throw new Error('AngularCache.put(key, value, options): key: must be a string!'); + } else if (options && options.maxAge && options.maxAge !== null) { _validateNumberOption(options.maxAge, function (err) { if (err) { - throw new Error('AngularCache.put(): maxAge: ' + err); + throw new Error('AngularCache.put(key, value, options): maxAge: ' + err); } }); - } - if (options && options.deleteOnExpire) { - if (!angular.isString(options.deleteOnExpire)) { - throw new Error('AngularCache.put(): deleteOnExpire: must be a string!'); - } - } - if (angular.isUndefined(value)) { + } else if (options && options.deleteOnExpire && !angular.isString(options.deleteOnExpire)) { + throw new Error('AngularCache.put(key, value, options): deleteOnExpire: must be a string!'); + } else if (angular.isUndefined(value)) { return; } - var lruEntry = lruHash[key] || (lruHash[key] = {key: key}); - - _refresh(lruEntry); + var now = new Date().getTime(), + deleteOnExpire, item; - if (!(key in data)) { - size++; - } else { - if (data[key].timeoutId) { - $timeout.cancel(data[key].timeoutId); - } - } + data[key] = data[key] || {}; + item = data[key]; - data[key] = { - value: value, - timestamp: (options && options.timestamp) || new Date().getTime() - }; + item.value = value; + item.created = (options && parseInt(options.created, 10)) || item.created || now; + item.modified = (options && parseInt(options.modified, 10)) || now; + item.accessed = (options && parseInt(options.accessed, 10)) || now; if (options && options.deleteOnExpire) { - data[key].deleteOnExpire = options.deleteOnExpire; + item.deleteOnExpire = options.deleteOnExpire; } if (options && options.maxAge) { - data[key].maxAge = options.maxAge; + item.maxAge = options.maxAge; } - if (data[key] || config.maxAge) { - if ((data[key].deleteOnExpire === 'aggressive' || config.deleteOnExpire === 'aggressive') && - (data[key].maxAge || config.maxAge)) { - data[key].expires = data[key].timestamp + (data[key].maxAge || config.maxAge); - heap.push(data[key]); - _setTimeoutToRemove(key, data[key].maxAge || config.maxAge); - } + if (item.maxAge || config.maxAge) { + item.expires = item.created + (item.maxAge || config.maxAge); } - _syncToStorage(key); + deleteOnExpire = item.deleteOnExpire || config.deleteOnExpire; + + if (deleteOnExpire === 'aggressive' && item.expires) { + expiresHeap.push(item); + } - if (size > config.capacity) { - this.remove(staleEnd.key); + if (config.storageMode !== 'none' && storage) { + storage.setItem(prefix + '.keys', angular.toJson(_keys(data))); + storage.setItem(prefix + '.data.' + key, angular.toJson(item)); + } + + lruHeap.push(item); + + if (lruHeap.size() > config.capacity) { + lruHeap.removeMin(); } return value; @@ -783,43 +736,40 @@ * @privileged */ this.get = function (key, onExpire) { - var lruEntry = lruHash[key], - item = data[key], - maxAge, - deleteOnExpire; - - if (!lruEntry || !item) { + if (!angular.isString(key)) { + throw new Error('AngularCache.get(key, onExpire): key: must be a string!'); + } else if (onExpire && typeof onExpire !== 'function') { + throw new Error('AngularCache.get(key, onExpire): onExpire: must be a function!'); + } else if (!(key in data)) { return; } - maxAge = item.maxAge || config.maxAge; - deleteOnExpire = item.deleteOnExpire || config.deleteOnExpire; + var value = data[key].value, + now = new Date().getTime(); - // There is no timeout to delete this item, so we must do it here if it's expired. - if (maxAge && deleteOnExpire === 'passive') { - if ((new Date().getTime() - item.timestamp) > maxAge) { - // This item is expired so remove it - this.remove(key); - lruEntry = null; - - if (config.onExpire) { - config.onExpire(key, item.value, onExpire); - return; - } else if (onExpire && typeof onExpire === 'function') { - onExpire(key, item.value); - return; - } else { - // cache miss - return; - } + data[key].accessed = now; + + if ('expires' in data[key] && data[key].expires < now) { + this.remove(key); + if (config.storageMode !== 'none' && storage) { + storage.setItem(prefix + '.keys', angular.toJson(_keys(data))); + storage.removeItem(prefix + '.data.' + key); } - } - _refresh(lruEntry); + if (config.onExpire) { + config.onExpire(key, data[key].value, onExpire); + } else if (onExpire && typeof onExpire === 'function') { + onExpire(key, data[key].value); + } + value = undefined; + } - _syncToStorage(key); + if (config.storageMode !== 'none' && storage) { + storage.setItem(prefix + '.keys', angular.toJson(_keys(data))); + storage.setItem(prefix + '.data.' + key, angular.toJson(data[key])); + } - return item.value; + return value; }; /** @@ -829,21 +779,6 @@ * @privileged */ this.remove = function (key) { - var lruEntry = lruHash[key]; - - if (!lruEntry) { - return; - } - - if (lruEntry === freshEnd) { - freshEnd = lruEntry.p; - } - if (lruEntry === staleEnd) { - staleEnd = lruEntry.n; - } - _link(lruEntry.n, lruEntry.p); - - delete lruHash[key]; delete data[key]; _syncToStorage(null); From 708dcb3f11586767f673fe482d8f29f78462fe8b Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Tue, 24 Sep 2013 19:46:34 -0600 Subject: [PATCH 3/8] Completed most of refactor using new BinaryHeaps. Started re-write of unit tests. --- karma.conf.js | 1 + src/angular-cache.js | 327 ++-- test/angularCacheFactory-test.js | 234 +++ test/angularCacheFactory.clearAll-test.js | 22 + test/angularCacheFactory.get-test.js | 24 + test/angularCacheFactory.info-test.js | 33 + test/angularCacheFactory.keySet-test.js | 29 + test/angularCacheFactory.keys-test.js | 23 + test/angularCacheFactory.removeAll-test.js | 33 + test/angularCacheFactorySpec.js | 379 ----- test/angularCacheSpec.js | 1660 ++++++++++---------- test/karma.start.js | 28 + 12 files changed, 1467 insertions(+), 1326 deletions(-) create mode 100644 test/angularCacheFactory-test.js create mode 100644 test/angularCacheFactory.clearAll-test.js create mode 100644 test/angularCacheFactory.get-test.js create mode 100644 test/angularCacheFactory.info-test.js create mode 100644 test/angularCacheFactory.keySet-test.js create mode 100644 test/angularCacheFactory.keys-test.js create mode 100644 test/angularCacheFactory.removeAll-test.js delete mode 100644 test/angularCacheFactorySpec.js create mode 100644 test/karma.start.js diff --git a/karma.conf.js b/karma.conf.js index 2777487..7c13c4a 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -11,6 +11,7 @@ module.exports = function (config) { 'test/vendor/angular-1.1.5.min.js', 'test/vendor/angular-mocks-1.1.5.js', 'src/angular-cache.js', + 'test/karma.start.js', 'test/*.js' ], logLevel: config.LOG_DEBUG, diff --git a/src/angular-cache.js b/src/angular-cache.js index f610076..2691071 100644 --- a/src/angular-cache.js +++ b/src/angular-cache.js @@ -23,12 +23,10 @@ * @class BinaryHeap * @desc BinaryHeap implementation of a priority queue. * @param {Function} weightFunc Function that determines how each node should be weighted. - * @param {Boolean} reverse Whether to reverse the ordering of the binary heap. */ - function BinaryHeap(weightFunc, reverse) { + function BinaryHeap(weightFunc) { this.heap = []; this.weightFunc = weightFunc; - this.reverse = reverse; } /** @@ -93,6 +91,15 @@ return null; }; + /** + * @method BinaryHeap.removeAll + * @desc Remove all nodes from this BinaryHeap. + * @public + */ + BinaryHeap.prototype.removeAll = function () { + this.heap = []; + }; + /** * @method BinaryHeap.size * @desc Return the size of the priority queue. @@ -154,7 +161,7 @@ if (child2N < length) { var child2 = this.heap[child2N], child2Weight = this.weightFunc(child2); - if (child2Weight < (swap === null ? nodeWeight : child1Weight)) { + if (child2Weight < (swap === null ? nodeWeight : this.weightFunc(this.heap[child1N]))) { swap = child2N; } } @@ -199,8 +206,10 @@ deleteOnExpire: 'none', onExpire: null, cacheFlushInterval: null, + recycleFreq: 1000, storageMode: 'none', - storageImpl: null + storageImpl: null, + verifyIntegrity: true }; }; @@ -229,32 +238,41 @@ * @privileged */ this.setCacheDefaults = function (options) { + var errStr = '$angularCacheFactoryProvider.setCacheDefaults(options): '; options = options || {}; if (!angular.isObject(options)) { - throw new Error('setOptions(): options: must be an object!'); + throw new Error(errStr + 'options: must be an object!'); } if ('capacity' in options) { _validateNumberOption(options.capacity, function (err) { if (err) { - throw new Error('setCacheDefaults(): capacity: ' + err); + throw new Error(errStr + 'capacity: ' + err); } }); } if ('deleteOnExpire' in options) { if (!angular.isString(options.deleteOnExpire)) { - throw new Error('setCacheDefaults(): deleteOnExpire: must be a string!'); + throw new Error(errStr + 'deleteOnExpire: must be a string!'); } else if (options.deleteOnExpire !== 'none' && options.deleteOnExpire !== 'passive' && options.deleteOnExpire !== 'aggressive') { - throw new Error('setCacheDefaults(): deleteOnExpire: accepted values are "none", "passive" or "aggressive"!'); + throw new Error(errStr + 'deleteOnExpire: accepted values are "none", "passive" or "aggressive"!'); } } if ('maxAge' in options) { _validateNumberOption(options.maxAge, function (err) { if (err) { - throw new Error('setCacheDefaults(): maxAge: ' + err); + throw new Error(errStr + 'maxAge: ' + err); + } + }); + } + + if ('recycleFreq' in options) { + _validateNumberOption(options.recycleFreq, function (err) { + if (err) { + throw new Error(errStr + 'recycleFreq: ' + err); } }); } @@ -262,33 +280,33 @@ if ('cacheFlushInterval' in options) { _validateNumberOption(options.cacheFlushInterval, function (err) { if (err) { - throw new Error('setCacheDefaults(): cacheFlushInterval: ' + err); + throw new Error(errStr + 'cacheFlushInterval: ' + err); } }); } if ('storageMode' in options) { if (!angular.isString(options.storageMode)) { - throw new Error('setCacheDefaults(): storageMode: must be a string!'); + throw new Error(errStr + 'storageMode: must be a string!'); } else if (options.storageMode !== 'none' && options.storageMode !== 'localStorage' && options.storageMode !== 'sessionStorage') { - throw new Error('setCacheDefaults(): storageMode: accepted values are "none", "localStorage" or "sessionStorage"'); + throw new Error(errStr + 'storageMode: accepted values are "none", "localStorage" or "sessionStorage"'); } if ('storageImpl' in options) { if (!angular.isObject(options.storageImpl)) { - throw new Error('setCacheDefaults(): [local|session]storageImpl: must be an object!'); + throw new Error(errStr + '[local|session]storageImpl: must be an object!'); } else if (!('setItem' in options.storageImpl) || typeof options.storageImpl.setItem !== 'function') { - throw new Error('setCacheDefaults(): [local|session]storageImpl: must implement "setItem(key, value)"!'); + throw new Error(errStr + '[local|session]storageImpl: must implement "setItem(key, value)"!'); } else if (!('getItem' in options.storageImpl) || typeof options.storageImpl.getItem !== 'function') { - throw new Error('setCacheDefaults(): [local|session]storageImpl: must implement "getItem(key)"!'); + throw new Error(errStr + '[local|session]storageImpl: must implement "getItem(key)"!'); } else if (!('removeItem' in options.storageImpl) || typeof options.storageImpl.removeItem !== 'function') { - throw new Error('setCacheDefaults(): [local|session]storageImpl: must implement "removeItem(key)"!'); + throw new Error(errStr + '[local|session]storageImpl: must implement "removeItem(key)"!'); } } } if ('onExpire' in options) { if (typeof options.onExpire !== 'function') { - throw new Error('setCacheDefaults(): onExpire: Must be a function!'); + throw new Error(errStr + 'onExpire: Must be a function!'); } } @@ -345,18 +363,14 @@ * @param {Object} [options] {{[capacity]: Number, [maxAge]: Number, [cacheFlushInterval]: Number, [deleteOnExpire]: String, [onExpire]: Function, [storageMode]: String, [storageImpl]: Object}} */ function AngularCache(cacheId, options) { - var size = 0, - config = angular.extend({}, { id: cacheId }), + var config = angular.extend({}, { id: cacheId }), data = {}, - lruHash = {}, expiresHeap = new BinaryHeap(function (x) { return x.expires; }), lruHeap = new BinaryHeap(function (x) { return x.accessed; }), - freshEnd = null, - staleEnd = null, prefix = 'angular-cache.caches.' + cacheId, cacheDirty = false, self = this, @@ -400,8 +414,8 @@ throw new Error('capacity: ' + err); } else { config.capacity = capacity; - while (size > config.capacity) { - self.remove(staleEnd.key); + while (lruHeap.size() > config.capacity) { + self.remove(lruHeap.peek().key, { verifyIntegrity: false }); } } }); @@ -437,12 +451,8 @@ if (config.maxAge) { for (var i = 0; i < keys.length; i++) { var key = keys[i]; - if ((data[key].deleteOnExpire || config.deleteOnExpire) === 'aggressive') { - if (!('maxAge' in data[key])) { - if ('timeoutId' in data[key]) { - $timeout.cancel(data[key].timeoutId); - } - } + if (!('maxAge' in data[key])) { + delete data[key].expires; } } } @@ -454,19 +464,13 @@ } else { if (maxAge !== config.maxAge) { config.maxAge = maxAge; + var now = new Date().getTime(); for (var i = 0; i < keys.length; i++) { var key = keys[i]; - if ((data[key].deleteOnExpire || config.deleteOnExpire) === 'aggressive') { - if (!('maxAge' in data[key])) { - if ('timeoutId' in data[key]) { - $timeout.cancel(data[key].timeoutId); - } - var isExpired = new Date().getTime() - data[key].timestamp > config.maxAge; - if (!isExpired) { - _setTimeoutToRemove(key, config.maxAge); - } else { - self.remove(key); - } + if (!('maxAge' in data[key])) { + data[key].expires = data[key].created + config.maxAge; + if (data[key].expires < now) { + self.remove(key, { verifyIntegrity: false }); } } } @@ -476,6 +480,35 @@ } } + /** + * @method _setRecycleFreq + * @desc Set the recycleFreq setting for this cache. + * @param {Number} recycleFreq The new recycleFreq for this cache. + * @private + * @ignore + */ + function _setRecycleFreq(recycleFreq) { + if (recycleFreq === null) { + if (config.recycleFreqId) { + clearInterval(config.recycleFreqId); + delete config.recycleFreqId; + } + config.recycleFreq = cacheDefaults.recycleFreq; + } else { + _validateNumberOption(recycleFreq, function (err) { + if (err) { + throw new Error('recycleFreq: ' + err); + } else { + config.recycleFreq = recycleFreq; + if (config.recycleFreqId) { + clearInterval(config.recycleFreqId); + } + config.recycleFreqId = setInterval(self.removeExpired, config.recycleFreq); + } + }); + } + } + /** * @method _setCacheFlushInterval * @desc Set the cacheFlushInterval for this cache. @@ -498,7 +531,6 @@ if (cacheFlushInterval !== config.cacheFlushInterval) { if (config.cacheFlushIntervalId) { clearInterval(config.cacheFlushIntervalId); - delete config.cacheFlushIntervalId; } config.cacheFlushInterval = cacheFlushInterval; config.cacheFlushIntervalId = setInterval(self.removeAll, config.cacheFlushInterval); @@ -521,7 +553,7 @@ if (!angular.isString(storageMode)) { throw new Error('storageMode: must be a string!'); } else if (storageMode !== 'none' && storageMode !== 'localStorage' && storageMode !== 'sessionStorage') { - throw new Error('storageMode: accepted values are "none", "localStorage" or "sessionStorage"'); + throw new Error('storageMode: accepted values are "none", "localStorage" or "sessionStorage"!'); } if ((config.storageMode === 'localStorage' || config.storageMode === 'sessionStorage') && (storageMode !== config.storageMode)) { @@ -565,22 +597,29 @@ * @method _setOptions * @desc Configure this cache with the given options. * @param {Object} options - * @param {Boolean} strict If true then any existing configuration will be reset to default before + * @param {Boolean} [strict] If true then any existing configuration will be reset to default before * applying the new options, otherwise only the options specified in the options hash will be altered. + * @param {Object} [opts] Configuration. * @private * @ignore */ - function _setOptions(options, strict) { + function _setOptions(options, strict, opts) { options = options || {}; + opts = opts || {}; strict = !!strict; if (!angular.isObject(options)) { - throw new Error('setOptions(): options: must be an object!'); + throw new Error('AngularCache.setOptions(options, strict): options: must be an object!'); } + _verifyIntegrity(opts.verifyIntegrity); + if (strict) { options = angular.extend({}, cacheDefaults, options); } + if ('verifyIntegrity' in options) { + config.verifyIntegrity = options.verifyIntegrity === true; + } if ('capacity' in options) { _setCapacity(options.capacity); } @@ -593,6 +632,10 @@ _setMaxAge(options.maxAge); } + if ('recycleFreq' in options) { + _setRecycleFreq(options.recycleFreq); + } + if ('cacheFlushInterval' in options) { _setCacheFlushInterval(options.cacheFlushInterval); } @@ -603,7 +646,7 @@ if ('onExpire' in options) { if (options.onExpire !== null && typeof options.onExpire !== 'function') { - throw new Error('onExpire: Must be a function!'); + throw new Error('onExpire: must be a function!'); } config.onExpire = options.onExpire; } @@ -660,6 +703,41 @@ } } + function _verifyIntegrity(verifyIntegrity) { + if (verifyIntegrity || (verifyIntegrity !== false && config.verifyIntegrity)) { + if (config.storageMode !== 'none' && storage) { + var keys = _keys(data); + storage.setItem(prefix + '.keys', angular.toJson(keys)); + for (var i = 0; i < keys.length; i++) { + storage.setItem(prefix + '.data.' + keys[i], angular.toJson(data[keys[i]])); + } + } + } + } + + function _saveKeysToStorage(keys) { + if (config.storageMode !== 'none' && storage) { + var keysToSave = keys || _keys(data); + storage.setItem(prefix + '.keys', angular.toJson(keysToSave)); + } + } + + function _saveItemToStorage(key) { + if (config.storageMode !== 'none' && storage) { + storage.setItem(prefix + '.data.' + key, angular.toJson(data[key])); + } + } + + function _removeAllFromStorage() { + if (config.storageMode !== 'none' && storage) { + var keys = _keys(data); + for (var i = 0; i < keys.length; i++) { + storage.removeItem(prefix + '.data.' + keys[i]); + } + storage.setItem(prefix + '.keys', angular.toJson([])); + } + } + /** * @method AngularCache.put * @desc Add a key-value pair with timestamp to the cache. @@ -670,15 +748,16 @@ * @privileged */ this.put = function (key, value, options) { + options = options || {}; if (!angular.isString(key)) { throw new Error('AngularCache.put(key, value, options): key: must be a string!'); - } else if (options && options.maxAge && options.maxAge !== null) { + } else if (options.maxAge && options.maxAge !== null) { _validateNumberOption(options.maxAge, function (err) { if (err) { throw new Error('AngularCache.put(key, value, options): maxAge: ' + err); } }); - } else if (options && options.deleteOnExpire && !angular.isString(options.deleteOnExpire)) { + } else if (options.deleteOnExpire && !angular.isString(options.deleteOnExpire)) { throw new Error('AngularCache.put(key, value, options): deleteOnExpire: must be a string!'); } else if (angular.isUndefined(value)) { return; @@ -687,18 +766,24 @@ var now = new Date().getTime(), deleteOnExpire, item; - data[key] = data[key] || {}; - item = data[key]; + _verifyIntegrity(options.verifyIntegrity); + + if (data[key]) { + expiresHeap.remove(data[key]); + lruHeap.remove(data[key]); + } else { + data[key] = { key: key }; + } + item = data[key]; item.value = value; - item.created = (options && parseInt(options.created, 10)) || item.created || now; - item.modified = (options && parseInt(options.modified, 10)) || now; - item.accessed = (options && parseInt(options.accessed, 10)) || now; + item.created = (parseInt(options.created, 10)) || item.created || now; + item.accessed = (parseInt(options.accessed, 10)) || now; - if (options && options.deleteOnExpire) { + if (options.deleteOnExpire) { item.deleteOnExpire = options.deleteOnExpire; } - if (options && options.maxAge) { + if (options.maxAge) { item.maxAge = options.maxAge; } @@ -708,19 +793,18 @@ deleteOnExpire = item.deleteOnExpire || config.deleteOnExpire; - if (deleteOnExpire === 'aggressive' && item.expires) { + if (item.expires && deleteOnExpire === 'aggressive') { expiresHeap.push(item); } - if (config.storageMode !== 'none' && storage) { - storage.setItem(prefix + '.keys', angular.toJson(_keys(data))); - storage.setItem(prefix + '.data.' + key, angular.toJson(item)); - } + // Sync with localStorage, etc. + _saveKeysToStorage(); + _saveItemToStorage(key); lruHeap.push(item); if (lruHeap.size() > config.capacity) { - lruHeap.removeMin(); + this.remove(lruHeap.peek().key, { verifyIntegrity: false }); } return value; @@ -730,64 +814,64 @@ * @method AngularCache.get * @desc Retrieve the item from the cache with the specified key. * @param {String} key The key of the item to retrieve. - * @param {Function} [onExpire] Callback to be executed if it is discovered the - * requested item has expired. + * @param {Object} [options] Configuration. * @returns {*} The value of the item in the cache with the specified key. * @privileged */ - this.get = function (key, onExpire) { + this.get = function (key, options) { + options = options || {}; if (!angular.isString(key)) { throw new Error('AngularCache.get(key, onExpire): key: must be a string!'); - } else if (onExpire && typeof onExpire !== 'function') { + } else if (options.onExpire && typeof options.onExpire !== 'function') { throw new Error('AngularCache.get(key, onExpire): onExpire: must be a function!'); } else if (!(key in data)) { return; } - var value = data[key].value, - now = new Date().getTime(); + _verifyIntegrity(options.verifyIntegrity); - data[key].accessed = now; + var item = data[key], + value = item.value, + now = new Date().getTime(), + deleteOnExpire = item.deleteOnExpire || config.deleteOnExpire; - if ('expires' in data[key] && data[key].expires < now) { - this.remove(key); - if (config.storageMode !== 'none' && storage) { - storage.setItem(prefix + '.keys', angular.toJson(_keys(data))); - storage.removeItem(prefix + '.data.' + key); - } + lruHeap.remove(item); + item.accessed = now; + lruHeap.push(item); + + if (deleteOnExpire === 'passive' && 'expires' in item && item.expires < now) { + this.remove(key, { verifyIntegrity: false }); if (config.onExpire) { - config.onExpire(key, data[key].value, onExpire); - } else if (onExpire && typeof onExpire === 'function') { - onExpire(key, data[key].value); + config.onExpire(key, item.value, (options.onExpire)); + } else if (options.onExpire) { + options.onExpire(key, item.value); } value = undefined; } - if (config.storageMode !== 'none' && storage) { - storage.setItem(prefix + '.keys', angular.toJson(_keys(data))); - storage.setItem(prefix + '.data.' + key, angular.toJson(data[key])); - } + _saveItemToStorage(key); return value; }; /** * @method AngularCache.remove - * @desc Remove the specified key-value pair from this cache. - * @param {String} key The key of the key-value pair to remove. + * @desc Remove the item with the specified key from this cache. + * @param {String} key The key of the item to remove. + * @param {Object} [options] Configuration. * @privileged */ - this.remove = function (key) { - delete data[key]; - - _syncToStorage(null); - + this.remove = function (key, options) { + options = options || {}; + _verifyIntegrity(options.verifyIntegrity); + lruHeap.remove(data[key]); + expiresHeap.remove(data[key]); if (config.storageMode !== 'none' && storage) { storage.removeItem(prefix + '.data.' + key); } - - size--; + delete data[key]; + _saveKeysToStorage(); }; /** @@ -796,23 +880,25 @@ * @privileged */ this.removeAll = function () { - if (config.storageMode !== 'none' && storage) { - var keys = _keys(data); - for (var i = 0; i < keys.length; i++) { - if (data[keys[i]].timeoutId) { - $timeout.cancel(data[keys[i]].timeoutId); - } - storage.removeItem(prefix + '.data.' + keys[i]); - } - } - + _removeAllFromStorage(); + lruHeap.removeAll(); + expiresHeap.removeAll(); data = {}; - size = 0; - lruHash = {}; - freshEnd = null; - staleEnd = null; + }; - _syncToStorage(null); + /** + * @method AngularCache.removeExpired + * @desc Remove all items from this cache that have expired. + * @param {Object} [options] Configuration. + * @privileged + */ + this.removeExpired = function (options) { + options = options || {}; + _verifyIntegrity(options.verifyIntegrity); + var now = new Date().getTime(); + while (expiresHeap.peek().expires < now) { + this.remove(expiresHeap.peek().key, { verifyIntegrity: false }); + } }; /** @@ -824,20 +910,20 @@ if (config.cacheFlushIntervalId) { clearInterval(config.cacheFlushIntervalId); } + if (config.recycleFreqId) { + clearInterval(config.recycleFreqId); + } + this.removeAll(); if (config.storageMode !== 'none' && storage) { - this.removeAll(); storage.removeItem(prefix + '.keys'); storage.removeItem(prefix); } storage = null; data = null; config = null; - lruHash = null; - size = null; - freshEnd = null; - staleEnd = null; prefix = null; self = null; + caches[cacheId] = null; delete caches[cacheId]; }; @@ -845,14 +931,17 @@ * @method AngularCache.info * @desc Return an object containing information about this cache. * @param {String} [key] The key of the item about which to retrieve information. - * @returns {Object} stats Object containing information about this cache. + * @returns {Object} stats Object containing information about this cache or the item with the + * specified key. * @privileged */ this.info = function (key) { if (key) { if (data[key]) { var info = { - timestamp: data[key].timestamp, + created: data[key].created, + accessed: data[key].accessed, + expires: data[key].expires, maxAge: data[key].maxAge || config.maxAge, deleteOnExpire: data[key].deleteOnExpire || config.deleteOnExpire, isExpired: false @@ -865,7 +954,7 @@ return data[key]; } } else { - return angular.extend({}, config, { size: size }); + return angular.extend({}, config, { size: lruHeap.size() }); } }; @@ -893,14 +982,15 @@ * @method AngularCache.setOptions * @desc Configure this cache with the given options. * @param {Object} options - * @param {Boolean} strict If true then any existing configuration will be reset to defaults before + * @param {Boolean} [strict] If true then any existing configuration will be reset to defaults before * applying the new options, otherwise only the options specified in the hash will be altered. + * @param {Object} [opts] Configuration. * @privileged */ this.setOptions = _setOptions; // Initialize this cache with the default and given options - _setOptions(options, true); + _setOptions(options, true, { verifyIntegrity: false }); } /** @@ -948,6 +1038,9 @@ * @public */ angularCacheFactory.get = function (cacheId) { + if (!angular.isString(cacheId)) { + throw new Error('$angularCacheFactory.get(cacheId): cacheId: must be a string!'); + } return caches[cacheId]; }; diff --git a/test/angularCacheFactory-test.js b/test/angularCacheFactory-test.js new file mode 100644 index 0000000..e4dbace --- /dev/null +++ b/test/angularCacheFactory-test.js @@ -0,0 +1,234 @@ +describe('$angularCacheFactory(cacheId, options)', function () { + it('should be able to create a default cache.', function () { + var cache = $angularCacheFactory('cache'); + expect(cache).toBeDefined(); + expect(cache.info().id).toEqual('cache'); + expect(cache.info().capacity).toEqual(CACHE_DEFAULTS.capacity); + expect(cache.info().maxAge).toEqual(CACHE_DEFAULTS.maxAge); + expect(cache.info().cacheFlushInterval).toEqual(CACHE_DEFAULTS.cacheFlushInterval); + expect(cache.info().deleteOnExpire).toEqual(CACHE_DEFAULTS.deleteOnExpire); + expect(cache.info().onExpire).toEqual(CACHE_DEFAULTS.onExpire); + expect(cache.info().recycleFreq).toEqual(CACHE_DEFAULTS.recycleFreq); + expect(cache.info().storageMode).toEqual(CACHE_DEFAULTS.storageMode); + expect(cache.info().storageImpl).toEqual(CACHE_DEFAULTS.storageImpl); + expect(cache.info().verifyIntegrity).toEqual(CACHE_DEFAULTS.verifyIntegrity); + cache.destroy(); + }); + it('should be able to create a cache with options.', function () { + var options = { + capacity: Math.floor((Math.random() * 100000) + 1), + maxAge: Math.floor((Math.random() * 100000) + 1), + cacheFlushInterval: Math.floor((Math.random() * 100000) + 1), + deleteOnExpire: 'aggressive', + storageMode: 'localStorage', + localStorageImpl: { + setItem: function () { + }, + getItem: function () { + }, + removeItem: function () { + } + }, + verifyIntegrity: false, + recycleFreq: 2000, + onExpire: function () { + } + }; + var cache = $angularCacheFactory('cache', options); + expect(cache).toBeDefined(); + expect(cache.info().id).toEqual('cache'); + expect(cache.info().capacity).toEqual(options.capacity); + expect(cache.info().maxAge).toEqual(options.maxAge); + expect(cache.info().cacheFlushInterval).toEqual(options.cacheFlushInterval); + expect(cache.info().deleteOnExpire).toEqual(options.deleteOnExpire); + expect(cache.info().storageMode).toEqual(options.storageMode); + expect(cache.info().localStorageImpl).not.toBeDefined(); // We don't expose this to the user + expect(cache.info().onExpire).toEqual(options.onExpire); + cache.destroy(); + expect($angularCacheFactory.get('cache')).not.toBeDefined(); + }); + it('should throw an exception if "capacity" is not a number or is less than zero.', function () { + try { + $angularCacheFactory('cache', { capacity: Math.floor((Math.random() * 100000) + 1) * -1 }); + fail(); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('capacity: must be greater than zero!'); + for (var i = 0; i < TYPES_EXCEPT_NUMBER.length; i++) { + try { + $angularCacheFactory('cache', { capacity: TYPES_EXCEPT_NUMBER[i] }); + fail(); + } catch (err) { + expect(err.message).toEqual('capacity: must be a number!'); + continue; + } + fail(); + } + }); + it('should validate maxAge.', function () { + var maxAge = Math.floor((Math.random() * 100000) + 1) * -1; + try { + $angularCacheFactory('cache', { maxAge: maxAge }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('maxAge: must be greater than zero!'); + maxAge = 'asdfasd'; + try { + $angularCacheFactory('cache', { maxAge: maxAge }); + expect('should not reach this!').toEqual(false); + } catch (err) { + msg = err.message; + } + expect(msg).toEqual('maxAge: must be a number!'); + }); + it('should validate cacheFlushInterval.', function () { + var cacheFlushInterval = Math.floor((Math.random() * 100000) + 1) * -1; + try { + $angularCacheFactory('cache', { cacheFlushInterval: cacheFlushInterval }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('cacheFlushInterval: must be greater than zero!'); + cacheFlushInterval = 'asdfasd'; + try { + $angularCacheFactory('cache', { cacheFlushInterval: cacheFlushInterval }); + expect('should not reach this!').toEqual(false); + } catch (err) { + msg = err.message; + } + expect(msg).toEqual('cacheFlushInterval: must be a number!'); + }); + it('should validate recycleFreq.', function () { + var recycleFreq = Math.floor((Math.random() * 100000) + 1) * -1; + try { + $angularCacheFactory('cache', { recycleFreq: recycleFreq }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('recycleFreq: must be greater than zero!'); + recycleFreq = 'asdfasd'; + try { + $angularCacheFactory('cache', { recycleFreq: recycleFreq }); + expect('should not reach this!').toEqual(false); + } catch (err) { + msg = err.message; + } + expect(msg).toEqual('recycleFreq: must be a number!'); + }); + it('should validate onExpire.', function () { + var onExpire = 234; + try { + $angularCacheFactory('cache', { onExpire: onExpire }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('onExpire: must be a function!'); + onExpire = {}; + try { + $angularCacheFactory('cache', { onExpire: onExpire }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('onExpire: must be a function!'); + onExpire = 'asdfasd'; + try { + $angularCacheFactory('cache', { onExpire: onExpire }); + expect('should not reach this!').toEqual(false); + } catch (err) { + msg = err.message; + } + expect(msg).toEqual('onExpire: must be a function!'); + }); + it('should validate deleteOnExpire.', function () { + var deleteOnExpire = 'fail'; + try { + $angularCacheFactory('cache', { deleteOnExpire: deleteOnExpire }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('deleteOnExpire: accepted values are "none", "passive" or "aggressive"!'); + deleteOnExpire = 234; + try { + $angularCacheFactory('cache', { deleteOnExpire: deleteOnExpire }); + expect('should not reach this!').toEqual(false); + } catch (err) { + msg = err.message; + } + expect(msg).toEqual('deleteOnExpire: must be a string!'); + }); + it('should validate storageMode.', function () { + var storageMode = 'fail'; + try { + $angularCacheFactory('cache', { storageMode: storageMode }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('storageMode: accepted values are "none", "localStorage" or "sessionStorage"!'); + storageMode = 234; + try { + $angularCacheFactory('cache', { storageMode: storageMode }); + expect('should not reach this!').toEqual(false); + } catch (err) { + msg = err.message; + } + expect(msg).toEqual('storageMode: must be a string!'); + }); + it('should validate storageImpl.', function () { + var storageImpl = 'fail'; + try { + $angularCacheFactory('cache', { storageImpl: storageImpl }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('[local|session]storageImpl: must be an object!'); + storageImpl = 234; + try { + $angularCacheFactory('cache', { storageImpl: storageImpl }); + expect('should not reach this!').toEqual(false); + } catch (err) { + msg = err.message; + } + expect(msg).toEqual('[local|session]storageImpl: must be an object!'); + }); + + it('should prevent a cache from being duplicated.', function () { + try { + $angularCacheFactory('cache'); + $angularCacheFactory('cache'); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('cacheId cache taken!'); + }); + it('should require cacheId to be a string.', function () { + var shouldBeAStringMsg = 'cacheId must be a string!'; + try { + $angularCacheFactory(3); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual(shouldBeAStringMsg); + try { + $angularCacheFactory({obj: 'obj'}); + } catch (err) { + msg = err.message; + } + expect(msg).toEqual(shouldBeAStringMsg); + try { + $angularCacheFactory(['obj']); + } catch (err) { + msg = err.message; + } + expect(msg).toEqual(shouldBeAStringMsg); + }); +}); \ No newline at end of file diff --git a/test/angularCacheFactory.clearAll-test.js b/test/angularCacheFactory.clearAll-test.js new file mode 100644 index 0000000..78a6938 --- /dev/null +++ b/test/angularCacheFactory.clearAll-test.js @@ -0,0 +1,22 @@ +describe('$angularCacheFactory.clearAll()', function () { + it('should call "removeAll()" on all caches in $angularCacheFactory', function () { + var cacheKeys = ['cache', 'cache1', 'cache2']; + + var cache = $angularCacheFactory(cacheKeys[0]); + cache.put('item', 'value'); + var cache1 = $angularCacheFactory(cacheKeys[1]); + cache1.put('item', 'value'); + var cache2 = $angularCacheFactory(cacheKeys[2]); + cache2.put('item', 'value'); + + $angularCacheFactory.clearAll(); + + expect(cache.get('item')).not.toBeDefined(); + expect(cache1.get('item')).not.toBeDefined(); + expect(cache2.get('item')).not.toBeDefined(); + + $angularCacheFactory.get(cacheKeys[0]).destroy(); + $angularCacheFactory.get(cacheKeys[1]).destroy(); + $angularCacheFactory.get(cacheKeys[2]).destroy(); + }); +}); diff --git a/test/angularCacheFactory.get-test.js b/test/angularCacheFactory.get-test.js new file mode 100644 index 0000000..b89d0ad --- /dev/null +++ b/test/angularCacheFactory.get-test.js @@ -0,0 +1,24 @@ +describe('$angularCacheFactory.get(cacheId)', function () { + it('should throw an exception if "cacheId" is not a string.', function () { + for (var i = 0; i < TYPES_EXCEPT_STRING.length; i++) { + try { + $angularCacheFactory.get(TYPES_EXCEPT_STRING[i]); + fail(); + } catch (err) { + expect(err.message).toEqual('$angularCacheFactory.get(cacheId): cacheId: must be a string!'); + continue; + } + fail(); + } + }); + it('should return "undefined" if the cache does not exist.', function () { + expect($angularCacheFactory.get('someNonExistentCache')).toEqual(undefined); + }); + it('should return the correct cache with the specified cacheId.', function () { + var cache = $angularCacheFactory('cache'), + cache2 = $angularCacheFactory('cache2'); + expect($angularCacheFactory.get('cache')).toEqual(cache); + expect($angularCacheFactory.get('cache2')).toEqual(cache2); + expect(cache).not.toEqual(cache2); + }); +}); \ No newline at end of file diff --git a/test/angularCacheFactory.info-test.js b/test/angularCacheFactory.info-test.js new file mode 100644 index 0000000..d8e9837 --- /dev/null +++ b/test/angularCacheFactory.info-test.js @@ -0,0 +1,33 @@ +describe('$angularCacheFactory.info()', function () { + it('should return the correct info for each cache produced by the factory.', function () { + var options = { + capacity: Math.floor((Math.random() * 100000) + 1), + maxAge: Math.floor((Math.random() * 100000) + 1), + cacheFlushInterval: Math.floor((Math.random() * 100000) + 1) + }; + + var cache = $angularCacheFactory('cache'); + var cache2 = $angularCacheFactory('cache2', { + maxAge: options.maxAge + }); + var cache3 = $angularCacheFactory('cache3', { + capacity: options.capacity, + cacheFlushInterval: options.cacheFlushInterval + }); + var info = $angularCacheFactory.info(); + expect(info.size).toEqual(3); + expect(info.caches.cache.id).toEqual('cache'); + expect(info.caches.cache.capacity).toEqual(Number.MAX_VALUE); + expect(info.caches.cache.size).toEqual(0); + + expect(info.caches.cache2.id).toEqual('cache2'); + expect(info.caches.cache2.capacity).toEqual(Number.MAX_VALUE); + expect(info.caches.cache2.size).toEqual(0); + + expect(info.caches.cache3.id).toEqual('cache3'); + expect(info.caches.cache3.cacheFlushInterval).toEqual(options.cacheFlushInterval); + expect(info.caches.cache3.capacity).toEqual(options.capacity); + expect(info.caches.cache3.size).toEqual(0); + expect(info.caches.cache3.cacheFlushIntervalId).toBeDefined(); + }); +}); diff --git a/test/angularCacheFactory.keySet-test.js b/test/angularCacheFactory.keySet-test.js new file mode 100644 index 0000000..92f9146 --- /dev/null +++ b/test/angularCacheFactory.keySet-test.js @@ -0,0 +1,29 @@ +describe('$angularCacheFactory.keySet()', function () { + it('should return the set of keys of all caches in $angularCacheFactory.', function () { + var cacheKeys = ['cache', 'cache1', 'cache2']; + + $angularCacheFactory(cacheKeys[0]); + $angularCacheFactory(cacheKeys[1]); + $angularCacheFactory(cacheKeys[2]); + + var keySet = $angularCacheFactory.keySet(); + + expect(keySet.hasOwnProperty(cacheKeys[0])).toEqual(true); + expect(keySet.hasOwnProperty(cacheKeys[1])).toEqual(true); + expect(keySet.hasOwnProperty(cacheKeys[2])).toEqual(true); + + expect(keySet[cacheKeys[0]]).toEqual(cacheKeys[0]); + expect(keySet[cacheKeys[1]]).toEqual(cacheKeys[1]); + expect(keySet[cacheKeys[2]]).toEqual(cacheKeys[2]); + + $angularCacheFactory.get(cacheKeys[0]).destroy(); + $angularCacheFactory.get(cacheKeys[1]).destroy(); + $angularCacheFactory.get(cacheKeys[2]).destroy(); + + keySet = $angularCacheFactory.keySet(); + + expect(keySet.hasOwnProperty(cacheKeys[0])).toEqual(false); + expect(keySet.hasOwnProperty(cacheKeys[1])).toEqual(false); + expect(keySet.hasOwnProperty(cacheKeys[2])).toEqual(false); + }); +}); diff --git a/test/angularCacheFactory.keys-test.js b/test/angularCacheFactory.keys-test.js new file mode 100644 index 0000000..662c83f --- /dev/null +++ b/test/angularCacheFactory.keys-test.js @@ -0,0 +1,23 @@ +describe('$angularCacheFactory.keys()', function () { + it('should return the array of keys of all caches in $angularCacheFactory.', function () { + var cacheKeys = ['cache', 'cache1', 'cache2']; + + $angularCacheFactory(cacheKeys[0]); + $angularCacheFactory(cacheKeys[1]); + $angularCacheFactory(cacheKeys[2]); + + var keys = $angularCacheFactory.keys(); + + expect(keys[0]).toEqual(cacheKeys[0]); + expect(keys[1]).toEqual(cacheKeys[1]); + expect(keys[2]).toEqual(cacheKeys[2]); + + $angularCacheFactory.get(cacheKeys[0]).destroy(); + $angularCacheFactory.get(cacheKeys[1]).destroy(); + $angularCacheFactory.get(cacheKeys[2]).destroy(); + + keys = $angularCacheFactory.keys(); + + expect(keys.length).toEqual(0); + }); +}); diff --git a/test/angularCacheFactory.removeAll-test.js b/test/angularCacheFactory.removeAll-test.js new file mode 100644 index 0000000..8e7e211 --- /dev/null +++ b/test/angularCacheFactory.removeAll-test.js @@ -0,0 +1,33 @@ +describe('$angularCacheFactory.removeAll()', function () { + it('should call "destroy()" on all caches currently owned by the factory.', function () { + var cacheKeys = ['cache', 'cache1', 'cache2'], + caches = []; + + caches.push($angularCacheFactory(cacheKeys[0])); + caches.push($angularCacheFactory(cacheKeys[1])); + caches.push($angularCacheFactory(cacheKeys[2])); + + spyOn(caches[0], 'destroy'); + spyOn(caches[1], 'destroy'); + spyOn(caches[2], 'destroy'); + $angularCacheFactory.removeAll(); + + expect(caches[0].destroy.callCount).toEqual(1); + expect(caches[1].destroy.callCount).toEqual(1); + expect(caches[2].destroy.callCount).toEqual(1); + }); + it('should result in all caches being removed from $angularCacheFactory.', function () { + var cacheKeys = ['cache', 'cache1', 'cache2'], + caches = []; + + caches.push($angularCacheFactory(cacheKeys[0])); + caches.push($angularCacheFactory(cacheKeys[1])); + caches.push($angularCacheFactory(cacheKeys[2])); + + $angularCacheFactory.removeAll(); + + expect($angularCacheFactory.get(cacheKeys[0])).not.toBeDefined(); + expect($angularCacheFactory.get(cacheKeys[1])).not.toBeDefined(); + expect($angularCacheFactory.get(cacheKeys[2])).not.toBeDefined(); + }); +}); diff --git a/test/angularCacheFactorySpec.js b/test/angularCacheFactorySpec.js deleted file mode 100644 index eaaf4f4..0000000 --- a/test/angularCacheFactorySpec.js +++ /dev/null @@ -1,379 +0,0 @@ -describe('AngularCacheFactory', function () { - - var $angularCacheFactory, $timeout; - beforeEach(module('jmdobry.angular-cache')); - beforeEach(inject(function ($injector) { - $angularCacheFactory = $injector.get('$angularCacheFactory'); - $timeout = $injector.get('$timeout'); - })); - - describe('$angularCacheFactory()', function () { - it('should be able to create a default cache', function () { - var cache = $angularCacheFactory('cache'); - expect(cache).toBeDefined(); - expect(cache.info().id).toEqual('cache'); - expect(cache.info().capacity).toEqual(Number.MAX_VALUE); - expect(cache.info().maxAge).toEqual(null); - expect(cache.info().cacheFlushInterval).toEqual(null); - cache.destroy(); - }); - it('should be able to create a cache with options', function () { - var options = { - capacity: Math.floor((Math.random() * 100000) + 1), - maxAge: Math.floor((Math.random() * 100000) + 1), - cacheFlushInterval: Math.floor((Math.random() * 100000) + 1), - deleteOnExpire: 'aggressive', - storageMode: 'localStorage', - localStorageImpl: { - setItem: function () { - }, - getItem: function () { - }, - removeItem: function () { - } - }, - onExpire: function () { - } - }; - var cache = $angularCacheFactory('cache', options); - expect(cache).toBeDefined(); - expect(cache.info().id).toEqual('cache'); - expect(cache.info().capacity).toEqual(options.capacity); - expect(cache.info().maxAge).toEqual(options.maxAge); - expect(cache.info().cacheFlushInterval).toEqual(options.cacheFlushInterval); - expect(cache.info().deleteOnExpire).toEqual(options.deleteOnExpire); - expect(cache.info().storageMode).toEqual(options.storageMode); - expect(cache.info().localStorageImpl).not.toBeDefined(); // We don't expose this to the user - expect(cache.info().onExpire).toEqual(options.onExpire); - cache.destroy(); - expect($angularCacheFactory.get('cache')).not.toBeDefined(); - }); - it('should validate capacity', function () { - var capacity = Math.floor((Math.random() * 100000) + 1) * -1; - try { - $angularCacheFactory('cache', { capacity: capacity }); - } catch (err) { - var msg = err.message; - } - expect(msg).toEqual('capacity: must be greater than zero!'); - capacity = 'asdfasd'; - try { - $angularCacheFactory('cache', { capacity: capacity }); - } catch (err) { - msg = err.message; - } - expect(msg).toEqual('capacity: must be a number!'); - }); - it('should validate maxAge', function () { - var maxAge = Math.floor((Math.random() * 100000) + 1) * -1; - try { - $angularCacheFactory('cache', { maxAge: maxAge }); - } catch (err) { - var msg = err.message; - } - expect(msg).toEqual('maxAge: must be greater than zero!'); - maxAge = 'asdfasd'; - try { - $angularCacheFactory('cache', { maxAge: maxAge }); - } catch (err) { - msg = err.message; - } - expect(msg).toEqual('maxAge: must be a number!'); - }); - it('should validate cacheFlushInterval', function () { - var cacheFlushInterval = Math.floor((Math.random() * 100000) + 1) * -1; - try { - $angularCacheFactory('cache', { cacheFlushInterval: cacheFlushInterval }); - } catch (err) { - var msg = err.message; - } - expect(msg).toEqual('cacheFlushInterval: must be greater than zero!'); - cacheFlushInterval = 'asdfasd'; - try { - $angularCacheFactory('cache', { cacheFlushInterval: cacheFlushInterval }); - } catch (err) { - msg = err.message; - } - expect(msg).toEqual('cacheFlushInterval: must be a number!'); - }); - it('should prevent a cache from being duplicated', function () { - try { - $angularCacheFactory('cache'); - $angularCacheFactory('cache'); - } catch (err) { - var msg = err.message; - } - expect(msg).toEqual('cacheId cache taken!'); - }); - it('should require cacheId to be a string', function () { - var shouldBeAStringMsg = 'cacheId must be a string!'; - try { - $angularCacheFactory(3); - } catch (err) { - var msg = err.message; - } - expect(msg).toEqual(shouldBeAStringMsg); - try { - $angularCacheFactory({obj: 'obj'}); - } catch (err) { - msg = err.message; - } - expect(msg).toEqual(shouldBeAStringMsg); - try { - $angularCacheFactory(['obj']); - } catch (err) { - msg = err.message; - } - expect(msg).toEqual(shouldBeAStringMsg); - }); - it('should load an existing cache from localStorage is storageMode was enabled', function () { - if (localStorage) { - localStorage.setItem('angular-cache.caches.lsCache.keys', angular.toJson(['lsItem1', 'lsItem2'])); - localStorage.setItem('angular-cache.caches.lsCache.data.lsItem1', angular.toJson({ - value: 'value1', - timestamp: new Date().getTime() - })); - localStorage.setItem('angular-cache.caches.lsCache.data.lsItem2', angular.toJson({ - value: 'value2', - timestamp: new Date().getTime(), - maxAge: 10000 - })); - var lsCache = $angularCacheFactory('lsCache', { storageMode: 'localStorage', maxAge: 10, deleteOnExpire: 'aggressive' }); - expect(lsCache.get('lsItem1')).toEqual('value1'); - localStorage.removeItem('angular-cache.caches.lsCache.data.lsItem1'); - expect(localStorage.getItem('lsItem1')).toEqual(null); - expect(lsCache.get('lsItem1')).toEqual('value1'); - expect(localStorage.getItem('lsItem1')).toBeDefined(); - expect(lsCache.get('lsItem2')).toEqual('value2'); - expect(lsCache.info('lsItem2').maxAge).toEqual(10000); - waits(100); - runs(function () { - $timeout.flush(); - expect(lsCache.get('lsItem1')).toEqual(null); - expect(lsCache.get('lsItem2')).toEqual(null); - if (sessionStorage) { - sessionStorage.setItem('angular-cache.caches.ssCache.keys', angular.toJson(['ssItem1', 'ssItem2'])); - sessionStorage.setItem('angular-cache.caches.ssCache.data.ssItem1', angular.toJson({ - value: 'value1', - timestamp: new Date().getTime() - })); - sessionStorage.setItem('angular-cache.caches.ssCache.data.ssItem2', angular.toJson({ - value: 'value2', - timestamp: new Date().getTime() - })); - var ssCache = $angularCacheFactory('ssCache', { storageMode: 'sessionStorage', maxAge: 10, deleteOnExpire: 'aggressive' }); - expect(ssCache.get('ssItem1')).toEqual('value1'); - expect(ssCache.get('ssItem2')).toEqual('value2'); - waits(100); - runs(function () { - $timeout.flush(); - expect(ssCache.get('ssItem1')).toEqual(null); - expect(ssCache.get('ssItem2')).toEqual(null); - lsCache.destroy(); - ssCache.destroy(); - }); - } - }); - } - }); - it('should allow use of custom localStorage/sessionStorage implementations', function () { - var myLocalStorage = { - localData: {}, - setItem: function (key, value) { - this.localData[key] = value; - }, - getItem: function (key) { - return this.localData[key]; - }, - removeItem: function (key) { - delete this.localData[key]; - } - }; - var mySessionStorage = { - localData: {}, - setItem: function (key, value) { - this.localData[key] = value; - }, - getItem: function (key) { - return this.localData[key]; - }, - removeItem: function (key) { - delete this.localData[key]; - } - }; - myLocalStorage.setItem('angular-cache.caches.lsCache.keys', angular.toJson(['item1', 'item2'])); - myLocalStorage.setItem('angular-cache.caches.lsCache.data.item1', angular.toJson({ - value: 'value1', - timestamp: new Date().getTime() - })); - myLocalStorage.setItem('angular-cache.caches.lsCache.data.item2', angular.toJson({ - value: 'value2', - timestamp: new Date().getTime() - })); - var lsCache = $angularCacheFactory('lsCache', { storageImpl: myLocalStorage, storageMode: 'localStorage', maxAge: 10, deleteOnExpire: 'aggressive' }); - expect(lsCache.get('item1')).toEqual('value1'); - expect(lsCache.get('item2')).toEqual('value2'); - waits(100); - runs(function () { - $timeout.flush(); - expect(lsCache.get('item1')).toEqual(null); - expect(lsCache.get('item2')).toEqual(null); - mySessionStorage.setItem('angular-cache.caches.ssCache.keys', angular.toJson(['item1', 'item2'])); - mySessionStorage.setItem('angular-cache.caches.ssCache.data.item1', angular.toJson({ - value: 'value1', - timestamp: new Date().getTime() - })); - mySessionStorage.setItem('angular-cache.caches.ssCache.data.item2', angular.toJson({ - value: 'value2', - timestamp: new Date().getTime() - })); - var ssCache = $angularCacheFactory('ssCache', { storageImpl: mySessionStorage, storageMode: 'sessionStorage', maxAge: 10, deleteOnExpire: 'aggressive' }); - expect(ssCache.get('item1')).toEqual('value1'); - expect(ssCache.get('item2')).toEqual('value2'); - waits(100); - runs(function () { - $timeout.flush(); - expect(ssCache.get('item1')).toEqual(null); - expect(ssCache.get('item2')).toEqual(null); - lsCache.destroy(); - ssCache.destroy(); - }); - }); - }); - }); - describe('$angularCacheFactory.get(cachedId)', function () { - it('should return the correct cache with the specified cacheId', function () { - var cache = $angularCacheFactory('cache'); - expect($angularCacheFactory.get('cache')).toEqual(cache); - cache.destroy(); - }); - it('should return \"undefined\" if the cache doesn\'t exist', function () { - expect($angularCacheFactory.get('someNonExistentCache')).toEqual(undefined); - }); - }); - describe('$angularCacheFactory.info()', function () { - it('should return the correct info for each cache produced by the factory', function () { - var options = { - capacity: Math.floor((Math.random() * 100000) + 1), - maxAge: Math.floor((Math.random() * 100000) + 1), - cacheFlushInterval: Math.floor((Math.random() * 100000) + 1) - }; - - var cache = $angularCacheFactory('cache'); - var cache2 = $angularCacheFactory('cache2', { - maxAge: options.maxAge - }); - var cache3 = $angularCacheFactory('cache3', { - capacity: options.capacity, - cacheFlushInterval: options.cacheFlushInterval - }); - var info = $angularCacheFactory.info(); - expect(info.size).toEqual(3); - expect(info.caches.cache.id).toEqual('cache'); - expect(info.caches.cache.capacity).toEqual(Number.MAX_VALUE); - expect(info.caches.cache.size).toEqual(0); - - expect(info.caches.cache2.id).toEqual('cache2'); - expect(info.caches.cache2.capacity).toEqual(Number.MAX_VALUE); - expect(info.caches.cache2.size).toEqual(0); - - expect(info.caches.cache3.id).toEqual('cache3'); - expect(info.caches.cache3.cacheFlushInterval).toEqual(options.cacheFlushInterval); - expect(info.caches.cache3.capacity).toEqual(options.capacity); - expect(info.caches.cache3.size).toEqual(0); - expect(info.caches.cache3.cacheFlushIntervalId).toBeDefined(); - cache.destroy(); - cache2.destroy(); - cache3.destroy(); - }); - }); - describe('$angularCacheFactory.keySet()', function () { - it('should return the correct set of keys associated the caches currently owned by the factory', function () { - var cacheKeys = ['cache', 'cache1', 'cache2']; - - $angularCacheFactory(cacheKeys[0]); - $angularCacheFactory(cacheKeys[1]); - $angularCacheFactory(cacheKeys[2]); - - var keySet = $angularCacheFactory.keySet(); - - expect(keySet.hasOwnProperty(cacheKeys[0])).toEqual(true); - expect(keySet.hasOwnProperty(cacheKeys[1])).toEqual(true); - expect(keySet.hasOwnProperty(cacheKeys[2])).toEqual(true); - - expect(keySet[cacheKeys[0]]).toEqual(cacheKeys[0]); - expect(keySet[cacheKeys[1]]).toEqual(cacheKeys[1]); - expect(keySet[cacheKeys[2]]).toEqual(cacheKeys[2]); - - $angularCacheFactory.get(cacheKeys[0]).destroy(); - $angularCacheFactory.get(cacheKeys[1]).destroy(); - $angularCacheFactory.get(cacheKeys[2]).destroy(); - - keySet = $angularCacheFactory.keySet(); - - expect(keySet.hasOwnProperty(cacheKeys[0])).toEqual(false); - expect(keySet.hasOwnProperty(cacheKeys[1])).toEqual(false); - expect(keySet.hasOwnProperty(cacheKeys[2])).toEqual(false); - }); - }); - describe('$angularCacheFactory.keys()', function () { - it('should return the correct array of keys associated the caches currently owned by the factory', function () { - var cacheKeys = ['cache', 'cache1', 'cache2']; - - $angularCacheFactory(cacheKeys[0]); - $angularCacheFactory(cacheKeys[1]); - $angularCacheFactory(cacheKeys[2]); - - var keys = $angularCacheFactory.keys(); - - expect(keys[0]).toEqual(cacheKeys[0]); - expect(keys[1]).toEqual(cacheKeys[1]); - expect(keys[2]).toEqual(cacheKeys[2]); - - $angularCacheFactory.get(cacheKeys[0]).destroy(); - $angularCacheFactory.get(cacheKeys[1]).destroy(); - $angularCacheFactory.get(cacheKeys[2]).destroy(); - - keys = $angularCacheFactory.keys(); - - expect(keys.length).toEqual(0); - }); - }); - describe('$angularCacheFactory.removeAll()', function () { - it('should call "destroy()" on all caches currently owned by the factory', function () { - var cacheKeys = ['cache', 'cache1', 'cache2']; - - $angularCacheFactory(cacheKeys[0]); - $angularCacheFactory(cacheKeys[1]); - $angularCacheFactory(cacheKeys[2]); - - $angularCacheFactory.removeAll(); - - expect($angularCacheFactory.get(cacheKeys[0])).not.toBeDefined(); - expect($angularCacheFactory.get(cacheKeys[1])).not.toBeDefined(); - expect($angularCacheFactory.get(cacheKeys[2])).not.toBeDefined(); - }); - }); - describe('$angularCacheFactory.clearAll()', function () { - it('should call "removeAll()" on all caches currently owned by the factory', function () { - var cacheKeys = ['cache', 'cache1', 'cache2']; - - var cache = $angularCacheFactory(cacheKeys[0]); - cache.put('item', 'value'); - var cache1 = $angularCacheFactory(cacheKeys[1]); - cache1.put('item', 'value'); - var cache2 = $angularCacheFactory(cacheKeys[2]); - cache2.put('item', 'value'); - - $angularCacheFactory.clearAll(); - - expect(cache.get('item')).not.toBeDefined(); - expect(cache1.get('item')).not.toBeDefined(); - expect(cache2.get('item')).not.toBeDefined(); - - $angularCacheFactory.get(cacheKeys[0]).destroy(); - $angularCacheFactory.get(cacheKeys[1]).destroy(); - $angularCacheFactory.get(cacheKeys[2]).destroy(); - }); - }); -}); \ No newline at end of file diff --git a/test/angularCacheSpec.js b/test/angularCacheSpec.js index 2824665..f1c12c2 100644 --- a/test/angularCacheSpec.js +++ b/test/angularCacheSpec.js @@ -1,830 +1,830 @@ -describe('AngularCache', function () { - - var $angularCacheFactory, $timeout; - beforeEach(module('jmdobry.angular-cache')); - beforeEach(inject(function ($injector) { - $angularCacheFactory = $injector.get('$angularCacheFactory'); - $timeout = $injector.get('$timeout'); - })); - - it('should clear itself if cacheFlushInterval is specified', function () { - var cache = $angularCacheFactory('cache', { cacheFlushInterval: 10 }); - cache.put('item1', 'value1'); - expect(cache.get('item1')).toEqual('value1'); - cache.put('item2', 'value2'); - expect(cache.get('item2')).toEqual('value2'); - waits(100); - runs(function () { - expect(cache.get('item1')).toEqual(undefined); - expect(cache.get('item2')).toEqual(undefined); - cache.destroy(); - }); - }); - it('should clear itself and web storage if cacheFlushInterval and storageMode are specified', function () { - var localStorageCache = $angularCacheFactory('localStorageCache', { cacheFlushInterval: 10, storageMode: 'localStorage' }), - sessionStorageCache = $angularCacheFactory('sessionStorageCache', { cacheFlushInterval: 10, storageMode: 'sessionStorage' }); - - localStorageCache.put('item1', 'value1'); - sessionStorageCache.put('item1', 'value1'); - - if (localStorage) { - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); - expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); - } - if (sessionStorage) { - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); - expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); - } - - waits(100); - runs(function () { - expect(localStorageCache.get('item1')).toEqual(undefined); - expect(sessionStorageCache.get('item1')).toEqual(undefined); - if (localStorage) { - expect(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).toEqual(null); - expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); - } - if (sessionStorage) { - expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).toEqual(null); - expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); - } - localStorageCache.destroy(); - sessionStorageCache.destroy(); - }); - }); - describe('AngularCache.put(key, value, options)', function () { - it('should disallow keys that aren\'t a string', function () { - var cache = $angularCacheFactory('cache'); - var mustBeAStringMsg = 'AngularCache.put(): key: must be a string!'; - try { - cache.put(2, 'value'); - } catch (err) { - var errorMsg = err.message; - } - expect(errorMsg).toEqual(mustBeAStringMsg); - try { - cache.put(true, 'value'); - } catch (err) { - errorMsg = err.message; - } - expect(errorMsg).toEqual(mustBeAStringMsg); - try { - cache.put({ obj: 'obj' }, 'value'); - } catch (err) { - errorMsg = err.message; - } - expect(errorMsg).toEqual(mustBeAStringMsg); - cache.destroy(); - }); - it('should not add values that aren\'t defined', function () { - var cache = $angularCacheFactory('cache'); - cache.put('item', null); - expect(cache.get('item')).toEqual(undefined); - cache.put('item', undefined); - expect(cache.get('item')).toEqual(undefined); - cache.destroy(); - }); - it('should validate maxAge', function () { - var cache = $angularCacheFactory('cache'); - try { - cache.put('item', 'value', { maxAge: 'als;dlfkajsd'}); - } catch (err) { - var errorMsg = err.message; - } - expect(errorMsg).toEqual('AngularCache.put(): maxAge: must be a number!'); - try { - cache.put('item', 'value', { maxAge: Math.floor((Math.random() * 100000) + 1) * -1 }); - } catch (err) { - errorMsg = err.message; - } - expect(errorMsg).toEqual('AngularCache.put(): maxAge: must be greater than zero!'); - errorMsg = null; - try { - cache.put('item', 'value', { maxAge: Math.floor((Math.random() * 100000) + 1) }); - } catch (err) { - errorMsg = 'should not reach this!'; - } - expect(errorMsg).toEqual(null); - cache.destroy(); - }); - it('should increase the size of the cache by one', function () { - var cache = $angularCacheFactory('cache'); - expect(cache.info().size).toEqual(0); - cache.put('item', 'value1'); - expect(cache.info().size).toEqual(1); - cache.put('item2', 'value2'); - expect(cache.info().size).toEqual(2); - cache.destroy(); - }); - it('should overwrite an item if it is re-added to the cache', function () { - var cache = $angularCacheFactory('cache'); - expect(cache.info().size).toEqual(0); - cache.put('item', 'value1'); - expect(cache.info().size).toEqual(1); - cache.put('item', 'value2'); - expect(cache.info().size).toEqual(1); - expect(cache.get('item')).toEqual('value2'); - cache.destroy(); - }); - it('should remove the least recently used item if the capacity has been reached', function () { - var cache = $angularCacheFactory('cache', { capacity: 2 }); - expect(cache.info().size).toEqual(0); - cache.put('item1', 'value1'); - expect(cache.info().size).toEqual(1); - cache.put('item2', 'value2'); - expect(cache.info().size).toEqual(2); - cache.put('item3', 'value3'); - expect(cache.info().size).toEqual(2); - expect(cache.get('item1')).toEqual(undefined); - expect(cache.get('item2')).toEqual('value2'); - expect(cache.get('item3')).toEqual('value3'); - cache.get('item2'); - cache.put('item1', 'value1'); - expect(cache.get('item3')).toEqual(undefined); - expect(cache.get('item1')).toEqual('value1'); - expect(cache.get('item2')).toEqual('value2'); - cache.destroy(); - }); - it('should not delete items if maxAge is specified and deleteOnExpire is set to "none"', function () { - var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'none' }); - cache.put('item1', 'value1'); - expect(cache.get('item1')).toEqual('value1'); - waits(100); - runs(function () { - expect(cache.get('item1')).toEqual('value1'); - expect(cache.info('item1').isExpired).toEqual(true); - cache.destroy(); - }); - }); - it('should set a timeout for an item to expire if maxAge is specified and deleteOnExpire is set to "aggressive"', function () { - var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive' }); - cache.put('item1', 'value1'); - expect(cache.get('item1')).toEqual('value1'); - waits(100); - runs(function () { - $timeout.flush(); - expect(cache.info('item1')).toEqual(undefined); - expect(cache.get('item1')).toEqual(undefined); - cache.destroy(); - }); - }); - it('should should lazy delete an item when maxAge is specified and deleteOnExpire is set to "passive"', function () { - var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'passive' }); - cache.put('item1', 'value1'); - expect(cache.get('item1')).toEqual('value1'); - waits(100); - runs(function () { - expect(cache.info('item1').isExpired).toEqual(true); - expect(cache.get('item1')).toEqual(undefined); - cache.destroy(); - }); - }); - it('should not delete items if maxAge is specified and deleteOnExpire is set to "none" for an item', function () { - var cache = $angularCacheFactory('cache'); - cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'none' }); - expect(cache.get('item1')).toEqual('value1'); - waits(100); - runs(function () { - expect(cache.get('item1')).toEqual('value1'); - expect(cache.info('item1').isExpired).toEqual(true); - cache.destroy(); - }); - }); - it('should set a timeout for an item to expire if maxAge for item is specified and deleteOnExpire is set to "aggressive"', function () { - var cache = $angularCacheFactory('cache'); - cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'aggressive' }); - expect(cache.get('item1')).toEqual('value1'); - waits(100); - runs(function () { - $timeout.flush(); - expect(cache.info('item1')).toEqual(undefined); - expect(cache.get('item1')).toEqual(undefined); - cache.destroy(); - }); - }); - it('should passively expire an item if maxAge for the item is specified and deleteOnExpire is set to "passive"', function () { - var cache = $angularCacheFactory('cache'); - cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); - expect(cache.get('item1')).toEqual('value1'); - waits(100); - runs(function () { - expect(cache.info('item1').isExpired).toEqual(true); - expect(cache.get('item1')).toEqual(undefined); - cache.destroy(); - }); - }); - it('maxAge for a specific item should override maxAge for the cache', function () { - var cache = $angularCacheFactory('cache', { maxAge: 1000, deleteOnExpire: 'aggressive' }); - cache.put('item1', 'value1', { maxAge: 5 }); - expect(cache.info('item1').maxAge).toEqual(5); - expect(cache.get('item1')).toEqual('value1'); - waits(100); - runs(function () { - $timeout.flush(); - expect(cache.get('item1')).toEqual(undefined); - cache.destroy(); - }); - }); - it('deleteOnExpire set to "passive" for a specific item should override deleteOnExpire set to "aggressive" for the cache', function () { - var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive' }); - cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); - expect(cache.get('item1')).toEqual('value1'); - expect(cache.info('item1').deleteOnExpire).toEqual("passive"); - waits(100); - runs(function () { - expect(cache.info('item1').isExpired).toEqual(true); - expect(cache.get('item1')).toEqual(undefined); - cache.destroy(); - }); - }); - it('should save data to localStorage when storageMode is used', function () { - var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), - sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); - - localStorageCache.put('item1', 'value1'); - sessionStorageCache.put('item1', 'value1'); - - if (localStorage) { - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); - expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); - } - if (sessionStorage) { - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); - expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); - } - - localStorageCache.destroy(); - sessionStorageCache.destroy(); - }); - }); - describe('AngularCache.get(key)', function () { - it('should return the correct value for the specified key', function () { - var cache = $angularCacheFactory('cache'); - var value1 = 'value1', - value2 = 2, - value3 = { - value3: 'stuff' - }; - cache.put('item1', value1); - cache.put('item2', value2); - cache.put('item3', value3); - expect(cache.get('item1')).toEqual(value1); - expect(cache.get('item2')).toEqual(value2); - expect(cache.get('item3')).toEqual(value3); - cache.destroy(); - }); - it('should return undefined if the key isn\'t in the cache', function () { - var cache = $angularCacheFactory('cache'); - expect(cache.get('item')).toEqual(undefined); - cache.destroy(); - }); - it('should execute globally configured \'onExpire\' callback if the item is expired in passive mode and global \'onExpire\' callback is configured', function () { - var cache = $angularCacheFactory('cache', { - maxAge: 10, - onExpire: function (key, value, done) { - done(key, value, 'executed global callback'); - } - }); - cache.put('item', 'value'); - waits(100); - runs(function () { - cache.get('item', function (key, value, test) { - expect(key).toEqual('item'); - expect(value).toEqual('value'); - expect(test).toEqual('executed global callback'); - }); - cache.destroy(); - }); - }); - it('should execute globally configured \'onExpire\' callback when an item is aggressively deleted and global \'onExpire\' callback is configured', function () { - var onExpire = jasmine.createSpy(); - var cache = $angularCacheFactory('cache', { - maxAge: 10, - deleteOnExpire: 'aggressive', - onExpire: onExpire - }); - cache.put('item', 'value'); - waits(100); - runs(function () { - $timeout.flush(); - expect(onExpire).toHaveBeenCalled(); - expect(onExpire).toHaveBeenCalledWith('item', 'value'); - cache.destroy(); - }); - }); - it('should execute local \'onExpire\' callback if the item is expired in passive mode and global \'onExpire\' callback is NOT configured', function () { - var cache = $angularCacheFactory('cache', { - maxAge: 10 - }); - cache.put('item', 'value'); - waits(100); - runs(function () { - cache.get('item', function (key, value) { - expect(key).toEqual('item'); - expect(value).toEqual('value'); - }); - cache.destroy(); - }); - }); - }); - describe('AngularCache.remove(key)', function () { - it('should remove the item with the specified key', function () { - var cache = $angularCacheFactory('cache'); - var value1 = 'value1', - value2 = 2, - value3 = { - value3: 'stuff' - }; - cache.put('item1', value1); - cache.put('item2', value2); - cache.put('item3', value3); - cache.remove('item1'); - expect(cache.get('item1')).toEqual(undefined); - cache.remove('item2'); - expect(cache.get('item2')).toEqual(undefined); - cache.remove('item3'); - expect(cache.get('item3')).toEqual(undefined); - cache.destroy(); - }); - it('should reduce the size of the cache by one if the size is greater than zero', function () { - var cache = $angularCacheFactory('cache'); - cache.put('item1', 'value1'); - expect(cache.info().size).toEqual(1); - cache.put('item2', 'value2'); - expect(cache.info().size).toEqual(2); - cache.remove('item1'); - expect(cache.info().size).toEqual(1); - cache.remove('item2'); - expect(cache.info().size).toEqual(0); - cache.remove('item1'); - expect(cache.info().size).toEqual(0); - cache.remove('item2'); - expect(cache.info().size).toEqual(0); - cache.destroy(); - }); - it('should remove items from localStorage when storageMode is used', function () { - var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), - sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); - - localStorageCache.put('item1', 'value1'); - sessionStorageCache.put('item1', 'value1'); - - if (localStorage) { - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); - expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); - } - if (sessionStorage) { - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); - expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); - } - - localStorageCache.remove('item1'); - sessionStorageCache.remove('item1'); - - if (localStorage) { - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); - expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); - } - if (sessionStorage) { - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); - expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); - } - - localStorageCache.destroy(); - sessionStorageCache.destroy(); - }); - }); - describe('AngularCache.removeAll()', function () { - it('should remove all items in the cache', function () { - var cache = $angularCacheFactory('cache'); - var value1 = 'value1', - value2 = 2, - value3 = { - value3: 'stuff' - }; - cache.put('item1', value1); - cache.put('item2', value2); - cache.put('item3', value3); - cache.removeAll(); - expect(cache.get('item1')).toEqual(undefined); - expect(cache.get('item2')).toEqual(undefined); - expect(cache.get('item3')).toEqual(undefined); - cache.destroy(); - }); - it('should remove items from localStorage when storageMode is used', function () { - var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), - sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); - - localStorageCache.put('item1', 'value1'); - sessionStorageCache.put('item1', 'value1'); - localStorageCache.put('item2', 'value2'); - sessionStorageCache.put('item2', 'value2'); - - if (localStorage) { - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2')).value).toEqual('value2'); - expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1","item2"]'); - } - if (sessionStorage) { - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2')).value).toEqual('value2'); - expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1","item2"]'); - } - - localStorageCache.removeAll(); - sessionStorageCache.removeAll(); - - if (localStorage) { - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2'))).toEqual(null); - expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); - } - if (sessionStorage) { - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2'))).toEqual(null); - expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); - } - - localStorageCache.destroy(); - sessionStorageCache.destroy(); - }); - }); - describe('AngularCache.destroy()', function () { - it('should completely destroy the cache', function () { - var cache = $angularCacheFactory('cache'); - cache.destroy(); - expect($angularCacheFactory.get('cache')).toEqual(undefined); - }); - it('should remove items from localStorage when storageMode is used', function () { - var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), - sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); - - localStorageCache.put('item1', 'value1'); - sessionStorageCache.put('item1', 'value1'); - localStorageCache.put('item2', 'value2'); - sessionStorageCache.put('item2', 'value2'); - - if (localStorage) { - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2')).value).toEqual('value2'); - expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1","item2"]'); - } - if (sessionStorage) { - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2')).value).toEqual('value2'); - expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1","item2"]'); - } - - localStorageCache.destroy(); - sessionStorageCache.destroy(); - - if (localStorage) { - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2'))).toEqual(null); - expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual(null); - } - if (sessionStorage) { - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2'))).toEqual(null); - expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual(null); - } - }); - }); - describe('AngularCache.info()', function () { - it('should return the correct values', function () { - var onExpire = function () { - }; - var cache = $angularCacheFactory('cache'), - cache2 = $angularCacheFactory('cache2', { maxAge: 1000 }), - cache3 = $angularCacheFactory('cache3', { cacheFlushInterval: 1000 }), - cache4 = $angularCacheFactory('cache4', { capacity: 1000 }), - cache5 = $angularCacheFactory('cache5', { storageMode: 'localStorage' }), - cache6 = $angularCacheFactory('cache6', { storageMode: 'sessionStorage' }); - cache7 = $angularCacheFactory('cache7', { maxAge: 100, onExpire: onExpire }); - expect(cache.info()).toEqual({ - id: 'cache', - capacity: Number.MAX_VALUE, - size: 0, - maxAge: null, - cacheFlushInterval: null, - deleteOnExpire: 'none', - storageMode: 'none', - onExpire: null - }); - cache.put('item', 'value'); - cache.put('item2', 'value2', { maxAge: 200, deleteOnExpire: 'aggressive' }); - - // AngularCache#info(key) - expect(typeof cache.info('item').timestamp).toEqual('number'); - expect(cache.info('item').maxAge).toEqual(null); - expect(cache.info('item').deleteOnExpire).toEqual('none'); - expect(typeof cache.info('item2').timestamp).toEqual('number'); - expect(cache.info('item2').maxAge).toEqual(200); - expect(cache.info('item2').deleteOnExpire).toEqual('aggressive'); - - expect(cache.info()).toEqual({ - id: 'cache', - capacity: Number.MAX_VALUE, - size: 2, - maxAge: null, - cacheFlushInterval: null, - deleteOnExpire: 'none', - storageMode: 'none', - onExpire: null - }); - expect(cache2.info()).toEqual({ - id: 'cache2', - capacity: Number.MAX_VALUE, - maxAge: 1000, - size: 0, - cacheFlushInterval: null, - deleteOnExpire: 'none', - storageMode: 'none', - onExpire: null - }); - expect(cache3.info().id).toEqual('cache3'); - expect(cache3.info().capacity).toEqual(Number.MAX_VALUE); - expect(cache3.info().cacheFlushInterval).toEqual(1000); - expect(cache3.info().size).toEqual(0); - expect(cache4.info()).toEqual({ - id: 'cache4', - capacity: 1000, - size: 0, - maxAge: null, - cacheFlushInterval: null, - deleteOnExpire: 'none', - storageMode: 'none', - onExpire: null - }); - if (localStorage) { - expect(cache5.info().storageMode).toEqual('localStorage'); - } else { - expect(cache5.info().storageMode).toEqual(null); - } - if (sessionStorage) { - expect(cache6.info().storageMode).toEqual('sessionStorage'); - } else { - expect(cache6.info().storageMode).toEqual(null); - } - expect(cache7.info().onExpire).toEqual(onExpire); - cache.destroy(); - cache2.destroy(); - cache3.destroy(); - cache4.destroy(); - cache5.destroy(); - cache6.destroy(); - cache7.destroy(); - }); - }); - describe('AngularCache.keySet()', function () { - it('should return the correct set of keys of all items currently in a cache', function () { - var itemKeys = ['item1', 'item2', 'item3']; - - var cache = $angularCacheFactory('cache'); - - cache.put(itemKeys[0], itemKeys[0]); - cache.put(itemKeys[1], itemKeys[1]); - cache.put(itemKeys[2], itemKeys[2]); - - var keySet = cache.keySet(); - - expect(keySet.hasOwnProperty(itemKeys[0])).toEqual(true); - expect(keySet.hasOwnProperty(itemKeys[1])).toEqual(true); - expect(keySet.hasOwnProperty(itemKeys[2])).toEqual(true); - - expect(keySet[itemKeys[0]]).toEqual(itemKeys[0]); - expect(keySet[itemKeys[1]]).toEqual(itemKeys[1]); - expect(keySet[itemKeys[2]]).toEqual(itemKeys[2]); - - cache.remove(itemKeys[0]); - cache.remove(itemKeys[1]); - cache.remove(itemKeys[2]); - - keySet = cache.keySet(); - - expect(keySet.hasOwnProperty(itemKeys[0])).toEqual(false); - expect(keySet.hasOwnProperty(itemKeys[1])).toEqual(false); - expect(keySet.hasOwnProperty(itemKeys[2])).toEqual(false); - cache.destroy(); - }); - }); - describe('AngularCache.keys()', function () { - it('should return the correct array of keys of all items currently in a cache', function () { - var itemKeys = ['item1', 'item2', 'item3']; - - var cache = $angularCacheFactory('cache'); - - cache.put(itemKeys[0], itemKeys[0]); - cache.put(itemKeys[1], itemKeys[1]); - cache.put(itemKeys[2], itemKeys[2]); - - var keys = cache.keys(); - - expect(keys[0]).toEqual(itemKeys[0]); - expect(keys[1]).toEqual(itemKeys[1]); - expect(keys[2]).toEqual(itemKeys[2]); - - cache.remove(itemKeys[0]); - cache.remove(itemKeys[1]); - cache.remove(itemKeys[2]); - - keys = cache.keys(); - - expect(keys.length).toEqual(0); - cache.destroy(); - }); - }); - describe('AngularCache.setOptions()', function () { - it('should correctly reset to defaults if strict mode is true', function () { - var onExpire = function () { - }; - var cache = $angularCacheFactory('cache', { - maxAge: 100, - cacheFlushInterval: 200, - onExpire: onExpire, - storageMode: 'localStorage' - }); - expect(cache.info().maxAge).toEqual(100); - expect(cache.info().cacheFlushInterval).toEqual(200); - expect(cache.info().onExpire).toEqual(onExpire); - expect(cache.info().storageMode).toEqual('localStorage'); - cache.setOptions({ }, true); - expect(cache.info().maxAge).toEqual(null); - expect(cache.info().cacheFlushInterval).toEqual(null); - expect(cache.info().onExpire).toEqual(null); - expect(cache.info().storageMode).toEqual('none'); - cache.destroy(); - }); - it('should correctly modify the capacity of a cache', function () { - var cache = $angularCacheFactory('cache'); - expect(cache.info().capacity).toEqual(Number.MAX_VALUE); - cache.setOptions({ capacity: 5 }, false); - expect(cache.info().capacity).toEqual(5); - cache.put('item1', 1); - cache.put('item2', 2); - cache.put('item3', 3); - cache.put('item4', 4); - cache.put('item5', 5); - cache.put('item6', 6); - expect(cache.get('item1')).not.toBeDefined(); - cache.setOptions({ capacity: 3 }, false); - // Least-recently used items over the new capacity should have been removed. - expect(cache.get('item2')).not.toBeDefined(); - expect(cache.get('item3')).not.toBeDefined(); - expect(cache.info().size).toEqual(3); - cache.destroy(); - }); - it('should correctly modify the maxAge of a cache', function () { - var cache = $angularCacheFactory('cache'); - expect(cache.info().maxAge).toEqual(null); - cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); - expect(cache.info().maxAge).toEqual(10); - cache.put('item1', 1); - cache.put('item2', 2); - waits(100); - runs(function () { - $timeout.flush(); - expect(cache.get('item1')).not.toBeDefined(); - expect(cache.get('item2')).not.toBeDefined(); - cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); - expect(cache.info().maxAge).toEqual(10); - cache.put('item1', 1); - cache.put('item2', 2); - waits(100); - // The new items should be removed after 500 ms (the new maxAge) - runs(function () { - $timeout.flush(); - expect(cache.get('item1')).not.toBeDefined(); - expect(cache.get('item2')).not.toBeDefined(); - cache.destroy(); - }); - }); - }); - it('should correctly modify the cacheFlushInterval of a cache', function () { - var cache = $angularCacheFactory('cache'); - expect(cache.info().cacheFlushInterval).toEqual(null); - cache.setOptions({ cacheFlushInterval: 10 }, false); - expect(cache.info().cacheFlushInterval).toEqual(10); - cache.put('item1', 1); - cache.put('item2', 2); - waits(100); - // The first items should be removed after 2000 ms - runs(function () { - expect(cache.get('item1')).not.toBeDefined(); - expect(cache.get('item2')).not.toBeDefined(); - cache.setOptions({ cacheFlushInterval: 10 }, false); - expect(cache.info().cacheFlushInterval).toEqual(10); - cache.put('item1', 1); - cache.put('item2', 2); - waits(100); - // The new items should be removed after 500 ms (the new maxAge) - runs(function () { - expect(cache.get('item1')).not.toBeDefined(); - expect(cache.get('item2')).not.toBeDefined(); - cache.destroy(); - }); - }); - }); - it('should correctly modify the deleteOnExpire of a cache', function () { - var cache = $angularCacheFactory('cache', { maxAge: 10 }); - expect(cache.info().deleteOnExpire).toEqual('none'); - cache.setOptions({ deleteOnExpire: 'passive' }, false); - expect(cache.info().deleteOnExpire).toEqual('passive'); - cache.put('item1', 1); - cache.put('item2', 2); - waits(100); - // The first items should be removed after 2000 ms - runs(function () { - expect(cache.get('item1')).not.toBeDefined(); - expect(cache.get('item2')).not.toBeDefined(); - cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); - expect(cache.info().deleteOnExpire).toEqual('aggressive'); - cache.put('item1', 1); - cache.put('item2', 2); - waits(100); - // The new items should be removed after 500 ms (the new maxAge) - runs(function () { - $timeout.flush(); - expect(cache.get('item1')).not.toBeDefined(); - expect(cache.get('item2')).not.toBeDefined(); - cache.destroy(); - }); - }); - }); - it('should correctly set configuration to default when \'strict\' is true', function () { - var cache = $angularCacheFactory('cache', { - capacity: 10, - maxAge: 1000, - cacheFlushInterval: 1000, - deleteOnExpire: 'aggressive', - storageMode: 'none' - }); - cache.setOptions({}, true); - expect(cache.info()).toEqual({ - capacity: Number.MAX_VALUE, - maxAge: null, - cacheFlushInterval: null, - id: 'cache', - size: 0, - deleteOnExpire: 'none', - storageMode: 'none', - onExpire: null - }); - }); - it('should correctly switch to using local/session storage when storageMode is activated', function () { - var cache = $angularCacheFactory('cache'), - cache2 = $angularCacheFactory('cache2'); - cache.put('item', 'value'); - cache2.put('item', 'value'); - cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'localStorage' }); - cache2.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'sessionStorage' }); - - if (localStorage) { - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); - } - if (sessionStorage) { - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); - } - waits(100); - runs(function () { - $timeout.flush(); - expect(cache.get('item')).toEqual(null); - expect(cache2.get('item')).toEqual(null); - if (localStorage) { - expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); - } - if (sessionStorage) { - expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); - } - cache.destroy(); - cache2.destroy(); - }); - }); - it('should correctly stop using local/session storage when storageMode is deactivated', function () { - var cache = $angularCacheFactory('cache', { storageMode: 'localStorage' }), - cache2 = $angularCacheFactory('cache2', { storageMode: 'sessionStorage' }); - cache.put('item', 'value'); - cache2.put('item', 'value'); - - if (localStorage) { - expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); - } - if (sessionStorage) { - expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); - } - - cache.setOptions({ storageMode: 'none' }, true); - cache2.setOptions({ storageMode: 'none' }, true); - - if (localStorage) { - expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); - } - if (sessionStorage) { - expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); - } - - cache.destroy(); - cache2.destroy(); - }); - }); -}); \ No newline at end of file +//describe('AngularCache', function () { +// +// var $angularCacheFactory, $timeout; +// beforeEach(module('jmdobry.angular-cache')); +// beforeEach(inject(function ($injector) { +// $angularCacheFactory = $injector.get('$angularCacheFactory'); +// $timeout = $injector.get('$timeout'); +// })); +// +// it('should clear itself if cacheFlushInterval is specified', function () { +// var cache = $angularCacheFactory('cache', { cacheFlushInterval: 10 }); +// cache.put('item1', 'value1'); +// expect(cache.get('item1')).toEqual('value1'); +// cache.put('item2', 'value2'); +// expect(cache.get('item2')).toEqual('value2'); +// waits(100); +// runs(function () { +// expect(cache.get('item1')).toEqual(undefined); +// expect(cache.get('item2')).toEqual(undefined); +// cache.destroy(); +// }); +// }); +// it('should clear itself and web storage if cacheFlushInterval and storageMode are specified', function () { +// var localStorageCache = $angularCacheFactory('localStorageCache', { cacheFlushInterval: 10, storageMode: 'localStorage' }), +// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { cacheFlushInterval: 10, storageMode: 'sessionStorage' }); +// +// localStorageCache.put('item1', 'value1'); +// sessionStorageCache.put('item1', 'value1'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); +// } +// +// waits(100); +// runs(function () { +// expect(localStorageCache.get('item1')).toEqual(undefined); +// expect(sessionStorageCache.get('item1')).toEqual(undefined); +// if (localStorage) { +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).toEqual(null); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); +// } +// if (sessionStorage) { +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).toEqual(null); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); +// } +// localStorageCache.destroy(); +// sessionStorageCache.destroy(); +// }); +// }); +// describe('AngularCache.put(key, value, options)', function () { +// it('should disallow keys that aren\'t a string', function () { +// var cache = $angularCacheFactory('cache'); +// var mustBeAStringMsg = 'AngularCache.put(): key: must be a string!'; +// try { +// cache.put(2, 'value'); +// } catch (err) { +// var errorMsg = err.message; +// } +// expect(errorMsg).toEqual(mustBeAStringMsg); +// try { +// cache.put(true, 'value'); +// } catch (err) { +// errorMsg = err.message; +// } +// expect(errorMsg).toEqual(mustBeAStringMsg); +// try { +// cache.put({ obj: 'obj' }, 'value'); +// } catch (err) { +// errorMsg = err.message; +// } +// expect(errorMsg).toEqual(mustBeAStringMsg); +// cache.destroy(); +// }); +// it('should not add values that aren\'t defined', function () { +// var cache = $angularCacheFactory('cache'); +// cache.put('item', null); +// expect(cache.get('item')).toEqual(undefined); +// cache.put('item', undefined); +// expect(cache.get('item')).toEqual(undefined); +// cache.destroy(); +// }); +// it('should validate maxAge', function () { +// var cache = $angularCacheFactory('cache'); +// try { +// cache.put('item', 'value', { maxAge: 'als;dlfkajsd'}); +// } catch (err) { +// var errorMsg = err.message; +// } +// expect(errorMsg).toEqual('AngularCache.put(): maxAge: must be a number!'); +// try { +// cache.put('item', 'value', { maxAge: Math.floor((Math.random() * 100000) + 1) * -1 }); +// } catch (err) { +// errorMsg = err.message; +// } +// expect(errorMsg).toEqual('AngularCache.put(): maxAge: must be greater than zero!'); +// errorMsg = null; +// try { +// cache.put('item', 'value', { maxAge: Math.floor((Math.random() * 100000) + 1) }); +// } catch (err) { +// errorMsg = 'should not reach this!'; +// } +// expect(errorMsg).toEqual(null); +// cache.destroy(); +// }); +// it('should increase the size of the cache by one', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.info().size).toEqual(0); +// cache.put('item', 'value1'); +// expect(cache.info().size).toEqual(1); +// cache.put('item2', 'value2'); +// expect(cache.info().size).toEqual(2); +// cache.destroy(); +// }); +// it('should overwrite an item if it is re-added to the cache', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.info().size).toEqual(0); +// cache.put('item', 'value1'); +// expect(cache.info().size).toEqual(1); +// cache.put('item', 'value2'); +// expect(cache.info().size).toEqual(1); +// expect(cache.get('item')).toEqual('value2'); +// cache.destroy(); +// }); +// it('should remove the least recently used item if the capacity has been reached', function () { +// var cache = $angularCacheFactory('cache', { capacity: 2 }); +// expect(cache.info().size).toEqual(0); +// cache.put('item1', 'value1'); +// expect(cache.info().size).toEqual(1); +// cache.put('item2', 'value2'); +// expect(cache.info().size).toEqual(2); +// cache.put('item3', 'value3'); +// expect(cache.info().size).toEqual(2); +// expect(cache.get('item1')).toEqual(undefined); +// expect(cache.get('item2')).toEqual('value2'); +// expect(cache.get('item3')).toEqual('value3'); +// cache.get('item2'); +// cache.put('item1', 'value1'); +// expect(cache.get('item3')).toEqual(undefined); +// expect(cache.get('item1')).toEqual('value1'); +// expect(cache.get('item2')).toEqual('value2'); +// cache.destroy(); +// }); +// it('should not delete items if maxAge is specified and deleteOnExpire is set to "none"', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'none' }); +// cache.put('item1', 'value1'); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// expect(cache.get('item1')).toEqual('value1'); +// expect(cache.info('item1').isExpired).toEqual(true); +// cache.destroy(); +// }); +// }); +// it('should set a timeout for an item to expire if maxAge is specified and deleteOnExpire is set to "aggressive"', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive' }); +// cache.put('item1', 'value1'); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(cache.info('item1')).toEqual(undefined); +// expect(cache.get('item1')).toEqual(undefined); +// cache.destroy(); +// }); +// }); +// it('should should lazy delete an item when maxAge is specified and deleteOnExpire is set to "passive"', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'passive' }); +// cache.put('item1', 'value1'); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// expect(cache.info('item1').isExpired).toEqual(true); +// expect(cache.get('item1')).toEqual(undefined); +// cache.destroy(); +// }); +// }); +// it('should not delete items if maxAge is specified and deleteOnExpire is set to "none" for an item', function () { +// var cache = $angularCacheFactory('cache'); +// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'none' }); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// expect(cache.get('item1')).toEqual('value1'); +// expect(cache.info('item1').isExpired).toEqual(true); +// cache.destroy(); +// }); +// }); +// it('should set a timeout for an item to expire if maxAge for item is specified and deleteOnExpire is set to "aggressive"', function () { +// var cache = $angularCacheFactory('cache'); +// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'aggressive' }); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(cache.info('item1')).toEqual(undefined); +// expect(cache.get('item1')).toEqual(undefined); +// cache.destroy(); +// }); +// }); +// it('should passively expire an item if maxAge for the item is specified and deleteOnExpire is set to "passive"', function () { +// var cache = $angularCacheFactory('cache'); +// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// expect(cache.info('item1').isExpired).toEqual(true); +// expect(cache.get('item1')).toEqual(undefined); +// cache.destroy(); +// }); +// }); +// it('maxAge for a specific item should override maxAge for the cache', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 1000, deleteOnExpire: 'aggressive' }); +// cache.put('item1', 'value1', { maxAge: 5 }); +// expect(cache.info('item1').maxAge).toEqual(5); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(cache.get('item1')).toEqual(undefined); +// cache.destroy(); +// }); +// }); +// it('deleteOnExpire set to "passive" for a specific item should override deleteOnExpire set to "aggressive" for the cache', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive' }); +// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); +// expect(cache.get('item1')).toEqual('value1'); +// expect(cache.info('item1').deleteOnExpire).toEqual("passive"); +// waits(100); +// runs(function () { +// expect(cache.info('item1').isExpired).toEqual(true); +// expect(cache.get('item1')).toEqual(undefined); +// cache.destroy(); +// }); +// }); +// it('should save data to localStorage when storageMode is used', function () { +// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), +// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); +// +// localStorageCache.put('item1', 'value1'); +// sessionStorageCache.put('item1', 'value1'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); +// } +// +// localStorageCache.destroy(); +// sessionStorageCache.destroy(); +// }); +// }); +// describe('AngularCache.get(key)', function () { +// it('should return the correct value for the specified key', function () { +// var cache = $angularCacheFactory('cache'); +// var value1 = 'value1', +// value2 = 2, +// value3 = { +// value3: 'stuff' +// }; +// cache.put('item1', value1); +// cache.put('item2', value2); +// cache.put('item3', value3); +// expect(cache.get('item1')).toEqual(value1); +// expect(cache.get('item2')).toEqual(value2); +// expect(cache.get('item3')).toEqual(value3); +// cache.destroy(); +// }); +// it('should return undefined if the key isn\'t in the cache', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.get('item')).toEqual(undefined); +// cache.destroy(); +// }); +// it('should execute globally configured \'onExpire\' callback if the item is expired in passive mode and global \'onExpire\' callback is configured', function () { +// var cache = $angularCacheFactory('cache', { +// maxAge: 10, +// onExpire: function (key, value, done) { +// done(key, value, 'executed global callback'); +// } +// }); +// cache.put('item', 'value'); +// waits(100); +// runs(function () { +// cache.get('item', function (key, value, test) { +// expect(key).toEqual('item'); +// expect(value).toEqual('value'); +// expect(test).toEqual('executed global callback'); +// }); +// cache.destroy(); +// }); +// }); +// it('should execute globally configured \'onExpire\' callback when an item is aggressively deleted and global \'onExpire\' callback is configured', function () { +// var onExpire = jasmine.createSpy(); +// var cache = $angularCacheFactory('cache', { +// maxAge: 10, +// deleteOnExpire: 'aggressive', +// onExpire: onExpire +// }); +// cache.put('item', 'value'); +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(onExpire).toHaveBeenCalled(); +// expect(onExpire).toHaveBeenCalledWith('item', 'value'); +// cache.destroy(); +// }); +// }); +// it('should execute local \'onExpire\' callback if the item is expired in passive mode and global \'onExpire\' callback is NOT configured', function () { +// var cache = $angularCacheFactory('cache', { +// maxAge: 10 +// }); +// cache.put('item', 'value'); +// waits(100); +// runs(function () { +// cache.get('item', function (key, value) { +// expect(key).toEqual('item'); +// expect(value).toEqual('value'); +// }); +// cache.destroy(); +// }); +// }); +// }); +// describe('AngularCache.remove(key)', function () { +// it('should remove the item with the specified key', function () { +// var cache = $angularCacheFactory('cache'); +// var value1 = 'value1', +// value2 = 2, +// value3 = { +// value3: 'stuff' +// }; +// cache.put('item1', value1); +// cache.put('item2', value2); +// cache.put('item3', value3); +// cache.remove('item1'); +// expect(cache.get('item1')).toEqual(undefined); +// cache.remove('item2'); +// expect(cache.get('item2')).toEqual(undefined); +// cache.remove('item3'); +// expect(cache.get('item3')).toEqual(undefined); +// cache.destroy(); +// }); +// it('should reduce the size of the cache by one if the size is greater than zero', function () { +// var cache = $angularCacheFactory('cache'); +// cache.put('item1', 'value1'); +// expect(cache.info().size).toEqual(1); +// cache.put('item2', 'value2'); +// expect(cache.info().size).toEqual(2); +// cache.remove('item1'); +// expect(cache.info().size).toEqual(1); +// cache.remove('item2'); +// expect(cache.info().size).toEqual(0); +// cache.remove('item1'); +// expect(cache.info().size).toEqual(0); +// cache.remove('item2'); +// expect(cache.info().size).toEqual(0); +// cache.destroy(); +// }); +// it('should remove items from localStorage when storageMode is used', function () { +// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), +// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); +// +// localStorageCache.put('item1', 'value1'); +// sessionStorageCache.put('item1', 'value1'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); +// } +// +// localStorageCache.remove('item1'); +// sessionStorageCache.remove('item1'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); +// } +// +// localStorageCache.destroy(); +// sessionStorageCache.destroy(); +// }); +// }); +// describe('AngularCache.removeAll()', function () { +// it('should remove all items in the cache', function () { +// var cache = $angularCacheFactory('cache'); +// var value1 = 'value1', +// value2 = 2, +// value3 = { +// value3: 'stuff' +// }; +// cache.put('item1', value1); +// cache.put('item2', value2); +// cache.put('item3', value3); +// cache.removeAll(); +// expect(cache.get('item1')).toEqual(undefined); +// expect(cache.get('item2')).toEqual(undefined); +// expect(cache.get('item3')).toEqual(undefined); +// cache.destroy(); +// }); +// it('should remove items from localStorage when storageMode is used', function () { +// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), +// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); +// +// localStorageCache.put('item1', 'value1'); +// sessionStorageCache.put('item1', 'value1'); +// localStorageCache.put('item2', 'value2'); +// sessionStorageCache.put('item2', 'value2'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2')).value).toEqual('value2'); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1","item2"]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2')).value).toEqual('value2'); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1","item2"]'); +// } +// +// localStorageCache.removeAll(); +// sessionStorageCache.removeAll(); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2'))).toEqual(null); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2'))).toEqual(null); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); +// } +// +// localStorageCache.destroy(); +// sessionStorageCache.destroy(); +// }); +// }); +// describe('AngularCache.destroy()', function () { +// it('should completely destroy the cache', function () { +// var cache = $angularCacheFactory('cache'); +// cache.destroy(); +// expect($angularCacheFactory.get('cache')).toEqual(undefined); +// }); +// it('should remove items from localStorage when storageMode is used', function () { +// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), +// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); +// +// localStorageCache.put('item1', 'value1'); +// sessionStorageCache.put('item1', 'value1'); +// localStorageCache.put('item2', 'value2'); +// sessionStorageCache.put('item2', 'value2'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2')).value).toEqual('value2'); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1","item2"]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2')).value).toEqual('value2'); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1","item2"]'); +// } +// +// localStorageCache.destroy(); +// sessionStorageCache.destroy(); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2'))).toEqual(null); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual(null); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2'))).toEqual(null); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual(null); +// } +// }); +// }); +// describe('AngularCache.info()', function () { +// it('should return the correct values', function () { +// var onExpire = function () { +// }; +// var cache = $angularCacheFactory('cache'), +// cache2 = $angularCacheFactory('cache2', { maxAge: 1000 }), +// cache3 = $angularCacheFactory('cache3', { cacheFlushInterval: 1000 }), +// cache4 = $angularCacheFactory('cache4', { capacity: 1000 }), +// cache5 = $angularCacheFactory('cache5', { storageMode: 'localStorage' }), +// cache6 = $angularCacheFactory('cache6', { storageMode: 'sessionStorage' }); +// cache7 = $angularCacheFactory('cache7', { maxAge: 100, onExpire: onExpire }); +// expect(cache.info()).toEqual({ +// id: 'cache', +// capacity: Number.MAX_VALUE, +// size: 0, +// maxAge: null, +// cacheFlushInterval: null, +// deleteOnExpire: 'none', +// storageMode: 'none', +// onExpire: null +// }); +// cache.put('item', 'value'); +// cache.put('item2', 'value2', { maxAge: 200, deleteOnExpire: 'aggressive' }); +// +// // AngularCache#info(key) +// expect(typeof cache.info('item').timestamp).toEqual('number'); +// expect(cache.info('item').maxAge).toEqual(null); +// expect(cache.info('item').deleteOnExpire).toEqual('none'); +// expect(typeof cache.info('item2').timestamp).toEqual('number'); +// expect(cache.info('item2').maxAge).toEqual(200); +// expect(cache.info('item2').deleteOnExpire).toEqual('aggressive'); +// +// expect(cache.info()).toEqual({ +// id: 'cache', +// capacity: Number.MAX_VALUE, +// size: 2, +// maxAge: null, +// cacheFlushInterval: null, +// deleteOnExpire: 'none', +// storageMode: 'none', +// onExpire: null +// }); +// expect(cache2.info()).toEqual({ +// id: 'cache2', +// capacity: Number.MAX_VALUE, +// maxAge: 1000, +// size: 0, +// cacheFlushInterval: null, +// deleteOnExpire: 'none', +// storageMode: 'none', +// onExpire: null +// }); +// expect(cache3.info().id).toEqual('cache3'); +// expect(cache3.info().capacity).toEqual(Number.MAX_VALUE); +// expect(cache3.info().cacheFlushInterval).toEqual(1000); +// expect(cache3.info().size).toEqual(0); +// expect(cache4.info()).toEqual({ +// id: 'cache4', +// capacity: 1000, +// size: 0, +// maxAge: null, +// cacheFlushInterval: null, +// deleteOnExpire: 'none', +// storageMode: 'none', +// onExpire: null +// }); +// if (localStorage) { +// expect(cache5.info().storageMode).toEqual('localStorage'); +// } else { +// expect(cache5.info().storageMode).toEqual(null); +// } +// if (sessionStorage) { +// expect(cache6.info().storageMode).toEqual('sessionStorage'); +// } else { +// expect(cache6.info().storageMode).toEqual(null); +// } +// expect(cache7.info().onExpire).toEqual(onExpire); +// cache.destroy(); +// cache2.destroy(); +// cache3.destroy(); +// cache4.destroy(); +// cache5.destroy(); +// cache6.destroy(); +// cache7.destroy(); +// }); +// }); +// describe('AngularCache.keySet()', function () { +// it('should return the correct set of keys of all items currently in a cache', function () { +// var itemKeys = ['item1', 'item2', 'item3']; +// +// var cache = $angularCacheFactory('cache'); +// +// cache.put(itemKeys[0], itemKeys[0]); +// cache.put(itemKeys[1], itemKeys[1]); +// cache.put(itemKeys[2], itemKeys[2]); +// +// var keySet = cache.keySet(); +// +// expect(keySet.hasOwnProperty(itemKeys[0])).toEqual(true); +// expect(keySet.hasOwnProperty(itemKeys[1])).toEqual(true); +// expect(keySet.hasOwnProperty(itemKeys[2])).toEqual(true); +// +// expect(keySet[itemKeys[0]]).toEqual(itemKeys[0]); +// expect(keySet[itemKeys[1]]).toEqual(itemKeys[1]); +// expect(keySet[itemKeys[2]]).toEqual(itemKeys[2]); +// +// cache.remove(itemKeys[0]); +// cache.remove(itemKeys[1]); +// cache.remove(itemKeys[2]); +// +// keySet = cache.keySet(); +// +// expect(keySet.hasOwnProperty(itemKeys[0])).toEqual(false); +// expect(keySet.hasOwnProperty(itemKeys[1])).toEqual(false); +// expect(keySet.hasOwnProperty(itemKeys[2])).toEqual(false); +// cache.destroy(); +// }); +// }); +// describe('AngularCache.keys()', function () { +// it('should return the correct array of keys of all items currently in a cache', function () { +// var itemKeys = ['item1', 'item2', 'item3']; +// +// var cache = $angularCacheFactory('cache'); +// +// cache.put(itemKeys[0], itemKeys[0]); +// cache.put(itemKeys[1], itemKeys[1]); +// cache.put(itemKeys[2], itemKeys[2]); +// +// var keys = cache.keys(); +// +// expect(keys[0]).toEqual(itemKeys[0]); +// expect(keys[1]).toEqual(itemKeys[1]); +// expect(keys[2]).toEqual(itemKeys[2]); +// +// cache.remove(itemKeys[0]); +// cache.remove(itemKeys[1]); +// cache.remove(itemKeys[2]); +// +// keys = cache.keys(); +// +// expect(keys.length).toEqual(0); +// cache.destroy(); +// }); +// }); +// describe('AngularCache.setOptions()', function () { +// it('should correctly reset to defaults if strict mode is true', function () { +// var onExpire = function () { +// }; +// var cache = $angularCacheFactory('cache', { +// maxAge: 100, +// cacheFlushInterval: 200, +// onExpire: onExpire, +// storageMode: 'localStorage' +// }); +// expect(cache.info().maxAge).toEqual(100); +// expect(cache.info().cacheFlushInterval).toEqual(200); +// expect(cache.info().onExpire).toEqual(onExpire); +// expect(cache.info().storageMode).toEqual('localStorage'); +// cache.setOptions({ }, true); +// expect(cache.info().maxAge).toEqual(null); +// expect(cache.info().cacheFlushInterval).toEqual(null); +// expect(cache.info().onExpire).toEqual(null); +// expect(cache.info().storageMode).toEqual('none'); +// cache.destroy(); +// }); +// it('should correctly modify the capacity of a cache', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.info().capacity).toEqual(Number.MAX_VALUE); +// cache.setOptions({ capacity: 5 }, false); +// expect(cache.info().capacity).toEqual(5); +// cache.put('item1', 1); +// cache.put('item2', 2); +// cache.put('item3', 3); +// cache.put('item4', 4); +// cache.put('item5', 5); +// cache.put('item6', 6); +// expect(cache.get('item1')).not.toBeDefined(); +// cache.setOptions({ capacity: 3 }, false); +// // Least-recently used items over the new capacity should have been removed. +// expect(cache.get('item2')).not.toBeDefined(); +// expect(cache.get('item3')).not.toBeDefined(); +// expect(cache.info().size).toEqual(3); +// cache.destroy(); +// }); +// it('should correctly modify the maxAge of a cache', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.info().maxAge).toEqual(null); +// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); +// expect(cache.info().maxAge).toEqual(10); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); +// expect(cache.info().maxAge).toEqual(10); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// // The new items should be removed after 500 ms (the new maxAge) +// runs(function () { +// $timeout.flush(); +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// cache.destroy(); +// }); +// }); +// }); +// it('should correctly modify the cacheFlushInterval of a cache', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.info().cacheFlushInterval).toEqual(null); +// cache.setOptions({ cacheFlushInterval: 10 }, false); +// expect(cache.info().cacheFlushInterval).toEqual(10); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// // The first items should be removed after 2000 ms +// runs(function () { +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// cache.setOptions({ cacheFlushInterval: 10 }, false); +// expect(cache.info().cacheFlushInterval).toEqual(10); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// // The new items should be removed after 500 ms (the new maxAge) +// runs(function () { +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// cache.destroy(); +// }); +// }); +// }); +// it('should correctly modify the deleteOnExpire of a cache', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 10 }); +// expect(cache.info().deleteOnExpire).toEqual('none'); +// cache.setOptions({ deleteOnExpire: 'passive' }, false); +// expect(cache.info().deleteOnExpire).toEqual('passive'); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// // The first items should be removed after 2000 ms +// runs(function () { +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); +// expect(cache.info().deleteOnExpire).toEqual('aggressive'); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// // The new items should be removed after 500 ms (the new maxAge) +// runs(function () { +// $timeout.flush(); +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// cache.destroy(); +// }); +// }); +// }); +// it('should correctly set configuration to default when \'strict\' is true', function () { +// var cache = $angularCacheFactory('cache', { +// capacity: 10, +// maxAge: 1000, +// cacheFlushInterval: 1000, +// deleteOnExpire: 'aggressive', +// storageMode: 'none' +// }); +// cache.setOptions({}, true); +// expect(cache.info()).toEqual({ +// capacity: Number.MAX_VALUE, +// maxAge: null, +// cacheFlushInterval: null, +// id: 'cache', +// size: 0, +// deleteOnExpire: 'none', +// storageMode: 'none', +// onExpire: null +// }); +// }); +// it('should correctly switch to using local/session storage when storageMode is activated', function () { +// var cache = $angularCacheFactory('cache'), +// cache2 = $angularCacheFactory('cache2'); +// cache.put('item', 'value'); +// cache2.put('item', 'value'); +// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'localStorage' }); +// cache2.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'sessionStorage' }); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); +// } +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(cache.get('item')).toEqual(null); +// expect(cache2.get('item')).toEqual(null); +// if (localStorage) { +// expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); +// } +// if (sessionStorage) { +// expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); +// } +// cache.destroy(); +// cache2.destroy(); +// }); +// }); +// it('should correctly stop using local/session storage when storageMode is deactivated', function () { +// var cache = $angularCacheFactory('cache', { storageMode: 'localStorage' }), +// cache2 = $angularCacheFactory('cache2', { storageMode: 'sessionStorage' }); +// cache.put('item', 'value'); +// cache2.put('item', 'value'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); +// } +// +// cache.setOptions({ storageMode: 'none' }, true); +// cache2.setOptions({ storageMode: 'none' }, true); +// +// if (localStorage) { +// expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); +// } +// if (sessionStorage) { +// expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); +// } +// +// cache.destroy(); +// cache2.destroy(); +// }); +// }); +//}); \ No newline at end of file diff --git a/test/karma.start.js b/test/karma.start.js new file mode 100644 index 0000000..c20ab74 --- /dev/null +++ b/test/karma.start.js @@ -0,0 +1,28 @@ +var fail = function () { + expect('should not reach this!').toEqual('failure'); + }, + TYPES_EXCEPT_STRING = [123, 123.123, null, undefined, {}, [], true, false], + TYPES_EXCEPT_NUMBER = ['string', null, undefined, {}, [], true, false], + TYPES_EXCEPT_OBJECT = ['string', 123, 123.123, null, undefined, [], true, false], + TYPES_EXCEPT_ARRAY = ['string', 123, 123.123, null, undefined, {}, true, false], + TYPES_EXCEPT_BOOLEAN = ['string', 123, 123.123, null, undefined, {}, []], + CACHE_DEFAULTS = { + capacity: Number.MAX_VALUE, + maxAge: null, + deleteOnExpire: 'none', + onExpire: null, + cacheFlushInterval: null, + recycleFreq: 1000, + storageMode: 'none', + storageImpl: null, + verifyIntegrity: true + }; + +var $angularCacheFactory; +beforeEach(module('jmdobry.angular-cache')); +beforeEach(inject(function ($injector) { + $angularCacheFactory = $injector.get('$angularCacheFactory'); +})); +afterEach(function () { + $angularCacheFactory.removeAll(); +}); \ No newline at end of file From b8e91786312714d441b3170564ed881e4a9a7649 Mon Sep 17 00:00:00 2001 From: jmdobry Date: Thu, 26 Sep 2013 00:42:18 -0600 Subject: [PATCH 4/8] Finished the tests for `$angularCacheFactory`. #58 --- Gruntfile.js | 4 +- test/angularCache.destroy-test.js | 41 +++++ test/angularCache.get-test.js | 65 ++++++++ test/angularCache.info-test.js | 86 ++++++++++ test/angularCache.keySet-test.js | 31 ++++ test/angularCache.keys-test.js | 25 +++ test/angularCache.put-test.js | 188 ++++++++++++++++++++++ test/angularCache.remove-test.js | 62 +++++++ test/angularCache.removeAll-test.js | 51 ++++++ test/angularCache.removeExpired-test.js | 0 test/angularCache.setOptions-test.js | 183 +++++++++++++++++++++ test/angularCacheFactory-test.js | 188 ++++++++++++---------- test/angularCacheFactory.clearAll-test.js | 58 +++++-- test/angularCacheFactory.info-test.js | 48 +++--- test/angularCacheFactory.keySet-test.js | 19 +++ test/angularCacheFactory.keys-test.js | 11 +- test/karma.start.js | 14 +- 17 files changed, 945 insertions(+), 129 deletions(-) create mode 100644 test/angularCache.destroy-test.js create mode 100644 test/angularCache.get-test.js create mode 100644 test/angularCache.info-test.js create mode 100644 test/angularCache.keySet-test.js create mode 100644 test/angularCache.keys-test.js create mode 100644 test/angularCache.put-test.js create mode 100644 test/angularCache.remove-test.js create mode 100644 test/angularCache.removeAll-test.js create mode 100644 test/angularCache.removeExpired-test.js create mode 100644 test/angularCache.setOptions-test.js diff --git a/Gruntfile.js b/Gruntfile.js index c31bb71..0b5ea6c 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -59,9 +59,7 @@ module.exports = function (grunt) { preprocessors: { 'src/angular-cache.js': ['coverage'] }, - reporters: { - reporters: ['progress', 'coverage'] - } + reporters: ['progress', 'coverage'] } }, jsdoc : { diff --git a/test/angularCache.destroy-test.js b/test/angularCache.destroy-test.js new file mode 100644 index 0000000..b1c54ad --- /dev/null +++ b/test/angularCache.destroy-test.js @@ -0,0 +1,41 @@ +describe('AngularCache.destroy()', function () { + it('should destroy the cache and remove all traces of its existence.', function () { + var cache = $angularCacheFactory('cache'); + cache.destroy(); + expect($angularCacheFactory.get('cache')).toEqual(undefined); + }); + it('should remove items from localStorage when storageMode is used', function () { + var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), + sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); + + localStorageCache.put('item1', 'value1'); + sessionStorageCache.put('item1', 'value1'); + localStorageCache.put('item2', 'value2'); + sessionStorageCache.put('item2', 'value2'); + + if (localStorage) { + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2')).value).toEqual('value2'); + expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1","item2"]'); + } + if (sessionStorage) { + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2')).value).toEqual('value2'); + expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1","item2"]'); + } + + localStorageCache.destroy(); + sessionStorageCache.destroy(); + + if (localStorage) { + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2'))).toEqual(null); + expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual(null); + } + if (sessionStorage) { + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2'))).toEqual(null); + expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual(null); + } + }); +}); \ No newline at end of file diff --git a/test/angularCache.get-test.js b/test/angularCache.get-test.js new file mode 100644 index 0000000..332d7cb --- /dev/null +++ b/test/angularCache.get-test.js @@ -0,0 +1,65 @@ +//describe('AngularCache.get(key)', function () { +// it('should return the correct value for the specified key', function () { +// var cache = $angularCacheFactory('cache'); +// var value1 = 'value1', +// value2 = 2, +// value3 = { +// value3: 'stuff' +// }; +// cache.put('item1', value1); +// cache.put('item2', value2); +// cache.put('item3', value3); +// expect(cache.get('item1')).toEqual(value1); +// expect(cache.get('item2')).toEqual(value2); +// expect(cache.get('item3')).toEqual(value3); +// }); +// it('should return undefined if the key isn\'t in the cache', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.get('item')).toEqual(undefined); +// }); +// it('should execute globally configured \'onExpire\' callback if the item is expired in passive mode and global \'onExpire\' callback is configured', function () { +// var cache = $angularCacheFactory('cache', { +// maxAge: 10, +// onExpire: function (key, value, done) { +// done(key, value, 'executed global callback'); +// } +// }); +// cache.put('item', 'value'); +// waits(100); +// runs(function () { +// cache.get('item', function (key, value, test) { +// expect(key).toEqual('item'); +// expect(value).toEqual('value'); +// expect(test).toEqual('executed global callback'); +// }); +// }); +// }); +// it('should execute globally configured \'onExpire\' callback when an item is aggressively deleted and global \'onExpire\' callback is configured', function () { +// var onExpire = jasmine.createSpy(); +// var cache = $angularCacheFactory('cache', { +// maxAge: 10, +// deleteOnExpire: 'aggressive', +// onExpire: onExpire +// }); +// cache.put('item', 'value'); +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(onExpire).toHaveBeenCalled(); +// expect(onExpire).toHaveBeenCalledWith('item', 'value'); +// }); +// }); +// it('should execute local \'onExpire\' callback if the item is expired in passive mode and global \'onExpire\' callback is NOT configured', function () { +// var cache = $angularCacheFactory('cache', { +// maxAge: 10 +// }); +// cache.put('item', 'value'); +// waits(100); +// runs(function () { +// cache.get('item', function (key, value) { +// expect(key).toEqual('item'); +// expect(value).toEqual('value'); +// }); +// }); +// }); +//}); \ No newline at end of file diff --git a/test/angularCache.info-test.js b/test/angularCache.info-test.js new file mode 100644 index 0000000..3a2a688 --- /dev/null +++ b/test/angularCache.info-test.js @@ -0,0 +1,86 @@ +//describe('AngularCache.info()', function () { +// it('should return the correct values', function () { +// var onExpire = function () { +// }; +// var cache = $angularCacheFactory('cache'), +// cache2 = $angularCacheFactory('cache2', { maxAge: 1000 }), +// cache3 = $angularCacheFactory('cache3', { cacheFlushInterval: 1000 }), +// cache4 = $angularCacheFactory('cache4', { capacity: 1000 }), +// cache5 = $angularCacheFactory('cache5', { storageMode: 'localStorage' }), +// cache6 = $angularCacheFactory('cache6', { storageMode: 'sessionStorage' }); +// cache7 = $angularCacheFactory('cache7', { maxAge: 100, onExpire: onExpire }); +// expect(cache.info()).toEqual({ +// id: 'cache', +// capacity: Number.MAX_VALUE, +// size: 0, +// maxAge: null, +// cacheFlushInterval: null, +// deleteOnExpire: 'none', +// storageMode: 'none', +// onExpire: null +// }); +// cache.put('item', 'value'); +// cache.put('item2', 'value2', { maxAge: 200, deleteOnExpire: 'aggressive' }); +// +// // AngularCache#info(key) +// expect(typeof cache.info('item').timestamp).toEqual('number'); +// expect(cache.info('item').maxAge).toEqual(null); +// expect(cache.info('item').deleteOnExpire).toEqual('none'); +// expect(typeof cache.info('item2').timestamp).toEqual('number'); +// expect(cache.info('item2').maxAge).toEqual(200); +// expect(cache.info('item2').deleteOnExpire).toEqual('aggressive'); +// +// expect(cache.info()).toEqual({ +// id: 'cache', +// capacity: Number.MAX_VALUE, +// size: 2, +// maxAge: null, +// cacheFlushInterval: null, +// deleteOnExpire: 'none', +// storageMode: 'none', +// onExpire: null +// }); +// expect(cache2.info()).toEqual({ +// id: 'cache2', +// capacity: Number.MAX_VALUE, +// maxAge: 1000, +// size: 0, +// cacheFlushInterval: null, +// deleteOnExpire: 'none', +// storageMode: 'none', +// onExpire: null +// }); +// expect(cache3.info().id).toEqual('cache3'); +// expect(cache3.info().capacity).toEqual(Number.MAX_VALUE); +// expect(cache3.info().cacheFlushInterval).toEqual(1000); +// expect(cache3.info().size).toEqual(0); +// expect(cache4.info()).toEqual({ +// id: 'cache4', +// capacity: 1000, +// size: 0, +// maxAge: null, +// cacheFlushInterval: null, +// deleteOnExpire: 'none', +// storageMode: 'none', +// onExpire: null +// }); +// if (localStorage) { +// expect(cache5.info().storageMode).toEqual('localStorage'); +// } else { +// expect(cache5.info().storageMode).toEqual(null); +// } +// if (sessionStorage) { +// expect(cache6.info().storageMode).toEqual('sessionStorage'); +// } else { +// expect(cache6.info().storageMode).toEqual(null); +// } +// expect(cache7.info().onExpire).toEqual(onExpire); +// cache.destroy(); +// cache2.destroy(); +// cache3.destroy(); +// cache4.destroy(); +// cache5.destroy(); +// cache6.destroy(); +// cache7.destroy(); +// }); +//}); \ No newline at end of file diff --git a/test/angularCache.keySet-test.js b/test/angularCache.keySet-test.js new file mode 100644 index 0000000..b9f90b8 --- /dev/null +++ b/test/angularCache.keySet-test.js @@ -0,0 +1,31 @@ +describe('AngularCache.keySet()', function () { + it('should return the set of keys of all items in the cache.', function () { + var itemKeys = ['item1', 'item2', 'item3']; + + var cache = $angularCacheFactory('cache'); + + cache.put(itemKeys[0], itemKeys[0]); + cache.put(itemKeys[1], itemKeys[1]); + cache.put(itemKeys[2], itemKeys[2]); + + var keySet = cache.keySet(); + + expect(keySet.hasOwnProperty(itemKeys[0])).toEqual(true); + expect(keySet.hasOwnProperty(itemKeys[1])).toEqual(true); + expect(keySet.hasOwnProperty(itemKeys[2])).toEqual(true); + + expect(keySet[itemKeys[0]]).toEqual(itemKeys[0]); + expect(keySet[itemKeys[1]]).toEqual(itemKeys[1]); + expect(keySet[itemKeys[2]]).toEqual(itemKeys[2]); + + cache.remove(itemKeys[0]); + cache.remove(itemKeys[1]); + cache.remove(itemKeys[2]); + + keySet = cache.keySet(); + + expect(keySet.hasOwnProperty(itemKeys[0])).toEqual(false); + expect(keySet.hasOwnProperty(itemKeys[1])).toEqual(false); + expect(keySet.hasOwnProperty(itemKeys[2])).toEqual(false); + }); +}); \ No newline at end of file diff --git a/test/angularCache.keys-test.js b/test/angularCache.keys-test.js new file mode 100644 index 0000000..a03403b --- /dev/null +++ b/test/angularCache.keys-test.js @@ -0,0 +1,25 @@ +describe('AngularCache.keys()', function () { + it('should return the array of keys of all items in the cache.', function () { + var itemKeys = ['item1', 'item2', 'item3']; + + var cache = $angularCacheFactory('cache'); + + cache.put(itemKeys[0], itemKeys[0]); + cache.put(itemKeys[1], itemKeys[1]); + cache.put(itemKeys[2], itemKeys[2]); + + var keys = cache.keys(); + + expect(keys[0]).toEqual(itemKeys[0]); + expect(keys[1]).toEqual(itemKeys[1]); + expect(keys[2]).toEqual(itemKeys[2]); + + cache.remove(itemKeys[0]); + cache.remove(itemKeys[1]); + cache.remove(itemKeys[2]); + + keys = cache.keys(); + + expect(keys.length).toEqual(0); + }); +}); \ No newline at end of file diff --git a/test/angularCache.put-test.js b/test/angularCache.put-test.js new file mode 100644 index 0000000..be72069 --- /dev/null +++ b/test/angularCache.put-test.js @@ -0,0 +1,188 @@ +//describe('AngularCache.put(key, value, options)', function () { +// it('should disallow keys that aren\'t a string', function () { +// var cache = $angularCacheFactory('cache'); +// var mustBeAStringMsg = 'AngularCache.put(): key: must be a string!'; +// try { +// cache.put(2, 'value'); +// } catch (err) { +// var errorMsg = err.message; +// } +// expect(errorMsg).toEqual(mustBeAStringMsg); +// try { +// cache.put(true, 'value'); +// } catch (err) { +// errorMsg = err.message; +// } +// expect(errorMsg).toEqual(mustBeAStringMsg); +// try { +// cache.put({ obj: 'obj' }, 'value'); +// } catch (err) { +// errorMsg = err.message; +// } +// expect(errorMsg).toEqual(mustBeAStringMsg); +// }); +// it('should not add values that aren\'t defined', function () { +// var cache = $angularCacheFactory('cache'); +// cache.put('item', null); +// expect(cache.get('item')).toEqual(undefined); +// cache.put('item', undefined); +// expect(cache.get('item')).toEqual(undefined); +// }); +// it('should validate maxAge', function () { +// var cache = $angularCacheFactory('cache'); +// try { +// cache.put('item', 'value', { maxAge: 'als;dlfkajsd'}); +// } catch (err) { +// var errorMsg = err.message; +// } +// expect(errorMsg).toEqual('AngularCache.put(): maxAge: must be a number!'); +// try { +// cache.put('item', 'value', { maxAge: Math.floor((Math.random() * 100000) + 1) * -1 }); +// } catch (err) { +// errorMsg = err.message; +// } +// expect(errorMsg).toEqual('AngularCache.put(): maxAge: must be greater than zero!'); +// errorMsg = null; +// try { +// cache.put('item', 'value', { maxAge: Math.floor((Math.random() * 100000) + 1) }); +// } catch (err) { +// errorMsg = 'should not reach this!'; +// } +// expect(errorMsg).toEqual(null); +// }); +// it('should increase the size of the cache by one', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.info().size).toEqual(0); +// cache.put('item', 'value1'); +// expect(cache.info().size).toEqual(1); +// cache.put('item2', 'value2'); +// expect(cache.info().size).toEqual(2); +// }); +// it('should overwrite an item if it is re-added to the cache', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.info().size).toEqual(0); +// cache.put('item', 'value1'); +// expect(cache.info().size).toEqual(1); +// cache.put('item', 'value2'); +// expect(cache.info().size).toEqual(1); +// expect(cache.get('item')).toEqual('value2'); +// }); +// it('should remove the least recently used item if the capacity has been reached', function () { +// var cache = $angularCacheFactory('cache', { capacity: 2 }); +// expect(cache.info().size).toEqual(0); +// cache.put('item1', 'value1'); +// expect(cache.info().size).toEqual(1); +// cache.put('item2', 'value2'); +// expect(cache.info().size).toEqual(2); +// cache.put('item3', 'value3'); +// expect(cache.info().size).toEqual(2); +// expect(cache.get('item1')).toEqual(undefined); +// expect(cache.get('item2')).toEqual('value2'); +// expect(cache.get('item3')).toEqual('value3'); +// cache.get('item2'); +// cache.put('item1', 'value1'); +// expect(cache.get('item3')).toEqual(undefined); +// expect(cache.get('item1')).toEqual('value1'); +// expect(cache.get('item2')).toEqual('value2'); +// }); +// it('should not delete items if maxAge is specified and deleteOnExpire is set to "none"', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'none' }); +// cache.put('item1', 'value1'); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// expect(cache.get('item1')).toEqual('value1'); +// expect(cache.info('item1').isExpired).toEqual(true); +// }); +// }); +// it('should set a timeout for an item to expire if maxAge is specified and deleteOnExpire is set to "aggressive"', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive' }); +// cache.put('item1', 'value1'); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(cache.info('item1')).toEqual(undefined); +// expect(cache.get('item1')).toEqual(undefined); +// }); +// }); +// it('should should lazy delete an item when maxAge is specified and deleteOnExpire is set to "passive"', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'passive' }); +// cache.put('item1', 'value1'); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// expect(cache.info('item1').isExpired).toEqual(true); +// expect(cache.get('item1')).toEqual(undefined); +// }); +// }); +// it('should not delete items if maxAge is specified and deleteOnExpire is set to "none" for an item', function () { +// var cache = $angularCacheFactory('cache'); +// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'none' }); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// expect(cache.get('item1')).toEqual('value1'); +// expect(cache.info('item1').isExpired).toEqual(true); +// }); +// }); +// it('should set a timeout for an item to expire if maxAge for item is specified and deleteOnExpire is set to "aggressive"', function () { +// var cache = $angularCacheFactory('cache'); +// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'aggressive' }); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(cache.info('item1')).toEqual(undefined); +// expect(cache.get('item1')).toEqual(undefined); +// }); +// }); +// it('should passively expire an item if maxAge for the item is specified and deleteOnExpire is set to "passive"', function () { +// var cache = $angularCacheFactory('cache'); +// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// expect(cache.info('item1').isExpired).toEqual(true); +// expect(cache.get('item1')).toEqual(undefined); +// }); +// }); +// it('maxAge for a specific item should override maxAge for the cache', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 1000, deleteOnExpire: 'aggressive' }); +// cache.put('item1', 'value1', { maxAge: 5 }); +// expect(cache.info('item1').maxAge).toEqual(5); +// expect(cache.get('item1')).toEqual('value1'); +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(cache.get('item1')).toEqual(undefined); +// }); +// }); +// it('deleteOnExpire set to "passive" for a specific item should override deleteOnExpire set to "aggressive" for the cache', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive' }); +// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); +// expect(cache.get('item1')).toEqual('value1'); +// expect(cache.info('item1').deleteOnExpire).toEqual("passive"); +// waits(100); +// runs(function () { +// expect(cache.info('item1').isExpired).toEqual(true); +// expect(cache.get('item1')).toEqual(undefined); +// }); +// }); +// it('should save data to localStorage when storageMode is used', function () { +// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), +// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); +// +// localStorageCache.put('item1', 'value1'); +// sessionStorageCache.put('item1', 'value1'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); +// } +// }); +//}); \ No newline at end of file diff --git a/test/angularCache.remove-test.js b/test/angularCache.remove-test.js new file mode 100644 index 0000000..1081430 --- /dev/null +++ b/test/angularCache.remove-test.js @@ -0,0 +1,62 @@ +//describe('AngularCache.remove(key)', function () { +// it('should remove the item with the specified key', function () { +// var cache = $angularCacheFactory('cache'); +// var value1 = 'value1', +// value2 = 2, +// value3 = { +// value3: 'stuff' +// }; +// cache.put('item1', value1); +// cache.put('item2', value2); +// cache.put('item3', value3); +// cache.remove('item1'); +// expect(cache.get('item1')).toEqual(undefined); +// cache.remove('item2'); +// expect(cache.get('item2')).toEqual(undefined); +// cache.remove('item3'); +// expect(cache.get('item3')).toEqual(undefined); +// }); +// it('should reduce the size of the cache by one if the size is greater than zero', function () { +// var cache = $angularCacheFactory('cache'); +// cache.put('item1', 'value1'); +// expect(cache.info().size).toEqual(1); +// cache.put('item2', 'value2'); +// expect(cache.info().size).toEqual(2); +// cache.remove('item1'); +// expect(cache.info().size).toEqual(1); +// cache.remove('item2'); +// expect(cache.info().size).toEqual(0); +// cache.remove('item1'); +// expect(cache.info().size).toEqual(0); +// cache.remove('item2'); +// expect(cache.info().size).toEqual(0); +// }); +// it('should remove items from localStorage when storageMode is used', function () { +// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), +// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); +// +// localStorageCache.put('item1', 'value1'); +// sessionStorageCache.put('item1', 'value1'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); +// } +// +// localStorageCache.remove('item1'); +// sessionStorageCache.remove('item1'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); +// } +// }); +//}); \ No newline at end of file diff --git a/test/angularCache.removeAll-test.js b/test/angularCache.removeAll-test.js new file mode 100644 index 0000000..eb5bac2 --- /dev/null +++ b/test/angularCache.removeAll-test.js @@ -0,0 +1,51 @@ +//describe('AngularCache.removeAll()', function () { +// it('should remove all items in the cache', function () { +// var cache = $angularCacheFactory('cache'); +// var value1 = 'value1', +// value2 = 2, +// value3 = { +// value3: 'stuff' +// }; +// cache.put('item1', value1); +// cache.put('item2', value2); +// cache.put('item3', value3); +// cache.removeAll(); +// expect(cache.get('item1')).toEqual(undefined); +// expect(cache.get('item2')).toEqual(undefined); +// expect(cache.get('item3')).toEqual(undefined); +// }); +// it('should remove items from localStorage when storageMode is used', function () { +// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), +// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); +// +// localStorageCache.put('item1', 'value1'); +// sessionStorageCache.put('item1', 'value1'); +// localStorageCache.put('item2', 'value2'); +// sessionStorageCache.put('item2', 'value2'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2')).value).toEqual('value2'); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1","item2"]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2')).value).toEqual('value2'); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1","item2"]'); +// } +// +// localStorageCache.removeAll(); +// sessionStorageCache.removeAll(); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2'))).toEqual(null); +// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2'))).toEqual(null); +// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); +// } +// }); +//}); \ No newline at end of file diff --git a/test/angularCache.removeExpired-test.js b/test/angularCache.removeExpired-test.js new file mode 100644 index 0000000..e69de29 diff --git a/test/angularCache.setOptions-test.js b/test/angularCache.setOptions-test.js new file mode 100644 index 0000000..e27d265 --- /dev/null +++ b/test/angularCache.setOptions-test.js @@ -0,0 +1,183 @@ +//describe('AngularCache.setOptions()', function () { +// it('should correctly reset to defaults if strict mode is true', function () { +// var onExpire = function () { +// }; +// var cache = $angularCacheFactory('cache', { +// maxAge: 100, +// cacheFlushInterval: 200, +// onExpire: onExpire, +// storageMode: 'localStorage' +// }); +// expect(cache.info().maxAge).toEqual(100); +// expect(cache.info().cacheFlushInterval).toEqual(200); +// expect(cache.info().onExpire).toEqual(onExpire); +// expect(cache.info().storageMode).toEqual('localStorage'); +// cache.setOptions({ }, true); +// expect(cache.info().maxAge).toEqual(null); +// expect(cache.info().cacheFlushInterval).toEqual(null); +// expect(cache.info().onExpire).toEqual(null); +// expect(cache.info().storageMode).toEqual('none'); +// }); +// it('should correctly modify the capacity of a cache', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.info().capacity).toEqual(Number.MAX_VALUE); +// cache.setOptions({ capacity: 5 }, false); +// expect(cache.info().capacity).toEqual(5); +// cache.put('item1', 1); +// cache.put('item2', 2); +// cache.put('item3', 3); +// cache.put('item4', 4); +// cache.put('item5', 5); +// cache.put('item6', 6); +// expect(cache.get('item1')).not.toBeDefined(); +// cache.setOptions({ capacity: 3 }, false); +// // Least-recently used items over the new capacity should have been removed. +// expect(cache.get('item2')).not.toBeDefined(); +// expect(cache.get('item3')).not.toBeDefined(); +// expect(cache.info().size).toEqual(3); +// }); +// it('should correctly modify the maxAge of a cache', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.info().maxAge).toEqual(null); +// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); +// expect(cache.info().maxAge).toEqual(10); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); +// expect(cache.info().maxAge).toEqual(10); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// // The new items should be removed after 500 ms (the new maxAge) +// runs(function () { +// $timeout.flush(); +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// }); +// }); +// }); +// it('should correctly modify the cacheFlushInterval of a cache', function () { +// var cache = $angularCacheFactory('cache'); +// expect(cache.info().cacheFlushInterval).toEqual(null); +// cache.setOptions({ cacheFlushInterval: 10 }, false); +// expect(cache.info().cacheFlushInterval).toEqual(10); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// // The first items should be removed after 2000 ms +// runs(function () { +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// cache.setOptions({ cacheFlushInterval: 10 }, false); +// expect(cache.info().cacheFlushInterval).toEqual(10); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// // The new items should be removed after 500 ms (the new maxAge) +// runs(function () { +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// }); +// }); +// }); +// it('should correctly modify the deleteOnExpire of a cache', function () { +// var cache = $angularCacheFactory('cache', { maxAge: 10 }); +// expect(cache.info().deleteOnExpire).toEqual('none'); +// cache.setOptions({ deleteOnExpire: 'passive' }, false); +// expect(cache.info().deleteOnExpire).toEqual('passive'); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// // The first items should be removed after 2000 ms +// runs(function () { +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); +// expect(cache.info().deleteOnExpire).toEqual('aggressive'); +// cache.put('item1', 1); +// cache.put('item2', 2); +// waits(100); +// // The new items should be removed after 500 ms (the new maxAge) +// runs(function () { +// $timeout.flush(); +// expect(cache.get('item1')).not.toBeDefined(); +// expect(cache.get('item2')).not.toBeDefined(); +// }); +// }); +// }); +// it('should correctly set configuration to default when \'strict\' is true', function () { +// var cache = $angularCacheFactory('cache', { +// capacity: 10, +// maxAge: 1000, +// cacheFlushInterval: 1000, +// deleteOnExpire: 'aggressive', +// storageMode: 'none' +// }); +// cache.setOptions({}, true); +// expect(cache.info()).toEqual({ +// capacity: Number.MAX_VALUE, +// maxAge: null, +// cacheFlushInterval: null, +// id: 'cache', +// size: 0, +// deleteOnExpire: 'none', +// storageMode: 'none', +// onExpire: null +// }); +// }); +// it('should correctly switch to using local/session storage when storageMode is activated', function () { +// var cache = $angularCacheFactory('cache'), +// cache2 = $angularCacheFactory('cache2'); +// cache.put('item', 'value'); +// cache2.put('item', 'value'); +// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'localStorage' }); +// cache2.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'sessionStorage' }); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); +// } +// waits(100); +// runs(function () { +// $timeout.flush(); +// expect(cache.get('item')).toEqual(null); +// expect(cache2.get('item')).toEqual(null); +// if (localStorage) { +// expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); +// } +// if (sessionStorage) { +// expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); +// } +// }); +// }); +// it('should correctly stop using local/session storage when storageMode is deactivated', function () { +// var cache = $angularCacheFactory('cache', { storageMode: 'localStorage' }), +// cache2 = $angularCacheFactory('cache2', { storageMode: 'sessionStorage' }); +// cache.put('item', 'value'); +// cache2.put('item', 'value'); +// +// if (localStorage) { +// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); +// } +// if (sessionStorage) { +// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); +// } +// +// cache.setOptions({ storageMode: 'none' }, true); +// cache2.setOptions({ storageMode: 'none' }, true); +// +// if (localStorage) { +// expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); +// } +// if (sessionStorage) { +// expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); +// } +// }); +//}); \ No newline at end of file diff --git a/test/angularCacheFactory-test.js b/test/angularCacheFactory-test.js index e4dbace..9d113d1 100644 --- a/test/angularCacheFactory-test.js +++ b/test/angularCacheFactory-test.js @@ -49,7 +49,7 @@ describe('$angularCacheFactory(cacheId, options)', function () { }); it('should throw an exception if "capacity" is not a number or is less than zero.', function () { try { - $angularCacheFactory('cache', { capacity: Math.floor((Math.random() * 100000) + 1) * -1 }); + $angularCacheFactory('capacityCache99', { capacity: Math.floor((Math.random() * 100000) + 1) * -1 }); fail(); } catch (err) { var msg = err.message; @@ -57,7 +57,7 @@ describe('$angularCacheFactory(cacheId, options)', function () { expect(msg).toEqual('capacity: must be greater than zero!'); for (var i = 0; i < TYPES_EXCEPT_NUMBER.length; i++) { try { - $angularCacheFactory('cache', { capacity: TYPES_EXCEPT_NUMBER[i] }); + $angularCacheFactory('capacityCache' + i, { capacity: TYPES_EXCEPT_NUMBER[i] }); fail(); } catch (err) { expect(err.message).toEqual('capacity: must be a number!'); @@ -69,82 +69,98 @@ describe('$angularCacheFactory(cacheId, options)', function () { it('should validate maxAge.', function () { var maxAge = Math.floor((Math.random() * 100000) + 1) * -1; try { - $angularCacheFactory('cache', { maxAge: maxAge }); - expect('should not reach this!').toEqual(false); + $angularCacheFactory('maxAgeCache99', { maxAge: maxAge }); + fail(); } catch (err) { var msg = err.message; } expect(msg).toEqual('maxAge: must be greater than zero!'); - maxAge = 'asdfasd'; - try { - $angularCacheFactory('cache', { maxAge: maxAge }); - expect('should not reach this!').toEqual(false); - } catch (err) { - msg = err.message; + for (var i = 0; i < TYPES_EXCEPT_NUMBER.length; i++) { + try { + $angularCacheFactory('maxAgeCache' + i, { maxAge: TYPES_EXCEPT_NUMBER[i] }); + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } + } catch (err) { + expect(err.message).toEqual('maxAge: must be a number!'); + continue; + } + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } } - expect(msg).toEqual('maxAge: must be a number!'); }); it('should validate cacheFlushInterval.', function () { var cacheFlushInterval = Math.floor((Math.random() * 100000) + 1) * -1; try { - $angularCacheFactory('cache', { cacheFlushInterval: cacheFlushInterval }); - expect('should not reach this!').toEqual(false); + $angularCacheFactory('cacheFlushIntervalCache99', { cacheFlushInterval: cacheFlushInterval }); + fail(); } catch (err) { var msg = err.message; } expect(msg).toEqual('cacheFlushInterval: must be greater than zero!'); - cacheFlushInterval = 'asdfasd'; - try { - $angularCacheFactory('cache', { cacheFlushInterval: cacheFlushInterval }); - expect('should not reach this!').toEqual(false); - } catch (err) { - msg = err.message; + for (var i = 0; i < TYPES_EXCEPT_NUMBER.length; i++) { + try { + $angularCacheFactory('cacheFlushIntervalCache' + i, { cacheFlushInterval: TYPES_EXCEPT_NUMBER[i] }); + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } + } catch (err) { + expect(err.message).toEqual('cacheFlushInterval: must be a number!'); + continue; + } + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } } - expect(msg).toEqual('cacheFlushInterval: must be a number!'); }); it('should validate recycleFreq.', function () { var recycleFreq = Math.floor((Math.random() * 100000) + 1) * -1; try { - $angularCacheFactory('cache', { recycleFreq: recycleFreq }); - expect('should not reach this!').toEqual(false); + $angularCacheFactory('recycleFreqCache99', { recycleFreq: recycleFreq }); + fail(); } catch (err) { var msg = err.message; } expect(msg).toEqual('recycleFreq: must be greater than zero!'); - recycleFreq = 'asdfasd'; - try { - $angularCacheFactory('cache', { recycleFreq: recycleFreq }); - expect('should not reach this!').toEqual(false); - } catch (err) { - msg = err.message; + for (var i = 0; i < TYPES_EXCEPT_NUMBER.length; i++) { + try { + $angularCacheFactory('recycleFreqCache' + i, { recycleFreq: TYPES_EXCEPT_NUMBER[i] }); + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } + } catch (err) { + expect(err.message).toEqual('recycleFreq: must be a number!'); + continue; + } + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } } - expect(msg).toEqual('recycleFreq: must be a number!'); }); it('should validate onExpire.', function () { var onExpire = 234; try { - $angularCacheFactory('cache', { onExpire: onExpire }); - expect('should not reach this!').toEqual(false); - } catch (err) { - var msg = err.message; - } - expect(msg).toEqual('onExpire: must be a function!'); - onExpire = {}; - try { - $angularCacheFactory('cache', { onExpire: onExpire }); + $angularCacheFactory('onExpireCache99', { onExpire: onExpire }); expect('should not reach this!').toEqual(false); } catch (err) { var msg = err.message; } expect(msg).toEqual('onExpire: must be a function!'); - onExpire = 'asdfasd'; - try { - $angularCacheFactory('cache', { onExpire: onExpire }); - expect('should not reach this!').toEqual(false); - } catch (err) { - msg = err.message; + for (var i = 0; i < TYPES_EXCEPT_FUNCTION.length; i++) { + try { + $angularCacheFactory('onExpireCache' + i, { onExpire: TYPES_EXCEPT_FUNCTION[i] }); + if (TYPES_EXCEPT_FUNCTION[i] !== null) { + fail(); + } + } catch (err) { + expect(err.message).toEqual('onExpire: must be a function!'); + continue; + } + if (TYPES_EXCEPT_FUNCTION[i] !== null) { + fail(); + } } - expect(msg).toEqual('onExpire: must be a function!'); }); it('should validate deleteOnExpire.', function () { var deleteOnExpire = 'fail'; @@ -155,14 +171,16 @@ describe('$angularCacheFactory(cacheId, options)', function () { var msg = err.message; } expect(msg).toEqual('deleteOnExpire: accepted values are "none", "passive" or "aggressive"!'); - deleteOnExpire = 234; - try { - $angularCacheFactory('cache', { deleteOnExpire: deleteOnExpire }); - expect('should not reach this!').toEqual(false); - } catch (err) { - msg = err.message; + for (var i = 0; i < TYPES_EXCEPT_STRING.length; i++) { + try { + $angularCacheFactory('deleteOnExpireCache' + i, { deleteOnExpire: TYPES_EXCEPT_STRING[i] }); + fail(); + } catch (err) { + expect(err.message).toEqual('deleteOnExpire: must be a string!'); + continue; + } + fail(); } - expect(msg).toEqual('deleteOnExpire: must be a string!'); }); it('should validate storageMode.', function () { var storageMode = 'fail'; @@ -173,34 +191,41 @@ describe('$angularCacheFactory(cacheId, options)', function () { var msg = err.message; } expect(msg).toEqual('storageMode: accepted values are "none", "localStorage" or "sessionStorage"!'); - storageMode = 234; - try { - $angularCacheFactory('cache', { storageMode: storageMode }); - expect('should not reach this!').toEqual(false); - } catch (err) { - msg = err.message; + for (var i = 0; i < TYPES_EXCEPT_STRING.length; i++) { + try { + $angularCacheFactory('storageModeCache' + i, { storageMode: TYPES_EXCEPT_STRING[i] }); + fail(); + } catch (err) { + expect(err.message).toEqual('storageMode: must be a string!'); + continue; + } + fail(); } - expect(msg).toEqual('storageMode: must be a string!'); }); it('should validate storageImpl.', function () { var storageImpl = 'fail'; try { - $angularCacheFactory('cache', { storageImpl: storageImpl }); + $angularCacheFactory('cache', { storageMode: 'localStorage', storageImpl: storageImpl }); expect('should not reach this!').toEqual(false); } catch (err) { var msg = err.message; } expect(msg).toEqual('[local|session]storageImpl: must be an object!'); - storageImpl = 234; - try { - $angularCacheFactory('cache', { storageImpl: storageImpl }); - expect('should not reach this!').toEqual(false); - } catch (err) { - msg = err.message; + for (var i = 0; i < TYPES_EXCEPT_OBJECT.length; i++) { + try { + $angularCacheFactory('storageImplCache' + i, { storageMode: 'localStorage', storageImpl: TYPES_EXCEPT_OBJECT[i] }); + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } + } catch (err) { + expect(err.message.length).not.toEqual(0); + continue; + } + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } } - expect(msg).toEqual('[local|session]storageImpl: must be an object!'); }); - it('should prevent a cache from being duplicated.', function () { try { $angularCacheFactory('cache'); @@ -211,24 +236,15 @@ describe('$angularCacheFactory(cacheId, options)', function () { expect(msg).toEqual('cacheId cache taken!'); }); it('should require cacheId to be a string.', function () { - var shouldBeAStringMsg = 'cacheId must be a string!'; - try { - $angularCacheFactory(3); - } catch (err) { - var msg = err.message; - } - expect(msg).toEqual(shouldBeAStringMsg); - try { - $angularCacheFactory({obj: 'obj'}); - } catch (err) { - msg = err.message; - } - expect(msg).toEqual(shouldBeAStringMsg); - try { - $angularCacheFactory(['obj']); - } catch (err) { - msg = err.message; + for (var i = 0; i < TYPES_EXCEPT_STRING.length; i++) { + try { + $angularCacheFactory(TYPES_EXCEPT_STRING[i]); + fail(TYPES_EXCEPT_STRING[i]); + } catch (err) { + expect(err.message.length).not.toEqual(0); + continue; + } + fail(TYPES_EXCEPT_STRING[i]); } - expect(msg).toEqual(shouldBeAStringMsg); }); }); \ No newline at end of file diff --git a/test/angularCacheFactory.clearAll-test.js b/test/angularCacheFactory.clearAll-test.js index 78a6938..ef333fd 100644 --- a/test/angularCacheFactory.clearAll-test.js +++ b/test/angularCacheFactory.clearAll-test.js @@ -1,22 +1,52 @@ describe('$angularCacheFactory.clearAll()', function () { - it('should call "removeAll()" on all caches in $angularCacheFactory', function () { - var cacheKeys = ['cache', 'cache1', 'cache2']; + it('should call "removeAll()" on all caches in $angularCacheFactory.', function () { + var cacheKeys = ['cache', 'cache1', 'cache2'], + caches = []; - var cache = $angularCacheFactory(cacheKeys[0]); - cache.put('item', 'value'); - var cache1 = $angularCacheFactory(cacheKeys[1]); - cache1.put('item', 'value'); - var cache2 = $angularCacheFactory(cacheKeys[2]); - cache2.put('item', 'value'); + caches.push($angularCacheFactory(cacheKeys[0])); + caches[0].put('item', 'value'); + caches[0].put('item2', 'value2'); + caches.push($angularCacheFactory(cacheKeys[1])); + caches[1].put('item', 'value'); + caches[1].put('item2', 'value2'); + caches.push($angularCacheFactory(cacheKeys[2])); + caches[2].put('item', 'value'); + caches[2].put('item2', 'value2'); + + spyOn(caches[0], 'removeAll'); + spyOn(caches[1], 'removeAll'); + spyOn(caches[2], 'removeAll'); $angularCacheFactory.clearAll(); - expect(cache.get('item')).not.toBeDefined(); - expect(cache1.get('item')).not.toBeDefined(); - expect(cache2.get('item')).not.toBeDefined(); + expect(caches[0].removeAll.callCount).toEqual(1); + expect(caches[1].removeAll.callCount).toEqual(1); + expect(caches[2].removeAll.callCount).toEqual(1); + }); + it('should result in each cache being cleared.', function () { + var cacheKeys = ['cache', 'cache1', 'cache2'], + caches = []; + + caches.push($angularCacheFactory(cacheKeys[0])); + caches[0].put('item', 'value'); + caches[0].put('item2', 'value2'); + caches.push($angularCacheFactory(cacheKeys[1])); + caches[1].put('item', 'value'); + caches[1].put('item2', 'value2'); + caches.push($angularCacheFactory(cacheKeys[2])); + caches[2].put('item', 'value'); + caches[2].put('item2', 'value2'); + + $angularCacheFactory.clearAll(); - $angularCacheFactory.get(cacheKeys[0]).destroy(); - $angularCacheFactory.get(cacheKeys[1]).destroy(); - $angularCacheFactory.get(cacheKeys[2]).destroy(); + expect(caches[0].get('item')).not.toBeDefined(); + expect(caches[1].get('item')).not.toBeDefined(); + expect(caches[2].get('item')).not.toBeDefined(); + expect(caches[0].get('item2')).not.toBeDefined(); + expect(caches[1].get('item2')).not.toBeDefined(); + expect(caches[2].get('item2')).not.toBeDefined(); + expect(caches[0].info().size).toEqual(0); + expect(caches[1].info().size).toEqual(0); + expect(caches[2].info().size).toEqual(0); }); }); diff --git a/test/angularCacheFactory.info-test.js b/test/angularCacheFactory.info-test.js index d8e9837..9042f64 100644 --- a/test/angularCacheFactory.info-test.js +++ b/test/angularCacheFactory.info-test.js @@ -1,33 +1,45 @@ describe('$angularCacheFactory.info()', function () { - it('should return the correct info for each cache produced by the factory.', function () { + it('should return the correct info for $angularCacheFactory.', function () { var options = { capacity: Math.floor((Math.random() * 100000) + 1), maxAge: Math.floor((Math.random() * 100000) + 1), cacheFlushInterval: Math.floor((Math.random() * 100000) + 1) - }; + }, + caches = []; - var cache = $angularCacheFactory('cache'); - var cache2 = $angularCacheFactory('cache2', { + caches.push($angularCacheFactory('cache')); + caches.push($angularCacheFactory('cache2', { maxAge: options.maxAge - }); - var cache3 = $angularCacheFactory('cache3', { + })); + caches.push($angularCacheFactory('cache3', { capacity: options.capacity, cacheFlushInterval: options.cacheFlushInterval - }); + })); var info = $angularCacheFactory.info(); expect(info.size).toEqual(3); - expect(info.caches.cache.id).toEqual('cache'); - expect(info.caches.cache.capacity).toEqual(Number.MAX_VALUE); - expect(info.caches.cache.size).toEqual(0); - expect(info.caches.cache2.id).toEqual('cache2'); - expect(info.caches.cache2.capacity).toEqual(Number.MAX_VALUE); - expect(info.caches.cache2.size).toEqual(0); + expect(info.cacheDefaults.capacity).toEqual(CACHE_DEFAULTS.capacity); + expect(info.cacheDefaults.maxAge).toEqual(CACHE_DEFAULTS.maxAge); + expect(info.cacheDefaults.cacheFlushInterval).toEqual(CACHE_DEFAULTS.cacheFlushInterval); + expect(info.cacheDefaults.deleteOnExpire).toEqual(CACHE_DEFAULTS.deleteOnExpire); + expect(info.cacheDefaults.onExpire).toEqual(CACHE_DEFAULTS.onExpire); + expect(info.cacheDefaults.recycleFreq).toEqual(CACHE_DEFAULTS.recycleFreq); + expect(info.cacheDefaults.verifyIntegrity).toEqual(CACHE_DEFAULTS.verifyIntegrity); + expect(info.cacheDefaults.storageMode).toEqual(CACHE_DEFAULTS.storageMode); + expect(info.cacheDefaults.storageImpl).toEqual(CACHE_DEFAULTS.storageImpl); - expect(info.caches.cache3.id).toEqual('cache3'); - expect(info.caches.cache3.cacheFlushInterval).toEqual(options.cacheFlushInterval); - expect(info.caches.cache3.capacity).toEqual(options.capacity); - expect(info.caches.cache3.size).toEqual(0); - expect(info.caches.cache3.cacheFlushIntervalId).toBeDefined(); + expect(info.caches.cache.id).toEqual(caches[0].info().id); + expect(info.caches.cache.capacity).toEqual(caches[0].info().capacity); + expect(info.caches.cache.size).toEqual(caches[0].info().size); + + expect(info.caches.cache2.id).toEqual(caches[1].info().id); + expect(info.caches.cache2.capacity).toEqual(caches[1].info().capacity); + expect(info.caches.cache2.size).toEqual(caches[1].info().size); + expect(info.caches.cache2.maxAge).toEqual(caches[1].info().maxAge); + + expect(info.caches.cache3.id).toEqual(caches[2].info().id); + expect(info.caches.cache3.capacity).toEqual(caches[2].info().capacity); + expect(info.caches.cache3.size).toEqual(caches[2].info().size); + expect(info.caches.cache3.cacheFlushInterval).toEqual(caches[2].info().cacheFlushInterval); }); }); diff --git a/test/angularCacheFactory.keySet-test.js b/test/angularCacheFactory.keySet-test.js index 92f9146..5317f31 100644 --- a/test/angularCacheFactory.keySet-test.js +++ b/test/angularCacheFactory.keySet-test.js @@ -17,7 +17,23 @@ describe('$angularCacheFactory.keySet()', function () { expect(keySet[cacheKeys[2]]).toEqual(cacheKeys[2]); $angularCacheFactory.get(cacheKeys[0]).destroy(); + keySet = $angularCacheFactory.keySet(); + expect(keySet.hasOwnProperty(cacheKeys[0])).toEqual(false); + expect(keySet.hasOwnProperty(cacheKeys[1])).toEqual(true); + expect(keySet.hasOwnProperty(cacheKeys[2])).toEqual(true); + expect(keySet[cacheKeys[0]]).not.toBeDefined(); + expect(keySet[cacheKeys[1]]).toEqual(cacheKeys[1]); + expect(keySet[cacheKeys[2]]).toEqual(cacheKeys[2]); + $angularCacheFactory.get(cacheKeys[1]).destroy(); + keySet = $angularCacheFactory.keySet(); + expect(keySet.hasOwnProperty(cacheKeys[0])).toEqual(false); + expect(keySet.hasOwnProperty(cacheKeys[1])).toEqual(false); + expect(keySet.hasOwnProperty(cacheKeys[2])).toEqual(true); + expect(keySet[cacheKeys[0]]).not.toBeDefined(); + expect(keySet[cacheKeys[1]]).not.toBeDefined(); + expect(keySet[cacheKeys[2]]).toEqual(cacheKeys[2]); + $angularCacheFactory.get(cacheKeys[2]).destroy(); keySet = $angularCacheFactory.keySet(); @@ -25,5 +41,8 @@ describe('$angularCacheFactory.keySet()', function () { expect(keySet.hasOwnProperty(cacheKeys[0])).toEqual(false); expect(keySet.hasOwnProperty(cacheKeys[1])).toEqual(false); expect(keySet.hasOwnProperty(cacheKeys[2])).toEqual(false); + expect(keySet[cacheKeys[0]]).not.toBeDefined(); + expect(keySet[cacheKeys[1]]).not.toBeDefined(); + expect(keySet[cacheKeys[2]]).not.toBeDefined(); }); }); diff --git a/test/angularCacheFactory.keys-test.js b/test/angularCacheFactory.keys-test.js index 662c83f..007b3a9 100644 --- a/test/angularCacheFactory.keys-test.js +++ b/test/angularCacheFactory.keys-test.js @@ -7,13 +7,22 @@ describe('$angularCacheFactory.keys()', function () { $angularCacheFactory(cacheKeys[2]); var keys = $angularCacheFactory.keys(); - + expect(keys.length).toEqual(3); expect(keys[0]).toEqual(cacheKeys[0]); expect(keys[1]).toEqual(cacheKeys[1]); expect(keys[2]).toEqual(cacheKeys[2]); $angularCacheFactory.get(cacheKeys[0]).destroy(); + keys = $angularCacheFactory.keys(); + expect(keys.length).toEqual(2); + expect(keys.indexOf(cacheKeys[1])).not.toEqual(-1); + expect(keys.indexOf(cacheKeys[2])).not.toEqual(-1); + $angularCacheFactory.get(cacheKeys[1]).destroy(); + keys = $angularCacheFactory.keys(); + expect(keys.length).toEqual(1); + expect(keys.indexOf(cacheKeys[2])).not.toEqual(-1); + $angularCacheFactory.get(cacheKeys[2]).destroy(); keys = $angularCacheFactory.keys(); diff --git a/test/karma.start.js b/test/karma.start.js index c20ab74..cc0435a 100644 --- a/test/karma.start.js +++ b/test/karma.start.js @@ -1,11 +1,11 @@ -var fail = function () { - expect('should not reach this!').toEqual('failure'); +var fail = function (msg) { + expect('should not reach this!: ' + msg).toEqual('failure'); }, - TYPES_EXCEPT_STRING = [123, 123.123, null, undefined, {}, [], true, false], - TYPES_EXCEPT_NUMBER = ['string', null, undefined, {}, [], true, false], - TYPES_EXCEPT_OBJECT = ['string', 123, 123.123, null, undefined, [], true, false], - TYPES_EXCEPT_ARRAY = ['string', 123, 123.123, null, undefined, {}, true, false], - TYPES_EXCEPT_BOOLEAN = ['string', 123, 123.123, null, undefined, {}, []], + TYPES_EXCEPT_STRING = [123, 123.123, null, undefined, {}, [], true, false, function () {}], + TYPES_EXCEPT_NUMBER = ['string', null, undefined, {}, [], true, false, function () {}], + TYPES_EXCEPT_OBJECT = ['string', 123, 123.123, null, undefined, true, false, function () {}], + TYPES_EXCEPT_BOOLEAN = ['string', 123, 123.123, null, undefined, {}, [], function () {}], + TYPES_EXCEPT_FUNCTION = ['string', 123, 123.123, null, undefined, {}, [], true, false], CACHE_DEFAULTS = { capacity: Number.MAX_VALUE, maxAge: null, From a803befc55f1e4bc961670ac336846e674a9551b Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Thu, 26 Sep 2013 09:09:03 -0600 Subject: [PATCH 5/8] Added test files for BinaryHeap tests. --- src/angular-cache.js | 17 +- test/angularCacheSpec.js | 830 ----------------------------- test/binaryHeap-test.js | 2 + test/binaryHeap.bubbleDown-test.js | 2 + test/binaryHeap.bubbleUp-test.js | 2 + test/binaryHeap.peek-test.js | 2 + test/binaryHeap.pop-test.js | 2 + test/binaryHeap.push-test.js | 2 + test/binaryHeap.remove-test.js | 2 + test/binaryHeap.removeAll-test.js | 2 + 10 files changed, 26 insertions(+), 837 deletions(-) delete mode 100644 test/angularCacheSpec.js create mode 100644 test/binaryHeap-test.js create mode 100644 test/binaryHeap.bubbleDown-test.js create mode 100644 test/binaryHeap.bubbleUp-test.js create mode 100644 test/binaryHeap.peek-test.js create mode 100644 test/binaryHeap.pop-test.js create mode 100644 test/binaryHeap.push-test.js create mode 100644 test/binaryHeap.remove-test.js create mode 100644 test/binaryHeap.removeAll-test.js diff --git a/src/angular-cache.js b/src/angular-cache.js index 2691071..dae0861 100644 --- a/src/angular-cache.js +++ b/src/angular-cache.js @@ -25,8 +25,11 @@ * @param {Function} weightFunc Function that determines how each node should be weighted. */ function BinaryHeap(weightFunc) { - this.heap = []; + weightFunc = weightFunc || function (x) { + return x; + }; this.weightFunc = weightFunc; + this.heap = []; } /** @@ -51,17 +54,17 @@ }; /** - * @method BinaryHeap.removeMin + * @method BinaryHeap.pop * @desc Remove and return the minimum element in the binary heap. * @returns {*} * @public */ - BinaryHeap.prototype.removeMin = function () { + BinaryHeap.prototype.pop = function () { var front = this.heap[0], end = this.heap.pop(); if (this.heap.length > 0) { this.heap[0] = end; - this.sinkDown(0); + this.bubbleDown(0); } return front; }; @@ -83,7 +86,7 @@ if (i !== length - 1) { this.heap[i] = end; this.bubbleUp(i); - this.sinkDown(i); + this.bubbleDown(i); } return removed; } @@ -136,11 +139,11 @@ }; /** - * @method BinaryHeap.sinkDown + * @method BinaryHeap.bubbleDown * @param {Number} n The index of the element to sink down. * @ignore */ - BinaryHeap.prototype.sinkDown = function (n) { + BinaryHeap.prototype.bubbleDown = function (n) { var length = this.heap.length, node = this.heap[n], nodeWeight = this.weightFunc(node); diff --git a/test/angularCacheSpec.js b/test/angularCacheSpec.js deleted file mode 100644 index f1c12c2..0000000 --- a/test/angularCacheSpec.js +++ /dev/null @@ -1,830 +0,0 @@ -//describe('AngularCache', function () { -// -// var $angularCacheFactory, $timeout; -// beforeEach(module('jmdobry.angular-cache')); -// beforeEach(inject(function ($injector) { -// $angularCacheFactory = $injector.get('$angularCacheFactory'); -// $timeout = $injector.get('$timeout'); -// })); -// -// it('should clear itself if cacheFlushInterval is specified', function () { -// var cache = $angularCacheFactory('cache', { cacheFlushInterval: 10 }); -// cache.put('item1', 'value1'); -// expect(cache.get('item1')).toEqual('value1'); -// cache.put('item2', 'value2'); -// expect(cache.get('item2')).toEqual('value2'); -// waits(100); -// runs(function () { -// expect(cache.get('item1')).toEqual(undefined); -// expect(cache.get('item2')).toEqual(undefined); -// cache.destroy(); -// }); -// }); -// it('should clear itself and web storage if cacheFlushInterval and storageMode are specified', function () { -// var localStorageCache = $angularCacheFactory('localStorageCache', { cacheFlushInterval: 10, storageMode: 'localStorage' }), -// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { cacheFlushInterval: 10, storageMode: 'sessionStorage' }); -// -// localStorageCache.put('item1', 'value1'); -// sessionStorageCache.put('item1', 'value1'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); -// } -// -// waits(100); -// runs(function () { -// expect(localStorageCache.get('item1')).toEqual(undefined); -// expect(sessionStorageCache.get('item1')).toEqual(undefined); -// if (localStorage) { -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).toEqual(null); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); -// } -// if (sessionStorage) { -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).toEqual(null); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); -// } -// localStorageCache.destroy(); -// sessionStorageCache.destroy(); -// }); -// }); -// describe('AngularCache.put(key, value, options)', function () { -// it('should disallow keys that aren\'t a string', function () { -// var cache = $angularCacheFactory('cache'); -// var mustBeAStringMsg = 'AngularCache.put(): key: must be a string!'; -// try { -// cache.put(2, 'value'); -// } catch (err) { -// var errorMsg = err.message; -// } -// expect(errorMsg).toEqual(mustBeAStringMsg); -// try { -// cache.put(true, 'value'); -// } catch (err) { -// errorMsg = err.message; -// } -// expect(errorMsg).toEqual(mustBeAStringMsg); -// try { -// cache.put({ obj: 'obj' }, 'value'); -// } catch (err) { -// errorMsg = err.message; -// } -// expect(errorMsg).toEqual(mustBeAStringMsg); -// cache.destroy(); -// }); -// it('should not add values that aren\'t defined', function () { -// var cache = $angularCacheFactory('cache'); -// cache.put('item', null); -// expect(cache.get('item')).toEqual(undefined); -// cache.put('item', undefined); -// expect(cache.get('item')).toEqual(undefined); -// cache.destroy(); -// }); -// it('should validate maxAge', function () { -// var cache = $angularCacheFactory('cache'); -// try { -// cache.put('item', 'value', { maxAge: 'als;dlfkajsd'}); -// } catch (err) { -// var errorMsg = err.message; -// } -// expect(errorMsg).toEqual('AngularCache.put(): maxAge: must be a number!'); -// try { -// cache.put('item', 'value', { maxAge: Math.floor((Math.random() * 100000) + 1) * -1 }); -// } catch (err) { -// errorMsg = err.message; -// } -// expect(errorMsg).toEqual('AngularCache.put(): maxAge: must be greater than zero!'); -// errorMsg = null; -// try { -// cache.put('item', 'value', { maxAge: Math.floor((Math.random() * 100000) + 1) }); -// } catch (err) { -// errorMsg = 'should not reach this!'; -// } -// expect(errorMsg).toEqual(null); -// cache.destroy(); -// }); -// it('should increase the size of the cache by one', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.info().size).toEqual(0); -// cache.put('item', 'value1'); -// expect(cache.info().size).toEqual(1); -// cache.put('item2', 'value2'); -// expect(cache.info().size).toEqual(2); -// cache.destroy(); -// }); -// it('should overwrite an item if it is re-added to the cache', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.info().size).toEqual(0); -// cache.put('item', 'value1'); -// expect(cache.info().size).toEqual(1); -// cache.put('item', 'value2'); -// expect(cache.info().size).toEqual(1); -// expect(cache.get('item')).toEqual('value2'); -// cache.destroy(); -// }); -// it('should remove the least recently used item if the capacity has been reached', function () { -// var cache = $angularCacheFactory('cache', { capacity: 2 }); -// expect(cache.info().size).toEqual(0); -// cache.put('item1', 'value1'); -// expect(cache.info().size).toEqual(1); -// cache.put('item2', 'value2'); -// expect(cache.info().size).toEqual(2); -// cache.put('item3', 'value3'); -// expect(cache.info().size).toEqual(2); -// expect(cache.get('item1')).toEqual(undefined); -// expect(cache.get('item2')).toEqual('value2'); -// expect(cache.get('item3')).toEqual('value3'); -// cache.get('item2'); -// cache.put('item1', 'value1'); -// expect(cache.get('item3')).toEqual(undefined); -// expect(cache.get('item1')).toEqual('value1'); -// expect(cache.get('item2')).toEqual('value2'); -// cache.destroy(); -// }); -// it('should not delete items if maxAge is specified and deleteOnExpire is set to "none"', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'none' }); -// cache.put('item1', 'value1'); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// expect(cache.get('item1')).toEqual('value1'); -// expect(cache.info('item1').isExpired).toEqual(true); -// cache.destroy(); -// }); -// }); -// it('should set a timeout for an item to expire if maxAge is specified and deleteOnExpire is set to "aggressive"', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive' }); -// cache.put('item1', 'value1'); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(cache.info('item1')).toEqual(undefined); -// expect(cache.get('item1')).toEqual(undefined); -// cache.destroy(); -// }); -// }); -// it('should should lazy delete an item when maxAge is specified and deleteOnExpire is set to "passive"', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'passive' }); -// cache.put('item1', 'value1'); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// expect(cache.info('item1').isExpired).toEqual(true); -// expect(cache.get('item1')).toEqual(undefined); -// cache.destroy(); -// }); -// }); -// it('should not delete items if maxAge is specified and deleteOnExpire is set to "none" for an item', function () { -// var cache = $angularCacheFactory('cache'); -// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'none' }); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// expect(cache.get('item1')).toEqual('value1'); -// expect(cache.info('item1').isExpired).toEqual(true); -// cache.destroy(); -// }); -// }); -// it('should set a timeout for an item to expire if maxAge for item is specified and deleteOnExpire is set to "aggressive"', function () { -// var cache = $angularCacheFactory('cache'); -// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'aggressive' }); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(cache.info('item1')).toEqual(undefined); -// expect(cache.get('item1')).toEqual(undefined); -// cache.destroy(); -// }); -// }); -// it('should passively expire an item if maxAge for the item is specified and deleteOnExpire is set to "passive"', function () { -// var cache = $angularCacheFactory('cache'); -// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// expect(cache.info('item1').isExpired).toEqual(true); -// expect(cache.get('item1')).toEqual(undefined); -// cache.destroy(); -// }); -// }); -// it('maxAge for a specific item should override maxAge for the cache', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 1000, deleteOnExpire: 'aggressive' }); -// cache.put('item1', 'value1', { maxAge: 5 }); -// expect(cache.info('item1').maxAge).toEqual(5); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(cache.get('item1')).toEqual(undefined); -// cache.destroy(); -// }); -// }); -// it('deleteOnExpire set to "passive" for a specific item should override deleteOnExpire set to "aggressive" for the cache', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive' }); -// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); -// expect(cache.get('item1')).toEqual('value1'); -// expect(cache.info('item1').deleteOnExpire).toEqual("passive"); -// waits(100); -// runs(function () { -// expect(cache.info('item1').isExpired).toEqual(true); -// expect(cache.get('item1')).toEqual(undefined); -// cache.destroy(); -// }); -// }); -// it('should save data to localStorage when storageMode is used', function () { -// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), -// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); -// -// localStorageCache.put('item1', 'value1'); -// sessionStorageCache.put('item1', 'value1'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); -// } -// -// localStorageCache.destroy(); -// sessionStorageCache.destroy(); -// }); -// }); -// describe('AngularCache.get(key)', function () { -// it('should return the correct value for the specified key', function () { -// var cache = $angularCacheFactory('cache'); -// var value1 = 'value1', -// value2 = 2, -// value3 = { -// value3: 'stuff' -// }; -// cache.put('item1', value1); -// cache.put('item2', value2); -// cache.put('item3', value3); -// expect(cache.get('item1')).toEqual(value1); -// expect(cache.get('item2')).toEqual(value2); -// expect(cache.get('item3')).toEqual(value3); -// cache.destroy(); -// }); -// it('should return undefined if the key isn\'t in the cache', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.get('item')).toEqual(undefined); -// cache.destroy(); -// }); -// it('should execute globally configured \'onExpire\' callback if the item is expired in passive mode and global \'onExpire\' callback is configured', function () { -// var cache = $angularCacheFactory('cache', { -// maxAge: 10, -// onExpire: function (key, value, done) { -// done(key, value, 'executed global callback'); -// } -// }); -// cache.put('item', 'value'); -// waits(100); -// runs(function () { -// cache.get('item', function (key, value, test) { -// expect(key).toEqual('item'); -// expect(value).toEqual('value'); -// expect(test).toEqual('executed global callback'); -// }); -// cache.destroy(); -// }); -// }); -// it('should execute globally configured \'onExpire\' callback when an item is aggressively deleted and global \'onExpire\' callback is configured', function () { -// var onExpire = jasmine.createSpy(); -// var cache = $angularCacheFactory('cache', { -// maxAge: 10, -// deleteOnExpire: 'aggressive', -// onExpire: onExpire -// }); -// cache.put('item', 'value'); -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(onExpire).toHaveBeenCalled(); -// expect(onExpire).toHaveBeenCalledWith('item', 'value'); -// cache.destroy(); -// }); -// }); -// it('should execute local \'onExpire\' callback if the item is expired in passive mode and global \'onExpire\' callback is NOT configured', function () { -// var cache = $angularCacheFactory('cache', { -// maxAge: 10 -// }); -// cache.put('item', 'value'); -// waits(100); -// runs(function () { -// cache.get('item', function (key, value) { -// expect(key).toEqual('item'); -// expect(value).toEqual('value'); -// }); -// cache.destroy(); -// }); -// }); -// }); -// describe('AngularCache.remove(key)', function () { -// it('should remove the item with the specified key', function () { -// var cache = $angularCacheFactory('cache'); -// var value1 = 'value1', -// value2 = 2, -// value3 = { -// value3: 'stuff' -// }; -// cache.put('item1', value1); -// cache.put('item2', value2); -// cache.put('item3', value3); -// cache.remove('item1'); -// expect(cache.get('item1')).toEqual(undefined); -// cache.remove('item2'); -// expect(cache.get('item2')).toEqual(undefined); -// cache.remove('item3'); -// expect(cache.get('item3')).toEqual(undefined); -// cache.destroy(); -// }); -// it('should reduce the size of the cache by one if the size is greater than zero', function () { -// var cache = $angularCacheFactory('cache'); -// cache.put('item1', 'value1'); -// expect(cache.info().size).toEqual(1); -// cache.put('item2', 'value2'); -// expect(cache.info().size).toEqual(2); -// cache.remove('item1'); -// expect(cache.info().size).toEqual(1); -// cache.remove('item2'); -// expect(cache.info().size).toEqual(0); -// cache.remove('item1'); -// expect(cache.info().size).toEqual(0); -// cache.remove('item2'); -// expect(cache.info().size).toEqual(0); -// cache.destroy(); -// }); -// it('should remove items from localStorage when storageMode is used', function () { -// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), -// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); -// -// localStorageCache.put('item1', 'value1'); -// sessionStorageCache.put('item1', 'value1'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); -// } -// -// localStorageCache.remove('item1'); -// sessionStorageCache.remove('item1'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); -// } -// -// localStorageCache.destroy(); -// sessionStorageCache.destroy(); -// }); -// }); -// describe('AngularCache.removeAll()', function () { -// it('should remove all items in the cache', function () { -// var cache = $angularCacheFactory('cache'); -// var value1 = 'value1', -// value2 = 2, -// value3 = { -// value3: 'stuff' -// }; -// cache.put('item1', value1); -// cache.put('item2', value2); -// cache.put('item3', value3); -// cache.removeAll(); -// expect(cache.get('item1')).toEqual(undefined); -// expect(cache.get('item2')).toEqual(undefined); -// expect(cache.get('item3')).toEqual(undefined); -// cache.destroy(); -// }); -// it('should remove items from localStorage when storageMode is used', function () { -// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), -// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); -// -// localStorageCache.put('item1', 'value1'); -// sessionStorageCache.put('item1', 'value1'); -// localStorageCache.put('item2', 'value2'); -// sessionStorageCache.put('item2', 'value2'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2')).value).toEqual('value2'); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1","item2"]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2')).value).toEqual('value2'); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1","item2"]'); -// } -// -// localStorageCache.removeAll(); -// sessionStorageCache.removeAll(); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2'))).toEqual(null); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2'))).toEqual(null); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); -// } -// -// localStorageCache.destroy(); -// sessionStorageCache.destroy(); -// }); -// }); -// describe('AngularCache.destroy()', function () { -// it('should completely destroy the cache', function () { -// var cache = $angularCacheFactory('cache'); -// cache.destroy(); -// expect($angularCacheFactory.get('cache')).toEqual(undefined); -// }); -// it('should remove items from localStorage when storageMode is used', function () { -// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), -// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); -// -// localStorageCache.put('item1', 'value1'); -// sessionStorageCache.put('item1', 'value1'); -// localStorageCache.put('item2', 'value2'); -// sessionStorageCache.put('item2', 'value2'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2')).value).toEqual('value2'); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1","item2"]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2')).value).toEqual('value2'); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1","item2"]'); -// } -// -// localStorageCache.destroy(); -// sessionStorageCache.destroy(); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2'))).toEqual(null); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual(null); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2'))).toEqual(null); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual(null); -// } -// }); -// }); -// describe('AngularCache.info()', function () { -// it('should return the correct values', function () { -// var onExpire = function () { -// }; -// var cache = $angularCacheFactory('cache'), -// cache2 = $angularCacheFactory('cache2', { maxAge: 1000 }), -// cache3 = $angularCacheFactory('cache3', { cacheFlushInterval: 1000 }), -// cache4 = $angularCacheFactory('cache4', { capacity: 1000 }), -// cache5 = $angularCacheFactory('cache5', { storageMode: 'localStorage' }), -// cache6 = $angularCacheFactory('cache6', { storageMode: 'sessionStorage' }); -// cache7 = $angularCacheFactory('cache7', { maxAge: 100, onExpire: onExpire }); -// expect(cache.info()).toEqual({ -// id: 'cache', -// capacity: Number.MAX_VALUE, -// size: 0, -// maxAge: null, -// cacheFlushInterval: null, -// deleteOnExpire: 'none', -// storageMode: 'none', -// onExpire: null -// }); -// cache.put('item', 'value'); -// cache.put('item2', 'value2', { maxAge: 200, deleteOnExpire: 'aggressive' }); -// -// // AngularCache#info(key) -// expect(typeof cache.info('item').timestamp).toEqual('number'); -// expect(cache.info('item').maxAge).toEqual(null); -// expect(cache.info('item').deleteOnExpire).toEqual('none'); -// expect(typeof cache.info('item2').timestamp).toEqual('number'); -// expect(cache.info('item2').maxAge).toEqual(200); -// expect(cache.info('item2').deleteOnExpire).toEqual('aggressive'); -// -// expect(cache.info()).toEqual({ -// id: 'cache', -// capacity: Number.MAX_VALUE, -// size: 2, -// maxAge: null, -// cacheFlushInterval: null, -// deleteOnExpire: 'none', -// storageMode: 'none', -// onExpire: null -// }); -// expect(cache2.info()).toEqual({ -// id: 'cache2', -// capacity: Number.MAX_VALUE, -// maxAge: 1000, -// size: 0, -// cacheFlushInterval: null, -// deleteOnExpire: 'none', -// storageMode: 'none', -// onExpire: null -// }); -// expect(cache3.info().id).toEqual('cache3'); -// expect(cache3.info().capacity).toEqual(Number.MAX_VALUE); -// expect(cache3.info().cacheFlushInterval).toEqual(1000); -// expect(cache3.info().size).toEqual(0); -// expect(cache4.info()).toEqual({ -// id: 'cache4', -// capacity: 1000, -// size: 0, -// maxAge: null, -// cacheFlushInterval: null, -// deleteOnExpire: 'none', -// storageMode: 'none', -// onExpire: null -// }); -// if (localStorage) { -// expect(cache5.info().storageMode).toEqual('localStorage'); -// } else { -// expect(cache5.info().storageMode).toEqual(null); -// } -// if (sessionStorage) { -// expect(cache6.info().storageMode).toEqual('sessionStorage'); -// } else { -// expect(cache6.info().storageMode).toEqual(null); -// } -// expect(cache7.info().onExpire).toEqual(onExpire); -// cache.destroy(); -// cache2.destroy(); -// cache3.destroy(); -// cache4.destroy(); -// cache5.destroy(); -// cache6.destroy(); -// cache7.destroy(); -// }); -// }); -// describe('AngularCache.keySet()', function () { -// it('should return the correct set of keys of all items currently in a cache', function () { -// var itemKeys = ['item1', 'item2', 'item3']; -// -// var cache = $angularCacheFactory('cache'); -// -// cache.put(itemKeys[0], itemKeys[0]); -// cache.put(itemKeys[1], itemKeys[1]); -// cache.put(itemKeys[2], itemKeys[2]); -// -// var keySet = cache.keySet(); -// -// expect(keySet.hasOwnProperty(itemKeys[0])).toEqual(true); -// expect(keySet.hasOwnProperty(itemKeys[1])).toEqual(true); -// expect(keySet.hasOwnProperty(itemKeys[2])).toEqual(true); -// -// expect(keySet[itemKeys[0]]).toEqual(itemKeys[0]); -// expect(keySet[itemKeys[1]]).toEqual(itemKeys[1]); -// expect(keySet[itemKeys[2]]).toEqual(itemKeys[2]); -// -// cache.remove(itemKeys[0]); -// cache.remove(itemKeys[1]); -// cache.remove(itemKeys[2]); -// -// keySet = cache.keySet(); -// -// expect(keySet.hasOwnProperty(itemKeys[0])).toEqual(false); -// expect(keySet.hasOwnProperty(itemKeys[1])).toEqual(false); -// expect(keySet.hasOwnProperty(itemKeys[2])).toEqual(false); -// cache.destroy(); -// }); -// }); -// describe('AngularCache.keys()', function () { -// it('should return the correct array of keys of all items currently in a cache', function () { -// var itemKeys = ['item1', 'item2', 'item3']; -// -// var cache = $angularCacheFactory('cache'); -// -// cache.put(itemKeys[0], itemKeys[0]); -// cache.put(itemKeys[1], itemKeys[1]); -// cache.put(itemKeys[2], itemKeys[2]); -// -// var keys = cache.keys(); -// -// expect(keys[0]).toEqual(itemKeys[0]); -// expect(keys[1]).toEqual(itemKeys[1]); -// expect(keys[2]).toEqual(itemKeys[2]); -// -// cache.remove(itemKeys[0]); -// cache.remove(itemKeys[1]); -// cache.remove(itemKeys[2]); -// -// keys = cache.keys(); -// -// expect(keys.length).toEqual(0); -// cache.destroy(); -// }); -// }); -// describe('AngularCache.setOptions()', function () { -// it('should correctly reset to defaults if strict mode is true', function () { -// var onExpire = function () { -// }; -// var cache = $angularCacheFactory('cache', { -// maxAge: 100, -// cacheFlushInterval: 200, -// onExpire: onExpire, -// storageMode: 'localStorage' -// }); -// expect(cache.info().maxAge).toEqual(100); -// expect(cache.info().cacheFlushInterval).toEqual(200); -// expect(cache.info().onExpire).toEqual(onExpire); -// expect(cache.info().storageMode).toEqual('localStorage'); -// cache.setOptions({ }, true); -// expect(cache.info().maxAge).toEqual(null); -// expect(cache.info().cacheFlushInterval).toEqual(null); -// expect(cache.info().onExpire).toEqual(null); -// expect(cache.info().storageMode).toEqual('none'); -// cache.destroy(); -// }); -// it('should correctly modify the capacity of a cache', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.info().capacity).toEqual(Number.MAX_VALUE); -// cache.setOptions({ capacity: 5 }, false); -// expect(cache.info().capacity).toEqual(5); -// cache.put('item1', 1); -// cache.put('item2', 2); -// cache.put('item3', 3); -// cache.put('item4', 4); -// cache.put('item5', 5); -// cache.put('item6', 6); -// expect(cache.get('item1')).not.toBeDefined(); -// cache.setOptions({ capacity: 3 }, false); -// // Least-recently used items over the new capacity should have been removed. -// expect(cache.get('item2')).not.toBeDefined(); -// expect(cache.get('item3')).not.toBeDefined(); -// expect(cache.info().size).toEqual(3); -// cache.destroy(); -// }); -// it('should correctly modify the maxAge of a cache', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.info().maxAge).toEqual(null); -// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); -// expect(cache.info().maxAge).toEqual(10); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); -// expect(cache.info().maxAge).toEqual(10); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// // The new items should be removed after 500 ms (the new maxAge) -// runs(function () { -// $timeout.flush(); -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// cache.destroy(); -// }); -// }); -// }); -// it('should correctly modify the cacheFlushInterval of a cache', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.info().cacheFlushInterval).toEqual(null); -// cache.setOptions({ cacheFlushInterval: 10 }, false); -// expect(cache.info().cacheFlushInterval).toEqual(10); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// // The first items should be removed after 2000 ms -// runs(function () { -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// cache.setOptions({ cacheFlushInterval: 10 }, false); -// expect(cache.info().cacheFlushInterval).toEqual(10); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// // The new items should be removed after 500 ms (the new maxAge) -// runs(function () { -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// cache.destroy(); -// }); -// }); -// }); -// it('should correctly modify the deleteOnExpire of a cache', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 10 }); -// expect(cache.info().deleteOnExpire).toEqual('none'); -// cache.setOptions({ deleteOnExpire: 'passive' }, false); -// expect(cache.info().deleteOnExpire).toEqual('passive'); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// // The first items should be removed after 2000 ms -// runs(function () { -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); -// expect(cache.info().deleteOnExpire).toEqual('aggressive'); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// // The new items should be removed after 500 ms (the new maxAge) -// runs(function () { -// $timeout.flush(); -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// cache.destroy(); -// }); -// }); -// }); -// it('should correctly set configuration to default when \'strict\' is true', function () { -// var cache = $angularCacheFactory('cache', { -// capacity: 10, -// maxAge: 1000, -// cacheFlushInterval: 1000, -// deleteOnExpire: 'aggressive', -// storageMode: 'none' -// }); -// cache.setOptions({}, true); -// expect(cache.info()).toEqual({ -// capacity: Number.MAX_VALUE, -// maxAge: null, -// cacheFlushInterval: null, -// id: 'cache', -// size: 0, -// deleteOnExpire: 'none', -// storageMode: 'none', -// onExpire: null -// }); -// }); -// it('should correctly switch to using local/session storage when storageMode is activated', function () { -// var cache = $angularCacheFactory('cache'), -// cache2 = $angularCacheFactory('cache2'); -// cache.put('item', 'value'); -// cache2.put('item', 'value'); -// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'localStorage' }); -// cache2.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'sessionStorage' }); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); -// } -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(cache.get('item')).toEqual(null); -// expect(cache2.get('item')).toEqual(null); -// if (localStorage) { -// expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); -// } -// if (sessionStorage) { -// expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); -// } -// cache.destroy(); -// cache2.destroy(); -// }); -// }); -// it('should correctly stop using local/session storage when storageMode is deactivated', function () { -// var cache = $angularCacheFactory('cache', { storageMode: 'localStorage' }), -// cache2 = $angularCacheFactory('cache2', { storageMode: 'sessionStorage' }); -// cache.put('item', 'value'); -// cache2.put('item', 'value'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); -// } -// -// cache.setOptions({ storageMode: 'none' }, true); -// cache2.setOptions({ storageMode: 'none' }, true); -// -// if (localStorage) { -// expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); -// } -// if (sessionStorage) { -// expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); -// } -// -// cache.destroy(); -// cache2.destroy(); -// }); -// }); -//}); \ No newline at end of file diff --git a/test/binaryHeap-test.js b/test/binaryHeap-test.js new file mode 100644 index 0000000..4092045 --- /dev/null +++ b/test/binaryHeap-test.js @@ -0,0 +1,2 @@ +describe('BinaryHeap(weightFunc)', function () { +}); \ No newline at end of file diff --git a/test/binaryHeap.bubbleDown-test.js b/test/binaryHeap.bubbleDown-test.js new file mode 100644 index 0000000..75aea89 --- /dev/null +++ b/test/binaryHeap.bubbleDown-test.js @@ -0,0 +1,2 @@ +describe('BinaryHeap.bubbleDown(index)', function () { +}); \ No newline at end of file diff --git a/test/binaryHeap.bubbleUp-test.js b/test/binaryHeap.bubbleUp-test.js new file mode 100644 index 0000000..48822cc --- /dev/null +++ b/test/binaryHeap.bubbleUp-test.js @@ -0,0 +1,2 @@ +describe('BinaryHeap.bubbleUp(index)', function () { +}); \ No newline at end of file diff --git a/test/binaryHeap.peek-test.js b/test/binaryHeap.peek-test.js new file mode 100644 index 0000000..59af6be --- /dev/null +++ b/test/binaryHeap.peek-test.js @@ -0,0 +1,2 @@ +describe('BinaryHeap.peek()', function () { +}); \ No newline at end of file diff --git a/test/binaryHeap.pop-test.js b/test/binaryHeap.pop-test.js new file mode 100644 index 0000000..737e611 --- /dev/null +++ b/test/binaryHeap.pop-test.js @@ -0,0 +1,2 @@ +describe('BinaryHeap.pop()', function () { +}); \ No newline at end of file diff --git a/test/binaryHeap.push-test.js b/test/binaryHeap.push-test.js new file mode 100644 index 0000000..1876b2c --- /dev/null +++ b/test/binaryHeap.push-test.js @@ -0,0 +1,2 @@ +describe('BinaryHeap.push(node)', function () { +}); \ No newline at end of file diff --git a/test/binaryHeap.remove-test.js b/test/binaryHeap.remove-test.js new file mode 100644 index 0000000..16e8edf --- /dev/null +++ b/test/binaryHeap.remove-test.js @@ -0,0 +1,2 @@ +describe('BinaryHeap.remove(node)', function () { +}); \ No newline at end of file diff --git a/test/binaryHeap.removeAll-test.js b/test/binaryHeap.removeAll-test.js new file mode 100644 index 0000000..233c274 --- /dev/null +++ b/test/binaryHeap.removeAll-test.js @@ -0,0 +1,2 @@ +describe('BinaryHeap.removeAll()', function () { +}); \ No newline at end of file From 805128315ee9e4323def37e3013735213679e15b Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Sat, 5 Oct 2013 16:16:49 -0600 Subject: [PATCH 6/8] Finished the BinaryHeap tests. #51 #57 #58 --- src/angular-cache.js | 147 +++++++++++++++-------------- test/binaryHeap-test.js | 21 +++++ test/binaryHeap.bubbleDown-test.js | 2 - test/binaryHeap.bubbleUp-test.js | 2 - test/binaryHeap.peek-test.js | 136 ++++++++++++++++++++++++++ test/binaryHeap.pop-test.js | 76 +++++++++++++++ test/binaryHeap.push-test.js | 97 +++++++++++++++++++ test/binaryHeap.remove-test.js | 73 ++++++++++++++ test/binaryHeap.removeAll-test.js | 25 +++++ test/karma.start.js | 7 +- 10 files changed, 509 insertions(+), 77 deletions(-) delete mode 100644 test/binaryHeap.bubbleDown-test.js delete mode 100644 test/binaryHeap.bubbleUp-test.js diff --git a/src/angular-cache.js b/src/angular-cache.js index dae0861..abdd856 100644 --- a/src/angular-cache.js +++ b/src/angular-cache.js @@ -19,12 +19,85 @@ */ function BinaryHeapProvider() { this.$get = function () { + /** + * @method bubbleUp + * @param {Array} heap The heap. + * @param {Function} weightFunc The weight function. + * @param {Number} n The index of the element to bubble up. + * @ignore + */ + function bubbleUp(heap, weightFunc, n) { + var element = heap[n], + weight = weightFunc(element); + // When at 0, an element can not go up any further. + while (n > 0) { + // Compute the parent element's index, and fetch it. + var parentN = Math.floor((n + 1) / 2) - 1, + parent = heap[parentN]; + // If the parent has a lesser weight, things are in order and we + // are done. + if (weight >= weightFunc(parent)) { + break; + } else { + heap[parentN] = element; + heap[n] = parent; + n = parentN; + } + } + } + + /** + * @method bubbleDown + * @param {Array} heap The heap. + * @param {Function} weightFunc The weight function. + * @param {Number} n The index of the element to sink down. + * @ignore + */ + function bubbleDown(heap, weightFunc, n) { + var length = heap.length, + node = heap[n], + nodeWeight = weightFunc(node); + + while (true) { + var child2N = (n + 1) * 2, + child1N = child2N - 1; + var swap = null; + if (child1N < length) { + var child1 = heap[child1N], + child1Weight = weightFunc(child1); + // If the score is less than our node's, we need to swap. + if (child1Weight < nodeWeight) { + swap = child1N; + } + } + // Do the same checks for the other child. + if (child2N < length) { + var child2 = heap[child2N], + child2Weight = weightFunc(child2); + if (child2Weight < (swap === null ? nodeWeight : weightFunc(heap[child1N]))) { + swap = child2N; + } + } + + if (swap === null) { + break; + } else { + heap[n] = heap[swap]; + heap[swap] = node; + n = swap; + } + } + } + /** * @class BinaryHeap * @desc BinaryHeap implementation of a priority queue. * @param {Function} weightFunc Function that determines how each node should be weighted. */ function BinaryHeap(weightFunc) { + if (weightFunc && !angular.isFunction(weightFunc)) { + throw new Error('BinaryHeap(weightFunc): weightFunc: must be a function!'); + } weightFunc = weightFunc || function (x) { return x; }; @@ -40,7 +113,7 @@ */ BinaryHeap.prototype.push = function (node) { this.heap.push(node); - this.bubbleUp(this.heap.length - 1); + bubbleUp(this.heap, this.weightFunc, this.heap.length - 1); }; /** @@ -64,7 +137,7 @@ end = this.heap.pop(); if (this.heap.length > 0) { this.heap[0] = end; - this.bubbleDown(0); + bubbleDown(this.heap, this.weightFunc, 0); } return front; }; @@ -85,8 +158,8 @@ end = this.heap.pop(); if (i !== length - 1) { this.heap[i] = end; - this.bubbleUp(i); - this.bubbleDown(i); + bubbleUp(this.heap, this.weightFunc, i); + bubbleDown(this.heap, this.weightFunc, i); } return removed; } @@ -113,72 +186,6 @@ return this.heap.length; }; - /** - * @method BinaryHeap.bubbleUp - * @param {Number} n The index of the element to bubble up. - * @ignore - */ - BinaryHeap.prototype.bubbleUp = function (n) { - var element = this.heap[n], - weight = this.weightFunc(element); - // When at 0, an element can not go up any further. - while (n > 0) { - // Compute the parent element's index, and fetch it. - var parentN = Math.floor((n + 1) / 2) - 1, - parent = this.heap[parentN]; - // If the parent has a lesser weight, things are in order and we - // are done. - if (weight >= this.weightFunc(parent)) { - break; - } else { - this.heap[parentN] = element; - this.heap[n] = parent; - n = parentN; - } - } - }; - - /** - * @method BinaryHeap.bubbleDown - * @param {Number} n The index of the element to sink down. - * @ignore - */ - BinaryHeap.prototype.bubbleDown = function (n) { - var length = this.heap.length, - node = this.heap[n], - nodeWeight = this.weightFunc(node); - - while (true) { - var child2N = (n + 1) * 2, - child1N = child2N - 1; - var swap = null; - if (child1N < length) { - var child1 = this.heap[child1N], - child1Weight = this.weightFunc(child1); - // If the score is less than our node's, we need to swap. - if (child1Weight < nodeWeight) { - swap = child1N; - } - } - // Do the same checks for the other child. - if (child2N < length) { - var child2 = this.heap[child2N], - child2Weight = this.weightFunc(child2); - if (child2Weight < (swap === null ? nodeWeight : this.weightFunc(this.heap[child1N]))) { - swap = child2N; - } - } - - if (swap === null) { - break; - } else { - this.heap[n] = this.heap[swap]; - this.heap[swap] = node; - n = swap; - } - } - }; - return BinaryHeap; }; } diff --git a/test/binaryHeap-test.js b/test/binaryHeap-test.js index 4092045..cce9cf7 100644 --- a/test/binaryHeap-test.js +++ b/test/binaryHeap-test.js @@ -1,2 +1,23 @@ describe('BinaryHeap(weightFunc)', function () { + it('should create an empty heap with size 0.', function () { + var heap = new BinaryHeap(); + expect(heap.size()).toEqual(0); + }); + it('should throw an error if "weightFunc" is not a function.', function () { + var heap; + for (var i = 0; i < TYPES_EXCEPT_FUNCTION.length; i++) { + try { + heap = new BinaryHeap(TYPES_EXCEPT_FUNCTION[i]); + if (TYPES_EXCEPT_FUNCTION[i]) { + fail(); + } + } catch (err) { + expect(err.message).toEqual('BinaryHeap(weightFunc): weightFunc: must be a function!'); + continue; + } + if (TYPES_EXCEPT_FUNCTION[i]) { + fail(); + } + } + }); }); \ No newline at end of file diff --git a/test/binaryHeap.bubbleDown-test.js b/test/binaryHeap.bubbleDown-test.js deleted file mode 100644 index 75aea89..0000000 --- a/test/binaryHeap.bubbleDown-test.js +++ /dev/null @@ -1,2 +0,0 @@ -describe('BinaryHeap.bubbleDown(index)', function () { -}); \ No newline at end of file diff --git a/test/binaryHeap.bubbleUp-test.js b/test/binaryHeap.bubbleUp-test.js deleted file mode 100644 index 48822cc..0000000 --- a/test/binaryHeap.bubbleUp-test.js +++ /dev/null @@ -1,2 +0,0 @@ -describe('BinaryHeap.bubbleUp(index)', function () { -}); \ No newline at end of file diff --git a/test/binaryHeap.peek-test.js b/test/binaryHeap.peek-test.js index 59af6be..cd6bac3 100644 --- a/test/binaryHeap.peek-test.js +++ b/test/binaryHeap.peek-test.js @@ -1,2 +1,138 @@ describe('BinaryHeap.peek()', function () { + it('should show the item at the front of the BinaryHeap.', function () { + var heap = new BinaryHeap(); + var objHeap = new BinaryHeap(function (x) { + return x.value; + }); + var items = [20, 4, 33, 1, 0, 34, 22, 31, 32, 5, 6, 7], + objItems = []; + for (var i = 0; i < items.length; i++) { + objItems.push({ + value: items[i] + }); + } + + expect(heap.peek()).not.toBeDefined(); + expect(objHeap.peek()).not.toBeDefined(); + + heap.push(items[0]); + objHeap.push(objItems[0]); + expect(heap.peek()).toEqual(items[0]); + expect(objHeap.peek()).toEqual(objItems[0]); + + heap.push(items[1]); + objHeap.push(objItems[1]); + expect(heap.peek()).toEqual(items[1]); + expect(objHeap.peek()).toEqual(objItems[1]); + + heap.push(items[2]); + objHeap.push(objItems[2]); + expect(heap.peek()).toEqual(items[1]); + expect(objHeap.peek()).toEqual(objItems[1]); + + heap.push(items[3]); + objHeap.push(objItems[3]); + expect(heap.peek()).toEqual(items[3]); + expect(objHeap.peek()).toEqual(objItems[3]); + + heap.push(items[4]); + objHeap.push(objItems[4]); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[5]); + objHeap.push(objItems[5]); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[6]); + objHeap.push(objItems[6]); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[7]); + objHeap.push(objItems[7]); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[8]); + objHeap.push(objItems[8]); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[9]); + objHeap.push(objItems[9]); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[10]); + objHeap.push(objItems[10]); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[11]); + objHeap.push(objItems[11]); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + expect(heap.pop()).toEqual(0); + expect(objHeap.pop()).toEqual({ value: 0 }); + expect(heap.peek()).toEqual(1); + expect(objHeap.peek()).toEqual({ value: 1 }); + + expect(heap.pop()).toEqual(1); + expect(objHeap.pop()).toEqual({ value: 1 }); + expect(heap.peek()).toEqual(4); + expect(objHeap.peek()).toEqual({ value: 4 }); + + expect(heap.pop()).toEqual(4); + expect(objHeap.pop()).toEqual({ value: 4 }); + expect(heap.peek()).toEqual(5); + expect(objHeap.peek()).toEqual({ value: 5 }); + + expect(heap.pop()).toEqual(5); + expect(objHeap.pop()).toEqual({ value: 5 }); + expect(heap.peek()).toEqual(6); + expect(objHeap.peek()).toEqual({ value: 6 }); + + expect(heap.pop()).toEqual(6); + expect(objHeap.pop()).toEqual({ value: 6 }); + expect(heap.peek()).toEqual(7); + expect(objHeap.peek()).toEqual({ value: 7 }); + + expect(heap.pop()).toEqual(7); + expect(objHeap.pop()).toEqual({ value: 7 }); + expect(heap.peek()).toEqual(20); + expect(objHeap.peek()).toEqual({ value: 20 }); + + expect(heap.pop()).toEqual(20); + expect(objHeap.pop()).toEqual({ value: 20 }); + expect(heap.peek()).toEqual(22); + expect(objHeap.peek()).toEqual({ value: 22 }); + + expect(heap.pop()).toEqual(22); + expect(objHeap.pop()).toEqual({ value: 22 }); + expect(heap.peek()).toEqual(31); + expect(objHeap.peek()).toEqual({ value: 31 }); + + expect(heap.pop()).toEqual(31); + expect(objHeap.pop()).toEqual({ value: 31 }); + expect(heap.peek()).toEqual(32); + expect(objHeap.peek()).toEqual({ value: 32 }); + + expect(heap.pop()).toEqual(32); + expect(objHeap.pop()).toEqual({ value: 32 }); + expect(heap.peek()).toEqual(33); + expect(objHeap.peek()).toEqual({ value: 33 }); + + expect(heap.pop()).toEqual(33); + expect(objHeap.pop()).toEqual({ value: 33 }); + expect(heap.peek()).toEqual(34); + expect(objHeap.peek()).toEqual({ value: 34 }); + + expect(heap.pop()).toEqual(34); + expect(objHeap.pop()).toEqual({ value: 34 }); + expect(heap.peek()).not.toBeDefined(); + expect(objHeap.peek()).not.toBeDefined(); + }); }); \ No newline at end of file diff --git a/test/binaryHeap.pop-test.js b/test/binaryHeap.pop-test.js index 737e611..93342cd 100644 --- a/test/binaryHeap.pop-test.js +++ b/test/binaryHeap.pop-test.js @@ -1,2 +1,78 @@ describe('BinaryHeap.pop()', function () { + it('should pop the item off of the front of the BinaryHeap.', function () { + var heap = new BinaryHeap(); + var objHeap = new BinaryHeap(function (x) { + return x.value; + }); + var items = [20, 4, 33, 1, 0, 34, 22, 31, 32, 5, 6, 7]; + for (var i = 0; i < items.length; i++) { + heap.push(items[i]); + objHeap.push({ + value: items[i] + }); + } + + expect(heap.size()).toEqual(12); + expect(objHeap.size()).toEqual(12); + + expect(heap.pop()).toEqual(0); + expect(objHeap.pop()).toEqual({ value: 0 }); + expect(heap.size()).toEqual(11); + expect(objHeap.size()).toEqual(11); + + expect(heap.pop()).toEqual(1); + expect(objHeap.pop()).toEqual({ value: 1 }); + expect(heap.size()).toEqual(10); + expect(objHeap.size()).toEqual(10); + + expect(heap.pop()).toEqual(4); + expect(objHeap.pop()).toEqual({ value: 4 }); + expect(heap.size()).toEqual(9); + expect(objHeap.size()).toEqual(9); + + expect(heap.pop()).toEqual(5); + expect(objHeap.pop()).toEqual({ value: 5 }); + expect(heap.size()).toEqual(8); + expect(objHeap.size()).toEqual(8); + + expect(heap.pop()).toEqual(6); + expect(objHeap.pop()).toEqual({ value: 6 }); + expect(heap.size()).toEqual(7); + expect(objHeap.size()).toEqual(7); + + expect(heap.pop()).toEqual(7); + expect(objHeap.pop()).toEqual({ value: 7 }); + expect(heap.size()).toEqual(6); + expect(objHeap.size()).toEqual(6); + + expect(heap.pop()).toEqual(20); + expect(objHeap.pop()).toEqual({ value: 20 }); + expect(heap.size()).toEqual(5); + expect(objHeap.size()).toEqual(5); + + expect(heap.pop()).toEqual(22); + expect(objHeap.pop()).toEqual({ value: 22 }); + expect(heap.size()).toEqual(4); + expect(objHeap.size()).toEqual(4); + + expect(heap.pop()).toEqual(31); + expect(objHeap.pop()).toEqual({ value: 31 }); + expect(heap.size()).toEqual(3); + expect(objHeap.size()).toEqual(3); + + expect(heap.pop()).toEqual(32); + expect(objHeap.pop()).toEqual({ value: 32 }); + expect(heap.size()).toEqual(2); + expect(objHeap.size()).toEqual(2); + + expect(heap.pop()).toEqual(33); + expect(objHeap.pop()).toEqual({ value: 33 }); + expect(heap.size()).toEqual(1); + expect(objHeap.size()).toEqual(1); + + expect(heap.pop()).toEqual(34); + expect(objHeap.pop()).toEqual({ value: 34 }); + expect(heap.size()).toEqual(0); + expect(objHeap.size()).toEqual(0); + }); }); \ No newline at end of file diff --git a/test/binaryHeap.push-test.js b/test/binaryHeap.push-test.js index 1876b2c..6fbe2da 100644 --- a/test/binaryHeap.push-test.js +++ b/test/binaryHeap.push-test.js @@ -1,2 +1,99 @@ describe('BinaryHeap.push(node)', function () { + it('should push items to the front of the BinaryHeap.', function () { + var heap = new BinaryHeap(); + var objHeap = new BinaryHeap(function (x) { + return x.value; + }); + var items = [20, 4, 33, 1, 0, 34, 22, 31, 32, 5, 6, 7], + objItems = []; + for (var i = 0; i < items.length; i++) { + objItems.push({ + value: items[i] + }); + } + + heap.push(items[0]); + objHeap.push(objItems[0]); + expect(heap.size()).toEqual(1); + expect(objHeap.size()).toEqual(1); + expect(heap.peek()).toEqual(items[0]); + expect(objHeap.peek()).toEqual(objItems[0]); + + heap.push(items[1]); + objHeap.push(objItems[1]); + expect(heap.size()).toEqual(2); + expect(objHeap.size()).toEqual(2); + expect(heap.peek()).toEqual(items[1]); + expect(objHeap.peek()).toEqual(objItems[1]); + + heap.push(items[2]); + objHeap.push(objItems[2]); + expect(heap.size()).toEqual(3); + expect(objHeap.size()).toEqual(3); + expect(heap.peek()).toEqual(items[1]); + expect(objHeap.peek()).toEqual(objItems[1]); + + heap.push(items[3]); + objHeap.push(objItems[3]); + expect(heap.size()).toEqual(4); + expect(objHeap.size()).toEqual(4); + expect(heap.peek()).toEqual(items[3]); + expect(objHeap.peek()).toEqual(objItems[3]); + + heap.push(items[4]); + objHeap.push(objItems[4]); + expect(heap.size()).toEqual(5); + expect(objHeap.size()).toEqual(5); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[5]); + objHeap.push(objItems[5]); + expect(heap.size()).toEqual(6); + expect(objHeap.size()).toEqual(6); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[6]); + objHeap.push(objItems[6]); + expect(heap.size()).toEqual(7); + expect(objHeap.size()).toEqual(7); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[7]); + objHeap.push(objItems[7]); + expect(heap.size()).toEqual(8); + expect(objHeap.size()).toEqual(8); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[8]); + objHeap.push(objItems[8]); + expect(heap.size()).toEqual(9); + expect(objHeap.size()).toEqual(9); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[9]); + objHeap.push(objItems[9]); + expect(heap.size()).toEqual(10); + expect(objHeap.size()).toEqual(10); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[10]); + objHeap.push(objItems[10]); + expect(heap.size()).toEqual(11); + expect(objHeap.size()).toEqual(11); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + + heap.push(items[11]); + objHeap.push(objItems[11]); + expect(heap.size()).toEqual(12); + expect(objHeap.size()).toEqual(12); + expect(heap.peek()).toEqual(items[4]); + expect(objHeap.peek()).toEqual(objItems[4]); + }); }); \ No newline at end of file diff --git a/test/binaryHeap.remove-test.js b/test/binaryHeap.remove-test.js index 16e8edf..b4a2dd7 100644 --- a/test/binaryHeap.remove-test.js +++ b/test/binaryHeap.remove-test.js @@ -1,2 +1,75 @@ describe('BinaryHeap.remove(node)', function () { + it('should remove the item from the heap.', function () { + var heap = new BinaryHeap(); + var objHeap = new BinaryHeap(function (x) { + return x.value; + }); + var items = [20, 4, 33, 1, 0, 34, 22, 31, 32, 5, 6, 7]; + for (var i = 0; i < items.length; i++) { + heap.push(items[i]); + objHeap.push({ + value: items[i] + }); + } + + expect(heap.remove(0)).toEqual(0); + expect(objHeap.remove({ value: 0 })).toEqual({ value: 0 }); + expect(heap.peek()).toEqual(1); + expect(objHeap.peek()).toEqual({ value: 1 }); + + expect(heap.remove(1)).toEqual(1); + expect(objHeap.remove({ value: 1 })).toEqual({ value: 1 }); + expect(heap.peek()).toEqual(4); + expect(objHeap.peek()).toEqual({ value: 4 }); + + expect(heap.remove(4)).toEqual(4); + expect(objHeap.remove({ value: 4 })).toEqual({ value: 4 }); + expect(heap.peek()).toEqual(5); + expect(objHeap.peek()).toEqual({ value: 5 }); + + expect(heap.remove(5)).toEqual(5); + expect(objHeap.remove({ value: 5 })).toEqual({ value: 5 }); + expect(heap.peek()).toEqual(6); + expect(objHeap.peek()).toEqual({ value: 6 }); + + expect(heap.remove(6)).toEqual(6); + expect(objHeap.remove({ value: 6 })).toEqual({ value: 6 }); + expect(heap.peek()).toEqual(7); + expect(objHeap.peek()).toEqual({ value: 7 }); + + expect(heap.remove(7)).toEqual(7); + expect(objHeap.remove({ value: 7 })).toEqual({ value: 7 }); + expect(heap.peek()).toEqual(20); + expect(objHeap.peek()).toEqual({ value: 20 }); + + expect(heap.remove(20)).toEqual(20); + expect(objHeap.remove({ value: 20 })).toEqual({ value: 20 }); + expect(heap.peek()).toEqual(22); + expect(objHeap.peek()).toEqual({ value: 22 }); + + expect(heap.remove(22)).toEqual(22); + expect(objHeap.remove({ value: 22 })).toEqual({ value: 22 }); + expect(heap.peek()).toEqual(31); + expect(objHeap.peek()).toEqual({ value: 31 }); + + expect(heap.remove(31)).toEqual(31); + expect(objHeap.remove({ value: 31 })).toEqual({ value: 31 }); + expect(heap.peek()).toEqual(32); + expect(objHeap.peek()).toEqual({ value: 32 }); + + expect(heap.remove(32)).toEqual(32); + expect(objHeap.remove({ value: 32 })).toEqual({ value: 32 }); + expect(heap.peek()).toEqual(33); + expect(objHeap.peek()).toEqual({ value: 33 }); + + expect(heap.remove(33)).toEqual(33); + expect(objHeap.remove({ value: 33 })).toEqual({ value: 33 }); + expect(heap.peek()).toEqual(34); + expect(objHeap.peek()).toEqual({ value: 34 }); + + expect(heap.remove(34)).toEqual(34); + expect(objHeap.remove({ value: 34 })).toEqual({ value: 34 }); + expect(heap.peek()).not.toBeDefined(); + expect(objHeap.peek()).not.toBeDefined(); + }); }); \ No newline at end of file diff --git a/test/binaryHeap.removeAll-test.js b/test/binaryHeap.removeAll-test.js index 233c274..927a977 100644 --- a/test/binaryHeap.removeAll-test.js +++ b/test/binaryHeap.removeAll-test.js @@ -1,2 +1,27 @@ describe('BinaryHeap.removeAll()', function () { + it('should remove all items from the heap.', function () { + var heap = new BinaryHeap(); + var objHeap = new BinaryHeap(function (x) { + return x.value; + }); + var items = [20, 4, 33, 1, 0, 34, 22, 31, 32, 5, 6, 7]; + for (var i = 0; i < items.length; i++) { + heap.push(items[i]); + objHeap.push({ + value: items[i] + }); + } + + expect(heap.size()).toEqual(12); + expect(objHeap.size()).toEqual(12); + + heap.removeAll(); + objHeap.removeAll(); + + expect(heap.size()).toEqual(0); + expect(objHeap.size()).toEqual(0); + + expect(heap.peek()).not.toBeDefined(); + expect(objHeap.peek()).not.toBeDefined(); + }); }); \ No newline at end of file diff --git a/test/karma.start.js b/test/karma.start.js index cc0435a..8720876 100644 --- a/test/karma.start.js +++ b/test/karma.start.js @@ -18,10 +18,11 @@ var fail = function (msg) { verifyIntegrity: true }; -var $angularCacheFactory; +var $angularCacheFactory, BinaryHeap; beforeEach(module('jmdobry.angular-cache')); -beforeEach(inject(function ($injector) { - $angularCacheFactory = $injector.get('$angularCacheFactory'); +beforeEach(inject(function (_$angularCacheFactory_, _BinaryHeap_) { + $angularCacheFactory = _$angularCacheFactory_; + BinaryHeap = _BinaryHeap_; })); afterEach(function () { $angularCacheFactory.removeAll(); From 262fee9afc76b680133189ee7d719d8a65d9f2ff Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Sat, 5 Oct 2013 18:31:49 -0600 Subject: [PATCH 7/8] Finished test for $angularCacheFactoryProvider. #51, #57, #58 --- src/angular-cache.js | 6 +- test/angularCacheFactory-test.js | 87 +++++ ...heFactoryProvider.setCacheDefaults-test.js | 344 ++++++++++++++++++ test/karma.start.js | 6 +- 4 files changed, 438 insertions(+), 5 deletions(-) create mode 100644 test/angularCacheFactoryProvider.setCacheDefaults-test.js diff --git a/src/angular-cache.js b/src/angular-cache.js index abdd856..7324e80 100644 --- a/src/angular-cache.js +++ b/src/angular-cache.js @@ -299,7 +299,7 @@ if (!angular.isString(options.storageMode)) { throw new Error(errStr + 'storageMode: must be a string!'); } else if (options.storageMode !== 'none' && options.storageMode !== 'localStorage' && options.storageMode !== 'sessionStorage') { - throw new Error(errStr + 'storageMode: accepted values are "none", "localStorage" or "sessionStorage"'); + throw new Error(errStr + 'storageMode: accepted values are "none", "localStorage" or "sessionStorage"!'); } if ('storageImpl' in options) { if (!angular.isObject(options.storageImpl)) { @@ -316,7 +316,7 @@ if ('onExpire' in options) { if (typeof options.onExpire !== 'function') { - throw new Error(errStr + 'onExpire: Must be a function!'); + throw new Error(errStr + 'onExpire: must be a function!'); } } @@ -1036,7 +1036,7 @@ var key = keys[i]; info.caches[key] = caches[key].info(); } - info.cacheDefaults = cacheDefaults; + info.cacheDefaults = angular.extend({}, cacheDefaults); return info; }; diff --git a/test/angularCacheFactory-test.js b/test/angularCacheFactory-test.js index 9d113d1..140c4aa 100644 --- a/test/angularCacheFactory-test.js +++ b/test/angularCacheFactory-test.js @@ -225,6 +225,93 @@ describe('$angularCacheFactory(cacheId, options)', function () { fail(TYPES_EXCEPT_OBJECT[i]); } } + try { + $angularCacheFactory('storageImplCache-noSetItem', { + storageMode: 'localStorage', + storageImpl: { + getItem: function () { + }, + removeItem: function () { + } + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } + try { + $angularCacheFactory('storageImplCache-noGetItem', { + storageMode: 'localStorage', + storageImpl: { + setItem: function () { + }, + removeItem: function () { + } + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } + try { + $angularCacheFactory('storageImplCache-noRemoveItem', { + storageMode: 'localStorage', + storageImpl: { + getItem: function () { + }, + setItem: function () { + } + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } + try { + $angularCacheFactory('storageImplCache-stringGetItem', { + storageMode: 'localStorage', + storageImpl: { + getItem: 'should not be a string', + setItem: function () { + }, + removeItem: function () { + } + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } + try { + $angularCacheFactory('storageImplCache-stringSetItem', { + storageMode: 'localStorage', + storageImpl: { + getItem: function () { + }, + setItem: 'should not be a string', + removeItem: function () { + } + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } + try { + $angularCacheFactory('storageImplCache-stringRemoveItem', { + storageMode: 'localStorage', + storageImpl: { + setItem: function () { + }, + getItem: function () { + }, + removeItem: 'should not be a string' + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } }); it('should prevent a cache from being duplicated.', function () { try { diff --git a/test/angularCacheFactoryProvider.setCacheDefaults-test.js b/test/angularCacheFactoryProvider.setCacheDefaults-test.js new file mode 100644 index 0000000..6a732e3 --- /dev/null +++ b/test/angularCacheFactoryProvider.setCacheDefaults-test.js @@ -0,0 +1,344 @@ +describe('$angularCacheFactoryProvider.setCacheDefaults(options)', function () { + it('should have the correct defaults.', function () { + expect($angularCacheFactory.info().cacheDefaults).toEqual({ + capacity: CACHE_DEFAULTS.capacity, + maxAge: CACHE_DEFAULTS.maxAge, + cacheFlushInterval: CACHE_DEFAULTS.cacheFlushInterval, + deleteOnExpire: CACHE_DEFAULTS.deleteOnExpire, + onExpire: CACHE_DEFAULTS.onExpire, + recycleFreq: CACHE_DEFAULTS.recycleFreq, + storageMode: CACHE_DEFAULTS.storageMode, + storageImpl: CACHE_DEFAULTS.storageImpl, + verifyIntegrity: CACHE_DEFAULTS.verifyIntegrity + }); + var cache = $angularCacheFactory('cache'); + expect(cache).toBeDefined(); + expect(cache.info().id).toEqual('cache'); + expect(cache.info().capacity).toEqual(CACHE_DEFAULTS.capacity); + expect(cache.info().maxAge).toEqual(CACHE_DEFAULTS.maxAge); + expect(cache.info().cacheFlushInterval).toEqual(CACHE_DEFAULTS.cacheFlushInterval); + expect(cache.info().deleteOnExpire).toEqual(CACHE_DEFAULTS.deleteOnExpire); + expect(cache.info().onExpire).toEqual(CACHE_DEFAULTS.onExpire); + expect(cache.info().recycleFreq).toEqual(CACHE_DEFAULTS.recycleFreq); + expect(cache.info().storageMode).toEqual(CACHE_DEFAULTS.storageMode); + expect(cache.info().storageImpl).toEqual(CACHE_DEFAULTS.storageImpl); + expect(cache.info().verifyIntegrity).toEqual(CACHE_DEFAULTS.verifyIntegrity); + cache.destroy(); + }); + it('should set the default options.', function () { + var options = { + capacity: Math.floor((Math.random() * 100000) + 1), + maxAge: Math.floor((Math.random() * 100000) + 1), + cacheFlushInterval: Math.floor((Math.random() * 100000) + 1), + deleteOnExpire: 'aggressive', + storageMode: 'localStorage', + localStorageImpl: { + setItem: function () { + }, + getItem: function () { + }, + removeItem: function () { + } + }, + verifyIntegrity: false, + recycleFreq: 2000, + onExpire: function () { + } + }; + $angularCacheFactoryProvider.setCacheDefaults(options); + var cache = $angularCacheFactory('cache'); + expect(cache).toBeDefined(); + expect(cache.info().id).toEqual('cache'); + expect(cache.info().capacity).toEqual(options.capacity); + expect(cache.info().maxAge).toEqual(options.maxAge); + expect(cache.info().cacheFlushInterval).toEqual(options.cacheFlushInterval); + expect(cache.info().deleteOnExpire).toEqual(options.deleteOnExpire); + expect(cache.info().storageMode).toEqual(options.storageMode); + expect(cache.info().localStorageImpl).not.toBeDefined(); // We don't expose this to the user + expect(cache.info().onExpire).toEqual(options.onExpire); + cache.destroy(); + expect($angularCacheFactory.get('cache')).not.toBeDefined(); + }); + it('should throw an exception if "capacity" is not a number or is less than zero.', function () { + try { + $angularCacheFactoryProvider.setCacheDefaults({ capacity: Math.floor((Math.random() * 100000) + 1) * -1 }); + fail(); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): capacity: must be greater than zero!'); + for (var i = 0; i < TYPES_EXCEPT_NUMBER.length; i++) { + try { + $angularCacheFactoryProvider.setCacheDefaults({ capacity: TYPES_EXCEPT_NUMBER[i] }); + fail(); + } catch (err) { + expect(err.message).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): capacity: must be a number!'); + continue; + } + fail(); + } + }); + it('should validate maxAge.', function () { + var maxAge = Math.floor((Math.random() * 100000) + 1) * -1; + try { + $angularCacheFactoryProvider.setCacheDefaults({ maxAge: maxAge }); + fail(); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): maxAge: must be greater than zero!'); + for (var i = 0; i < TYPES_EXCEPT_NUMBER.length; i++) { + try { + $angularCacheFactoryProvider.setCacheDefaults({ maxAge: TYPES_EXCEPT_NUMBER[i] }); + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } + } catch (err) { + expect(err.message).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): maxAge: must be a number!'); + continue; + } + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } + } + }); + it('should validate cacheFlushInterval.', function () { + var cacheFlushInterval = Math.floor((Math.random() * 100000) + 1) * -1; + try { + $angularCacheFactoryProvider.setCacheDefaults({ cacheFlushInterval: cacheFlushInterval }); + fail(); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): cacheFlushInterval: must be greater than zero!'); + for (var i = 0; i < TYPES_EXCEPT_NUMBER.length; i++) { + try { + $angularCacheFactoryProvider.setCacheDefaults({ cacheFlushInterval: TYPES_EXCEPT_NUMBER[i] }); + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } + } catch (err) { + expect(err.message).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): cacheFlushInterval: must be a number!'); + continue; + } + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } + } + }); + it('should validate recycleFreq.', function () { + var recycleFreq = Math.floor((Math.random() * 100000) + 1) * -1; + try { + $angularCacheFactoryProvider.setCacheDefaults({ recycleFreq: recycleFreq }); + fail(); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): recycleFreq: must be greater than zero!'); + for (var i = 0; i < TYPES_EXCEPT_NUMBER.length; i++) { + try { + $angularCacheFactoryProvider.setCacheDefaults({ recycleFreq: TYPES_EXCEPT_NUMBER[i] }); + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } + } catch (err) { + expect(err.message).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): recycleFreq: must be a number!'); + continue; + } + if (TYPES_EXCEPT_NUMBER[i] !== null) { + fail(); + } + } + }); + it('should validate onExpire.', function () { + var onExpire = 234; + try { + $angularCacheFactoryProvider.setCacheDefaults({ onExpire: onExpire }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): onExpire: must be a function!'); + for (var i = 0; i < TYPES_EXCEPT_FUNCTION.length; i++) { + try { + $angularCacheFactoryProvider.setCacheDefaults({ onExpire: TYPES_EXCEPT_FUNCTION[i] }); + if (TYPES_EXCEPT_FUNCTION[i] !== null) { + fail(); + } + } catch (err) { + expect(err.message).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): onExpire: must be a function!'); + continue; + } + if (TYPES_EXCEPT_FUNCTION[i] !== null) { + fail(); + } + } + }); + it('should validate deleteOnExpire.', function () { + var deleteOnExpire = 'fail'; + try { + $angularCacheFactoryProvider.setCacheDefaults({ deleteOnExpire: deleteOnExpire }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): deleteOnExpire: accepted values are "none", "passive" or "aggressive"!'); + for (var i = 0; i < TYPES_EXCEPT_STRING.length; i++) { + try { + $angularCacheFactoryProvider.setCacheDefaults({ deleteOnExpire: TYPES_EXCEPT_STRING[i] }); + fail(); + } catch (err) { + expect(err.message).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): deleteOnExpire: must be a string!'); + continue; + } + fail(); + } + }); + it('should validate storageMode.', function () { + var storageMode = 'fail'; + try { + $angularCacheFactoryProvider.setCacheDefaults({ storageMode: storageMode }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): storageMode: accepted values are "none", "localStorage" or "sessionStorage"!'); + for (var i = 0; i < TYPES_EXCEPT_STRING.length; i++) { + try { + $angularCacheFactoryProvider.setCacheDefaults({ storageMode: TYPES_EXCEPT_STRING[i] }); + fail(); + } catch (err) { + expect(err.message).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): storageMode: must be a string!'); + continue; + } + fail(); + } + }); + it('should validate storageImpl.', function () { + var storageImpl = 'fail'; + try { + $angularCacheFactoryProvider.setCacheDefaults({ storageMode: 'localStorage', storageImpl: storageImpl }); + expect('should not reach this!').toEqual(false); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('$angularCacheFactoryProvider.setCacheDefaults(options): [local|session]storageImpl: must be an object!'); + for (var i = 0; i < TYPES_EXCEPT_OBJECT.length; i++) { + try { + $angularCacheFactoryProvider.setCacheDefaults({ storageMode: 'localStorage', storageImpl: TYPES_EXCEPT_OBJECT[i] }); + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } + } catch (err) { + expect(err.message.length).not.toEqual(0); + continue; + } + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } + } + try { + $angularCacheFactoryProvider.setCacheDefaults({ + storageMode: 'localStorage', + storageImpl: { + getItem: function () { + }, + removeItem: function () { + } + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } + try { + $angularCacheFactoryProvider.setCacheDefaults({ + storageMode: 'localStorage', + storageImpl: { + setItem: function () { + }, + removeItem: function () { + } + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } + try { + $angularCacheFactoryProvider.setCacheDefaults({ + storageMode: 'localStorage', + storageImpl: { + getItem: function () { + }, + setItem: function () { + } + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } + try { + $angularCacheFactoryProvider.setCacheDefaults({ + storageMode: 'localStorage', + storageImpl: { + getItem: 'should not be a string', + setItem: function () { + }, + removeItem: function () { + } + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } + try { + $angularCacheFactoryProvider.setCacheDefaults({ + storageMode: 'localStorage', + storageImpl: { + getItem: function () { + }, + setItem: 'should not be a string', + removeItem: function () { + } + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } + try { + $angularCacheFactoryProvider.setCacheDefaults({ + storageMode: 'localStorage', + storageImpl: { + setItem: function () { + }, + getItem: function () { + }, + removeItem: 'should not be a string' + } + }); + fail(); + } catch (err) { + expect(err.message.length).not.toEqual(0); + } + }); + it('should require options to be an object.', function () { + for (var i = 0; i < TYPES_EXCEPT_OBJECT.length; i++) { + try { + $angularCacheFactoryProvider.setCacheDefaults(TYPES_EXCEPT_OBJECT[i]); + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } + } catch (err) { + expect(err.message.length).not.toEqual(0); + continue; + } + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } + } + }); +}); \ No newline at end of file diff --git a/test/karma.start.js b/test/karma.start.js index 8720876..d1e1576 100644 --- a/test/karma.start.js +++ b/test/karma.start.js @@ -18,8 +18,10 @@ var fail = function (msg) { verifyIntegrity: true }; -var $angularCacheFactory, BinaryHeap; -beforeEach(module('jmdobry.angular-cache')); +var $angularCacheFactoryProvider, $angularCacheFactory, BinaryHeap; +beforeEach(module('jmdobry.angular-cache', function (_$angularCacheFactoryProvider_) { + $angularCacheFactoryProvider = _$angularCacheFactoryProvider_; +})); beforeEach(inject(function (_$angularCacheFactory_, _BinaryHeap_) { $angularCacheFactory = _$angularCacheFactory_; BinaryHeap = _BinaryHeap_; From f4f327d97f9fbd9c8dea1d49de3c37b1ba439a79 Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Sat, 5 Oct 2013 21:45:33 -0600 Subject: [PATCH 8/8] Finished re-write of unit tests. #51, #57, #58 --- src/angular-cache.js | 70 ++--- test/angularCache.destroy-test.js | 3 +- test/angularCache.get-test.js | 181 +++++++----- test/angularCache.info-test.js | 167 +++++------ test/angularCache.put-test.js | 409 ++++++++++++++------------ test/angularCache.remove-test.js | 124 ++++---- test/angularCache.removeAll-test.js | 102 +++---- test/angularCache.setOptions-test.js | 422 +++++++++++++++------------ test/angularCacheFactory-test.js | 14 +- 9 files changed, 815 insertions(+), 677 deletions(-) diff --git a/src/angular-cache.js b/src/angular-cache.js index 7324e80..a2660bb 100644 --- a/src/angular-cache.js +++ b/src/angular-cache.js @@ -95,7 +95,7 @@ * @param {Function} weightFunc Function that determines how each node should be weighted. */ function BinaryHeap(weightFunc) { - if (weightFunc && !angular.isFunction(weightFunc)) { + if (weightFunc && !angular.isFunction(weightFunc)) { throw new Error('BinaryHeap(weightFunc): weightFunc: must be a function!'); } weightFunc = weightFunc || function (x) { @@ -388,29 +388,6 @@ options = options || {}; - /** - * @method _setTimeoutToRemove - * @desc Removes the item with the given key from this cache after the number of - * milliseconds specified by delay. - * @param {String} key The key of the item to be removed at the end of the timeout. - * @param {Number} delay The delay in milliseconds. - * @private - * @ignore - */ - function _setTimeoutToRemove(key, delay) { - data[key].timeoutId = $timeout(function () { - var value; - if (data[key]) { - value = data[key].value; - } - expiresHeap.remove(data[key]); - self.remove(key); - if (config.onExpire) { - config.onExpire(key, value); - } - }, delay); - } - /** * @method _setCapacity * @desc Set the capacity for this cache. @@ -463,6 +440,7 @@ var key = keys[i]; if (!('maxAge' in data[key])) { delete data[key].expires; + expiresHeap.remove(data[key]); } } } @@ -478,7 +456,9 @@ for (var i = 0; i < keys.length; i++) { var key = keys[i]; if (!('maxAge' in data[key])) { + expiresHeap.remove(data[key]); data[key].expires = data[key].created + config.maxAge; + expiresHeap.push(data[key]); if (data[key].expires < now) { self.remove(key, { verifyIntegrity: false }); } @@ -504,6 +484,7 @@ delete config.recycleFreqId; } config.recycleFreq = cacheDefaults.recycleFreq; + config.recycleFreqId = setInterval(self.removeExpired, config.recycleFreq); } else { _validateNumberOption(recycleFreq, function (err) { if (err) { @@ -678,12 +659,18 @@ var data = angular.fromJson(storage.getItem(prefix + '.data.' + keys[i])), maxAge = data.maxAge || config.maxAge, deleteOnExpire = data.deleteOnExpire || config.deleteOnExpire; - if (maxAge && ((new Date().getTime() - data.timestamp) > maxAge) && deleteOnExpire === 'aggressive') { + if (maxAge && ((new Date().getTime() - data.created) > maxAge) && deleteOnExpire === 'aggressive') { storage.removeItem(prefix + '.data.' + keys[i]); } else { var options = { - timestamp: data.timestamp + created: data.created }; + if (data.expires) { + options.expires = data.expires; + } + if (data.accessed) { + options.accessed = data.accessed; + } if (data.maxAge) { options.maxAge = data.maxAge; } @@ -761,6 +748,8 @@ options = options || {}; if (!angular.isString(key)) { throw new Error('AngularCache.put(key, value, options): key: must be a string!'); + } else if (options && !angular.isObject(options)) { + throw new Error('AngularCache.put(key, value, options): options: must be an object!'); } else if (options.maxAge && options.maxAge !== null) { _validateNumberOption(options.maxAge, function (err) { if (err) { @@ -769,6 +758,8 @@ }); } else if (options.deleteOnExpire && !angular.isString(options.deleteOnExpire)) { throw new Error('AngularCache.put(key, value, options): deleteOnExpire: must be a string!'); + } else if (options.deleteOnExpire && options.deleteOnExpire !== 'none' && deleteOnExpire !== 'passive' && deleteOnExpire !== 'aggressive') { + throw new Error('AngularCache.put(key, value, options): deleteOnExpire: accepted values are "none", "passive" or "aggressive"!'); } else if (angular.isUndefined(value)) { return; } @@ -831,9 +822,11 @@ this.get = function (key, options) { options = options || {}; if (!angular.isString(key)) { - throw new Error('AngularCache.get(key, onExpire): key: must be a string!'); - } else if (options.onExpire && typeof options.onExpire !== 'function') { - throw new Error('AngularCache.get(key, onExpire): onExpire: must be a function!'); + throw new Error('AngularCache.get(key, options): key: must be a string!'); + } else if (options && !angular.isObject(options)) { + throw new Error('AngularCache.get(key, options): options: must be an object!'); + } else if (options.onExpire && !angular.isFunction(options.onExpire)) { + throw new Error('AngularCache.get(key, options): onExpire: must be a function!'); } else if (!(key in data)) { return; } @@ -905,10 +898,17 @@ this.removeExpired = function (options) { options = options || {}; _verifyIntegrity(options.verifyIntegrity); - var now = new Date().getTime(); - while (expiresHeap.peek().expires < now) { - this.remove(expiresHeap.peek().key, { verifyIntegrity: false }); + var now = new Date().getTime(), + item = expiresHeap.peek(); + + while (item && item.expires && item.expires < now) { + self.remove(item.key, { verifyIntegrity: false }); + if (config.onExpire) { + config.onExpire(item.key, item.value); + } + item = expiresHeap.peek(); } + }; /** @@ -930,6 +930,8 @@ } storage = null; data = null; + lruHeap = null; + expiresHeap = null; config = null; prefix = null; self = null; @@ -957,14 +959,14 @@ isExpired: false }; if (info.maxAge) { - info.isExpired = (new Date().getTime() - info.timestamp) > info.maxAge; + info.isExpired = (new Date().getTime() - info.created) > info.maxAge; } return info; } else { return data[key]; } } else { - return angular.extend({}, config, { size: lruHeap.size() }); + return angular.extend({}, config, { size: lruHeap && lruHeap.size() || 0 }); } }; diff --git a/test/angularCache.destroy-test.js b/test/angularCache.destroy-test.js index b1c54ad..7856a36 100644 --- a/test/angularCache.destroy-test.js +++ b/test/angularCache.destroy-test.js @@ -2,9 +2,10 @@ describe('AngularCache.destroy()', function () { it('should destroy the cache and remove all traces of its existence.', function () { var cache = $angularCacheFactory('cache'); cache.destroy(); + expect(cache.info()).toEqual({ size: 0 }); expect($angularCacheFactory.get('cache')).toEqual(undefined); }); - it('should remove items from localStorage when storageMode is used', function () { + it('should remove items from localStorage when storageMode is used.', function () { var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); diff --git a/test/angularCache.get-test.js b/test/angularCache.get-test.js index 332d7cb..0980611 100644 --- a/test/angularCache.get-test.js +++ b/test/angularCache.get-test.js @@ -1,65 +1,116 @@ -//describe('AngularCache.get(key)', function () { -// it('should return the correct value for the specified key', function () { -// var cache = $angularCacheFactory('cache'); -// var value1 = 'value1', -// value2 = 2, -// value3 = { -// value3: 'stuff' -// }; -// cache.put('item1', value1); -// cache.put('item2', value2); -// cache.put('item3', value3); -// expect(cache.get('item1')).toEqual(value1); -// expect(cache.get('item2')).toEqual(value2); -// expect(cache.get('item3')).toEqual(value3); -// }); -// it('should return undefined if the key isn\'t in the cache', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.get('item')).toEqual(undefined); -// }); -// it('should execute globally configured \'onExpire\' callback if the item is expired in passive mode and global \'onExpire\' callback is configured', function () { -// var cache = $angularCacheFactory('cache', { -// maxAge: 10, -// onExpire: function (key, value, done) { -// done(key, value, 'executed global callback'); -// } -// }); -// cache.put('item', 'value'); -// waits(100); -// runs(function () { -// cache.get('item', function (key, value, test) { -// expect(key).toEqual('item'); -// expect(value).toEqual('value'); -// expect(test).toEqual('executed global callback'); -// }); -// }); -// }); -// it('should execute globally configured \'onExpire\' callback when an item is aggressively deleted and global \'onExpire\' callback is configured', function () { -// var onExpire = jasmine.createSpy(); -// var cache = $angularCacheFactory('cache', { -// maxAge: 10, -// deleteOnExpire: 'aggressive', -// onExpire: onExpire -// }); -// cache.put('item', 'value'); -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(onExpire).toHaveBeenCalled(); -// expect(onExpire).toHaveBeenCalledWith('item', 'value'); -// }); -// }); -// it('should execute local \'onExpire\' callback if the item is expired in passive mode and global \'onExpire\' callback is NOT configured', function () { -// var cache = $angularCacheFactory('cache', { -// maxAge: 10 -// }); -// cache.put('item', 'value'); -// waits(100); -// runs(function () { -// cache.get('item', function (key, value) { -// expect(key).toEqual('item'); -// expect(value).toEqual('value'); -// }); -// }); -// }); -//}); \ No newline at end of file +describe('AngularCache.get(key)', function () { + it('should throw an error if "key" is not a string.', function () { + var cache = $angularCacheFactory('cache'); + for (var i = 0; i < TYPES_EXCEPT_STRING.length; i++) { + try { + cache.get(TYPES_EXCEPT_STRING[i]); + fail(TYPES_EXCEPT_STRING[i]); + } catch (err) { + expect(err.message).toEqual('AngularCache.get(key, options): key: must be a string!'); + continue; + } + fail(TYPES_EXCEPT_STRING[i]); + } + }); + it('should throw an error if "options" is not an object.', function () { + var cache = $angularCacheFactory('cache'); + for (var i = 0; i < TYPES_EXCEPT_OBJECT.length; i++) { + try { + cache.get('item', TYPES_EXCEPT_OBJECT[i]); + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } + } catch (err) { + expect(err.message).toEqual('AngularCache.get(key, options): options: must be an object!'); + continue; + } + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } + } + }); + it('should throw an error if "onExpire" is not a function.', function () { + var cache = $angularCacheFactory('cache'); + for (var i = 0; i < TYPES_EXCEPT_FUNCTION.length; i++) { + try { + cache.get('item', { onExpire: TYPES_EXCEPT_FUNCTION[i] }); + if (TYPES_EXCEPT_FUNCTION[i] !== null && TYPES_EXCEPT_FUNCTION[i] !== undefined && TYPES_EXCEPT_FUNCTION[i] !== false) { + fail(TYPES_EXCEPT_FUNCTION[i]); + } + } catch (err) { + expect(err.message).toEqual('AngularCache.get(key, options): onExpire: must be a function!'); + continue; + } + if (TYPES_EXCEPT_FUNCTION[i] !== null && TYPES_EXCEPT_FUNCTION[i] !== undefined && TYPES_EXCEPT_FUNCTION[i] !== false) { + fail(TYPES_EXCEPT_FUNCTION[i]); + } + } + }); + it('should return the correct value for the specified key.', function () { + var cache = $angularCacheFactory('cache'); + var value1 = 'value1', + value2 = 2, + value3 = { + value3: 'stuff' + }; + cache.put('item1', value1); + cache.put('item2', value2); + cache.put('item3', value3); + expect(cache.get('item1')).toEqual(value1); + expect(cache.get('item2')).toEqual(value2); + expect(cache.get('item3')).toEqual(value3); + }); + it('should return undefined if the key isn\'t in the cache.', function () { + var cache = $angularCacheFactory('cache'); + expect(cache.get('item')).toEqual(undefined); + }); + it('should execute globally configured "onExpire" callback if the item is expired in passive mode and global "onExpire" callback is configured.', function () { + var cache = $angularCacheFactory('cache', { + maxAge: 10, + recycleFreq: 20, + deleteOnExpire: 'passive', + onExpire: function (key, value, done) { + done(key, value, 'executed global callback'); + } + }); + cache.put('item', 'value'); + waits(100); + runs(function () { + cache.get('item', { onExpire: function (key, value, test) { + expect(key).toEqual('item'); + expect(value).toEqual('value'); + expect(test).toEqual('executed global callback'); + }}); + }); + }); + it('should execute globally configured "onExpire" callback when an item is aggressively deleted and global "onExpire" callback is configured.', function () { + var onExpire = jasmine.createSpy(); + var cache = $angularCacheFactory('cache', { + maxAge: 10, + recycleFreq: 20, + deleteOnExpire: 'aggressive', + onExpire: onExpire + }); + cache.put('item', 'value'); + waits(100); + runs(function () { + expect(onExpire).toHaveBeenCalled(); + expect(onExpire).toHaveBeenCalledWith('item', 'value'); + }); + }); + it('should execute local "onExpire" callback if the item is expired in passive mode and global "onExpire" callback is NOT configured.', function () { + var cache = $angularCacheFactory('cache', { + maxAge: 10, + deleteOnExpire: 'passive', + recycleFreq: 20 + }); + cache.put('item', 'value'); + waits(100); + runs(function () { + cache.get('item', { onExpire: function (key, value) { + expect(key).toEqual('item'); + expect(value).toEqual('value'); + }}); + }); + }); +}); \ No newline at end of file diff --git a/test/angularCache.info-test.js b/test/angularCache.info-test.js index 3a2a688..bb4a38f 100644 --- a/test/angularCache.info-test.js +++ b/test/angularCache.info-test.js @@ -1,86 +1,81 @@ -//describe('AngularCache.info()', function () { -// it('should return the correct values', function () { -// var onExpire = function () { -// }; -// var cache = $angularCacheFactory('cache'), -// cache2 = $angularCacheFactory('cache2', { maxAge: 1000 }), -// cache3 = $angularCacheFactory('cache3', { cacheFlushInterval: 1000 }), -// cache4 = $angularCacheFactory('cache4', { capacity: 1000 }), -// cache5 = $angularCacheFactory('cache5', { storageMode: 'localStorage' }), -// cache6 = $angularCacheFactory('cache6', { storageMode: 'sessionStorage' }); -// cache7 = $angularCacheFactory('cache7', { maxAge: 100, onExpire: onExpire }); -// expect(cache.info()).toEqual({ -// id: 'cache', -// capacity: Number.MAX_VALUE, -// size: 0, -// maxAge: null, -// cacheFlushInterval: null, -// deleteOnExpire: 'none', -// storageMode: 'none', -// onExpire: null -// }); -// cache.put('item', 'value'); -// cache.put('item2', 'value2', { maxAge: 200, deleteOnExpire: 'aggressive' }); -// -// // AngularCache#info(key) -// expect(typeof cache.info('item').timestamp).toEqual('number'); -// expect(cache.info('item').maxAge).toEqual(null); -// expect(cache.info('item').deleteOnExpire).toEqual('none'); -// expect(typeof cache.info('item2').timestamp).toEqual('number'); -// expect(cache.info('item2').maxAge).toEqual(200); -// expect(cache.info('item2').deleteOnExpire).toEqual('aggressive'); -// -// expect(cache.info()).toEqual({ -// id: 'cache', -// capacity: Number.MAX_VALUE, -// size: 2, -// maxAge: null, -// cacheFlushInterval: null, -// deleteOnExpire: 'none', -// storageMode: 'none', -// onExpire: null -// }); -// expect(cache2.info()).toEqual({ -// id: 'cache2', -// capacity: Number.MAX_VALUE, -// maxAge: 1000, -// size: 0, -// cacheFlushInterval: null, -// deleteOnExpire: 'none', -// storageMode: 'none', -// onExpire: null -// }); -// expect(cache3.info().id).toEqual('cache3'); -// expect(cache3.info().capacity).toEqual(Number.MAX_VALUE); -// expect(cache3.info().cacheFlushInterval).toEqual(1000); -// expect(cache3.info().size).toEqual(0); -// expect(cache4.info()).toEqual({ -// id: 'cache4', -// capacity: 1000, -// size: 0, -// maxAge: null, -// cacheFlushInterval: null, -// deleteOnExpire: 'none', -// storageMode: 'none', -// onExpire: null -// }); -// if (localStorage) { -// expect(cache5.info().storageMode).toEqual('localStorage'); -// } else { -// expect(cache5.info().storageMode).toEqual(null); -// } -// if (sessionStorage) { -// expect(cache6.info().storageMode).toEqual('sessionStorage'); -// } else { -// expect(cache6.info().storageMode).toEqual(null); -// } -// expect(cache7.info().onExpire).toEqual(onExpire); -// cache.destroy(); -// cache2.destroy(); -// cache3.destroy(); -// cache4.destroy(); -// cache5.destroy(); -// cache6.destroy(); -// cache7.destroy(); -// }); -//}); \ No newline at end of file +describe('AngularCache.info()', function () { + it('should return the correct values.', function () { + var onExpire = function () { + }; + var cache = $angularCacheFactory('cache'), + cache2 = $angularCacheFactory('cache2', { maxAge: 1000 }), + cache3 = $angularCacheFactory('cache3', { cacheFlushInterval: 1000 }), + cache4 = $angularCacheFactory('cache4', { capacity: 1000 }), + cache5 = $angularCacheFactory('cache5', { storageMode: 'localStorage' }), + cache6 = $angularCacheFactory('cache6', { storageMode: 'sessionStorage' }); + cache7 = $angularCacheFactory('cache7', { maxAge: 100, onExpire: onExpire }); + var cacheInfo = cache.info(); + expect(cacheInfo.id).toEqual('cache'); + expect(cacheInfo.capacity).toEqual(Number.MAX_VALUE); + expect(cacheInfo.size).toEqual(0); + expect(cacheInfo.recycleFreq).toEqual(1000); + expect(cacheInfo.maxAge).toEqual(null); + expect(cacheInfo.cacheFlushInterval).toEqual(null); + expect(typeof cacheInfo.recycleFreqId).toEqual('number'); + expect(cacheInfo.deleteOnExpire).toEqual('none'); + expect(cacheInfo.storageMode).toEqual('none'); + expect(cacheInfo.onExpire).toEqual(null); + cache.put('item', 'value'); + cache.put('item2', 'value2', { maxAge: 200, deleteOnExpire: 'aggressive' }); + + // AngularCache#info(key) + expect(cache.info('non-existent item')).not.toBeDefined(); + expect(typeof cache.info('item').created).toEqual('number'); + expect(typeof cache.info('item').expires).toEqual('undefined'); + expect(typeof cache.info('item').accessed).toEqual('number'); + expect(cache.info('item').maxAge).toEqual(null); + expect(cache.info('item').deleteOnExpire).toEqual('none'); + expect(typeof cache.info('item2').created).toEqual('number'); + expect(typeof cache.info('item2').expires).toEqual('number'); + expect(typeof cache.info('item2').accessed).toEqual('number'); + expect(cache.info('item2').maxAge).toEqual(200); + expect(cache.info('item2').deleteOnExpire).toEqual('aggressive'); + + expect(cache.info().size).toEqual(2); + + var cacheInfo2 = cache2.info(); + expect(cacheInfo2.id).toEqual('cache2'); + expect(cacheInfo2.capacity).toEqual(Number.MAX_VALUE); + expect(cacheInfo2.size).toEqual(0); + expect(cacheInfo2.recycleFreq).toEqual(1000); + expect(cacheInfo2.maxAge).toEqual(1000); + expect(cacheInfo2.cacheFlushInterval).toEqual(null); + expect(typeof cacheInfo2.recycleFreqId).toEqual('number'); + expect(cacheInfo2.deleteOnExpire).toEqual('none'); + expect(cacheInfo2.storageMode).toEqual('none'); + expect(cacheInfo2.onExpire).toEqual(null); + + expect(cache3.info().id).toEqual('cache3'); + expect(cache3.info().capacity).toEqual(Number.MAX_VALUE); + expect(cache3.info().cacheFlushInterval).toEqual(1000); + expect(cache3.info().size).toEqual(0); + + var cacheInfo4 = cache4.info(); + expect(cacheInfo4.id).toEqual('cache4'); + expect(cacheInfo4.capacity).toEqual(1000); + expect(cacheInfo4.size).toEqual(0); + expect(cacheInfo4.recycleFreq).toEqual(1000); + expect(cacheInfo4.maxAge).toEqual(null); + expect(cacheInfo4.cacheFlushInterval).toEqual(null); + expect(typeof cacheInfo4.recycleFreqId).toEqual('number'); + expect(cacheInfo4.deleteOnExpire).toEqual('none'); + expect(cacheInfo4.storageMode).toEqual('none'); + expect(cacheInfo4.onExpire).toEqual(null); + if (localStorage) { + expect(cache5.info().storageMode).toEqual('localStorage'); + } else { + expect(cache5.info().storageMode).toEqual(null); + } + if (sessionStorage) { + expect(cache6.info().storageMode).toEqual('sessionStorage'); + } else { + expect(cache6.info().storageMode).toEqual(null); + } + expect(cache7.info().onExpire).toEqual(onExpire); + }); +}); \ No newline at end of file diff --git a/test/angularCache.put-test.js b/test/angularCache.put-test.js index be72069..ae76cd0 100644 --- a/test/angularCache.put-test.js +++ b/test/angularCache.put-test.js @@ -1,188 +1,221 @@ -//describe('AngularCache.put(key, value, options)', function () { -// it('should disallow keys that aren\'t a string', function () { -// var cache = $angularCacheFactory('cache'); -// var mustBeAStringMsg = 'AngularCache.put(): key: must be a string!'; -// try { -// cache.put(2, 'value'); -// } catch (err) { -// var errorMsg = err.message; -// } -// expect(errorMsg).toEqual(mustBeAStringMsg); -// try { -// cache.put(true, 'value'); -// } catch (err) { -// errorMsg = err.message; -// } -// expect(errorMsg).toEqual(mustBeAStringMsg); -// try { -// cache.put({ obj: 'obj' }, 'value'); -// } catch (err) { -// errorMsg = err.message; -// } -// expect(errorMsg).toEqual(mustBeAStringMsg); -// }); -// it('should not add values that aren\'t defined', function () { -// var cache = $angularCacheFactory('cache'); -// cache.put('item', null); -// expect(cache.get('item')).toEqual(undefined); -// cache.put('item', undefined); -// expect(cache.get('item')).toEqual(undefined); -// }); -// it('should validate maxAge', function () { -// var cache = $angularCacheFactory('cache'); -// try { -// cache.put('item', 'value', { maxAge: 'als;dlfkajsd'}); -// } catch (err) { -// var errorMsg = err.message; -// } -// expect(errorMsg).toEqual('AngularCache.put(): maxAge: must be a number!'); -// try { -// cache.put('item', 'value', { maxAge: Math.floor((Math.random() * 100000) + 1) * -1 }); -// } catch (err) { -// errorMsg = err.message; -// } -// expect(errorMsg).toEqual('AngularCache.put(): maxAge: must be greater than zero!'); -// errorMsg = null; -// try { -// cache.put('item', 'value', { maxAge: Math.floor((Math.random() * 100000) + 1) }); -// } catch (err) { -// errorMsg = 'should not reach this!'; -// } -// expect(errorMsg).toEqual(null); -// }); -// it('should increase the size of the cache by one', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.info().size).toEqual(0); -// cache.put('item', 'value1'); -// expect(cache.info().size).toEqual(1); -// cache.put('item2', 'value2'); -// expect(cache.info().size).toEqual(2); -// }); -// it('should overwrite an item if it is re-added to the cache', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.info().size).toEqual(0); -// cache.put('item', 'value1'); -// expect(cache.info().size).toEqual(1); -// cache.put('item', 'value2'); -// expect(cache.info().size).toEqual(1); -// expect(cache.get('item')).toEqual('value2'); -// }); -// it('should remove the least recently used item if the capacity has been reached', function () { -// var cache = $angularCacheFactory('cache', { capacity: 2 }); -// expect(cache.info().size).toEqual(0); -// cache.put('item1', 'value1'); -// expect(cache.info().size).toEqual(1); -// cache.put('item2', 'value2'); -// expect(cache.info().size).toEqual(2); -// cache.put('item3', 'value3'); -// expect(cache.info().size).toEqual(2); -// expect(cache.get('item1')).toEqual(undefined); -// expect(cache.get('item2')).toEqual('value2'); -// expect(cache.get('item3')).toEqual('value3'); -// cache.get('item2'); -// cache.put('item1', 'value1'); -// expect(cache.get('item3')).toEqual(undefined); -// expect(cache.get('item1')).toEqual('value1'); -// expect(cache.get('item2')).toEqual('value2'); -// }); -// it('should not delete items if maxAge is specified and deleteOnExpire is set to "none"', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'none' }); -// cache.put('item1', 'value1'); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// expect(cache.get('item1')).toEqual('value1'); -// expect(cache.info('item1').isExpired).toEqual(true); -// }); -// }); -// it('should set a timeout for an item to expire if maxAge is specified and deleteOnExpire is set to "aggressive"', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive' }); -// cache.put('item1', 'value1'); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(cache.info('item1')).toEqual(undefined); -// expect(cache.get('item1')).toEqual(undefined); -// }); -// }); -// it('should should lazy delete an item when maxAge is specified and deleteOnExpire is set to "passive"', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'passive' }); -// cache.put('item1', 'value1'); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// expect(cache.info('item1').isExpired).toEqual(true); -// expect(cache.get('item1')).toEqual(undefined); -// }); -// }); -// it('should not delete items if maxAge is specified and deleteOnExpire is set to "none" for an item', function () { -// var cache = $angularCacheFactory('cache'); -// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'none' }); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// expect(cache.get('item1')).toEqual('value1'); -// expect(cache.info('item1').isExpired).toEqual(true); -// }); -// }); -// it('should set a timeout for an item to expire if maxAge for item is specified and deleteOnExpire is set to "aggressive"', function () { -// var cache = $angularCacheFactory('cache'); -// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'aggressive' }); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(cache.info('item1')).toEqual(undefined); -// expect(cache.get('item1')).toEqual(undefined); -// }); -// }); -// it('should passively expire an item if maxAge for the item is specified and deleteOnExpire is set to "passive"', function () { -// var cache = $angularCacheFactory('cache'); -// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// expect(cache.info('item1').isExpired).toEqual(true); -// expect(cache.get('item1')).toEqual(undefined); -// }); -// }); -// it('maxAge for a specific item should override maxAge for the cache', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 1000, deleteOnExpire: 'aggressive' }); -// cache.put('item1', 'value1', { maxAge: 5 }); -// expect(cache.info('item1').maxAge).toEqual(5); -// expect(cache.get('item1')).toEqual('value1'); -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(cache.get('item1')).toEqual(undefined); -// }); -// }); -// it('deleteOnExpire set to "passive" for a specific item should override deleteOnExpire set to "aggressive" for the cache', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive' }); -// cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); -// expect(cache.get('item1')).toEqual('value1'); -// expect(cache.info('item1').deleteOnExpire).toEqual("passive"); -// waits(100); -// runs(function () { -// expect(cache.info('item1').isExpired).toEqual(true); -// expect(cache.get('item1')).toEqual(undefined); -// }); -// }); -// it('should save data to localStorage when storageMode is used', function () { -// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), -// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); -// -// localStorageCache.put('item1', 'value1'); -// sessionStorageCache.put('item1', 'value1'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); -// } -// }); -//}); \ No newline at end of file +describe('AngularCache.put(key, value, options)', function () { + it('should throw an error if "key" is not a string.', function () { + var cache = $angularCacheFactory('cache'); + for (var i = 0; i < TYPES_EXCEPT_STRING.length; i++) { + try { + cache.put(TYPES_EXCEPT_STRING[i], 'value'); + fail(TYPES_EXCEPT_STRING[i]); + } catch (err) { + expect(err.message).toEqual('AngularCache.put(key, value, options): key: must be a string!'); + continue; + } + fail(TYPES_EXCEPT_STRING[i]); + } + }); + it('should throw an error if "options" is not an object.', function () { + var cache = $angularCacheFactory('cache'); + for (var i = 0; i < TYPES_EXCEPT_OBJECT.length; i++) { + try { + cache.put('item', 'value', TYPES_EXCEPT_OBJECT[i]); + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } + } catch (err) { + expect(err.message).toEqual('AngularCache.put(key, value, options): options: must be an object!'); + continue; + } + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } + } + }); + it('should throw an error if "maxAge" is not valid.', function () { + var cache = $angularCacheFactory('cache'); + var maxAge = Math.floor((Math.random() * 100000) + 1) * -1; + try { + cache.put('item', 'value', { maxAge: maxAge }); + fail(); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('AngularCache.put(key, value, options): maxAge: must be greater than zero!'); + for (var i = 0; i < TYPES_EXCEPT_NUMBER.length; i++) { + try { + cache.put('item', 'value', { maxAge: TYPES_EXCEPT_NUMBER[i] }); + if (TYPES_EXCEPT_NUMBER[i] !== null && TYPES_EXCEPT_NUMBER[i] !== undefined && TYPES_EXCEPT_NUMBER[i] !== false) { + fail(TYPES_EXCEPT_NUMBER[i]); + } + } catch (err) { + expect(err.message).toEqual('AngularCache.put(key, value, options): maxAge: must be a number!'); + continue; + } + if (TYPES_EXCEPT_NUMBER[i] !== null && TYPES_EXCEPT_NUMBER[i] !== undefined && TYPES_EXCEPT_NUMBER[i] !== false) { + fail(TYPES_EXCEPT_NUMBER[i]); + } + } + }); + it('should throw an error if "deleteOnExpire" is not valid.', function () { + var cache = $angularCacheFactory('cache'); + var deleteOnExpire = 'fail'; + try { + cache.put('item', 'value', { deleteOnExpire: deleteOnExpire }); + fail('should not reach this!'); + } catch (err) { + var msg = err.message; + } + expect(msg).toEqual('AngularCache.put(key, value, options): deleteOnExpire: accepted values are "none", "passive" or "aggressive"!'); + for (var i = 0; i < TYPES_EXCEPT_STRING.length; i++) { + try { + cache.put('item', 'value', { deleteOnExpire: TYPES_EXCEPT_STRING[i] }); + if (TYPES_EXCEPT_STRING[i] !== null && TYPES_EXCEPT_STRING[i] !== undefined && TYPES_EXCEPT_STRING[i] !== false) { + fail(TYPES_EXCEPT_STRING[i]); + } + } catch (err) { + expect(err.message).toEqual('AngularCache.put(key, value, options): deleteOnExpire: must be a string!'); + continue; + } + if (TYPES_EXCEPT_STRING[i] !== null && TYPES_EXCEPT_STRING[i] !== undefined && TYPES_EXCEPT_STRING[i] !== false) { + fail(TYPES_EXCEPT_STRING[i]); + } + } + }); + it('should not add values that are not defined.', function () { + var cache = $angularCacheFactory('cache'); + cache.put('item', null); + expect(cache.get('item')).toEqual(undefined); + cache.put('item', undefined); + expect(cache.get('item')).toEqual(undefined); + }); + it('should increase the size of the cache by one.', function () { + var cache = $angularCacheFactory('cache'); + expect(cache.info().size).toEqual(0); + cache.put('item', 'value1'); + expect(cache.info().size).toEqual(1); + cache.put('item2', 'value2'); + expect(cache.info().size).toEqual(2); + }); + it('should overwrite an item if it is re-added to the cache.', function () { + var cache = $angularCacheFactory('cache'); + expect(cache.info().size).toEqual(0); + cache.put('item', 'value1'); + expect(cache.info().size).toEqual(1); + cache.put('item', 'value2'); + expect(cache.info().size).toEqual(1); + expect(cache.get('item')).toEqual('value2'); + }); + it('should remove the least recently used item if the capacity has been reached.', function () { + var cache = $angularCacheFactory('cache', { capacity: 2 }); + expect(cache.info().size).toEqual(0); + cache.put('item1', 'value1'); + expect(cache.info().size).toEqual(1); + cache.put('item2', 'value2'); + expect(cache.info().size).toEqual(2); + cache.put('item3', 'value3'); + expect(cache.info().size).toEqual(2); + expect(cache.get('item1')).toEqual(undefined); + expect(cache.get('item2')).toEqual('value2'); + expect(cache.get('item3')).toEqual('value3'); + cache.get('item2'); + cache.put('item1', 'value1'); + expect(cache.get('item3')).toEqual(undefined); + expect(cache.get('item1')).toEqual('value1'); + expect(cache.get('item2')).toEqual('value2'); + }); + it('should not delete items if maxAge is specified and deleteOnExpire is set to "none".', function () { + var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'none', recycleFreq: 20 }); + cache.put('item1', 'value1'); + expect(cache.get('item1')).toEqual('value1'); + waits(100); + runs(function () { + expect(cache.get('item1')).toEqual('value1'); + expect(cache.info('item1').isExpired).toEqual(true); + }); + }); + it('should remove items if maxAge is specified and deleteOnExpire is set to "aggressive".', function () { + var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive', recycleFreq: 20 }); + cache.put('item1', 'value1'); + expect(cache.get('item1')).toEqual('value1'); + waits(100); + runs(function () { + expect(cache.info('item1')).not.toBeDefined(); + expect(cache.get('item1')).not.toBeDefined(); + }); + }); + it('should should lazy delete an item when maxAge is specified and deleteOnExpire is set to "passive".', function () { + var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'passive' }); + cache.put('item1', 'value1'); + expect(cache.get('item1')).toEqual('value1'); + waits(100); + runs(function () { + expect(cache.info('item1').isExpired).toEqual(true); + expect(cache.get('item1')).not.toBeDefined(); + }); + }); + it('should not delete items if maxAge is specified and deleteOnExpire is set to "none" for an item.', function () { + var cache = $angularCacheFactory('cache'); + cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'none' }); + expect(cache.get('item1')).toEqual('value1'); + waits(100); + runs(function () { + expect(cache.get('item1')).toEqual('value1'); + expect(cache.info('item1').isExpired).toEqual(true); + }); + }); + it('should remove an item if maxAge for item is specified and deleteOnExpire is set to "aggressive".', function () { + var cache = $angularCacheFactory('cache', { recycleFreq: 10 }); + cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'aggressive' }); + expect(cache.get('item1')).toEqual('value1'); + waits(100); + runs(function () { + expect(cache.info('item1')).not.toBeDefined(); + expect(cache.get('item1')).not.toBeDefined(); + }); + }); + it('should passively expire an item if maxAge for the item is specified and deleteOnExpire is set to "passive".', function () { + var cache = $angularCacheFactory('cache'); + cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); + expect(cache.get('item1')).toEqual('value1'); + waits(100); + runs(function () { + expect(cache.info('item1').isExpired).toEqual(true); + expect(cache.get('item1')).toEqual(undefined); + }); + }); + it('maxAge for a specific item should override maxAge for the cache.', function () { + var cache = $angularCacheFactory('cache', { maxAge: 1000, deleteOnExpire: 'aggressive', recycleFreq: 20 }); + cache.put('item1', 'value1', { maxAge: 5 }); + expect(cache.info('item1').maxAge).toEqual(5); + expect(cache.get('item1')).toEqual('value1'); + waits(100); + runs(function () { + expect(cache.get('item1')).toEqual(undefined); + }); + }); + it('deleteOnExpire set to "passive" for a specific item should override deleteOnExpire set to "aggressive" for the cache.', function () { + var cache = $angularCacheFactory('cache', { maxAge: 10, deleteOnExpire: 'aggressive' }); + cache.put('item1', 'value1', { maxAge: 10, deleteOnExpire: 'passive' }); + expect(cache.get('item1')).toEqual('value1'); + expect(cache.info('item1').deleteOnExpire).toEqual("passive"); + waits(100); + runs(function () { + expect(cache.info('item1').isExpired).toEqual(true); + expect(cache.get('item1')).toEqual(undefined); + }); + }); + it('should save data to localStorage when storageMode is used.', function () { + var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), + sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); + + localStorageCache.put('item1', 'value1'); + sessionStorageCache.put('item1', 'value1'); + + if (localStorage) { + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); + expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); + } + if (sessionStorage) { + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); + expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); + } + }); +}); \ No newline at end of file diff --git a/test/angularCache.remove-test.js b/test/angularCache.remove-test.js index 1081430..f8470ab 100644 --- a/test/angularCache.remove-test.js +++ b/test/angularCache.remove-test.js @@ -1,62 +1,62 @@ -//describe('AngularCache.remove(key)', function () { -// it('should remove the item with the specified key', function () { -// var cache = $angularCacheFactory('cache'); -// var value1 = 'value1', -// value2 = 2, -// value3 = { -// value3: 'stuff' -// }; -// cache.put('item1', value1); -// cache.put('item2', value2); -// cache.put('item3', value3); -// cache.remove('item1'); -// expect(cache.get('item1')).toEqual(undefined); -// cache.remove('item2'); -// expect(cache.get('item2')).toEqual(undefined); -// cache.remove('item3'); -// expect(cache.get('item3')).toEqual(undefined); -// }); -// it('should reduce the size of the cache by one if the size is greater than zero', function () { -// var cache = $angularCacheFactory('cache'); -// cache.put('item1', 'value1'); -// expect(cache.info().size).toEqual(1); -// cache.put('item2', 'value2'); -// expect(cache.info().size).toEqual(2); -// cache.remove('item1'); -// expect(cache.info().size).toEqual(1); -// cache.remove('item2'); -// expect(cache.info().size).toEqual(0); -// cache.remove('item1'); -// expect(cache.info().size).toEqual(0); -// cache.remove('item2'); -// expect(cache.info().size).toEqual(0); -// }); -// it('should remove items from localStorage when storageMode is used', function () { -// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), -// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); -// -// localStorageCache.put('item1', 'value1'); -// sessionStorageCache.put('item1', 'value1'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); -// } -// -// localStorageCache.remove('item1'); -// sessionStorageCache.remove('item1'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); -// } -// }); -//}); \ No newline at end of file +describe('AngularCache.remove(key)', function () { + it('should remove the item with the specified key.', function () { + var cache = $angularCacheFactory('cache'); + var value1 = 'value1', + value2 = 2, + value3 = { + value3: 'stuff' + }; + cache.put('item1', value1); + cache.put('item2', value2); + cache.put('item3', value3); + cache.remove('item1'); + expect(cache.get('item1')).toEqual(undefined); + cache.remove('item2'); + expect(cache.get('item2')).toEqual(undefined); + cache.remove('item3'); + expect(cache.get('item3')).toEqual(undefined); + }); + it('should reduce the size of the cache by one if the size is greater than zero.', function () { + var cache = $angularCacheFactory('cache'); + cache.put('item1', 'value1'); + expect(cache.info().size).toEqual(1); + cache.put('item2', 'value2'); + expect(cache.info().size).toEqual(2); + cache.remove('item1'); + expect(cache.info().size).toEqual(1); + cache.remove('item2'); + expect(cache.info().size).toEqual(0); + cache.remove('item1'); + expect(cache.info().size).toEqual(0); + cache.remove('item2'); + expect(cache.info().size).toEqual(0); + }); + it('should remove items from localStorage when storageMode is used.', function () { + var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), + sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); + + localStorageCache.put('item1', 'value1'); + sessionStorageCache.put('item1', 'value1'); + + if (localStorage) { + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); + expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1"]'); + } + if (sessionStorage) { + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); + expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1"]'); + } + + localStorageCache.remove('item1'); + sessionStorageCache.remove('item1'); + + if (localStorage) { + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); + expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); + } + if (sessionStorage) { + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); + expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); + } + }); +}); \ No newline at end of file diff --git a/test/angularCache.removeAll-test.js b/test/angularCache.removeAll-test.js index eb5bac2..fd3b872 100644 --- a/test/angularCache.removeAll-test.js +++ b/test/angularCache.removeAll-test.js @@ -1,51 +1,51 @@ -//describe('AngularCache.removeAll()', function () { -// it('should remove all items in the cache', function () { -// var cache = $angularCacheFactory('cache'); -// var value1 = 'value1', -// value2 = 2, -// value3 = { -// value3: 'stuff' -// }; -// cache.put('item1', value1); -// cache.put('item2', value2); -// cache.put('item3', value3); -// cache.removeAll(); -// expect(cache.get('item1')).toEqual(undefined); -// expect(cache.get('item2')).toEqual(undefined); -// expect(cache.get('item3')).toEqual(undefined); -// }); -// it('should remove items from localStorage when storageMode is used', function () { -// var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), -// sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); -// -// localStorageCache.put('item1', 'value1'); -// sessionStorageCache.put('item1', 'value1'); -// localStorageCache.put('item2', 'value2'); -// sessionStorageCache.put('item2', 'value2'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2')).value).toEqual('value2'); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1","item2"]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2')).value).toEqual('value2'); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1","item2"]'); -// } -// -// localStorageCache.removeAll(); -// sessionStorageCache.removeAll(); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2'))).toEqual(null); -// expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2'))).toEqual(null); -// expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); -// } -// }); -//}); \ No newline at end of file +describe('AngularCache.removeAll()', function () { + it('should remove all items in the cache.', function () { + var cache = $angularCacheFactory('cache'); + var value1 = 'value1', + value2 = 2, + value3 = { + value3: 'stuff' + }; + cache.put('item1', value1); + cache.put('item2', value2); + cache.put('item3', value3); + cache.removeAll(); + expect(cache.get('item1')).toEqual(undefined); + expect(cache.get('item2')).toEqual(undefined); + expect(cache.get('item3')).toEqual(undefined); + }); + it('should remove items from localStorage when storageMode is used.', function () { + var localStorageCache = $angularCacheFactory('localStorageCache', { storageMode: 'localStorage' }), + sessionStorageCache = $angularCacheFactory('sessionStorageCache', { storageMode: 'sessionStorage' }); + + localStorageCache.put('item1', 'value1'); + sessionStorageCache.put('item1', 'value1'); + localStorageCache.put('item2', 'value2'); + sessionStorageCache.put('item2', 'value2'); + + if (localStorage) { + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1')).value).toEqual('value1'); + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2')).value).toEqual('value2'); + expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('["item1","item2"]'); + } + if (sessionStorage) { + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1')).value).toEqual('value1'); + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2')).value).toEqual('value2'); + expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('["item1","item2"]'); + } + + localStorageCache.removeAll(); + sessionStorageCache.removeAll(); + + if (localStorage) { + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item1'))).toEqual(null); + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.localStorageCache.data.item2'))).toEqual(null); + expect(localStorage.getItem('angular-cache.caches.localStorageCache.keys')).toEqual('[]'); + } + if (sessionStorage) { + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item1'))).toEqual(null); + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.data.item2'))).toEqual(null); + expect(sessionStorage.getItem('angular-cache.caches.sessionStorageCache.keys')).toEqual('[]'); + } + }); +}); \ No newline at end of file diff --git a/test/angularCache.setOptions-test.js b/test/angularCache.setOptions-test.js index e27d265..4a98a65 100644 --- a/test/angularCache.setOptions-test.js +++ b/test/angularCache.setOptions-test.js @@ -1,183 +1,239 @@ -//describe('AngularCache.setOptions()', function () { -// it('should correctly reset to defaults if strict mode is true', function () { -// var onExpire = function () { -// }; -// var cache = $angularCacheFactory('cache', { -// maxAge: 100, -// cacheFlushInterval: 200, -// onExpire: onExpire, -// storageMode: 'localStorage' -// }); -// expect(cache.info().maxAge).toEqual(100); -// expect(cache.info().cacheFlushInterval).toEqual(200); -// expect(cache.info().onExpire).toEqual(onExpire); -// expect(cache.info().storageMode).toEqual('localStorage'); -// cache.setOptions({ }, true); -// expect(cache.info().maxAge).toEqual(null); -// expect(cache.info().cacheFlushInterval).toEqual(null); -// expect(cache.info().onExpire).toEqual(null); -// expect(cache.info().storageMode).toEqual('none'); -// }); -// it('should correctly modify the capacity of a cache', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.info().capacity).toEqual(Number.MAX_VALUE); -// cache.setOptions({ capacity: 5 }, false); -// expect(cache.info().capacity).toEqual(5); -// cache.put('item1', 1); -// cache.put('item2', 2); -// cache.put('item3', 3); -// cache.put('item4', 4); -// cache.put('item5', 5); -// cache.put('item6', 6); -// expect(cache.get('item1')).not.toBeDefined(); -// cache.setOptions({ capacity: 3 }, false); -// // Least-recently used items over the new capacity should have been removed. -// expect(cache.get('item2')).not.toBeDefined(); -// expect(cache.get('item3')).not.toBeDefined(); -// expect(cache.info().size).toEqual(3); -// }); -// it('should correctly modify the maxAge of a cache', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.info().maxAge).toEqual(null); -// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); -// expect(cache.info().maxAge).toEqual(10); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); -// expect(cache.info().maxAge).toEqual(10); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// // The new items should be removed after 500 ms (the new maxAge) -// runs(function () { -// $timeout.flush(); -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// }); -// }); -// }); -// it('should correctly modify the cacheFlushInterval of a cache', function () { -// var cache = $angularCacheFactory('cache'); -// expect(cache.info().cacheFlushInterval).toEqual(null); -// cache.setOptions({ cacheFlushInterval: 10 }, false); -// expect(cache.info().cacheFlushInterval).toEqual(10); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// // The first items should be removed after 2000 ms -// runs(function () { -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// cache.setOptions({ cacheFlushInterval: 10 }, false); -// expect(cache.info().cacheFlushInterval).toEqual(10); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// // The new items should be removed after 500 ms (the new maxAge) -// runs(function () { -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// }); -// }); -// }); -// it('should correctly modify the deleteOnExpire of a cache', function () { -// var cache = $angularCacheFactory('cache', { maxAge: 10 }); -// expect(cache.info().deleteOnExpire).toEqual('none'); -// cache.setOptions({ deleteOnExpire: 'passive' }, false); -// expect(cache.info().deleteOnExpire).toEqual('passive'); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// // The first items should be removed after 2000 ms -// runs(function () { -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); -// expect(cache.info().deleteOnExpire).toEqual('aggressive'); -// cache.put('item1', 1); -// cache.put('item2', 2); -// waits(100); -// // The new items should be removed after 500 ms (the new maxAge) -// runs(function () { -// $timeout.flush(); -// expect(cache.get('item1')).not.toBeDefined(); -// expect(cache.get('item2')).not.toBeDefined(); -// }); -// }); -// }); -// it('should correctly set configuration to default when \'strict\' is true', function () { -// var cache = $angularCacheFactory('cache', { -// capacity: 10, -// maxAge: 1000, -// cacheFlushInterval: 1000, -// deleteOnExpire: 'aggressive', -// storageMode: 'none' -// }); -// cache.setOptions({}, true); -// expect(cache.info()).toEqual({ -// capacity: Number.MAX_VALUE, -// maxAge: null, -// cacheFlushInterval: null, -// id: 'cache', -// size: 0, -// deleteOnExpire: 'none', -// storageMode: 'none', -// onExpire: null -// }); -// }); -// it('should correctly switch to using local/session storage when storageMode is activated', function () { -// var cache = $angularCacheFactory('cache'), -// cache2 = $angularCacheFactory('cache2'); -// cache.put('item', 'value'); -// cache2.put('item', 'value'); -// cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'localStorage' }); -// cache2.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'sessionStorage' }); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); -// } -// waits(100); -// runs(function () { -// $timeout.flush(); -// expect(cache.get('item')).toEqual(null); -// expect(cache2.get('item')).toEqual(null); -// if (localStorage) { -// expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); -// } -// if (sessionStorage) { -// expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); -// } -// }); -// }); -// it('should correctly stop using local/session storage when storageMode is deactivated', function () { -// var cache = $angularCacheFactory('cache', { storageMode: 'localStorage' }), -// cache2 = $angularCacheFactory('cache2', { storageMode: 'sessionStorage' }); -// cache.put('item', 'value'); -// cache2.put('item', 'value'); -// -// if (localStorage) { -// expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); -// } -// if (sessionStorage) { -// expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); -// } -// -// cache.setOptions({ storageMode: 'none' }, true); -// cache2.setOptions({ storageMode: 'none' }, true); -// -// if (localStorage) { -// expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); -// } -// if (sessionStorage) { -// expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); -// } -// }); -//}); \ No newline at end of file +describe('AngularCache.setOptions()', function () { + it('should throw an error if "options" is not an object.', function () { + var cache = $angularCacheFactory('cache'); + for (var i = 0; i < TYPES_EXCEPT_OBJECT.length; i++) { + try { + cache.setOptions(TYPES_EXCEPT_OBJECT[i]); + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } + } catch (err) { + expect(err.message).toEqual('AngularCache.setOptions(options, strict): options: must be an object!'); + continue; + } + if (TYPES_EXCEPT_OBJECT[i] !== null && TYPES_EXCEPT_OBJECT[i] !== undefined && TYPES_EXCEPT_OBJECT[i] !== false) { + fail(TYPES_EXCEPT_OBJECT[i]); + } + } + }); + it('should correctly reset to defaults if strict mode is true', function () { + var onExpire = function () { + }; + var cache = $angularCacheFactory('cache', { + maxAge: 100, + cacheFlushInterval: 200, + onExpire: onExpire, + storageMode: 'localStorage' + }); + expect(cache.info().maxAge).toEqual(100); + expect(cache.info().cacheFlushInterval).toEqual(200); + expect(cache.info().onExpire).toEqual(onExpire); + expect(cache.info().storageMode).toEqual('localStorage'); + cache.setOptions({ }, true); + expect(cache.info().maxAge).toEqual(null); + expect(cache.info().cacheFlushInterval).toEqual(null); + expect(cache.info().onExpire).toEqual(null); + expect(cache.info().storageMode).toEqual('none'); + }); + it('should correctly modify the capacity of a cache', function () { + var cache = $angularCacheFactory('cache'); + expect(cache.info().capacity).toEqual(Number.MAX_VALUE); + cache.setOptions({ capacity: 5 }, false); + expect(cache.info().capacity).toEqual(5); + cache.put('item1', 1); + cache.put('item2', 2); + cache.put('item3', 3); + cache.put('item4', 4); + cache.put('item5', 5); + cache.put('item6', 6); + expect(cache.get('item1')).not.toBeDefined(); + waits(50); + runs(function () { + cache.get('item2'); + cache.get('item3'); + cache.get('item6'); + cache.setOptions({ capacity: 3 }, false); + // Least-recently used items over the new capacity should have been removed. + expect(cache.get('item4')).not.toBeDefined(); + expect(cache.get('item5')).not.toBeDefined(); + expect(cache.info().size).toEqual(3); + }); + }); + it('should correctly modify the maxAge of a cache', function () { + var cache = $angularCacheFactory('cache'); + expect(cache.info().maxAge).toEqual(null); + cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', recycleFreq: 20 }, false); + expect(cache.info().maxAge).toEqual(10); + cache.put('item1', 1); + cache.put('item2', 2); + waits(100); + runs(function () { + expect(cache.get('item1')).not.toBeDefined(); + expect(cache.get('item2')).not.toBeDefined(); + cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', recycleFreq: 20 }, false); + expect(cache.info().maxAge).toEqual(10); + cache.put('item1', 1); + cache.put('item2', 2); + waits(100); + // The new items should be removed after 500 ms (the new maxAge) + runs(function () { + expect(cache.get('item1')).not.toBeDefined(); + expect(cache.get('item2')).not.toBeDefined(); + cache.put('item1', 1); + cache.put('item2', 2, { maxAge: 25, deleteOnExpire: 'aggressive' }); + cache.setOptions({ maxAge: null, deleteOnExpire: 'none', recycleFreq: 20 }, false); + expect(cache.info().maxAge).toEqual(null); + waits(100); + // The new items should be removed after 500 ms (the new maxAge) + runs(function () { + expect(cache.get('item1')).toEqual(1); + expect(cache.info('item1').expires).not.toBeDefined(); + expect(cache.get('item2')).not.toBeDefined(); + expect(cache.info('item2')).not.toBeDefined(); + + cache.setOptions({ maxAge: 1000, deleteOnExpire: 'aggressive', recycleFreq: 20 }, false); + cache.put('item1', 1); + cache.put('item2', 2); + waits(100); + // The new items should be removed after 500 ms (the new maxAge) + runs(function () { + cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive' }, false); + expect(cache.get('item1')).not.toBeDefined(); + expect(cache.get('item2')).not.toBeDefined(); + }); + }); + }); + }); + }); + it('should correctly modify the cacheFlushInterval of a cache', function () { + var cache = $angularCacheFactory('cache'); + expect(cache.info().cacheFlushInterval).toEqual(null); + cache.setOptions({ cacheFlushInterval: 10 }, false); + expect(cache.info().cacheFlushInterval).toEqual(10); + cache.put('item1', 1); + cache.put('item2', 2); + waits(100); + // The first items should be removed after 2000 ms + runs(function () { + expect(cache.get('item1')).not.toBeDefined(); + expect(cache.get('item2')).not.toBeDefined(); + cache.setOptions({ cacheFlushInterval: 20 }, false); + expect(cache.info().cacheFlushInterval).toEqual(20); + cache.put('item1', 1); + cache.put('item2', 2); + waits(100); + // The new items should be removed after 500 ms (the new maxAge) + runs(function () { + expect(cache.get('item1')).not.toBeDefined(); + expect(cache.get('item2')).not.toBeDefined(); + cache.setOptions({ cacheFlushInterval: 20 }, false); + expect(cache.info().cacheFlushInterval).toEqual(20); + cache.put('item1', 1); + cache.put('item2', 2); + waits(100); + // The new items should be removed after 500 ms (the new maxAge) + runs(function () { + expect(cache.get('item1')).not.toBeDefined(); + expect(cache.get('item2')).not.toBeDefined(); + }); + }); + }); + }); + it('should correctly modify the deleteOnExpire of a cache', function () { + var cache = $angularCacheFactory('cache', { maxAge: 10 }); + expect(cache.info().deleteOnExpire).toEqual('none'); + cache.setOptions({ deleteOnExpire: 'passive' }, false); + expect(cache.info().deleteOnExpire).toEqual('passive'); + cache.put('item1', 1); + cache.put('item2', 2); + waits(100); + // The first items should be removed after 2000 ms + runs(function () { + expect(cache.get('item1')).not.toBeDefined(); + expect(cache.get('item2')).not.toBeDefined(); + cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', recycleFreq: 20 }, false); + expect(cache.info().deleteOnExpire).toEqual('aggressive'); + cache.put('item1', 1); + cache.put('item2', 2); + waits(100); + // The new items should be removed after 500 ms (the new maxAge) + runs(function () { + expect(cache.get('item1')).not.toBeDefined(); + expect(cache.get('item2')).not.toBeDefined(); + }); + }); + }); + it('should correctly set configuration to default when "strict" is true', function () { + var cache = $angularCacheFactory('cache', { + capacity: 10, + maxAge: 1000, + cacheFlushInterval: 1000, + deleteOnExpire: 'aggressive', + storageMode: 'none' + }); + cache.setOptions({}, true); + var cacheInfo = cache.info(); + expect(cacheInfo.id).toEqual('cache'); + expect(cacheInfo.capacity).toEqual(Number.MAX_VALUE); + expect(cacheInfo.size).toEqual(0); + expect(cacheInfo.recycleFreq).toEqual(1000); + expect(cacheInfo.maxAge).toEqual(null); + expect(cacheInfo.cacheFlushInterval).toEqual(null); + expect(typeof cacheInfo.recycleFreqId).toEqual('number'); + expect(cacheInfo.deleteOnExpire).toEqual('none'); + expect(cacheInfo.storageMode).toEqual('none'); + expect(cacheInfo.onExpire).toEqual(null); + + cache.setOptions({ recycleFreq: null }); + expect(cache.info().recycleFreq).toEqual(1000); + }); + it('should correctly switch to using local/session storage when storageMode is activated', function () { + var cache = $angularCacheFactory('cache'), + cache2 = $angularCacheFactory('cache2'); + cache.put('item', 'value'); + cache2.put('item', 'value'); + cache.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'localStorage', recycleFreq: 20 }); + cache2.setOptions({ maxAge: 10, deleteOnExpire: 'aggressive', storageMode: 'sessionStorage', recycleFreq: 20 }); + + if (localStorage) { + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); + } + if (sessionStorage) { + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); + } + waits(100); + runs(function () { + expect(cache.get('item')).not.toBeDefined(); + expect(cache2.get('item')).not.toBeDefined(); + if (localStorage) { + expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); + } + if (sessionStorage) { + expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); + } + }); + }); + it('should correctly stop using local/session storage when storageMode is deactivated', function () { + var cache = $angularCacheFactory('cache', { storageMode: 'localStorage' }), + cache2 = $angularCacheFactory('cache2', { storageMode: 'sessionStorage' }); + cache.put('item', 'value'); + cache2.put('item', 'value'); + + if (localStorage) { + expect(angular.fromJson(localStorage.getItem('angular-cache.caches.cache.data.item')).value).toEqual('value'); + } + if (sessionStorage) { + expect(angular.fromJson(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).value).toEqual('value'); + } + + cache.setOptions({ storageMode: 'none' }, true); + cache2.setOptions({ storageMode: 'none' }, true); + + if (localStorage) { + expect(localStorage.getItem('angular-cache.caches.cache.data.item')).toEqual(null); + } + if (sessionStorage) { + expect(sessionStorage.getItem('angular-cache.caches.cache2.data.item')).toEqual(null); + } + }); +}); \ No newline at end of file diff --git a/test/angularCacheFactory-test.js b/test/angularCacheFactory-test.js index 140c4aa..d151489 100644 --- a/test/angularCacheFactory-test.js +++ b/test/angularCacheFactory-test.js @@ -79,14 +79,14 @@ describe('$angularCacheFactory(cacheId, options)', function () { try { $angularCacheFactory('maxAgeCache' + i, { maxAge: TYPES_EXCEPT_NUMBER[i] }); if (TYPES_EXCEPT_NUMBER[i] !== null) { - fail(); + fail(TYPES_EXCEPT_NUMBER[i]); } } catch (err) { expect(err.message).toEqual('maxAge: must be a number!'); continue; } if (TYPES_EXCEPT_NUMBER[i] !== null) { - fail(); + fail(TYPES_EXCEPT_NUMBER[i]); } } }); @@ -166,7 +166,7 @@ describe('$angularCacheFactory(cacheId, options)', function () { var deleteOnExpire = 'fail'; try { $angularCacheFactory('cache', { deleteOnExpire: deleteOnExpire }); - expect('should not reach this!').toEqual(false); + fail('should not reach this!'); } catch (err) { var msg = err.message; } @@ -174,12 +174,12 @@ describe('$angularCacheFactory(cacheId, options)', function () { for (var i = 0; i < TYPES_EXCEPT_STRING.length; i++) { try { $angularCacheFactory('deleteOnExpireCache' + i, { deleteOnExpire: TYPES_EXCEPT_STRING[i] }); - fail(); + fail(TYPES_EXCEPT_STRING[i]); } catch (err) { expect(err.message).toEqual('deleteOnExpire: must be a string!'); continue; } - fail(); + fail(TYPES_EXCEPT_STRING[i]); } }); it('should validate storageMode.', function () { @@ -194,12 +194,12 @@ describe('$angularCacheFactory(cacheId, options)', function () { for (var i = 0; i < TYPES_EXCEPT_STRING.length; i++) { try { $angularCacheFactory('storageModeCache' + i, { storageMode: TYPES_EXCEPT_STRING[i] }); - fail(); + fail(TYPES_EXCEPT_STRING[i]); } catch (err) { expect(err.message).toEqual('storageMode: must be a string!'); continue; } - fail(); + fail(TYPES_EXCEPT_STRING[i]); } }); it('should validate storageImpl.', function () {