const TEST_PAGE =
  "https://example.org/browser/browser/base/content/test/general/dummy_page.html";
const TEST_REFERRER = "http://mochi.test:8888/";

const ReferrerInfo = Components.Constructor(
  "@mozilla.org/referrer-info;1",
  "nsIReferrerInfo",
  "init"
);

let referrerInfo = new ReferrerInfo(
  Ci.nsIReferrerInfo.ORIGIN,
  true,
  Services.io.newURI(TEST_REFERRER)
);
let deReferrerInfo = E10SUtils.serializeReferrerInfo(referrerInfo);

var checkResult = async function (isRemote, browserKey, uri) {
  is(
    gBrowser.selectedBrowser.isRemoteBrowser,
    isRemote,
    "isRemoteBrowser should be correct"
  );

  is(
    gBrowser.selectedBrowser.permanentKey,
    browserKey,
    "browser.permanentKey should be correct"
  );

  if (SpecialPowers.Services.appinfo.sessionHistoryInParent) {
    let sessionHistory =
      gBrowser.selectedBrowser.browsingContext.sessionHistory;
    let entry = sessionHistory.getEntryAtIndex(sessionHistory.count - 1);
    let args = { uri, referrerInfo: deReferrerInfo, isRemote };
    Assert.equal(entry.URI.spec, args.uri, "Uri should be correct");

    // Main process like about:mozilla does not trigger the real network request.
    // So we don't store referrerInfo in sessionHistory in that case.
    // Besides, the referrerInfo stored in sessionHistory was computed, we only
    // check pre-computed things.
    if (args.isRemote) {
      let resultReferrerInfo = entry.referrerInfo;
      let expectedReferrerInfo = E10SUtils.deserializeReferrerInfo(
        args.referrerInfo
      );

      Assert.equal(
        resultReferrerInfo.originalReferrer.spec,
        expectedReferrerInfo.originalReferrer.spec,
        "originalReferrer should be correct"
      );
      Assert.equal(
        resultReferrerInfo.sendReferrer,
        expectedReferrerInfo.sendReferrer,
        "sendReferrer should be correct"
      );
      Assert.equal(
        resultReferrerInfo.referrerPolicy,
        expectedReferrerInfo.referrerPolicy,
        "referrerPolicy should be correct"
      );
    } else {
      Assert.equal(entry.referrerInfo, null, "ReferrerInfo should be correct");
    }

    return;
  }

  await SpecialPowers.spawn(
    gBrowser.selectedBrowser,
    [{ uri, referrerInfo: deReferrerInfo, isRemote }],
    async function (args) {
      let webNav = content.docShell.QueryInterface(Ci.nsIWebNavigation);
      let sessionHistory = webNav.sessionHistory;
      let entry = sessionHistory.legacySHistory.getEntryAtIndex(
        sessionHistory.count - 1
      );

      var { E10SUtils } = SpecialPowers.ChromeUtils.importESModule(
        "resource://gre/modules/E10SUtils.sys.mjs"
      );

      Assert.equal(entry.URI.spec, args.uri, "Uri should be correct");

      // Main process like about:mozilla does not trigger the real network request.
      // So we don't store referrerInfo in sessionHistory in that case.
      // Besides, the referrerInfo stored in sessionHistory was computed, we only
      // check pre-computed things.
      if (args.isRemote) {
        let resultReferrerInfo = entry.referrerInfo;
        let expectedReferrerInfo = E10SUtils.deserializeReferrerInfo(
          args.referrerInfo
        );

        Assert.equal(
          resultReferrerInfo.originalReferrer.spec,
          expectedReferrerInfo.originalReferrer.spec,
          "originalReferrer should be correct"
        );
        Assert.equal(
          resultReferrerInfo.sendReferrer,
          expectedReferrerInfo.sendReferrer,
          "sendReferrer should be correct"
        );
        Assert.equal(
          resultReferrerInfo.referrerPolicy,
          expectedReferrerInfo.referrerPolicy,
          "referrerPolicy should be correct"
        );
      } else {
        Assert.equal(
          entry.referrerInfo,
          null,
          "ReferrerInfo should be correct"
        );
      }
    }
  );
};
var waitForLoad = async function (uri) {
  info("waitForLoad " + uri);
  let loadURIOptions = {
    triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
    referrerInfo,
  };
  gBrowser.selectedBrowser.webNavigation.loadURI(
    Services.io.newURI(uri),
    loadURIOptions
  );

  await BrowserTestUtils.browserStopped(gBrowser, uri);
};

// Tests referrerInfo when navigating from a page in the remote process to main
// process and vice versa.
add_task(async function test_navigation() {
  // Navigate from non remote to remote
  gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank");
  let testURI = TEST_PAGE;
  let { permanentKey } = gBrowser.selectedBrowser;
  await waitForLoad(testURI);
  await checkResult(true, permanentKey, testURI);
  gBrowser.removeCurrentTab();

  // Navigate from remote to non-remote
  gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TEST_PAGE);
  // Wait for the non-blank page to finish loading
  await BrowserTestUtils.browserStopped(gBrowser, TEST_PAGE);
  testURI = "about:mozilla";
  permanentKey = gBrowser.selectedBrowser.permanentKey;
  await waitForLoad(testURI);
  await checkResult(false, permanentKey, testURI);

  gBrowser.removeCurrentTab();
});
