chromium/chrome/test/data/extensions/api_test/file_browser/file_browser_handler_lazy/background.js

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * This extension provides two file browser handlers: 'ReadOnly' and
 * 'ReadWrite'. 'ReadOnly' handler handles .xul files and has read-only file
 * access. 'ReadWrite' handler handles .tiff files and has read-write file
 * access. The extension does not have persistent background page.
 *
 * The extension waits until 'ReadWrite' handler is executed and then runs tests
 * for it. The tests verify that the extension is able to read and write the
 * handled file. If there is an error before the tests are run,
 * chrome.test.notifyFail will be called, and further onExecute events will be
 * ignored.
 *
 * 'ReadOnly' handler is ignored by this test extension, but it must be defined
 * to conform to the expectations of file_browser/handler_test_runner
 *
 * The handlers are executed by 'file_browser/handler_test_runner' extension.
 * 'ReadWrite' handler are executed once, and should carry exactly one  handled
 * file.
 */

// Initial content of handled files. The content is set in
// external_filesystem_apitest.cc.
var kInitialTestFileContent = 'This is some test content.';
// Content written by write test.
var kTextToWrite = ' Yay!';

/**
 * Asserts that |value| equals |expectedValue|. If the assert fails, current
 * test fails with |errorMessage|. Otherwise, |callback()| is called.
 */
function assertEqAndRunCallback(expectedValue, value, errorMessage, callback) {
  chrome.test.assertEq(expectedValue, value, errorMessage);
  callback();
}

/**
 * Attempts to read file and asserts that the read success and file content are
 * as expected (|expectSuccess|, |expectedContent|). On success |callback| is
 * called, otherwise current test is failed.
 *
 * @param {FileEntry} entry Entry to be read.
 * @param {boolean} expectSuccess Whether the read should succeed.
 * @param {string} expectedContent If the read succeeds, the expected content to
 *     be read from file. If the read fails, it is ignored.
 * @param {function()} callback Function called if the read ends as defined by
 *     |expectSuccess| and |expectedContent|.
 */
function readAndExpectContent(entry, expectSuccess, expectedContent, callback) {
  var error = 'Reading file \'' + entry.fullPath + '\'.';
  var reader = new FileReader();

  reader.onload = function() {
    chrome.test.assertTrue(expectSuccess, error);
    assertEqAndRunCallback(expectedContent, reader.result, error, callback);
  };

  entry.file(reader.readAsText.bind(reader),
             assertEqAndRunCallback.bind(null,
                 false, expectSuccess, error, callback));
};

/**
 * Attempts to write |content| to the end of the |entry| and verifies that the
 * operation success is as expected. On success |callback| is called, else the
 * current test is failed.
 *
 * @param {FileEntry} entry File entry to be read.
 * @param {string} content String content to be appended to the file.
 * @param {boolean} expectSuccess Whether the write should succeed.
 * @param {function()} callback Function called if write ends as defined by
 *     |expectSuccess|.
 */
function write(entry, content, expectSuccess, callback) {
  var error = 'Writing to: \'' + entry.fullPath + '\'.';

  entry.createWriter(function(writer) {
    writer.onerror = assertEqAndRunCallback.bind(null, expectSuccess, false,
                                                 error, callback);
    writer.onwrite = assertEqAndRunCallback.bind(null, expectSuccess, true,
                                                 error, callback);

    writer.seek(kInitialTestFileContent.length);
    var blob = new Blob([kTextToWrite], {type: 'text/plain'});
    writer.write(blob);
  },
  assertEqAndRunCallback.bind(null, expectSuccess, false,
      'Getting writer for: \'' + entry.fullPath + '\'.', callback));
};

/**
 * Runs read test.
 *
 * @params {FileEntry} entry File entry for which the test should be run.
 * @params {boolean} expectSuccess Whether the read should succeed.
 */
function readTest(entry, expectSuccess) {
  readAndExpectContent(entry, expectSuccess, kInitialTestFileContent,
                       chrome.test.succeed)
}

/**
 * Runs test for a file that is not executed for any handler. Test tries to get
 * an existing file entry from the |entry|'s filesystem. The file path is
 * constructed by appending '.foo' to the |entry|'s path (the Chrome part of the
 * test should ensure that the file exists). The get operation is expected to
 * fail.
 */
function getSiblingTest(entry) {
  var error = 'Got file (\'' + entry.fullPath.concat('.foo') + '\') for which' +
              'file access was not granted.';
  entry.filesystem.root.getFile(entry.fullPath.concat('.foo'), {},
                                function (entry) { chrome.test.fail(error); },
                                chrome.test.succeed);
}

/**
 * Runs write test.
 * Attempts to write to the entry. If the write operation ends as expected, the
 * test verifies new content of the file.
 *
 * @param {FileEntry} entry Entry to be written.
 * @param {boolean} expectSuccess Whether the test should succeed.
 */
function writeTest(entry, expectSuccess) {
  var verifyFileContent = function() {
    var expectedContent = kInitialTestFileContent;
    if (expectSuccess)
      expectedContent = expectedContent.concat(kTextToWrite);

    readAndExpectContent(entry, true, expectedContent, chrome.test.succeed);
  };

  write(entry, kTextToWrite, expectSuccess, verifyFileContent);
}

/**
 * Listens for onExecute events, and runs tests once the event for 'ReadWrite'
 * handler is received.
 */
function executeListener(id, details) {
  if (id == 'ReadWrite') {
    var fileEntries = details.entries;
    if (!fileEntries || fileEntries.length != 1) {
      chrome.test.notifyFail('Unexpected file entries size.');
      return;
    }

    var entry = fileEntries[0];

    // Run tests for read-write handler.
    chrome.test.runTests([
        function readReadWrite() {
          readTest(entry, true);
        },
        function getSilblingReadWrite() {
          getSiblingTest(entry);
        },
        function writeReadWrite() {
          writeTest(entry, true);
        },
    ]);
  } else if (id != 'ReadOnly') {
    chrome.test.notifyFail('Unexpected action id: ' + id);
    return;
  }
}

chrome.fileBrowserHandler.onExecute.addListener(executeListener);