/* 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/. */
"use strict";

add_task(async function test_create_error() {
  // lastError is the only means to communicate errors in the menus.create API,
  // so make sure that a warning is logged to the console if the error is not
  // checked.
  let waitForConsole = new Promise(resolve => {
    SimpleTest.waitForExplicitFinish();
    SimpleTest.monitorConsole(resolve, [
      // Callback exists, lastError is checked. Should not be logged.
      {
        message: /Unchecked lastError value: Error: ID already exists: some_id/,
        forbid: true,
      },
      // No callback, lastError not checked. Should be logged.
      {
        message:
          /Unchecked lastError value: Error: Cannot find menu item with id noCb/,
      },
      // Callback exists, lastError not checked. Should be logged.
      {
        message:
          /Unchecked lastError value: Error: Cannot find menu item with id cbIgnoreError/,
      },
    ]);
  });

  async function background() {
    // Note: browser.menus.create returns the menu ID instead of a promise, so
    // we have to use callbacks.
    await new Promise(resolve => {
      browser.menus.create({ id: "some_id", title: "menu item" }, () => {
        browser.test.assertEq(
          null,
          browser.runtime.lastError,
          "Expected no error"
        );
        resolve();
      });
    });

    // Callback exists, lastError is checked:
    await new Promise(resolve => {
      browser.menus.create({ id: "some_id", title: "menu item" }, () => {
        browser.test.assertEq(
          "ID already exists: some_id",
          browser.runtime.lastError.message,
          "Expected error"
        );
        resolve();
      });
    });

    // No callback, lastError not checked:
    browser.menus.create({ id: "noCb", parentId: "noCb", title: "menu item" });

    // Callback exists, lastError not checked:
    await new Promise(resolve => {
      browser.menus.create(
        { id: "cbIgnoreError", parentId: "cbIgnoreError", title: "menu item" },
        () => {
          resolve();
        }
      );
    });

    // Do another roundtrip with the menus API to ensure that any console
    // error messages from the previous call are flushed.
    await browser.menus.removeAll();

    browser.test.sendMessage("done");
  }

  const extension = ExtensionTestUtils.loadExtension({
    manifest: { permissions: ["menus"] },
    background,
  });
  await extension.startup();
  await extension.awaitMessage("done");

  await extension.unload();

  SimpleTest.endMonitorConsole();
  await waitForConsole;
});

add_task(async function test_update_error() {
  async function background() {
    const id = browser.menus.create({ title: "menu item" });

    await browser.test.assertRejects(
      browser.menus.update(id, { parentId: "bogus" }),
      "Cannot find menu item with id bogus",
      "menus.update with invalid parentMenuId should fail"
    );

    await browser.test.assertRejects(
      browser.menus.update(id, { parentId: id }),
      "MenuItem cannot be an ancestor (or self) of its new parent.",
      "menus.update cannot assign itself as the parent of a menu."
    );

    await browser.test.assertRejects(
      browser.menus.update("1234", { checked: true }),
      "Cannot find menu item with id 1234",
      "menus.update with invalid menuItemId should fail"
    );

    browser.test.sendMessage("done");
  }

  const extension = ExtensionTestUtils.loadExtension({
    manifest: { permissions: ["menus"] },
    background,
  });
  await extension.startup();
  await extension.awaitMessage("done");
  await extension.unload();
});

add_task(async function test_remove_error() {
  async function background() {
    await browser.test.assertRejects(
      browser.menus.remove("1234"),
      "Cannot find menu item with id 1234",
      "menus.remove with invalid menuItemId should fail"
    );

    browser.test.sendMessage("done");
  }

  const extension = ExtensionTestUtils.loadExtension({
    manifest: { permissions: ["menus"] },
    background,
  });
  await extension.startup();
  await extension.awaitMessage("done");
  await extension.unload();
});

add_task(async function test_invalid_documentUrlPatterns() {
  const extension = ExtensionTestUtils.loadExtension({
    manifest: {
      permissions: ["menus"],
    },
    async background() {
      await new Promise(resolve => {
        browser.menus.create(
          {
            title: "invalid url",
            contexts: ["tab"],
            documentUrlPatterns: ["test1"],
          },
          () => {
            browser.test.assertEq(
              "Invalid url pattern: test1",
              browser.runtime.lastError.message,
              "Expected invalid match pattern"
            );
            resolve();
          }
        );
      });
      await new Promise(resolve => {
        browser.menus.create(
          {
            title: "invalid url",
            contexts: ["link"],
            targetUrlPatterns: ["test2"],
          },
          () => {
            browser.test.assertEq(
              "Invalid url pattern: test2",
              browser.runtime.lastError.message,
              "Expected invalid match pattern"
            );
            resolve();
          }
        );
      });
      browser.test.sendMessage("done");
    },
  });
  await extension.startup();
  await extension.awaitMessage("done");
  await extension.unload();
});
