From f3f925604f901d17fb6b4141b598d9abef325b9b Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 18 Aug 2016 00:13:35 -0700 Subject: [PATCH] [stub/BrowserStorage] reimplement and test the BrowserStorage stub --- .../__tests__/stub_browser_storage.js | 85 ++++++++++++++++ src/test_utils/stub_browser_storage.js | 96 +++++++++++++++++-- src/ui/public/chrome/api/__tests__/apps.js | 6 +- 3 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 src/test_utils/__tests__/stub_browser_storage.js diff --git a/src/test_utils/__tests__/stub_browser_storage.js b/src/test_utils/__tests__/stub_browser_storage.js new file mode 100644 index 0000000000000..83e4a7440ddd3 --- /dev/null +++ b/src/test_utils/__tests__/stub_browser_storage.js @@ -0,0 +1,85 @@ +import expect from 'expect.js'; + +import StubBrowserStorage from '../stub_browser_storage'; + +describe('StubBrowserStorage', () => { + describe('#getItem() / #setItem()', () => { + it('stores items as strings', () => { + const store = new StubBrowserStorage(); + store.setItem(1, 1); + expect(store.getItem(1)).to.be('1'); + }); + + it('stores keys as strings', () => { + const store = new StubBrowserStorage(); + store.setItem(1, 1); + expect(store.key(0)).to.be('1'); + }); + + it('returns null for missing keys', () => { + const store = new StubBrowserStorage(); + expect(store.getItem('unknown key')).to.be(null); + }); + }); + + describe('#length', () => { + it('reports the number of items stored', () => { + const store = new StubBrowserStorage(); + store.setItem(1, 1); + store.setItem(2, 2); + store.setItem(3, 3); + store.setItem(4, 4); + expect(store).to.have.length(4); + }); + + it('does not trip on items getting reset', () => { + const store = new StubBrowserStorage(); + store.setItem(1, 1); + store.setItem(1, 2); + expect(store).to.have.length(1); + }); + }); + + describe('#key()', () => { + it('returns the key as a specific index', () => { + const store = new StubBrowserStorage(); + store.setItem(1, 2); + expect(store.key(0)).to.be('1'); + expect(store.key(1)).to.be(undefined); + }); + }); + + describe('size limiting', () => { + it('allows limiting the storage size', () => { + const store = new StubBrowserStorage(); + store._setSizeLimit(10); + store.setItem('abc', 'def'); // store size is 6, key.length + val.length + expect(() => { + store.setItem('ghi', 'jkl'); + }).throwError(/quota/); + }); + + it('allows defining the limit as infinity', () => { + const store = new StubBrowserStorage(); + store._setSizeLimit(Infinity); + store.setItem('abc', 'def'); + store.setItem('ghi', 'jkl'); // unlike the previous test, this doesn't throw + }); + + it('requires setting the limit before keys', () => { + const store = new StubBrowserStorage(); + store.setItem('key', 'val'); + expect(() => { + store._setSizeLimit(10); + }).throwError(/before setting/); + }); + + it('respects removed items', () => { + const store = new StubBrowserStorage(); + store._setSizeLimit(10); + store.setItem('abc', 'def'); + store.removeItem('abc'); + store.setItem('ghi', 'jkl'); // unlike the previous test, this doesn't throw + }); + }); +}); diff --git a/src/test_utils/stub_browser_storage.js b/src/test_utils/stub_browser_storage.js index 812cd85ce4d75..cf628e0eca515 100644 --- a/src/test_utils/stub_browser_storage.js +++ b/src/test_utils/stub_browser_storage.js @@ -1,10 +1,92 @@ -const store = Symbol('store'); +const keys = Symbol('keys'); +const values = Symbol('values'); +const remainingSize = Symbol('remainingSize'); export default class StubBrowserStorage { - constructor() { this[store] = new Map(); } - getItem(k) { return this[store].get(k); } - setItem(k, v) { return this[store].set(k, String(v)); } - removeItem(k) { return this[store].delete(k); } - getKeys() { return [ ...this[store].keys() ]; } - getValues() { return [ ...this[store].values() ]; } + constructor() { + this[keys] = []; + this[values] = []; + this[remainingSize] = 5000000; // 5mb, minimum browser storage size + } + + get length() { + return this[keys].length; + } + + key(i) { + return this[keys][i]; + } + + getItem(key) { + key = String(key); + + const i = this[keys].indexOf(key); + if (i === -1) return null; + return this[values][i]; + } + + setItem(key, value) { + key = String(key); + value = String(value); + this._takeUpSpace(this._calcSizeOfAdd(key, value)); + + const i = this[keys].indexOf(key); + if (i === -1) { + this[keys].push(key); + this[values].push(value); + } else { + this[values][i] = value; + } + } + + removeItem(key) { + key = String(key); + this._takeUpSpace(this._calcSizeOfRemove(key)); + + const i = this[keys].indexOf(key); + if (i === -1) return; + this[keys].splice(i, 1); + this[values].splice(i, 1); + } + + // non-standard api methods + _getKeys() { + return this[keys].slice(); + } + + _getValues() { + return this[values].slice(); + } + + _setSizeLimit(limit) { + if (this[keys].length) { + throw new Error('You must call _setSizeLimit() before setting any values'); + } + + this[remainingSize] = limit; + } + + _calcSizeOfAdd(key, value) { + const i = this[keys].indexOf(key); + if (i === -1) { + return key.length + value.length; + } + return value.length - this[values][i].length; + } + + _calcSizeOfRemove(key) { + const i = this[keys].indexOf(key); + if (i === -1) { + return 0; + } + return 0 - (key.length + this[values][i].length); + } + + _takeUpSpace(delta) { + if (this[remainingSize] - delta < 0) { + throw new Error('something about quota exceeded, browsers are not consistent here'); + } + + this[remainingSize] -= delta; + } } diff --git a/src/ui/public/chrome/api/__tests__/apps.js b/src/ui/public/chrome/api/__tests__/apps.js index 54f3a8a61dd81..7e6040b1aa8ce 100644 --- a/src/ui/public/chrome/api/__tests__/apps.js +++ b/src/ui/public/chrome/api/__tests__/apps.js @@ -149,11 +149,11 @@ describe('Chrome API :: apps', function () { const chrome = {}; const store = new StubBrowserStorage(); setup(chrome, { appUrlStore: store }); - expect(chrome.getLastUrlFor('app')).to.equal(undefined); + expect(chrome.getLastUrlFor('app')).to.equal(null); chrome.setLastUrlFor('app', 'url'); expect(chrome.getLastUrlFor('app')).to.equal('url'); - expect(store.getKeys().length).to.equal(1); - expect(store.getValues().shift()).to.equal('url'); + expect(store._getKeys().length).to.equal(1); + expect(store._getValues().shift()).to.equal('url'); }); }); });