Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stub/BrowserStorage] reimplement and test the BrowserStorage stub #8021

Merged
merged 1 commit into from
Aug 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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