chromium/chrome/test/data/extensions/api_test/file_system_provider/big_file/test.js

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

'use strict';

/**
 * @type {DOMFileSystem}
 */
var fileSystem = null;

/**
 * Map of opened files, from a <code>openRequestId</code> to <code>filePath
 * </code>.
 * @type {Object<number, string>}
 */
var openedFiles = {};

/**
 * @type {string}
 * @const
 */
var TESTING_TEXT = 'We are bytes at the 5th GB of the file!';

/**
 * @type {number}
 * @const
 */
var TESTING_TEXT_OFFSET = 5 * 1000 * 1000 * 1000;

/**
 * Metadata for a testing file with 6GB file size.
 * @type {Object}
 * @const
 */
var TESTING_6GB_FILE = Object.freeze({
  isDirectory: false,
  name: '6gb.txt',
  size: 6 * 1024 * 1024 * 1024,
  modificationTime: new Date(2014, 1, 25, 7, 36, 12)
});

/**
 * Requests opening a file at <code>filePath</code>. Further file operations
 * will be associated with the <code>requestId</code>
 *
 * @param {OpenFileRequestedOptions} options Options.
 * @param {function()} onSuccess Success callback.
 * @param {function(string)} onError Error callback.
 */
function onOpenFileRequested(options, onSuccess, onError) {
  if (options.fileSystemId !== test_util.FILE_SYSTEM_ID) {
    onError('INVALID_OPERATION');  // enum ProviderError.
    return;
  }

  if (options.mode !== 'READ') {
    onError('ACCESS_DENIED');  // enum ProviderError.
    return;
  }

  if (options.filePath !== '/' + TESTING_6GB_FILE.name) {
    onError('NOT_FOUND');  // enum ProviderError.
    return;
  }

  openedFiles[options.requestId] = options.filePath;
  onSuccess();
}

/**
 * Requests closing a file previously opened with <code>openRequestId</code>.
 *
 * @param {CloseFileRequestedOptions} options Options.
 * @param {function()} onSuccess Success callback.
 * @param {function(string)} onError Error callback.
 */
function onCloseFileRequested(options, onSuccess, onError) {
  if (options.fileSystemId !== test_util.FILE_SYSTEM_ID ||
      !openedFiles[options.openRequestId]) {
    onError('INVALID_OPERATION');  // enum ProviderError.
    return;
  }

  delete openedFiles[options.openRequestId];
  onSuccess();
}

/**
 * Requests reading contents of a file, previously opened with <code>
 * openRequestId</code>.
 *
 * @param {ReadFileRequestedOptions} options Options.
 * @param {function(ArrayBuffer, boolean)} onSuccess Success callback with a
 *     chunk of data, and information if more data will be provided later.
 * @param {function(string)} onError Error callback.
 */
function onReadFileRequested(options, onSuccess, onError) {
  var filePath = openedFiles[options.openRequestId];
  if (options.fileSystemId !== test_util.FILE_SYSTEM_ID || !filePath) {
    onError('INVALID_OPERATION');  // enum ProviderError.
    return;
  }

  if (filePath === '/' + TESTING_6GB_FILE.name) {
    if (options.offset < TESTING_TEXT_OFFSET ||
        options.offset >= TESTING_TEXT_OFFSET + TESTING_TEXT.length) {
      console.error('Reading from a wrong location in the file!');
      onError('FAILED');  // enum ProviderError.
      return;
    }

    var buffer = TESTING_TEXT.substr(
        options.offset - TESTING_TEXT_OFFSET, options.length);
    var reader = new FileReader();
    reader.onload = function(e) {
      onSuccess(e.target.result, false /* hasMore */);
    };
    reader.readAsArrayBuffer(new Blob([buffer]));
    return;
  }

  onError('INVALID_OPERATION');  // enum ProviderError.
}

/**
 * Sets up the tests. Called once per all test cases. In case of a failure,
 * the callback is not called.
 *
 * @param {function()} callback Success callback.
 */
function setUp(callback) {
  chrome.fileSystemProvider.onGetMetadataRequested.addListener(
      test_util.onGetMetadataRequestedDefault);

  test_util.defaultMetadata['/' + TESTING_6GB_FILE.name] =
      TESTING_6GB_FILE;

  chrome.fileSystemProvider.onOpenFileRequested.addListener(
      onOpenFileRequested);
  chrome.fileSystemProvider.onReadFileRequested.addListener(
      onReadFileRequested);
  chrome.fileSystemProvider.onCloseFileRequested.addListener(
      onCloseFileRequested);

  test_util.mountFileSystem(callback);
}

/**
 * Runs all of the test cases, one by one.
 */
function runTests() {
  chrome.test.runTests([
    // Read contents of a new file, which is 6GB in size. Such size does not
    // fit in a 32bit int nor in size_t (unsigned). It should be safe to assume,
    // that if 6GB are supported, then there is no 32bit bottle neck, and the
    // next one would be 64bit. File System Provider API should support files
    // with size greater or equal to 2^53.
    function readBigFileSuccess() {
      test_util.fileSystem.root.getFile(
          TESTING_6GB_FILE.name,
          {create: false},
          chrome.test.callbackPass(function(fileEntry) {
            fileEntry.file(chrome.test.callbackPass(function(file) {
              // Read 10 bytes from the 5th GB.
              var fileSlice =
                  file.slice(TESTING_TEXT_OFFSET,
                             TESTING_TEXT_OFFSET + TESTING_TEXT.length);
              var fileReader = new FileReader();
              fileReader.onload = chrome.test.callbackPass(function(e) {
                var text = fileReader.result;
                chrome.test.assertEq(TESTING_TEXT, text);
              });
              fileReader.onerror = function(e) {
                chrome.test.fail(fileReader.error.name);
              };
              fileReader.readAsText(fileSlice);
            }),
            function(error) {
              chrome.test.fail(error.name);
            });
          }),
          function(error) {
            chrome.test.fail(error.name);
          });
    }
  ]);
}

// Setup and run all of the test cases.
setUp(runTests);