Make backends pluggable via FileSystem ctor, fixes #36.

This commit is contained in:
David Humphrey (:humph) david.humphrey@senecacollege.ca 2013-11-22 16:12:31 -05:00
parent 6cc4226b45
commit 6e16f86208
15 changed files with 2292 additions and 1395 deletions

1676
dist/idbfs.js vendored

File diff suppressed because it is too large Load Diff

4
dist/idbfs.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -18,7 +18,14 @@ module.exports = function(grunt) {
jshint: { jshint: {
// Don't bother with src/path.js // Don't bother with src/path.js
all: ['gruntfile.js', 'src/constants.js', 'src/error.js', 'src/fs.js', 'srs/shared.js'] all: ['gruntfile.js',
'src/constants.js',
'src/error.js',
'src/fs.js',
'src/shared.js',
'src/providers/**/*.js',
'src/filesystems-manager.js'
]
}, },
requirejs: { requirejs: {

View File

@ -8,7 +8,6 @@ define(function(require) {
var O_APPEND = 'APPEND'; var O_APPEND = 'APPEND';
return { return {
METADATA_STORE_NAME: 'metadata',
FILE_STORE_NAME: 'files', FILE_STORE_NAME: 'files',
IDB_RO: 'readonly', IDB_RO: 'readonly',
@ -45,7 +44,7 @@ define(function(require) {
'a': [O_WRITE, O_CREATE, O_APPEND], 'a': [O_WRITE, O_CREATE, O_APPEND],
'a+': [O_WRITE, O_READ, O_CREATE, O_APPEND], 'a+': [O_WRITE, O_READ, O_CREATE, O_APPEND],
'ax': [O_WRITE, O_CREATE, O_EXCLUSIVE, O_APPEND], 'ax': [O_WRITE, O_CREATE, O_EXCLUSIVE, O_APPEND],
'ax+': [O_WRITE, O_READ, O_CREATE, O_EXCLUSIVE, O_APPEND], 'ax+': [O_WRITE, O_READ, O_CREATE, O_EXCLUSIVE, O_APPEND]
}, },
FS_READY: 'READY', FS_READY: 'READY',

View File

@ -0,0 +1,60 @@
define(function(require) {
var guid = require('src/shared').guid;
var FS_READY = require('src/constants').FS_READY;
var FS_ERROR = require('src/constants').FS_ERROR;
var EFileSystemError = require('src/error').EFileSystemError;
var filesystems = {};
function FileSystemWrapper(fs) {
this.fs = fs;
this.openFiles = {};
this.nextDescriptor = 1;
this.queue = [];
}
FileSystemWrapper.prototype.allocDescriptor = function(openFileDescription) {
var fd = this.nextDescriptor ++;
this.openFiles[fd] = openFileDescription;
return fd;
};
FileSystemWrapper.prototype.releaseDescriptor = function(fd) {
delete this.openFiles[fd];
};
FileSystemWrapper.prototype.queueOrRun = function(operation) {
var error;
var fs = this.fs;
if(FS_READY == fs.readyState) {
operation.call(fs);
} else if(FS_ERROR == fs.readyState) {
error = new EFileSystemError('unknown error');
} else {
this.queue.push(operation);
}
return error;
};
FileSystemWrapper.prototype.runQueued = function() {
this.queue.forEach(function(operation) {
operation.call(this);
}.bind(this.fs));
this.queue = null;
};
return {
register: function(fs) {
fs.id = guid();
filesystems[fs.id] = new FileSystemWrapper(fs);
},
get: function(fs) {
return filesystems[fs.id];
}
};
});

1167
src/fs.js

File diff suppressed because it is too large Load Diff

126
src/providers/indexeddb.js Normal file
View File

@ -0,0 +1,126 @@
define(function(require) {
var FILE_STORE_NAME = require('src/constants').FILE_STORE_NAME;
var indexedDB = window.indexedDB ||
window.mozIndexedDB ||
window.webkitIndexedDB ||
window.msIndexedDB;
var IDB_RW = require('src/constants').IDB_RW;
var IDB_RO = require('src/constants').IDB_RO;
function IndexedDBContext(db, mode) {
var transaction = db.transaction(FILE_STORE_NAME, mode);
this.objectStore = transaction.objectStore(FILE_STORE_NAME);
}
IndexedDBContext.prototype.clear = function(callback) {
try {
var request = this.objectStore.clear();
request.onsuccess = function(event) {
callback();
};
request.onerror = function(error) {
callback(error);
};
} catch(e) {
callback(e);
}
};
IndexedDBContext.prototype.get = function(key, callback) {
try {
var request = this.objectStore.get(key);
request.onsuccess = function onsuccess(event) {
var result = event.target.result;
callback(null, result);
};
request.onerror = function onerror(error) {
callback(error);
};
} catch(e) {
callback(e);
}
};
IndexedDBContext.prototype.put = function(key, value, callback) {
try {
var request = this.objectStore.put(value, key);
request.onsuccess = function onsuccess(event) {
var result = event.target.result;
callback(null, result);
};
request.onerror = function onerror(error) {
callback(error);
};
} catch(e) {
callback(e);
}
};
IndexedDBContext.prototype.delete = function(key, callback) {
try {
var request = this.objectStore.delete(key);
request.onsuccess = function onsuccess(event) {
var result = event.target.result;
callback(null, result);
};
request.onerror = function(error) {
callback(error);
};
} catch(e) {
callback(e);
}
};
function IndexedDB(name) {
this.name = name || "local";
this.db = null;
}
IndexedDB.isSupported = function() {
return !!indexedDB;
};
IndexedDB.prototype.open = function(callback) {
var that = this;
// Bail if we already have a db open
if( that.db ) {
callback(null, false);
return;
}
// Keep track of whether we're accessing this db for the first time
// and therefore needs to get formatted.
var firstAccess = false;
// NOTE: we're not using versioned databases.
var openRequest = indexedDB.open(that.name);
// If the db doesn't exist, we'll create it
openRequest.onupgradeneeded = function onupgradeneeded(event) {
var db = event.target.result;
if(db.objectStoreNames.contains(FILE_STORE_NAME)) {
db.deleteObjectStore(FILE_STORE_NAME);
}
db.createObjectStore(FILE_STORE_NAME);
firstAccess = true;
};
openRequest.onsuccess = function onsuccess(event) {
that.db = event.target.result;
callback(null, firstAccess);
};
openRequest.onerror = function onerror(error) {
callback(error);
};
};
IndexedDB.prototype.getReadOnlyContext = function() {
return new IndexedDBContext(this.db, IDB_RO);
};
IndexedDB.prototype.getReadWriteContext = function() {
return new IndexedDBContext(this.db, IDB_RW);
};
return IndexedDB;
});

56
src/providers/memory.js Normal file
View File

@ -0,0 +1,56 @@
define(function(require) {
function MemoryContext(db, readOnly) {
this.readOnly = readOnly;
this.objectStore = db;
}
MemoryContext.prototype.clear = function(callback) {
if(this.readOnly) {
return callback("[MemoryContext] Error: write operation on read only context");
}
var objectStore = this.objectStore;
Object.keys(objectStore).forEach(function(key){
delete objectStore[key];
});
callback(null);
};
MemoryContext.prototype.get = function(key, callback) {
callback(null, this.objectStore[key]);
};
MemoryContext.prototype.put = function(key, value, callback) {
if(this.readOnly) {
return callback("[MemoryContext] Error: write operation on read only context");
}
this.objectStore[key] = value;
callback(null);
};
MemoryContext.prototype.delete = function(key, callback) {
if(this.readOnly) {
return callback("[MemoryContext] Error: write operation on read only context");
}
delete this.objectStore[key];
callback(null);
};
function Memory(name) {
this.name = name || "local";
this.db = {};
}
Memory.isSupported = function() {
return true;
};
Memory.prototype.open = function(callback) {
var that = this;
callback(null, true);
};
Memory.prototype.getReadOnlyContext = function() {
return new MemoryContext(this.db, true);
};
Memory.prototype.getReadWriteContext = function() {
return new MemoryContext(this.db, false);
};
return Memory;
});

View File

@ -0,0 +1,7 @@
define(function(require) {
return {
IndexedDB: require('src/providers/indexeddb'),
Memory: require('src/providers/memory'),
Default: require('src/providers/indexeddb')
};
});

39
tests/common.js Normal file
View File

@ -0,0 +1,39 @@
var TEST_DATABASE_NAME = '__test';
var DEFAULT_TIMEOUT = 5000;
var test_database_names = [];
window.onbeforeunload = function() {
test_database_names.forEach(function(name) {
indexedDB.deleteDatabase(name);
});
};
function mk_id(length) {
var text = '';
var tokens = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for( var i=0; i < length; i++ )
text += tokens.charAt(Math.floor(Math.random() * tokens.length));
return text;
};
function mk_db_name() {
var name = TEST_DATABASE_NAME + mk_id(5) + Date.now();
test_database_names.push(name);
return name;
};
function typed_array_equal(left, right) {
if(left.length !== right.length) {
return false;
}
for(var i = 0; i < left.length; ++ i) {
if(left[i] !== right[i]) {
return false;
}
}
return true;
};

View File

@ -14,6 +14,10 @@
<!-- include spec files here... --> <!-- include spec files here... -->
<!--script type="text/javascript" src="spec/SpecHelper.js"></script--> <!--script type="text/javascript" src="spec/SpecHelper.js"></script-->
<script type="text/javascript" src="common.js"></script>
<script type="text/javascript" src="spec/providers.spec.js"></script>
<script type="text/javascript" src="spec/providers.indexeddb.spec.js"></script>
<script type="text/javascript" src="spec/providers.memory.spec.js"></script>
<script type="text/javascript" src="spec/idbfs.spec.js"></script> <script type="text/javascript" src="spec/idbfs.spec.js"></script>
<script type="text/javascript"> <script type="text/javascript">

View File

@ -1,43 +1,3 @@
var TEST_DATABASE_NAME = '__test';
var DEFAULT_TIMEOUT = 5000;
var test_database_names = [];
window.onbeforeunload = function() {
test_database_names.forEach(function(name) {
indexedDB.deleteDatabase(name);
});
};
function mk_id(length) {
var text = '';
var tokens = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for( var i=0; i < length; i++ )
text += tokens.charAt(Math.floor(Math.random() * tokens.length));
return text;
};
function mk_db_name() {
var name = TEST_DATABASE_NAME + mk_id(5) + Date.now();
test_database_names.push(name);
return name;
};
function typed_array_equal(left, right) {
if(left.length !== right.length) {
return false;
}
for(var i = 0; i < left.length; ++ i) {
if(left[i] !== right[i]) {
return false;
}
}
return true;
};
describe("IDBFS", function() { describe("IDBFS", function() {
it("is defined", function() { it("is defined", function() {
expect(typeof IDBFS).not.toEqual(undefined); expect(typeof IDBFS).not.toEqual(undefined);
@ -51,7 +11,10 @@ describe("IDBFS", function() {
describe("fs", function() { describe("fs", function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -86,7 +49,10 @@ describe("fs", function() {
describe('fs.stat', function() { describe('fs.stat', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -192,7 +158,10 @@ describe('fs.stat', function() {
describe('fs.fstat', function() { describe('fs.fstat', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -243,7 +212,10 @@ describe('fs.fstat', function() {
describe('fs.lstat', function() { describe('fs.lstat', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -329,7 +301,10 @@ describe('fs.lstat', function() {
describe('fs.mkdir', function() { describe('fs.mkdir', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -412,7 +387,10 @@ describe('fs.mkdir', function() {
describe('fs.readdir', function() { describe('fs.readdir', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -502,7 +480,10 @@ describe('fs.readdir', function() {
describe('fs.rmdir', function() { describe('fs.rmdir', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -658,7 +639,10 @@ describe('fs.rmdir', function() {
describe('fs.open', function() { describe('fs.open', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -827,7 +811,10 @@ describe('fs.open', function() {
describe('fs.write', function() { describe('fs.write', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -921,7 +908,10 @@ describe('fs.write', function() {
describe('fs.writeFile, fs.readFile', function() { describe('fs.writeFile, fs.readFile', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -1098,7 +1088,10 @@ describe('fs.writeFile, fs.readFile', function() {
describe('fs.read', function() { describe('fs.read', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -1190,7 +1183,10 @@ describe('fs.read', function() {
describe('fs.close', function() { describe('fs.close', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -1234,7 +1230,10 @@ describe('fs.close', function() {
describe('fs.link', function() { describe('fs.link', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -1331,7 +1330,10 @@ describe('fs.link', function() {
describe('fs.unlink', function() { describe('fs.unlink', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -1435,7 +1437,10 @@ describe('fs.unlink', function() {
describe('fs.rename', function() { describe('fs.rename', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -1487,6 +1492,25 @@ describe('fs.rename', function() {
expect(_stats.nlinks).toEqual(1); expect(_stats.nlinks).toEqual(1);
}); });
}); });
});
describe('fs.lseek', function() {
beforeEach(function() {
this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
});
afterEach(function() {
indexedDB.deleteDatabase(this.db_name);
delete this.fs;
});
it('should be a function', function() {
expect(typeof this.fs.lseek).toEqual('function');
});
it('should not follow symbolic links', function () { it('should not follow symbolic links', function () {
var complete = false; var complete = false;
@ -1540,7 +1564,10 @@ describe('fs.rename', function() {
describe('fs.lseek', function() { describe('fs.lseek', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -1717,7 +1744,10 @@ describe('fs.lseek', function() {
describe('fs.symlink', function() { describe('fs.symlink', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -1794,7 +1824,10 @@ describe('fs.symlink', function() {
describe('fs.readlink', function() { describe('fs.readlink', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {
@ -1875,7 +1908,10 @@ describe('fs.readlink', function() {
describe('path resolution', function() { describe('path resolution', function() {
beforeEach(function() { beforeEach(function() {
this.db_name = mk_db_name(); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT'); this.fs = new IDBFS.FileSystem({
name: this.db_name,
flags: 'FORMAT'
});
}); });
afterEach(function() { afterEach(function() {

View File

@ -0,0 +1,188 @@
describe("IDBFS.Providers.IndexedDB", function() {
it("is supported -- if it isn't, none of these tests can run.", function() {
expect(IDBFS.Providers.IndexedDB.isSupported()).toEqual(true);
});
it("has open, getReadOnlyContext, and getReadWriteContext instance methods", function() {
var indexedDBProvider = new IDBFS.Providers.IndexedDB();
expect(typeof indexedDBProvider.open).toEqual('function');
expect(typeof indexedDBProvider.getReadOnlyContext).toEqual('function');
expect(typeof indexedDBProvider.getReadWriteContext).toEqual('function');
});
describe("open an IndexedDB provider", function() {
beforeEach(function() {
this.db_name = mk_db_name();
});
afterEach(function() {
indexedDB.deleteDatabase(this.db_name);
});
it("should open a new IndexedDB database", function() {
var complete = false;
var _error, _result;
var provider = new IDBFS.Providers.IndexedDB(this.db_name);
provider.open(function(err, firstAccess) {
_error = err;
_result = firstAccess;
complete = true;
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toEqual(null);
expect(_result).toEqual(true);
});
});
});
describe("Read/Write operations on an IndexedDB provider", function() {
beforeEach(function() {
this.db_name = mk_db_name();
});
afterEach(function() {
indexedDB.deleteDatabase(this.db_name);
});
it("should allow put() and get()", function() {
var complete = false;
var _error, _result;
var provider = new IDBFS.Providers.IndexedDB(this.db_name);
provider.open(function(err, firstAccess) {
_error = err;
var context = provider.getReadWriteContext();
context.put("key", "value", function(err, result) {
_error = _error || err;
context.get("key", function(err, result) {
_error = _error || err;
_result = result;
complete = true;
});
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toEqual(null);
expect(_result).toEqual("value");
});
});
it("should allow delete()", function() {
var complete = false;
var _error, _result;
var provider = new IDBFS.Providers.IndexedDB(this.db_name);
provider.open(function(err, firstAccess) {
_error = err;
var context = provider.getReadWriteContext();
context.put("key", "value", function(err, result) {
_error = _error || err;
context.delete("key", function(err, result) {
_error = _error || err;
context.get("key", function(err, result) {
_error = _error || err;
_result = result;
complete = true;
});
});
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toEqual(null);
expect(_result).toEqual(null);
});
});
it("should allow clear()", function() {
var complete = false;
var _error, _result1, _result2;
var provider = new IDBFS.Providers.IndexedDB(this.db_name);
provider.open(function(err, firstAccess) {
_error = err;
var context = provider.getReadWriteContext();
context.put("key1", "value1", function(err, result) {
_error = _error || err;
context.put("key2", "value2", function(err, result) {
_error = _error || err;
context.clear(function(err) {
_error = _error || err;
context.get("key1", function(err, result) {
_error = _error || err;
_result1 = result;
context.get("key2", function(err, result) {
_error = _error || err;
_result2 = result;
complete = true;
});
});
});
});
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toEqual(null);
expect(_result1).toEqual(null);
expect(_result2).toEqual(null);
});
});
it("should fail when trying to write on ReadOnlyContext", function() {
var complete = false;
var _error, _result;
var provider = new IDBFS.Providers.IndexedDB(this.db_name);
provider.open(function(err, firstAccess) {
_error = err;
var context = provider.getReadOnlyContext();
context.put("key1", "value1", function(err, result) {
_error = _error || err;
_result = result;
complete = true;
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toBeDefined();
expect(_result).toEqual(null);
});
});
});
});

View File

@ -0,0 +1,172 @@
describe("IDBFS.Providers.Memory", function() {
it("is supported -- if it isn't, none of these tests can run.", function() {
expect(IDBFS.Providers.Memory.isSupported()).toEqual(true);
});
it("has open, getReadOnlyContext, and getReadWriteContext instance methods", function() {
var indexedDBProvider = new IDBFS.Providers.Memory();
expect(typeof indexedDBProvider.open).toEqual('function');
expect(typeof indexedDBProvider.getReadOnlyContext).toEqual('function');
expect(typeof indexedDBProvider.getReadWriteContext).toEqual('function');
});
describe("open an Memory provider", function() {
it("should open a new Memory database", function() {
var complete = false;
var _error, _result;
var provider = new IDBFS.Providers.Memory(this.db_name);
provider.open(function(err, firstAccess) {
_error = err;
_result = firstAccess;
complete = true;
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toEqual(null);
expect(_result).toEqual(true);
});
});
});
describe("Read/Write operations on an Memory provider", function() {
it("should allow put() and get()", function() {
var complete = false;
var _error, _result;
var provider = new IDBFS.Providers.Memory(this.db_name);
provider.open(function(err, firstAccess) {
_error = err;
var context = provider.getReadWriteContext();
context.put("key", "value", function(err, result) {
_error = _error || err;
context.get("key", function(err, result) {
_error = _error || err;
_result = result;
complete = true;
});
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toEqual(null);
expect(_result).toEqual("value");
});
});
it("should allow delete()", function() {
var complete = false;
var _error, _result;
var provider = new IDBFS.Providers.Memory(this.db_name);
provider.open(function(err, firstAccess) {
_error = err;
var context = provider.getReadWriteContext();
context.put("key", "value", function(err, result) {
_error = _error || err;
context.delete("key", function(err, result) {
_error = _error || err;
context.get("key", function(err, result) {
_error = _error || err;
_result = result;
complete = true;
});
});
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toEqual(null);
expect(_result).toEqual(null);
});
});
it("should allow clear()", function() {
var complete = false;
var _error, _result1, _result2;
var provider = new IDBFS.Providers.Memory(this.db_name);
provider.open(function(err, firstAccess) {
_error = err;
var context = provider.getReadWriteContext();
context.put("key1", "value1", function(err, result) {
_error = _error || err;
context.put("key2", "value2", function(err, result) {
_error = _error || err;
context.clear(function(err) {
_error = _error || err;
context.get("key1", function(err, result) {
_error = _error || err;
_result1 = result;
context.get("key2", function(err, result) {
_error = _error || err;
_result2 = result;
complete = true;
});
});
});
});
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toEqual(null);
expect(_result1).toEqual(null);
expect(_result2).toEqual(null);
});
});
it("should fail when trying to write on ReadOnlyContext", function() {
var complete = false;
var _error, _result;
var provider = new IDBFS.Providers.Memory(this.db_name);
provider.open(function(err, firstAccess) {
_error = err;
var context = provider.getReadOnlyContext();
context.put("key1", "value1", function(err, result) {
_error = _error || err;
_result = result;
complete = true;
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toBeDefined();
expect(_result).toEqual(null);
});
});
});
});

View File

@ -0,0 +1,18 @@
describe("IDBFS.Providers", function() {
it("is defined", function() {
expect(typeof IDBFS.Providers).not.toEqual(undefined);
});
it("has IndexedDB constructor", function() {
expect(typeof IDBFS.Providers.IndexedDB).toEqual('function');
});
it("has Memory constructor", function() {
expect(typeof IDBFS.Providers.Memory).toEqual('function');
});
it("has a Default constructor", function() {
expect(typeof IDBFS.Providers.Default).toEqual('function');
});
});