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

Quelle  browser_Troubleshoot.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/. */


// Ideally this would be an xpcshell test, but Troubleshoot relies on things
// that aren't initialized outside of a XUL app environment like AddonManager
// and the "@mozilla.org/xre/app-info;1" component.

const { Troubleshoot } = ChromeUtils.importESModule(
  "resource://gre/modules/Troubleshoot.sys.mjs"
);
const { sinon } = ChromeUtils.importESModule(
  "resource://testing-common/Sinon.sys.mjs"
);

const { FeatureGate } = ChromeUtils.importESModule(
  "resource://featuregates/FeatureGate.sys.mjs"
);
const { PreferenceExperiments } = ChromeUtils.importESModule(
  "resource://normandy/lib/PreferenceExperiments.sys.mjs"
);
const { PreferenceRollouts } = ChromeUtils.importESModule(
  "resource://normandy/lib/PreferenceRollouts.sys.mjs"
);
const { AddonStudies } = ChromeUtils.importESModule(
  "resource://normandy/lib/AddonStudies.sys.mjs"
);
const { NormandyTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/NormandyTestUtils.sys.mjs"
);

NormandyTestUtils.init({ Assert });

add_task(async function snapshotSchema() {
  let snapshot = await Troubleshoot.snapshot();
  try {
    validateObject(snapshot, SNAPSHOT_SCHEMA);
    ok(true"The snapshot should conform to the schema.");
  } catch (err) {
    ok(false"Schema mismatch, " + err);
  }
});

add_task(async function experimentalFeatures() {
  let featureGates = await FeatureGate.all();
  ok(featureGates.length, "Should be at least one FeatureGate");

  let snapshot = await Troubleshoot.snapshot();
  for (let i = 0; i < snapshot.experimentalFeatures.length; i++) {
    let experimentalFeature = snapshot.experimentalFeatures[i];
    is(
      experimentalFeature[0],
      featureGates[i].title,
      "The first item in the array should be the title's l10n-id of the FeatureGate"
    );
    is(
      experimentalFeature[1],
      featureGates[i].preference,
      "The second item in the array should be the preference name for the FeatureGate"
    );
    is(
      experimentalFeature[2],
      Services.prefs.getBoolPref(featureGates[i].preference),
      "The third item in the array should be the preference value of the FeatureGate"
    );
  }
});

add_task(async function modifiedPreferences() {
  let prefs = [
    "javascript.troubleshoot",
    "troubleshoot.foo",
    "network.proxy.troubleshoot",
    "print.print_to_filename",
  ];
  prefs.forEach(function (p) {
    Services.prefs.setBoolPref(p, true);
    is(Services.prefs.getBoolPref(p), true"The pref should be set: " + p);
  });
  Services.prefs.setCharPref("dom.push.userAgentID""testvalue");
  let snapshot = await Troubleshoot.snapshot();
  let p = snapshot.modifiedPreferences;
  is(
    p["javascript.troubleshoot"],
    true,
    "The pref should be present because it's in the allowed prefs " +
      "and not in the pref regexes that are disallowed."
  );
  ok(
    !("troubleshoot.foo" in p),
    "The pref should be absent because it's not in the allowed prefs."
  );
  ok(
    !("network.proxy.troubleshoot" in p),
    "The pref should be absent because it's in the pref regexes " +
      "that are disallowed."
  );
  ok(
    !("dom.push.userAgentID" in p),
    "The pref should be absent because it's in the pref regexes " +
      "that are disallowed."
  );
  ok(
    !("print.print_to_filename" in p),
    "The pref should be absent because it's not in the allowed prefs."
  );
  prefs.forEach(p => Services.prefs.deleteBranch(p));
  Services.prefs.clearUserPref("dom.push.userAgentID");
});

add_task(async function unicodePreferences() {
  let name = "font.name.sans-serif.x-western";
  let utf8Value = "\xc4\x8capk\xc5\xafv Krasopis";
  let unicodeValue = "\u010Capk\u016Fv Krasopis";

  // set/getCharPref work with 8bit strings (utf8)
  Services.prefs.setCharPref(name, utf8Value);

  let snapshot = await Troubleshoot.snapshot();
  let p = snapshot.modifiedPreferences;
  is(p[name], unicodeValue, "The pref should have correct Unicode value.");
  Services.prefs.deleteBranch(name);
});

add_task(async function printingPreferences() {
  let prefs = [
    "javascript.print_to_filename",
    "print.print_bgimages",
    "print.print_to_filename",
  ];
  prefs.forEach(function (p) {
    Services.prefs.setBoolPref(p, true);
    is(Services.prefs.getBoolPref(p), true"The pref should be set: " + p);
  });
  let snapshot = await Troubleshoot.snapshot();
  let p = snapshot.printingPreferences;
  is(p["print.print_bgimages"], true"The pref should be present");
  ok(
    !("print.print_to_filename" in p),
    "The pref should not be present (sensitive)"
  );
  ok(
    !("javascript.print_to_filename" in p),
    "The pref should be absent because it's not a print pref."
  );
  prefs.forEach(p => Services.prefs.deleteBranch(p));
});

add_task(function normandy() {
  const {
    preferenceStudyFactory,
    branchedAddonStudyFactory,
    preferenceRolloutFactory,
  } = NormandyTestUtils.factories;

  return NormandyTestUtils.decorate(
    PreferenceExperiments.withMockExperiments([
      preferenceStudyFactory({
        userFacingName: "Test Pref Study B",
        branch: "test-branch-pref",
      }),
      preferenceStudyFactory({
        userFacingName: "Test Pref Study A",
        branch: "test-branch-pref",
      }),
    ]),
    AddonStudies.withStudies([
      branchedAddonStudyFactory({
        userFacingName: "Test Addon Study B",
        branch: "test-branch-addon",
      }),
      branchedAddonStudyFactory({
        userFacingName: "Test Addon Study A",
        branch: "test-branch-addon",
      }),
    ]),
    PreferenceRollouts.withTestMock({
      rollouts: [
        preferenceRolloutFactory({
          statue: "ACTIVE",
          slug: "test-pref-rollout-b",
        }),
        preferenceRolloutFactory({
          statue: "ACTIVE",
          slug: "test-pref-rollout-a",
        }),
      ],
    }),
    async function testNormandyInfoInTroubleshooting({
      prefExperiments,
      addonStudies,
      prefRollouts,
    }) {
      let snapshot = await Troubleshoot.snapshot();
      let info = snapshot.normandy;
      // The order should be flipped, since each category is sorted by slug.
      Assert.deepEqual(
        info.prefStudies,
        [prefExperiments[1], prefExperiments[0]],
        "prefs studies should exist in the right order"
      );
      Assert.deepEqual(
        info.addonStudies,
        [addonStudies[1], addonStudies[0]],
        "addon studies should exist in the right order"
      );
      Assert.deepEqual(
        info.prefRollouts,
        [prefRollouts[1], prefRollouts[0]],
        "pref rollouts should exist in the right order"
      );
    }
  )();
});

add_task(function normandyErrorHandling() {
  return NormandyTestUtils.decorate(
    NormandyTestUtils.withStub(PreferenceExperiments, "getAllActive", {
      returnValue: Promise.reject("Expected error - PreferenceExperiments"),
    }),
    NormandyTestUtils.withStub(AddonStudies, "getAllActive", {
      returnValue: Promise.reject("Expected error - AddonStudies"),
    }),
    NormandyTestUtils.withStub(PreferenceRollouts, "getAllActive", {
      returnValue: Promise.reject("Expected error - PreferenceRollouts"),
    }),
    async function testNormandyErrorHandling() {
      let consoleEndFn = TestUtils.listenForConsoleMessages();
      let snapshot = await Troubleshoot.snapshot();
      let info = snapshot.normandy;
      Assert.deepEqual(
        info.prefStudies,
        [],
        "prefs studies should be an empty list if there is an error"
      );
      Assert.deepEqual(
        info.addonStudies,
        [],
        "addon studies should be an empty list if there is an error"
      );
      Assert.deepEqual(
        info.prefRollouts,
        [],
        "pref rollouts should be an empty list if there is an error"
      );
      let msgs = await consoleEndFn();
      let expectedSet = new Set([
        /Expected error - PreferenceExperiments/,
        /Expected error - AddonStudies/,
        /Expected error - PreferenceRollouts/,
      ]);

      for (let msg of msgs) {
        msg = msg.wrappedJSObject;
        if (msg.level != "error") {
          continue;
        }

        let msgContents = msg.arguments[0];
        for (let expected of expectedSet) {
          if (expected.test(msgContents)) {
            expectedSet.delete(expected);
            break;
          }
        }
      }

      Assert.equal(
        expectedSet.size,
        0,
        "Should have no messages left in the expected set"
      );
    }
  )();
});

add_task(async function themes() {
  let snapshot = await Troubleshoot.snapshot();
  let foundTheme = false;
  for (let addon of snapshot.addons) {
    if (addon.type == "theme") {
      foundTheme = true;
      break;
    }
  }
  ok(foundTheme, "found a theme in the addons list");
});

// This is inspired by JSON Schema, or by the example on its Wikipedia page
// anyway.
const SNAPSHOT_SCHEMA = {
  type: "object",
  required: true,
  properties: {
    application: {
      required: true,
      type: "object",
      properties: {
        name: {
          required: true,
          type: "string",
        },
        version: {
          required: true,
          type: "string",
        },
        buildID: {
          required: true,
          type: "string",
        },
        distributionID: {
          required: true,
          type: "string",
        },
        userAgent: {
          required: true,
          type: "string",
        },
        osVersion: {
          required: true,
          type: "string",
        },
        osTheme: {
          type: "string",
        },
        rosetta: {
          required: false,
          type: "boolean",
        },
        vendor: {
          type: "string",
        },
        updateChannel: {
          type: "string",
        },
        supportURL: {
          type: "string",
        },
        launcherProcessState: {
          type: "number",
        },
        remoteAutoStart: {
          type: "boolean",
          required: true,
        },
        fissionAutoStart: {
          type: "boolean",
        },
        fissionDecisionStatus: {
          type: "string",
        },
        numTotalWindows: {
          type: "number",
        },
        numFissionWindows: {
          type: "number",
        },
        numRemoteWindows: {
          type: "number",
        },
        policiesStatus: {
          type: "number",
        },
        keyLocationServiceGoogleFound: {
          type: "boolean",
        },
        keySafebrowsingGoogleFound: {
          type: "boolean",
        },
        keyMozillaFound: {
          type: "boolean",
        },
        safeMode: {
          type: "boolean",
        },
        memorySizeBytes: {
          type: "number",
        },
        diskAvailableBytes: {
          type: "number",
        },
        pointingDevices: {
          required: false,
          type: "array",
        },
      },
    },
    crashes: {
      required: false,
      type: "object",
      properties: {
        pending: {
          required: true,
          type: "number",
        },
        submitted: {
          required: true,
          type: "array",
          items: {
            type: "object",
            properties: {
              id: {
                required: true,
                type: "string",
              },
              date: {
                required: true,
                type: "number",
              },
              pending: {
                required: true,
                type: "boolean",
              },
            },
          },
        },
      },
    },
    addons: {
      required: true,
      type: "array",
      items: {
        type: "object",
        properties: {
          name: {
            required: true,
            type: "string",
          },
          type: {
            required: true,
            type: "string",
          },
          version: {
            required: true,
            type: "string",
          },
          id: {
            required: true,
            type: "string",
          },
          isActive: {
            required: true,
            type: "boolean",
          },
        },
      },
    },
    securitySoftware: {
      required: false,
      type: "object",
      properties: {
        registeredAntiVirus: {
          required: true,
          type: "string",
        },
        registeredAntiSpyware: {
          required: true,
          type: "string",
        },
        registeredFirewall: {
          required: true,
          type: "string",
        },
      },
    },
    features: {
      required: true,
      type: "array",
      items: {
        type: "object",
        properties: {
          name: {
            required: true,
            type: "string",
          },
          version: {
            required: true,
            type: "string",
          },
          id: {
            required: true,
            type: "string",
          },
        },
      },
    },
    processes: {
      required: true,
      type: "object",
      properties: {
        maxWebContentProcesses: {
          required: true,
          type: "number",
        },
        remoteTypes: {
          required: true,
          type: "object",
        },
      },
    },
    experimentalFeatures: {
      required: true,
      type: "array",
    },
    environmentVariables: {
      required: true,
      type: "object",
    },
    modifiedPreferences: {
      required: true,
      type: "object",
    },
    printingPreferences: {
      required: true,
      type: "object",
    },
    lockedPreferences: {
      required: true,
      type: "object",
      properties: {
        "fission.autostart": {
          required: false,
          type: "boolean",
        },
        "fission.autostart.session": {
          required: false,
          type: "boolean",
        },
        "media.utility-process.enabled": {
          required: false,
          type: "boolean",
        },
        "media.utility-ffmpeg.enabled": {
          required: false,
          type: "boolean",
        },
        "media.utility-ffvpx.enabled": {
          required: false,
          type: "boolean",
        },
        "media.utility-wmf.enabled": {
          required: false,
          type: "boolean",
        },
        "media.utility-applemedia.enabled": {
          required: false,
          type: "boolean",
        },
        "media.utility-vorbis.enabled": {
          required: false,
          type: "boolean",
        },
        "media.utility-wav.enabled": {
          required: false,
          type: "boolean",
        },
        "media.utility-opus.enabled": {
          required: false,
          type: "boolean",
        },
      },
    },
    places: {
      required: true,
      type: "array",
      items: {
        type: "object",
        items: {
          entity: {
            required: true,
            type: "string",
          },
          count: {
            required: true,
            type: "number",
          },
          sizeBytes: {
            required: true,
            type: "number",
          },
          sizePerc: {
            required: true,
            type: "number",
          },
          efficiencyPerc: {
            required: true,
            type: "number",
          },
          sequentialityPerc: {
            required: true,
            type: "number",
          },
        },
      },
    },
    graphics: {
      required: true,
      type: "object",
      properties: {
        numTotalWindows: {
          required: true,
          type: "number",
        },
        numAcceleratedWindows: {
          required: true,
          type: "number",
        },
        graphicsDevicePixelRatios: {
          type: "array",
          items: {
            type: "number",
          },
        },
        windowLayerManagerType: {
          type: "string",
        },
        windowLayerManagerRemote: {
          type: "boolean",
        },
        numAcceleratedWindowsMessage: {
          type: "object",
          properties: {
            key: {
              required: true,
              type: "string",
            },
            args: {
              required: false,
              type: "object",
            },
          },
        },
        adapterDescription: {
          type: "string",
        },
        adapterVendorID: {
          type: "string",
        },
        adapterDeviceID: {
          type: "string",
        },
        adapterSubsysID: {
          type: "string",
        },
        adapterRAM: {
          type: "number",
        },
        adapterDrivers: {
          type: "string",
        },
        driverVendor: {
          type: "string",
        },
        driverVersion: {
          type: "string",
        },
        driverDate: {
          type: "string",
        },
        adapterDescription2: {
          type: "string",
        },
        adapterVendorID2: {
          type: "string",
        },
        adapterDeviceID2: {
          type: "string",
        },
        adapterSubsysID2: {
          type: "string",
        },
        adapterRAM2: {
          type: "number",
        },
        adapterDrivers2: {
          type: "string",
        },
        driverVendor2: {
          type: "string",
        },
        driverVersion2: {
          type: "string",
        },
        driverDate2: {
          type: "string",
        },
        isGPU2Active: {
          type: "boolean",
        },
        direct2DEnabled: {
          type: "boolean",
        },
        directWriteEnabled: {
          type: "boolean",
        },
        directWriteVersion: {
          type: "string",
        },
        clearTypeParameters: {
          type: "string",
        },
        webgl1Renderer: {
          type: "string",
        },
        webgl1Version: {
          type: "string",
        },
        webgl1DriverExtensions: {
          type: "string",
        },
        webgl1Extensions: {
          type: "string",
        },
        webgl1WSIInfo: {
          type: "string",
        },
        webgl2Renderer: {
          type: "string",
        },
        webgl2Version: {
          type: "string",
        },
        webgl2DriverExtensions: {
          type: "string",
        },
        webgl2Extensions: {
          type: "string",
        },
        webgl2WSIInfo: {
          type: "string",
        },
        webgpuDefaultAdapter: {
          type: "object",
        },
        webgpuFallbackAdapter: {
          type: "object",
        },
        info: {
          type: "object",
        },
        failures: {
          type: "object",
          properties: {
            key: {
              required: true,
              type: "string",
            },
            args: {
              required: false,
              type: "object",
            },
          },
        },
        indices: {
          type: "array",
          items: {
            type: "number",
          },
        },
        featureLog: {
          type: "object",
        },
        crashGuards: {
          type: "array",
        },
        direct2DEnabledMessage: {
          type: "object",
          properties: {
            key: {
              required: true,
              type: "string",
            },
            args: {
              required: false,
              type: "object",
            },
          },
        },
        targetFrameRate: {
          type: "number",
        },
        windowProtocol: {
          type: "string",
        },
        desktopEnvironment: {
          type: "string",
        },
        supportFontDetermination: {
          type: "string",
        },
      },
    },
    media: {
      required: true,
      type: "object",
      properties: {
        currentAudioBackend: {
          required: true,
          type: "string",
        },
        currentMaxAudioChannels: {
          required: true,
          type: "number",
        },
        currentPreferredSampleRate: {
          required: true,
          type: "number",
        },
        audioOutputDevices: {
          required: true,
          type: "array",
          items: {
            type: "object",
            properties: {
              name: {
                required: true,
                type: "string",
              },
              groupId: {
                required: true,
                type: "string",
              },
              vendor: {
                required: true,
                type: "string",
              },
              type: {
                required: true,
                type: "number",
              },
              state: {
                required: true,
                type: "number",
              },
              preferred: {
                required: true,
                type: "number",
              },
              supportedFormat: {
                required: true,
                type: "number",
              },
              defaultFormat: {
                required: true,
                type: "number",
              },
              maxChannels: {
                required: true,
                type: "number",
              },
              defaultRate: {
                required: true,
                type: "number",
              },
              maxRate: {
                required: true,
                type: "number",
              },
              minRate: {
                required: true,
                type: "number",
              },
              maxLatency: {
                required: true,
                type: "number",
              },
              minLatency: {
                required: true,
                type: "number",
              },
            },
          },
        },
        audioInputDevices: {
          required: true,
          type: "array",
          items: {
            type: "object",
            properties: {
              name: {
                required: true,
                type: "string",
              },
              groupId: {
                required: true,
                type: "string",
              },
              vendor: {
                required: true,
                type: "string",
              },
              type: {
                required: true,
                type: "number",
              },
              state: {
                required: true,
                type: "number",
              },
              preferred: {
                required: true,
                type: "number",
              },
              supportedFormat: {
                required: true,
                type: "number",
              },
              defaultFormat: {
                required: true,
                type: "number",
              },
              maxChannels: {
                required: true,
                type: "number",
              },
              defaultRate: {
                required: true,
                type: "number",
              },
              maxRate: {
                required: true,
                type: "number",
              },
              minRate: {
                required: true,
                type: "number",
              },
              maxLatency: {
                required: true,
                type: "number",
              },
              minLatency: {
                required: true,
                type: "number",
              },
            },
          },
        },
        codecSupportInfo: {
          required: false,
          type: "string",
        },
      },
    },
    accessibility: {
      required: true,
      type: "object",
      properties: {
        isActive: {
          required: true,
          type: "boolean",
        },
        forceDisabled: {
          type: "number",
        },
        handlerUsed: {
          type: "boolean",
        },
        instantiator: {
          type: "string",
        },
      },
    },
    libraryVersions: {
      required: true,
      type: "object",
      properties: {
        NSPR: {
          required: true,
          type: "object",
          properties: {
            minVersion: {
              required: true,
              type: "string",
            },
            version: {
              required: true,
              type: "string",
            },
          },
        },
        NSS: {
          required: true,
          type: "object",
          properties: {
            minVersion: {
              required: true,
              type: "string",
            },
            version: {
              required: true,
              type: "string",
            },
          },
        },
        NSSUTIL: {
          required: true,
          type: "object",
          properties: {
            minVersion: {
              required: true,
              type: "string",
            },
            version: {
              required: true,
              type: "string",
            },
          },
        },
        NSSSSL: {
          required: true,
          type: "object",
          properties: {
            minVersion: {
              required: true,
              type: "string",
            },
            version: {
              required: true,
              type: "string",
            },
          },
        },
        NSSSMIME: {
          required: true,
          type: "object",
          properties: {
            minVersion: {
              required: true,
              type: "string",
            },
            version: {
              required: true,
              type: "string",
            },
          },
        },
      },
    },
    userJS: {
      required: true,
      type: "object",
      properties: {
        exists: {
          required: true,
          type: "boolean",
        },
      },
    },
    sandbox: {
      required: false,
      type: "object",
      properties: {
        hasSeccompBPF: {
          required: AppConstants.platform == "linux",
          type: "boolean",
        },
        hasSeccompTSync: {
          required: AppConstants.platform == "linux",
          type: "boolean",
        },
        hasUserNamespaces: {
          required: AppConstants.platform == "linux",
          type: "boolean",
        },
        hasPrivilegedUserNamespaces: {
          required: AppConstants.platform == "linux",
          type: "boolean",
        },
        canSandboxContent: {
          required: false,
          type: "boolean",
        },
        canSandboxMedia: {
          required: false,
          type: "boolean",
        },
        contentSandboxLevel: {
          required: AppConstants.MOZ_SANDBOX,
          type: "number",
        },
        effectiveContentSandboxLevel: {
          required: AppConstants.MOZ_SANDBOX,
          type: "number",
        },
        contentWin32kLockdownState: {
          required: AppConstants.MOZ_SANDBOX && AppConstants.platform == "win",
          type: "string",
        },
        supportSandboxGpuLevel: {
          required: AppConstants.MOZ_SANDBOX && AppConstants.platform == "win",
          type: "number",
        },
        syscallLog: {
          required: AppConstants.platform == "linux",
          type: "array",
          items: {
            type: "object",
            properties: {
              index: {
                required: true,
                type: "number",
              },
              pid: {
                required: true,
                type: "number",
              },
              tid: {
                required: true,
                type: "number",
              },
              procType: {
                required: true,
                type: "string",
              },
              syscall: {
                required: true,
                type: "number",
              },
              args: {
                required: true,
                type: "array",
                items: {
                  type: "string",
                },
              },
            },
          },
        },
      },
    },
    startupCache: {
      required: false,
      type: "object",
      properties: {
        DiskCachePath: {
          required: true,
          type: "string",
        },
        IgnoreDiskCache: {
          required: true,
          type: "boolean",
        },
        FoundDiskCacheOnInit: {
          required: true,
          type: "boolean",
        },
        WroteToDiskCache: {
          required: true,
          type: "boolean",
        },
      },
    },
    intl: {
      required: true,
      type: "object",
      properties: {
        localeService: {
          required: true,
          type: "object",
          properties: {
            requested: {
              required: true,
              type: "array",
            },
            available: {
              required: true,
              type: "array",
            },
            supported: {
              required: true,
              type: "array",
            },
            regionalPrefs: {
              required: true,
              type: "array",
            },
            defaultLocale: {
              required: true,
              type: "string",
            },
          },
        },
        osPrefs: {
          required: true,
          type: "object",
          properties: {
            systemLocales: {
              required: true,
              type: "array",
            },
            regionalPrefsLocales: {
              required: true,
              type: "array",
            },
          },
        },
      },
    },
    remoteAgent: {
      type: "object",
      properties: {
        running: {
          required: true,
          type: "boolean",
        },
        url: {
          required: true,
          type: "string",
        },
      },
    },
    normandy: {
      type: "object",
      required: AppConstants.MOZ_NORMANDY,
      properties: {
        addonStudies: {
          type: "array",
          items: {
            type: "object",
            properties: {
              userFacingName: { type: "string", required: true },
              branch: { type: "string", required: true },
            },
          },
          required: true,
        },
        prefRollouts: {
          type: "array",
          items: {
            type: "object",
            properties: {
              slug: { type: "string", required: true },
              state: { type: "string", required: true },
            },
          },
          required: true,
        },
        prefStudies: {
          type: "array",
          items: {
            type: "object",
            properties: {
              userFacingName: { type: "string", required: true },
              branch: { type: "string", required: true },
            },
          },
          required: true,
        },
        nimbusExperiments: {
          type: "array",
          items: {
            type: "object",
            properties: {
              userFacingName: { type: "string", required: true },
              branch: {
                type: "object",
                properties: {
                  slug: { type: "string", required: true },
                },
              },
            },
          },
          required: true,
        },
        nimbusRollouts: {
          type: "array",
          items: {
            type: "object",
            properties: {
              featureId: { type: "string", required: true },
              slug: { type: "string", required: true },
            },
          },
        },
      },
    },
    remoteSettings: {
      type: "object",
      additionalProperties: true,
      properties: {
        isSynchronizationBroken: {
          required: true,
          type: "boolean",
        },
        lastCheck: {
          required: true,
          type: "string",
        },
        localTimestamp: {
          required: false,
          type: ["number""null"],
        },
        history: {
          required: true,
          type: "object",
          properties: {
            "settings-sync": {
              type: "array",
              items: {
                type: "object",
                properties: {
                  status: { type: "string", required: true },
                  datetime: { type: "string", required: true },
                  infos: { type: "object", required: true },
                },
              },
            },
          },
        },
      },
    },
    legacyUserStylesheets: {
      type: "object",
      properties: {
        active: {
          required: true,
          type: "boolean",
        },
        types: {
          required: true,
          type: "array",
        },
      },
    },
    contentAnalysis: {
      type: "object",
      properties: {
        active: {
          required: true,
          type: "boolean",
        },
        connected: {
          type: "boolean",
        },
        agentPath: {
          type: "string",
        },
        failedSignatureVerification: {
          type: "boolean",
        },
        requestCount: {
          type: "number",
        },
      },
    },
  },
};

/**
 * Throws an Error if obj doesn't conform to schema.  That way you get a nice
 * error message and a stack to help you figure out what went wrong, which you
 * wouldn't get if this just returned true or false instead.  There's still
 * room for improvement in communicating validation failures, however.
 *
 * @param obj    The object to validate.
 * @param schema The schema that obj should conform to.
 */

function validateObject(obj, schema) {
  if (obj === undefined && !schema.required) {
    return;
  }
  let types = Array.isArray(schema.type) ? schema.type : [schema.type];
  if (!types.every(elt => typeof elt == "string")) {
    throw schemaErr("'type' must be a string or array of strings", schema);
  }
  if (!types.includes(objType(obj))) {
    throw validationErr("Object is not of the expected type", obj, schema);
  }
  let lastError;
  for (let type of types) {
    let validatorFnName = "validateObject_" + type;
    if (!(validatorFnName in this)) {
      throw schemaErr("Validator function not defined for type", schema);
    }
    try {
      this[validatorFnName](obj, schema);
      return;
    } catch (e) {
      lastError = e;
    }
  }
  throw lastError;
}

function validateObject_object(obj, schema) {
  if (typeof schema.properties != "object") {
    // Don't care what obj's properties are.
    return;
  }
  // First check that all the schema's properties match the object.
  for (let prop in schema.properties) {
    validateObject(obj[prop], schema.properties[prop]);
  }
  // Now check that the object doesn't have any properties not in the schema.
  if (!schema.additionalProperties) {
    for (let prop in obj) {
      if (!(prop in schema.properties)) {
        throw validationErr(
          "Object has property " + prop + " not in schema",
          obj,
          schema
        );
      }
    }
  }
}

function validateObject_array(array, schema) {
  if (typeof schema.items != "object") {
    // Don't care what the array's elements are.
    return;
  }
  array.forEach(elt => validateObject(elt, schema.items));
}

function validateObject_string() {}
function validateObject_boolean() {}
function validateObject_number() {}

function validationErr(msg, obj, schema) {
  return new Error(
    "Validation error: " +
      msg +
      ": object=" +
      JSON.stringify(obj) +
      ", schema=" +
      JSON.stringify(schema)
  );
}

function schemaErr(msg, schema) {
  return new Error("Schema error: " + msg + ": " + JSON.stringify(schema));
}

function objType(obj) {
  let type = typeof obj;
  if (type != "object") {
    return type;
  }
  if (Array.isArray(obj)) {
    return "array";
  }
  if (obj === null) {
    return "null";
  }
  return type;
}

Messung V0.5
C=95 H=95 G=94

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