Skip to content

Commit

Permalink
[stub/BrowserStorage] reimplement and test the BrowserStorage stub
Browse files Browse the repository at this point in the history
  • Loading branch information
spalger committed Aug 18, 2016
1 parent d6f17cf commit f3f9256
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 10 deletions.
85 changes: 85 additions & 0 deletions src/test_utils/__tests__/stub_browser_storage.js
Original file line number Diff line number Diff line change
@@ -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
});
});
});
96 changes: 89 additions & 7 deletions src/test_utils/stub_browser_storage.js
Original file line number Diff line number Diff line change
@@ -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;
}
}
6 changes: 3 additions & 3 deletions src/ui/public/chrome/api/__tests__/apps.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
});
});
Expand Down

0 comments on commit f3f9256

Please sign in to comment.