Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/toolkit/components/extensions/child/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 10 kB image not shown  

Quelle  ext-test.js   Sprache: JAVA

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

ChromeUtils.defineLazyGetter(this"isXpcshell"function () {
  return Services.env.exists("XPCSHELL_TEST_PROFILE_DIR");
});

/**
 * Checks whether the given error matches the given expectations.
 *
 * @param {*} error
 *        The error to check.
 * @param {string | RegExp | Function | null} expectedError
 *        The expectation to check against. If this parameter is:
 *
 *        - a string, the error message must exactly equal the string.
 *        - a regular expression, it must match the error message.
 *        - a function, it is called with the error object and its
 *          return value is returned.
 * @param {BaseContext} context
 *
 * @returns {boolean}
 *        True if the error matches the expected error.
 */

const errorMatches = (error, expectedError, context) => {
  if (
    typeof error === "object" &&
    error !== null &&
    !context.principal.subsumes(Cu.getObjectPrincipal(error))
  ) {
    Cu.reportError("Error object belongs to the wrong scope.");
    return false;
  }

  if (typeof expectedError === "function") {
    return context.runSafeWithoutClone(expectedError, error);
  }

  if (
    typeof error !== "object" ||
    error == null ||
    typeof error.message !== "string"
  ) {
    return false;
  }

  if (typeof expectedError === "string") {
    return error.message === expectedError;
  }

  try {
    return expectedError.test(error.message);
  } catch (e) {
    Cu.reportError(e);
  }

  return false;
};

// Checks whether |v| should use string serialization instead of JSON.
function useStringInsteadOfJSON(v) {
  return (
    // undefined to string, or else it is omitted from object after stringify.
    v === undefined ||
    // Values that would have become null.
    (typeof v === "number" && (isNaN(v) || !isFinite(v)))
  );
}

// A very strict deep equality comparator that throws for unsupported values.
// For context, see https://bugzilla.mozilla.org/show_bug.cgi?id=1782816#c2
function deepEquals(a, b) {
  // Some values don't have a JSON representation. To disambiguate from null or
  // regular strings, we prepend this prefix instead.
  const NON_JSON_PREFIX = "#NOT_JSON_SERIALIZABLE#";

  function replacer(key, value) {
    if (typeof value == "object" && value !== null && !Array.isArray(value)) {
      const cls = ChromeUtils.getClassName(value);
      if (cls === "Object") {
        // Return plain object with keys sorted in a predictable order.
        return Object.fromEntries(
          Object.keys(value)
            .sort()
            .map(k => [k, value[k]])
        );
      }
      // Just throw to avoid potentially inaccurate serializations (e.g. {}).
      throw new ExtensionUtils.ExtensionError(`Unsupported obj type: ${cls}`);
    }

    if (useStringInsteadOfJSON(value)) {
      return `${NON_JSON_PREFIX}${value}`;
    }
    return value;
  }
  return JSON.stringify(a, replacer) === JSON.stringify(b, replacer);
}

/**
 * Serializes the given value for use in informative assertion messages.
 *
 * @param {*} value
 * @returns {string}
 */

const toSource = value => {
  function cannotJSONserialize(v) {
    return (
      useStringInsteadOfJSON(v) ||
      // Not a plain object. E.g. [object X], /regexp/, etc.
      (typeof v == "object" &&
        v !== null &&
        !Array.isArray(v) &&
        ChromeUtils.getClassName(v) !== "Object")
    );
  }
  try {
    if (cannotJSONserialize(value)) {
      return String(value);
    }

    const replacer = (k, v) => (cannotJSONserialize(v) ? String(v) : v);
    return JSON.stringify(value, replacer);
  } catch (e) {
    return "";
  }
};

this.test = class extends ExtensionAPI {
  getAPI(context) {
    const { extension } = context;

    function getStack(savedFrame = null) {
      if (savedFrame) {
        return ChromeUtils.createError("", savedFrame).stack.replace(
          /^/gm,
          " "
        );
      }
      return new context.Error().stack.replace(/^/gm, " ");
    }

    function assertTrue(value, msg) {
      extension.emit(
        "test-result",
        Boolean(value),
        String(msg),
        getStack(context.getCaller())
      );
    }

    class TestEventManager extends EventManager {
      constructor(...args) {
        super(...args);

        // A map to keep track of the listeners wrappers being added in
        // addListener (the wrapper will be needed to be able to remove
        // the listener from this EventManager instance if the extension
        // does call test.onMessage.removeListener).
        this._listenerWrappers = new Map();
        context.callOnClose({
          close: () => this._listenerWrappers.clear(),
        });
      }

      addListener(callback, ...args) {
        const listenerWrapper = function (...args) {
          try {
            callback.call(this, ...args);
          } catch (e) {
            assertTrue(false, `${e}\n${e.stack}`);
          }
        };
        super.addListener(listenerWrapper, ...args);
        this._listenerWrappers.set(callback, listenerWrapper);
      }

      removeListener(callback) {
        if (!this._listenerWrappers.has(callback)) {
          return;
        }

        super.removeListener(this._listenerWrappers.get(callback));
        this._listenerWrappers.delete(callback);
      }
    }

    if (!Cu.isInAutomation && !isXpcshell) {
      return { test: {} };
    }

    return {
      test: {
        withHandlingUserInput(callback) {
          // TODO(Bug 1598804): remove this once we don't expose anymore the
          // entire test API namespace based on an environment variable.
          if (!Cu.isInAutomation) {
            // This dangerous method should only be available if the
            // automation pref is set, which is the case in browser tests.
            throw new ExtensionUtils.ExtensionError(
              "withHandlingUserInput can only be called in automation"
            );
          }
          ExtensionCommon.withHandlingUserInput(
            context.contentWindow,
            callback
          );
        },

        sendMessage(...args) {
          extension.emit("test-message", ...args);
        },

        notifyPass(msg) {
          extension.emit("test-done"true, msg, getStack(context.getCaller()));
        },

        notifyFail(msg) {
          extension.emit(
            "test-done",
            false,
            msg,
            getStack(context.getCaller())
          );
        },

        log(msg) {
          extension.emit("test-log"true, msg, getStack(context.getCaller()));
        },

        fail(msg) {
          assertTrue(false, msg);
        },

        succeed(msg) {
          assertTrue(true, msg);
        },

        assertTrue(value, msg) {
          assertTrue(value, msg);
        },

        assertFalse(value, msg) {
          assertTrue(!value, msg);
        },

        assertDeepEq(expected, actual, msg) {
          // The bindings generated by Schemas.sys.mjs accepts any input, but the
          // WebIDL-generated binding expects a structurally cloneable input.
          // To ensure consistent behavior regardless of which mechanism was
          // used, verify that the inputs are structurally cloneable.
          // These will throw if the values cannot be cloned.
          function ensureStructurallyCloneable(v) {
            if (typeof v == "object" && v !== null) {
              // Waive xrays to unhide callable members, so that cloneInto will
              // throw if needed.
              v = ChromeUtils.waiveXrays(v);
            }
            new StructuredCloneHolder("test.assertEq"null, v, globalThis);
          }
          // When WebIDL bindings are used, the objects are already cloned
          // structurally, so we don't need to check again.
          if (!context.useWebIDLBindings) {
            ensureStructurallyCloneable(expected);
            ensureStructurallyCloneable(actual);
          }

          extension.emit(
            "test-eq",
            deepEquals(actual, expected),
            String(msg),
            toSource(expected),
            toSource(actual),
            getStack(context.getCaller())
          );
        },

        assertEq(expected, actual, msg) {
          let equal = expected === actual;

          expected = String(expected);
          actual = String(actual);

          if (!equal && expected === actual) {
            actual += " (different)";
          }
          extension.emit(
            "test-eq",
            equal,
            String(msg),
            expected,
            actual,
            getStack(context.getCaller())
          );
        },

        assertRejects(promise, expectedError, msg) {
          // Wrap in a native promise for consistency.
          promise = Promise.resolve(promise);

          return promise.then(
            () => {
              let message = `Promise resolved, expected rejection '${toSource(
                expectedError
              )}'`;
              if (msg) {
                message += `: ${msg}`;
              }
              assertTrue(false, message);
            },
            error => {
              let expected = toSource(expectedError);
              let message = `got '${toSource(error)}'`;
              if (msg) {
                message += `: ${msg}`;
              }

              assertTrue(
                errorMatches(error, expectedError, context),
                `Promise rejected, expecting rejection to match '${expected}', ${message}`
              );
            }
          );
        },

        assertThrows(func, expectedError, msg) {
          try {
            func();

            let message = `Function did not throw, expected error '${toSource(
              expectedError
            )}'`;
            if (msg) {
              message += `: ${msg}`;
            }
            assertTrue(false, message);
          } catch (error) {
            let expected = toSource(expectedError);
            let message = `got '${toSource(error)}'`;
            if (msg) {
              message += `: ${msg}`;
            }

            assertTrue(
              errorMatches(error, expectedError, context),
              `Function threw, expecting error to match '${expected}', ${message}`
            );
          }
        },

        onMessage: new TestEventManager({
          context,
          name: "test.onMessage",
          // TODO bug 1901294: Set resetIdleOnEvent=false. Tests should not be
          // relying on test.onMessage for its side effect of resetting the test
          // but set extensions.background.idle.timeout instead.
          resetIdleOnEvent: true,
          register: fire => {
            let handler = (event, ...args) => {
              fire.async(...args);
            };

            extension.on("test-harness-message", handler);
            return () => {
              extension.off("test-harness-message", handler);
            };
          },
        }).api(),
      },
    };
  }
};

Messung V0.5
C=92 H=100 G=95

¤ Dauer der Verarbeitung: 0.30 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.