Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/widget/windows/tests/unit/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 19 kB image not shown  

Quelle  test_windows_alert_service.js   Sprache: JAVA

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


/*
 * Test that Windows alert notifications generate expected XML.
 */


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

let gProfD = do_get_profile();

// Setup that allows to use the profile service in xpcshell tests,
// lifted from `toolkit/profile/xpcshell/head.js`.
function setupProfileService() {
  let gDataHome = gProfD.clone();
  gDataHome.append("data");
  gDataHome.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
  let gDataHomeLocal = gProfD.clone();
  gDataHomeLocal.append("local");
  gDataHomeLocal.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o755);

  let xreDirProvider = Cc["@mozilla.org/xre/directory-provider;1"].getService(
    Ci.nsIXREDirProvider
  );
  xreDirProvider.setUserDataDirectory(gDataHome, false);
  xreDirProvider.setUserDataDirectory(gDataHomeLocal, true);
}

add_setup(setupProfileService);

function makeAlert(options) {
  var alert = Cc["@mozilla.org/alert-notification;1"].createInstance(
    Ci.nsIAlertNotification
  );
  alert.init(
    options.name,
    options.imageURL,
    options.title,
    options.text,
    options.textClickable,
    options.cookie,
    options.dir,
    options.lang,
    options.data,
    options.principal,
    options.inPrivateBrowsing,
    options.requireInteraction,
    options.silent,
    options.vibrate || []
  );
  if (options.actions) {
    alert.actions = options.actions;
  }
  if (options.opaqueRelaunchData) {
    alert.opaqueRelaunchData = options.opaqueRelaunchData;
  }
  return alert;
}

/**
 * Take a `key1\nvalue1\n...` string encoding as used by the Windows native
 * notification server DLL, and split it into an object, keeping `action\n...`
 * intact.
 *
 * @param {string} t string encoding.
 * @returns {object} an object with keys and values.
 */

function parseOneEncoded(t) {
  var launch = {};

  var lines = t.split("\n");
  while (lines.length) {
    var key = lines.shift();
    var value;
    if (key === "action") {
      value = lines.join("\n");
      lines = [];
    } else {
      value = lines.shift();
    }
    launch[key] = value;
  }

  return launch;
}

/**
 * This complicated-looking function takes a (XML) string representation of a
 * Windows alert (toast notification), parses it into XML, extracts and further
 * parses internal data, and returns a simplified XML representation together
 * with the parsed internals.
 *
 * Doing this lets us compare JSON objects rather than stringified-JSON further
 * encoded as XML strings, which have lots of slashes and `"` characters to
 * contend with.
 *
 * @param {string} s XML string for Windows alert.

 * @returns {Array} a pair of a simplified XML string and an object with
 *                  `launch` and `actions` keys.
 */

function parseLaunchAndActions(s) {
  var document = new DOMParser().parseFromString(s, "text/xml");
  var root = document.documentElement;

  var launchString = root.getAttribute("launch");
  root.setAttribute("launch""launch");
  var launch = parseOneEncoded(launchString);

  // `actions` is keyed by "content" attribute.
  let actions = {};
  for (var actionElement of root.querySelectorAll("action")) {
    // `activationType="system"` is special.  Leave them alone.
    let systemActivationType =
      actionElement.getAttribute("activationType") === "system";

    let action = {};
    let names = [...actionElement.attributes].map(attribute => attribute.name);

    for (var name of names) {
      let value = actionElement.getAttribute(name);

      // Here is where we parse stringified-JSON to simplify comparisons.
      if (value.startsWith("{")) {
        value = JSON.parse(value);
        if ("opaqueRelaunchData" in value) {
          value.opaqueRelaunchData = JSON.parse(value.opaqueRelaunchData);
        }
      }

      if (name == "arguments" && !systemActivationType) {
        action[name] = parseOneEncoded(value);
      } else {
        action[name] = value;
      }

      if (name != "content" && !systemActivationType) {
        actionElement.removeAttribute(name);
      }
    }

    let actionName = actionElement.getAttribute("content");
    actions[actionName] = action;
  }

  return [new XMLSerializer().serializeToString(document), { launch, actions }];
}

function escape(s) {
  return s
    .replace(/&/g, "&")
    .replace(/"/g, """)
    .replace(/</g, "<")
    .replace(/>/g, ">")
    .replace(/\n/g, " ");
}

function unescape(s) {
  return s
    .replace(/&/g, "&")
    .replace(/"/g, '"')
    .replace(/</g, "<")
    .replace(/>/g, ">")
    .replace(/ /g, "\n");
}

function testAlert(when, { serverEnabled, profD, isBackgroundTaskMode } = {}) {
  let argumentString = action => {
    //   is "\n".
    let s = ``;
    if (serverEnabled) {
      s += `program ${AppConstants.MOZ_APP_NAME}`;
    } else {
      s += `invalid key invalid value`;
    }
    if (serverEnabled && profD) {
      s += ` profile ${profD.path}`;
    }
    if (serverEnabled) {
      s += " windowsTag ";
    }
    if (action) {
      s += ` action ${escape(JSON.stringify(action))}`;
    }

    return s;
  };

  let parsedArgumentString = action =>
    parseOneEncoded(unescape(argumentString(action)));

  let settingsAction = isBackgroundTaskMode
    ? ""
    : `<action content="Notification settings"/>`;

  let parsedSettingsAction = hostport => {
    if (isBackgroundTaskMode) {
      return [];
    }
    let content = "Notification settings";
    return [
      content,
      {
        content,
        arguments: parsedArgumentString(
          Object.assign(
            {
              action: "settings",
            },
            hostport && {
              launchUrl: hostport,
            }
          )
        ),
        placement: "contextmenu",
      },
    ];
  };

  let parsedSnoozeAction = hostport => {
    let content = `Disable notifications from ${hostport}`;
    return [
      content,
      {
        content,
        arguments: parsedArgumentString(
          Object.assign(
            {
              action: "snooze",
            },
            hostport && {
              launchUrl: hostport,
            }
          )
        ),
        placement: "contextmenu",
      },
    ];
  };

  let alertsService = Cc["@mozilla.org/system-alerts-service;1"]
    .getService(Ci.nsIAlertsService)
    .QueryInterface(Ci.nsIWindowsAlertsService);

  let name = "name";
  let title = "title";
  let text = "text";
  let imageURL = "file:///image.png";
  let actions = [
    { action: "action1", title: "title1", iconURL: "file:///iconURL1.png" },
    { action: "action2", title: "title2", iconURL: "file:///iconURL2.png" },
  ];
  let opaqueRelaunchData = { foo: 1, bar: "two" };

  let alert = makeAlert({ name, title, text });
  let expected = `<toast launch="launch"><visual><binding template="ToastText03"><text id="1">title</text><text id="2">text</text></binding></visual><actions>${settingsAction}</actions></toast>`;
  Assert.deepEqual(
    [
      expected.replace(""""),
      {
        launch: parsedArgumentString({ action: "" }),
        actions: Object.fromEntries(
          [parsedSettingsAction()].filter(x => x.length)
        ),
      },
    ],
    parseLaunchAndActions(alertsService.getXmlStringForWindowsAlert(alert)),
    when
  );

  alert = makeAlert({ name, title, text, imageURL });
  expected = `<toast launch="launch"><visual><binding template="ToastImageAndText03"><image id="1" src="file:///image.png"/>titletext${settingsAction}`;
  Assert.deepEqual(
    [
      expected.replace(""""),
      {
        launch: parsedArgumentString({ action: "" }),
        actions: Object.fromEntries(
          [parsedSettingsAction()].filter(x => x.length)
        ),
      },
    ],
    parseLaunchAndActions(alertsService.getXmlStringForWindowsAlert(alert)),
    when
  );

  alert = makeAlert({ name, title, text, imageURL, requireInteraction: true });
  expected = `<toast scenario="reminder" launch="launch"><visual><binding template="ToastImageAndText03"><image id="1" src="file:///image.png"/>titletext${settingsAction}`;
  Assert.deepEqual(
    [
      expected.replace(""""),
      {
        launch: parsedArgumentString({ action: "" }),
        actions: Object.fromEntries(
          [
            parsedSettingsAction(),
            [
              "Dismiss",
              {
                content: "Dismiss",
                arguments: "dismiss",
                activationType: "system",
              },
            ],
          ].filter(x => x.length)
        ),
      },
    ],
    parseLaunchAndActions(alertsService.getXmlStringForWindowsAlert(alert)),
    when
  );

  alert = makeAlert({ name, title, text, imageURL, actions });
  expected = `<toast launch="launch"><visual><binding template="ToastImageAndText03"><image id="1" src="file:///image.png"/>titletext${settingsAction}`;
  Assert.deepEqual(
    [
      expected.replace(""""),
      {
        launch: parsedArgumentString({ action: "" }),
        actions: Object.fromEntries(
          [
            parsedSettingsAction(),
            [
              "title1",
              {
                content: "title1",
                arguments: parsedArgumentString({ action: "action1" }),
              },
            ],
            [
              "title2",
              {
                content: "title2",
                arguments: parsedArgumentString({ action: "action2" }),
              },
            ],
          ].filter(x => x.length)
        ),
      },
    ],
    parseLaunchAndActions(alertsService.getXmlStringForWindowsAlert(alert)),
    when
  );

  // Chrome privileged alerts can use `windowsSystemActivationType`.
  let systemActions = [
    {
      action: "dismiss",
      title: "dismissTitle",
      windowsSystemActivationType: true,
    },
    {
      action: "snooze",
      title: "snoozeTitle",
      windowsSystemActivationType: true,
    },
  ];
  let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
  alert = makeAlert({
    name,
    title,
    text,
    imageURL,
    principal: systemPrincipal,
    actions: systemActions,
  });
  let parsedSettingsActionWithPrivilegedName = isBackgroundTaskMode
    ? []
    : [
        "Notification settings",
        {
          content: "Notification settings",
          arguments: parsedArgumentString({
            action: "settings",
            privilegedName: name,
          }),
          placement: "contextmenu",
        },
      ];

  expected = `<toast launch="launch"><visual><binding template="ToastGeneric"><image id="1" src="file:///image.png"/>titletext${settingsAction}`;
  Assert.deepEqual(
    [
      expected.replace(""""),
      {
        launch: parsedArgumentString({ action: "", privilegedName: name }),
        actions: Object.fromEntries(
          [
            parsedSettingsActionWithPrivilegedName,
            [
              "dismissTitle",
              {
                content: "dismissTitle",
                arguments: "dismiss",
                activationType: "system",
              },
            ],
            [
              "snoozeTitle",
              {
                content: "snoozeTitle",
                arguments: "snooze",
                activationType: "system",
              },
            ],
          ].filter(x => x.length)
        ),
      },
    ],
    parseLaunchAndActions(alertsService.getXmlStringForWindowsAlert(alert)),
    when
  );

  // But content unprivileged alerts can't use `windowsSystemActivationType`.
  let launchUrl = "https://example.com/foo/bar.html";
  const principaluri = Services.io.newURI(launchUrl);
  const principal = Services.scriptSecurityManager.createContentPrincipal(
    principaluri,
    {}
  );

  alert = makeAlert({
    name,
    title,
    text,
    imageURL,
    actions: systemActions,
    principal,
  });
  expected = `<toast launch="launch"><visual><binding template="ToastImageAndText04"><image id="1" src="file:///image.png"/>titletextvia example.com${settingsAction}`;
  Assert.deepEqual(
    [
      expected.replace(""""),
      {
        launch: parsedArgumentString({
          action: "",
          launchUrl: principaluri.hostPort,
        }),
        actions: Object.fromEntries(
          [
            parsedSnoozeAction(principaluri.hostPort),
            parsedSettingsAction(principaluri.hostPort),
            [
              "dismissTitle",
              {
                content: "dismissTitle",
                arguments: parsedArgumentString({
                  action: "dismiss",
                  launchUrl: principaluri.hostPort,
                }),
              },
            ],
            [
              "snoozeTitle",
              {
                content: "snoozeTitle",
                arguments: parsedArgumentString({
                  action: "snooze",
                  launchUrl: principaluri.hostPort,
                }),
              },
            ],
          ].filter(x => x.length)
        ),
      },
    ],
    parseLaunchAndActions(alertsService.getXmlStringForWindowsAlert(alert)),
    when
  );

  // Chrome privileged alerts can set `opaqueRelaunchData`.
  alert = makeAlert({
    name,
    title,
    text,
    imageURL,
    principal: systemPrincipal,
    opaqueRelaunchData: JSON.stringify(opaqueRelaunchData),
  });
  expected = `<toast launch="launch"><visual><binding template="ToastGeneric"><image id="1" src="file:///image.png"/>titletext${settingsAction}`;
  Assert.deepEqual(
    [
      expected.replace(""""),
      {
        launch: parsedArgumentString({
          action: "",
          opaqueRelaunchData: JSON.stringify(opaqueRelaunchData),
          privilegedName: name,
        }),
        actions: Object.fromEntries(
          [parsedSettingsActionWithPrivilegedName].filter(x => x.length)
        ),
      },
    ],
    parseLaunchAndActions(alertsService.getXmlStringForWindowsAlert(alert)),
    when
  );

  // But content unprivileged alerts can't set `opaqueRelaunchData`.
  alert = makeAlert({
    name,
    title,
    text,
    imageURL,
    principal,
    opaqueRelaunchData: JSON.stringify(opaqueRelaunchData),
  });
  expected = `<toast launch="launch"><visual><binding template="ToastImageAndText04"><image id="1" src="file:///image.png"/>titletextvia example.com${settingsAction}`;
  Assert.deepEqual(
    [
      expected.replace(""""),
      {
        launch: parsedArgumentString({
          action: "",
          launchUrl: principaluri.hostPort,
        }),
        actions: Object.fromEntries(
          [
            parsedSnoozeAction(principaluri.hostPort),
            parsedSettingsAction(principaluri.hostPort),
          ].filter(x => x.length)
        ),
      },
    ],
    parseLaunchAndActions(alertsService.getXmlStringForWindowsAlert(alert)),
    when
  );

  // Chrome privileged alerts can set action-specific relaunch parameters.
  let systemRelaunchActions = [
    {
      action: "action1",
      title: "title1",
      opaqueRelaunchData: JSON.stringify({ json: "data1" }),
    },
    {
      action: "action2",
      title: "title2",
      opaqueRelaunchData: JSON.stringify({ json: "data2" }),
    },
  ];
  systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
  alert = makeAlert({
    name,
    title,
    text,
    imageURL,
    principal: systemPrincipal,
    actions: systemRelaunchActions,
  });
  expected = `<toast launch="launch"><visual><binding template="ToastGeneric"><image id="1" src="file:///image.png"/>titletext${settingsAction}`;
  Assert.deepEqual(
    [
      expected.replace(""""),
      {
        launch: parsedArgumentString({ action: "", privilegedName: name }),
        actions: Object.fromEntries(
          [
            parsedSettingsActionWithPrivilegedName,
            [
              "title1",
              {
                content: "title1",
                arguments: parsedArgumentString(
                  {
                    action: "action1",
                    opaqueRelaunchData: JSON.stringify({ json: "data1" }),
                    privilegedName: name,
                  },
                  null,
                  name
                ),
              },
            ],

            [
              "title2",
              {
                content: "title2",
                arguments: parsedArgumentString(
                  {
                    action: "action2",
                    opaqueRelaunchData: JSON.stringify({ json: "data2" }),
                    privilegedName: name,
                  },
                  null,
                  name
                ),
              },
            ],
          ].filter(x => x.length)
        ),
      },
    ],
    parseLaunchAndActions(alertsService.getXmlStringForWindowsAlert(alert)),
    when
  );
}

add_task(async () => {
  Services.prefs.deleteBranch(
    "alerts.useSystemBackend.windows.notificationserver.enabled"
  );
  testAlert("when notification server pref is unset", {
    profD: gProfD,
  });

  Services.prefs.setBoolPref(
    "alerts.useSystemBackend.windows.notificationserver.enabled",
    false
  );
  testAlert("when notification server pref is false", { profD: gProfD });

  Services.prefs.setBoolPref(
    "alerts.useSystemBackend.windows.notificationserver.enabled",
    true
  );
  testAlert("when notification server pref is true", {
    serverEnabled: true,
    profD: gProfD,
  });
});

let condition = {
  skip_if: () => !AppConstants.MOZ_BACKGROUNDTASKS,
};

add_task(condition, async () => {
  const bts = Cc["@mozilla.org/backgroundtasks;1"]?.getService(
    Ci.nsIBackgroundTasks
  );

  // Pretend that this is a background task.
  bts.overrideBackgroundTaskNameForTesting("taskname");

  Services.prefs.setBoolPref(
    "alerts.useSystemBackend.windows.notificationserver.enabled",
    true
  );
  testAlert(
    "when notification server pref is true in background task, no default profile",
    { serverEnabled: true, isBackgroundTaskMode: true }
  );

  let profileService = Cc["@mozilla.org/toolkit/profile-service;1"].getService(
    Ci.nsIToolkitProfileService
  );

  let profilePath = do_get_profile();
  profilePath.append(`test_windows_alert_service`);
  let profile = profileService.createUniqueProfile(
    profilePath,
    "test_windows_alert_service"
  );

  profileService.defaultProfile = profile;

  testAlert(
    "when notification server pref is true in background task, default profile",
    { serverEnabled: true, isBackgroundTaskMode: true, profD: profilePath }
  );

  // No longer a background task,
  bts.overrideBackgroundTaskNameForTesting("");
});

Messung V0.5
C=96 H=92 G=93

¤ Dauer der Verarbeitung: 0.32 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.