/* Any copyright is dedicated to the Public Domain.
 http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

/*
 * Test loading inline scripts from cache:
 *   - Load document with inline script
 *   - Reload inside debugger with toolbox caching disabled
 *   - Reload inside debugger with toolbox caching enabled
 */

const server = createTestHTTPServer();

let docValue = 1;
server.registerPathHandler("/inline-cache.html", (request, response) => {
  response.setHeader("Content-Type", "text/html");
  // HTTP should assume cacheable by default.
  // Toolbox defaults to disabling cache for subsequent loads when open.
  response.setHeader("Cache-Control", "public, max-age=3600");
  response.write(`
    <html>
    <head>
    <script>
      let x = ${docValue};
    </script>
    </head>
    </html>
  `);
});

const SOURCE_URL = `http://localhost:${
  server.identity.primaryPort
}/inline-cache.html`;

/**
 * This is meant to simulate the developer editing the inline source and saving.
 * Effectively, we change the source during the test at specific controlled points.
 */
function makeChanges() {
  docValue++;
}

function getPageValue(tab) {
  return ContentTask.spawn(tab.linkedBrowser, {}, function() {
    return content.document.querySelector("script").textContent.trim();
  });
}

async function reloadTabAndDebugger(tab, dbg) {
  let navigated = waitForDispatch(dbg, "NAVIGATE");
  let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
  await reload(dbg, "inline-cache.html");
  return Promise.all([navigated, loaded]);
}

add_task(async function() {
  info("Load document with inline script");
  const tab = await addTab(SOURCE_URL);
  info("Open debugger");
  clearDebuggerPreferences();
  const toolbox = await openToolboxForTab(tab, "jsdebugger");
  const dbg = createDebuggerContext(toolbox);
  info("Reload tab to ensure debugger finds script");
  await reloadTabAndDebugger(tab, dbg);
  let pageValue = await getPageValue(tab);
  is(pageValue, "let x = 1;", "Content loads from network, has doc value 1");
  await waitForSource(dbg, "inline-cache.html");
  await selectSource(dbg, "inline-cache.html");
  await waitForLoadedSource(dbg, "inline-cache.html");
  let dbgValue = await findSource(dbg, "inline-cache.html");
  info(`Debugger text: ${dbgValue.text}`);
  ok(
    dbgValue.text.includes(pageValue),
    "Debugger loads from cache, gets value 1 like page"
  );

  info("Disable HTTP cache for page");
  await toolbox.target.activeTab.reconfigure({ cacheDisabled: true });
  makeChanges();

  info("Reload inside debugger with toolbox caching disabled (attempt 1)");
  await reloadTabAndDebugger(tab, dbg);
  pageValue = await getPageValue(tab);
  is(pageValue, "let x = 2;", "Content loads from network, has doc value 2");
  await waitForLoadedSource(dbg, "inline-cache.html");
  dbgValue = await findSource(dbg, "inline-cache.html");
  info(`Debugger text: ${dbgValue.text}`);
  ok(
    dbgValue.text.includes(pageValue),
    "Debugger loads from network, gets value 2 like page"
  );

  makeChanges();

  info("Reload inside debugger with toolbox caching disabled (attempt 2)");
  await reloadTabAndDebugger(tab, dbg);
  pageValue = await getPageValue(tab);
  is(pageValue, "let x = 3;", "Content loads from network, has doc value 3");
  await waitForLoadedSource(dbg, "inline-cache.html");
  dbgValue = await findSource(dbg, "inline-cache.html");
  info(`Debugger text: ${dbgValue.text}`);
  ok(
    dbgValue.text.includes(pageValue),
    "Debugger loads from network, gets value 3 like page"
  );

  info("Enable HTTP cache for page");
  await toolbox.target.activeTab.reconfigure({ cacheDisabled: false });
  makeChanges();

  // Even though the HTTP cache is now enabled, Gecko sets the VALIDATE_ALWAYS flag when
  // reloading the page.  So, it will always make a request to the server for the main
  // document contents.

  info("Reload inside debugger with toolbox caching enabled (attempt 1)");
  await reloadTabAndDebugger(tab, dbg);
  pageValue = await getPageValue(tab);
  is(pageValue, "let x = 4;", "Content loads from network, has doc value 4");
  await waitForLoadedSource(dbg, "inline-cache.html");
  dbgValue = await findSource(dbg, "inline-cache.html");
  info(`Debugger text: ${dbgValue.text}`);
  ok(
    dbgValue.text.includes(pageValue),
    "Debugger loads from cache, gets value 4 like page"
  );

  makeChanges();

  info("Reload inside debugger with toolbox caching enabled (attempt 2)");
  await reloadTabAndDebugger(tab, dbg);
  pageValue = await getPageValue(tab);
  is(pageValue, "let x = 5;", "Content loads from network, has doc value 5");
  await waitForLoadedSource(dbg, "inline-cache.html");
  dbgValue = await findSource(dbg, "inline-cache.html");
  info(`Debugger text: ${dbgValue.text}`);
  ok(
    dbgValue.text.includes(pageValue),
    "Debugger loads from cache, gets value 5 like page"
  );

  await toolbox.destroy();
  await removeTab(tab);
});
