/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "unusedVariable", caughtErrors: "none" }] */

function run_test() {
  test1();
  test2();
  test3();
  test4();
}

/**
 * Checks that getting an input stream from a storage stream which has never had
 * anything written to it throws a not-initialized exception.
 */
function test1() {
  var ss = Cc["@mozilla.org/storagestream;1"].createInstance(
    Ci.nsIStorageStream
  );
  ss.init(1024, 1024, null);

  var unusedVariable = ss.getOutputStream(0);
  var inp2 = ss.newInputStream(0);
  Assert.equal(inp2.available(), 0);
  Assert.ok(inp2.isNonBlocking());

  var sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
    Ci.nsIScriptableInputStream
  );
  sis.init(inp2);

  var threw = false;
  try {
    sis.read(1);
  } catch (ex) {
    if (ex.result == Cr.NS_BASE_STREAM_WOULD_BLOCK) {
      threw = true;
    } else {
      throw ex;
    }
  }
  Assert.ok(threw);
}

/**
 * Checks that getting an input stream from a storage stream to which 0 bytes of
 * data have been explicitly written doesn't throw an exception.
 */
function test2() {
  var ss = Cc["@mozilla.org/storagestream;1"].createInstance(
    Ci.nsIStorageStream
  );
  ss.init(1024, 1024, null);

  var out = ss.getOutputStream(0);
  out.write("", 0);
  try {
    ss.newInputStream(0);
  } catch (e) {
    do_throw("shouldn't throw exception when new input stream created");
  }
}

/**
 * Checks that reading any non-zero amount of data from a storage stream
 * which has had 0 bytes written to it explicitly works correctly.
 */
function test3() {
  var ss = Cc["@mozilla.org/storagestream;1"].createInstance(
    Ci.nsIStorageStream
  );
  ss.init(1024, 1024, null);

  var out = ss.getOutputStream(0);
  out.write("", 0);
  try {
    var inp = ss.newInputStream(0);
  } catch (e) {
    do_throw("newInputStream(0) shouldn't throw if write() is called: " + e);
  }

  Assert.ok(inp.isNonBlocking(), "next test expects a non-blocking stream");

  try {
    var threw = false;
    var bis = BIS(inp);
    bis.readByteArray(5);
  } catch (e) {
    if (e.result != Cr.NS_BASE_STREAM_WOULD_BLOCK) {
      do_throw("wrong error thrown: " + e);
    }
    threw = true;
  }
  Assert.ok(threw, "should have thrown (nsStorageInputStream is nonblocking)");
}

/**
 * Basic functionality test for storagestream: write data to it, get an input
 * stream, and read the data back to see that it matches.
 */
function test4() {
  var bytes = [65, 66, 67, 68, 69, 70, 71, 72, 73, 74];

  var ss = Cc["@mozilla.org/storagestream;1"].createInstance(
    Ci.nsIStorageStream
  );
  ss.init(1024, 1024, null);

  var outStream = ss.getOutputStream(0);

  var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(
    Ci.nsIBinaryOutputStream
  );
  bos.setOutputStream(outStream);

  bos.writeByteArray(bytes);
  bos.close();

  var inp = ss.newInputStream(0);
  var bis = BIS(inp);

  var count = 0;
  while (count < bytes.length) {
    var data = bis.read8(1);
    Assert.equal(data, bytes[count++]);
  }

  var threw = false;
  try {
    data = bis.read8(1);
  } catch (e) {
    if (e.result != Cr.NS_ERROR_FAILURE) {
      do_throw("wrong error thrown: " + e);
    }
    threw = true;
  }
  if (!threw) {
    do_throw("should have thrown but instead returned: '" + data + "'");
  }
}

function BIS(input) {
  var bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
    Ci.nsIBinaryInputStream
  );
  bis.setInputStream(input);
  return bis;
}
