// Helper routine.
function toString(obj) {
if (obj == undefined) {
return "undefined";
} else if (typeof obj == 'object') {
if (obj.length != undefined) {
var stringArray = [];
for (var i = 0; i < obj.length; ++i)
stringArray.push(toString(obj[i]));
stringArray.sort();
return '[' + stringArray.join(',\n ') + ']';
} else if (obj.isDirectory || obj.isFile) {
return 'ENTRY {path:' + obj.fullPath + ' name:' + obj.name + (obj.isDirectory ? ' type:DIRECTORY' : ' type:FILE') + '}';
} else {
return obj + "";
}
} else
return obj + "";
}
// Creates a test environment for the given entries where entries is an array of {fullPath:String, isDirectory:boolean} object.
// When the world is created successfully, successCallback is called with an object that holds all the created entry objects.
function createTestEnvironment(fileSystem, entries, successCallback, errorCallback)
{
var Helper = function(fileSystem, entries, successCallback, errorCallback)
{
this.fileSystem = fileSystem;
this.entries = entries;
this.current = 0;
this.successCallback = successCallback;
this.errorCallback = errorCallback;
this.environment = {};
this.createSuccessCallback = function(entry, size)
{
if (entry.isFile && size > 0) {
entry.createWriter(bindCallback(this, function(writer) {
writer.truncate(size);
writer.onerror = bindCallback(this, this.createErrorCallback);
writer.onwriteend = bindCallback(this, function() {
this.environment[entry.fullPath] = entry;
this.environment[entry.fullPath + '.size'] = size;
this.createNextEntry();
});
}), bindCallback(this, this.createErrorCallback));
return;
}
this.environment[entry.fullPath] = entry;
this.environment[entry.fullPath + '.size'] = 0;
this.createNextEntry();
}
this.createErrorCallback = function(error, entry)
{
testFailed('Got unexpected error ' + error.name + ' while creating ' + toString(entry));
this.errorCallback(error);
}
this.createNextEntry = function()
{
if (this.current >= this.entries.length) {
this.successCallback(this.environment);
return;
}
var entry = this.entries[this.current++];
if (entry.isDirectory)
fileSystem.root.getDirectory(entry.fullPath, {create:true}, bindCallback(this, this.createSuccessCallback), bindCallback(this, this.createErrorCallback));
else
fileSystem.root.getFile(entry.fullPath, {create:true}, bindCallback(this, this.createSuccessCallback, entry.size), bindCallback(this, this.createErrorCallback));
};
};
if (!entries || !entries.length) {
successCallback({});
return;
}
var helper = new Helper(fileSystem, entries, successCallback, errorCallback);
helper.createNextEntry();
}
function verifyTestEnvironment(fileSystem, entries, successCallback, errorCallback)
{
var Helper = function(fileSystem, entries, successCallback, errorCallback)
{
this.fileSystem = fileSystem;
this.entries = entries;
this.current = 0;
this.successCallback = successCallback;
this.errorCallback = errorCallback;
this.expectedNonexistent = false;
this.verifySuccessCallback = function(entry)
{
if (this.expectedNonexistent) {
testFailed('Found unexpected entry ' + entry.fullPath);
this.errorCallback();
return;
}
testPassed('Verified entry: ' + toString(entry));
this.verifyNextEntry();
}
this.verifyErrorCallback = function(error, entry)
{
if (this.expectedNonexistent) {
testPassed('Verified entry does NOT exist: ' + entry.fullPath);
this.verifyNextEntry();
return;
}
if (error == 'NotFoundError')
testFailed('Not found: ' + entry.fullPath);
else
testFailed('Got unexpected error ' + error.name + ' for ' + entry.fullPath);
this.errorCallback(error);
}
this.verifyNextEntry = function()
{
if (this.current >= this.entries.length) {
this.successCallback();
return;
}
var entry = this.entries[this.current++];
this.expectedNonexistent = entry.nonexistent;
if (entry.isDirectory)
fileSystem.root.getDirectory(entry.fullPath, {}, bindCallback(this, this.verifySuccessCallback), bindCallback(this, this.verifyErrorCallback, entry));
else
fileSystem.root.getFile(entry.fullPath, {}, bindCallback(this, this.verifySuccessCallback), bindCallback(this, this.verifyErrorCallback, entry));
};
};
if (!entries || !entries.length) {
successCallback();
return;
}
var helper = new Helper(fileSystem, entries, successCallback, errorCallback);
helper.verifyNextEntry();
}
// testCase must have precondition, postcondition and test function field.
// (See resources/op-*.js for examples.)
function runOperationTest(fileSystem, testCase, successCallback, errorCallback)
{
var OperationTestHelper = function(fileSystem, testCase, successCallback, errorCallback)
{
this.fileSystem = fileSystem;
this.testCase = testCase;
this.successCallback = successCallback;
this.errorCallback = errorCallback;
this.stage = '';
this.environment = {};
this.currentTest = 0;
this.currentReader = null;
this.readEntries = [];
this.getSymbolString = function(symbol)
{
return 'this.environment["' + symbol + '"]';
};
this.testSuccessCallback = function()
{
if (!this.expectedError) {
testPassed('Succeeded: ' + this.stage);
this.runNextTest();
} else
testFailed('Unexpectedly succeeded while ' + this.stage);
};
this.entry = null;
this.testGetSuccessCallback = function(entry)
{
if (!this.expectedError) {
testPassed('Succeeded: ' + this.stage);
this.entry = entry;
shouldBe.apply(this, ['this.environment[this.entry.fullPath].fullPath', '"' + entry.fullPath + '"']);
shouldBe.apply(this, ['this.environment[this.entry.fullPath].isFile + ""', '"' + entry.isFile + '"']);
shouldBe.apply(this, ['this.environment[this.entry.fullPath].isDirectory + ""', '"' + entry.isDirectory + '"']);
this.runNextTest();
} else
testFailed('Unexpectedly succeeded while ' + this.stage);
};
this.testCreateSuccessCallback = function(entry)
{
if (!this.expectedError) {
testPassed('Succeeded: ' + this.stage);
this.environment[entry.fullPath] = entry;
this.runNextTest();
} else
testFailed('Unexpectedly succeeded while ' + this.stage);
};
this.testGetParentSuccessCallback = function(entry)
{
if (!this.expectedError) {
testPassed('Succeeded: ' + this.stage);
debug('Parent entry: ' + toString(entry));
this.runNextTest();
} else
testFailed('Unexpectedly succeeded while ' + this.stage);
};
this.testReadEntriesSuccessCallback = function(entries)
{
if (this.expectedError)
testFailed('Unexpectedly succeeded while ' + this.stage);
this.readEntries.push.apply(this.readEntries, entries);
if (entries.length) {
this.currentReader.readEntries(bindCallback(this, this.testReadEntriesSuccessCallback), bindCallback(this, this.testErrorCallback));
return;
}
testPassed('Succeeded: ' + this.stage);
debug('Entries: ' + toString(this.readEntries));
this.runNextTest();
};
this.testMetadataSuccessCallback = function(metadata, entry)
{
if (!this.expectedError) {
testPassed('Succeeded: ' + this.stage);
var symbol = entry + '.returned.modificationTime';
this.environment[symbol] = metadata.modificationTime;
var entryMetadataString = this.getSymbolString(symbol);
if (entry != '/') {
shouldBeGreaterThanOrEqual.apply(this, [entryMetadataString, 'this.roundedStartDate']);
}
if (metadata.size) {
this.environment[entry + '.returned.size'] = metadata.size;
var entrySizeString = this.getSymbolString(entry + '.returned.size');
var expectedSizeString = this.getSymbolString(entry + '.size');
shouldBe.apply(this, [expectedSizeString, entrySizeString]);
}
this.runNextTest();
} else
testFailed('Unexpectedly succeeded while ' + this.stage);
};
this.testErrorCallback = function(error)
{
if (this.expectedError) {
shouldBe.apply(this, ['this.expectedError + ""', '"' + error.name + '"']);
this.runNextTest();
} else {
testFailed('Got unexpected error ' + error.name + ' while ' + this.stage);
this.errorCallback(error);
}
};
// Operations ---------------------------------------------------
this.getFile = function(entry, path, flags, expectedError)
{
this.expectedError = expectedError;
this.stage = '"' + entry + '".getFile("' + path + '")';
var successCallback = (flags && flags.create) ? this.testCreateSuccessCallback : this.testGetSuccessCallback;
this.environment[entry].getFile(path, flags, bindCallback(this, successCallback), bindCallback(this, this.testErrorCallback));
};
this.getDirectory = function(entry, path, flags, expectedError)
{
this.expectedError = expectedError;
this.stage = '"' + entry + '".getDirectory("' + path + '")';
var successCallback = (flags && flags.create) ? this.testCreateSuccessCallback : this.testGetSuccessCallback;
this.environment[entry].getDirectory(path, flags, bindCallback(this, successCallback), bindCallback(this, this.testErrorCallback));
};
this.getParent = function(entry, expectedError)
{
this.expectedError = expectedError;
this.stage = '"' + entry + '".getParent()';
this.environment[entry].getParent(bindCallback(this, this.testGetParentSuccessCallback), bindCallback(this, this.testErrorCallback));
};
this.getMetadata = function(entry, expectedError)
{
this.expectedError = expectedError;
this.stage = '"' + entry + '".getMetadata()';
this.environment[entry].getMetadata(bindCallback(this, this.testMetadataSuccessCallback, entry), bindCallback(this, this.testErrorCallback));
};
this.remove = function(entry, expectedError)
{
this.expectedError = expectedError;
this.stage = '"' + entry + '".remove()';
this.environment[entry].remove(bindCallback(this, this.testSuccessCallback), bindCallback(this, this.testErrorCallback));
};
this.removeRecursively = function(entry, expectedError)
{
this.expectedError = expectedError;
this.stage = '"' + entry + '".removeRecursively()';
this.environment[entry].removeRecursively(bindCallback(this, this.testSuccessCallback), bindCallback(this, this.testErrorCallback));
};
this.readDirectory = function(entry, expectedError)
{
this.expectedError = expectedError;
this.readEntries = [];
this.stage = '"' + entry + '".createReader().readEntries()';
this.currentReader = this.environment[entry].createReader();
this.currentReader.readEntries(bindCallback(this, this.testReadEntriesSuccessCallback), bindCallback(this, this.testErrorCallback));
};
this.copy = function(entry, destinationParent, newName, expectedError)
{
this.expectedError = expectedError;
this.stage = '"' + entry + '".copyTo("' + destinationParent + '", "' + newName + '")';
this.environment[entry].copyTo(this.environment[destinationParent], newName, bindCallback(this, this.testSuccessCallback), bindCallback(this, this.testErrorCallback));
};
this.move = function(entry, destinationParent, newName, expectedError)
{
this.expectedError = expectedError;
this.stage = '"' + entry + '".moveTo("' + destinationParent + '", "' + newName + '")';
this.environment[entry].moveTo(this.environment[destinationParent], newName, bindCallback(this, this.testSuccessCallback), bindCallback(this, this.testErrorCallback));
};
this.shouldBe = function(symbol1, symbol2)
{
shouldBe.apply(this, [this.getSymbolString(symbol1), this.getSymbolString(symbol2)]);
this.runNextTest();
};
this.shouldBeGreaterThanOrEqual = function(symbol1, symbol2)
{
shouldBeGreaterThanOrEqual.apply(this, [this.getSymbolString(symbol1), this.getSymbolString(symbol2)]);
this.runNextTest();
};
//---------------------------------------------------------------
this.start = function()
{
this.expectedError = '';
this.stage = 'resetting filesystem';
// Record rounded start date (current time minus 999 msec) here for the comparison. Entry.getMetadata() may return the last mod time in seconds accuracy while new Date() is milliseconds accuracy.
this.roundedStartDate = new Date((new Date()).getTime() - 999);
removeAllInDirectory(this.fileSystem.root, bindCallback(this, this.setUp), bindCallback(this, this.testErrorCallback));
};
this.setUp = function()
{
this.expectedError = '';
this.stage = 'setting up test precondition';
createTestEnvironment(this.fileSystem, this.testCase.precondition, bindCallback(this, this.runTests), bindCallback(this, this.testErrorCallback));
};
this.runNextTest = function()
{
if (this.currentTest >= this.testCase.tests.length) {
this.verify();
return;
}
this.testCase.tests[this.currentTest++](this);
};
this.runTests = function(environment)
{
this.environment = environment;
this.environment['/'] = this.fileSystem.root;
this.currentTest = 0;
this.runNextTest();
};
this.verify = function()
{
this.expectedError = '';
if (!this.testCase.postcondition) {
this.successCallback();
return;
}
this.stage = 'verifying test postcondition';
verifyTestEnvironment(this.fileSystem, this.testCase.postcondition, this.successCallback, bindCallback(this, this.testErrorCallback));
};
};
var helper = new OperationTestHelper(fileSystem, testCase, successCallback, errorCallback);
helper.start();
}
var currentTest = 0;
var fileSystem = null;
function runNextTest() {
if (currentTest >= testCases.length) {
debug('Finished running tests.');
finishJSTest();
return;
}
var testCase = testCases[currentTest++];
debug('* Running: ' + testCase.name);
runOperationTest(fileSystem, testCase, runNextTest, errorCallback);
}
function errorCallback(error) {
if (error && error.name)
testFailed('Got error ' + error.name);
finishJSTest();
}
function fileSystemCallback(fs)
{
fileSystem = fs;
runNextTest();
}
var jsTestIsAsync = true;
webkitRequestFileSystem(TEMPORARY, 100, fileSystemCallback, errorCallback);