Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/toolkit/components/nimbus/test/unit/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 87 kB image not shown  

Quelle  test_prefFlips.js   Sprache: JAVA

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


const { ExperimentAPI, _ExperimentFeature: ExperimentFeature } =
  ChromeUtils.importESModule("resource://nimbus/ExperimentAPI.sys.mjs");
const { PrefUtils } = ChromeUtils.importESModule(
  "resource://normandy/lib/PrefUtils.sys.mjs"
);
const { JsonSchema } = ChromeUtils.importESModule(
  "resource://gre/modules/JsonSchema.sys.mjs"
);
const { TelemetryTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/TelemetryTestUtils.sys.mjs"
);

const USER = "user";
const DEFAULT = "default";

const STRING_PREF = "test.nimbus.prefFlips.string";
const INT_PREF = "test.nimbus.prefFlips.int";
const BOOL_PREF = "test.nimbus.prefFlips.boolean";

const FEATURE_ID = "prefFlips";

const SET_BEFORE_VALUE = "set-before-value";
const USER_VALUE = "user-value";
const DEFAULT_VALUE = "default-value";

const PREF_FEATURES = {
  [USER]: new ExperimentFeature("test-set-pref-user-1", {
    description: "Test feature that sets prefs on the user branch via setPref",
    owner: "test@test.test",
    hasExposure: false,
    variables: {
      foo: {
        type: "string",
        description: "test variable",
        setPref: {
          branch: USER,
          pref: "nimbus.test-only.foo",
        },
      },
    },
  }),
  [DEFAULT]: new ExperimentFeature("test-set-pref-default-1", {
    description:
      "Test feature that sets prefs on the default branch via setPref",
    owner: "test@test.test",
    hasExposure: false,
    variables: {
      foo: {
        type: "string",
        description: "test variable",
        setPref: {
          branch: DEFAULT,
          pref: "nimbus.test-only.foo",
        },
      },
    },
  }),
};

function assertNoObservers(manager) {
  Assert.equal(
    manager._prefs.size,
    0,
    "There should be no active pref observers on ExperimentManager"
  );
  Assert.equal(
    manager._prefsBySlug.size,
    0,
    "There should be no active pref observers on ExperimentManager"
  );
  Assert.equal(
    manager._prefFlips._prefs.size,
    0,
    "There should be no prefFlips feature observers"
  );
}

function setPrefs(prefs) {
  for (const [name, { userBranchValue, defaultBranchValue }] of Object.entries(
    prefs
  )) {
    // If the different prefs have the same value, we must set the user branch
    // value first. Otherwise when we try to set the user branch value after
    // the default value, it will see the value already set for the user
    // branch (because it falls back to the default branch value) and will not
    // set it, leaving only a default branch pref.
    if (typeof userBranchValue !== "undefined") {
      PrefUtils.setPref(name, userBranchValue);
    }

    if (typeof defaultBranchValue !== "undefined") {
      PrefUtils.setPref(name, defaultBranchValue, { branch: DEFAULT });
    }
  }
}

function cleanupPrefs(prefs) {
  for (const name of Object.keys(prefs)) {
    Services.prefs.deleteBranch(name);
  }
}

function checkExpectedPrefs(prefs) {
  for (const [name, value] of Object.entries(prefs)) {
    Assert.equal(PrefUtils.getPref(name), value);
  }
}

function checkExpectedPrefBranches(prefs) {
  for (const [
    name,
    { defaultBranchValue = null, userBranchValue = null },
  ] of Object.entries(prefs)) {
    if (userBranchValue === null) {
      Assert.ok(
        !Services.prefs.prefHasUserValue(name),
        `Pref ${name} has no value on user branch`
      );
    } else {
      Assert.equal(
        PrefUtils.getPref(name, { branch: USER }),
        userBranchValue,
        `Pref ${name} has correct value on user branch`
      );
    }

    if (defaultBranchValue === null) {
      Assert.ok(
        !Services.prefs.prefHasDefaultValue(name),
        `Pref ${name} has no value on default branch`
      );
    } else {
      Assert.equal(
        PrefUtils.getPref(name, { branch: DEFAULT }),
        defaultBranchValue,
        `Pref ${name} has correct value on default branch`
      );
    }
  }
}

add_setup(function setup() {
  do_get_profile();
  Services.fog.initializeFOG();

  const cleanupFeatures = ExperimentTestUtils.addTestFeatures(
    PREF_FEATURES[USER],
    PREF_FEATURES[DEFAULT]
  );

  registerCleanupFunction(cleanupFeatures);
});

add_task(async function test_schema() {
  const schema = await fetch(
    "resource://nimbus/schemas/PrefFlipsFeature.schema.json"
  ).then(rsp => rsp.json());
  const validator = new JsonSchema.Validator(schema);

  const ALLOWED_TEST_CASES = [
    { prefs: {} },
    {
      prefs: {
        "foo.string": {
          branch: USER,
          value: "value",
        },
        "foo.int": {
          branch: USER,
          value: 123,
        },
        "foo.bool": {
          branch: USER,
          value: true,
        },
        "bar.string": {
          branch: DEFAULT,
          value: "value",
        },
        "bar.int": {
          branch: DEFAULT,
          value: 345,
        },
        "bar.bool": {
          branch: DEFAULT,
          value: false,
        },
      },
    },
  ];

  for (const obj of ALLOWED_TEST_CASES) {
    const result = validator.validate(obj);
    Assert.ok(
      result.valid,
      `validated: ${JSON.stringify(result.errors, null, 2)}`
    );
  }

  const DISALLOWED_TEST_CASES = [
    {},
    {
      prefs: {
        "foo.bar.baz": {
          branch: "other",
          value: "value",
        },
      },
    },
    {
      prefs: {
        "foo.bar.baz": {},
      },
    },
    {
      prefs: {
        "foo.bar.baz": {
          branch: USER,
        },
      },
    },
    {
      prefs: {
        "foo.bar.baz": {
          branch: DEFAULT,
        },
      },
    },
    {
      prefs: {
        "foo.bar.baz": {
          value: "value",
        },
      },
    },
    {
      prefs: {
        "foo.bar.baz": {
          branch: DEFAULT,
          value: null,
        },
      },
    },
  ];

  for (const obj of DISALLOWED_TEST_CASES) {
    const result = validator.validate(obj);
    Assert.ok(!result.valid);
  }
});

add_task(async function test_prefFlips() {
  const setUserPrefs = {
    prefs: {
      [STRING_PREF]: {
        branch: USER,
        value: "hello, world",
      },
      [INT_PREF]: {
        branch: USER,
        value: 123,
      },
      [BOOL_PREF]: {
        branch: USER,
        value: true,
      },
    },
  };
  const setDefaultPrefs = {
    prefs: {
      [STRING_PREF]: {
        branch: DEFAULT,
        value: "hello, world",
      },
      [INT_PREF]: {
        branch: DEFAULT,
        value: 123,
      },
      [BOOL_PREF]: {
        branch: DEFAULT,
        value: true,
      },
    },
  };

  const clearUserPrefs = {
    prefs: {
      [STRING_PREF]: {
        branch: USER,
        value: null,
      },
      [INT_PREF]: {
        branch: USER,
        value: null,
      },
      [BOOL_PREF]: {
        branch: USER,
        value: null,
      },
    },
  };

  const PRE_SET_PREFS = {
    [USER]: {
      [STRING_PREF]: { userBranchValue: "goodbye, world" },
      [INT_PREF]: { userBranchValue: 234 },
      [BOOL_PREF]: { userBranchValue: false },
    },
    [DEFAULT]: {
      [STRING_PREF]: { defaultBranchValue: "goodbye, world" },
      [INT_PREF]: { defaultBranchValue: 234 },
      [BOOL_PREF]: { defaultBranchValue: false },
    },
    BOTH_BRANCHES: {
      [STRING_PREF]: {
        userBranchValue: USER_VALUE,
        defaultBranchValue: DEFAULT_VALUE,
      },
      [INT_PREF]: { userBranchValue: 2, defaultBranchValue: 3 },
      [BOOL_PREF]: { userBranchValue: false, defaultBranchValue: false },
    },
  };

  const TEST_CASES = [
    {
      name: "Set prefs on the user branch",
      featureValue: setUserPrefs,
    },
    {
      name: "Set prefs on the user branch with pre-existing values on the user branch",
      featureValue: setUserPrefs,
      setPrefsBefore: PRE_SET_PREFS[USER],
    },
    {
      name: "Set prefs on the user branch with pre-existing values on the default branch",
      featureValue: setUserPrefs,
      setPrefsBefore: PRE_SET_PREFS[DEFAULT],
    },
    {
      name: "Set prefs on the user branch with pre-existing values on both branches",
      featureValue: setUserPrefs,
      setPrefsBefore: PRE_SET_PREFS.BOTH_BRANCHES,
    },
    {
      name: "Set prefs on the default branch",
      featureValue: setDefaultPrefs,
    },
    {
      name: "Set prefs on the default branch with pre-existing values on the default branch",
      featureValue: setDefaultPrefs,
      setPrefsBefore: PRE_SET_PREFS[DEFAULT],
    },
    {
      name: "Set prefs on the default branch with pre-existing values on the user branch",
      featureValue: setDefaultPrefs,
      setPrefsBefore: PRE_SET_PREFS[USER],
      expectedPrefs: {
        [STRING_PREF]: PRE_SET_PREFS[USER][STRING_PREF].userBranchValue,
        [INT_PREF]: PRE_SET_PREFS[USER][INT_PREF].userBranchValue,
        [BOOL_PREF]: PRE_SET_PREFS[USER][BOOL_PREF].userBranchValue,
      },
    },
    {
      name: "Set prefs on the default branch with pre-existing values on both branches",
      featureValue: setDefaultPrefs,
      setPrefsBefore: PRE_SET_PREFS.BOTH_BRANCHES,
      expectedPrefs: {
        [STRING_PREF]: PRE_SET_PREFS.BOTH_BRANCHES[STRING_PREF].userBranchValue,
        [INT_PREF]: PRE_SET_PREFS.BOTH_BRANCHES[INT_PREF].userBranchValue,
        [BOOL_PREF]: PRE_SET_PREFS.BOTH_BRANCHES[BOOL_PREF].userBranchValue,
      },
    },
    {
      name: "Clearing prefs on the user branch (with value null) without pre-existing values",
      featureValue: clearUserPrefs,
    },
    {
      name: "Clearing prefs on the user branch (with value null) with pre-existing values on the user branch",
      featureValue: clearUserPrefs,
      setPrefsBefore: PRE_SET_PREFS[USER],
    },
    {
      name: "Clearing prefs on the user branch (with value null) with pre-existing values on the default branch",
      featureValue: clearUserPrefs,
      setPrefsBefore: PRE_SET_PREFS[DEFAULT],
      // This will not affect the default branch prefs.
      expectedPrefs: {
        [STRING_PREF]: PRE_SET_PREFS[DEFAULT][STRING_PREF].defaultBranchValue,
        [INT_PREF]: PRE_SET_PREFS[DEFAULT][INT_PREF].defaultBranchValue,
        [BOOL_PREF]: PRE_SET_PREFS[DEFAULT][BOOL_PREF].defaultBranchValue,
      },
    },
    {
      name: "Clearing prefs on the user branch (with value null) with pre-existing values on both branches",
      featureValue: clearUserPrefs,
      setPrefsBefore: PRE_SET_PREFS.BOTH_BRANCHES,
      expectedPrefs: {
        [STRING_PREF]:
          PRE_SET_PREFS.BOTH_BRANCHES[STRING_PREF].defaultBranchValue,
        [INT_PREF]: PRE_SET_PREFS.BOTH_BRANCHES[INT_PREF].defaultBranchValue,
        [BOOL_PREF]: PRE_SET_PREFS.BOTH_BRANCHES[BOOL_PREF].defaultBranchValue,
      },
    },
  ];

  for (const [i, { name, ...testCase }] of TEST_CASES.entries()) {
    info(`Running test case ${i}: ${name}`);

    const sandbox = sinon.createSandbox();

    const {
      // The feature config to enroll.
      featureValue,

      // Prefs that should be set before enrollment. These will be undone after
      // each test case.
      setPrefsBefore = {},

      // Additional prefs to check after enrollment. They will be checked on the
      // user branch.
      expectedPrefs = {},
    } = testCase;

    const manager = ExperimentFakes.manager();
    sandbox.stub(ExperimentAPI, "_store").get(() => manager.store);

    await manager.onStartup();

    info("Setting initial values of prefs...");
    setPrefs(setPrefsBefore);

    // Collect the values of any prefs that will be set by the enrollment so we
    // can compare their values after unenrollment.
    const prefValuesBeforeEnrollment = Object.fromEntries(
      Object.keys(featureValue.prefs).map(prefName => [
        prefName,
        PrefUtils.getPref(prefName),
      ])
    );

    info("Enrolling...");
    const cleanup = await ExperimentFakes.enrollWithFeatureConfig(
      {
        featureId: FEATURE_ID,
        value: featureValue,
      },
      {
        manager,
        isRollout: true,
      }
    );

    info("Checking prefs were set by enrollment...");
    for (const [prefName, { branch, value }] of Object.entries(
      featureValue.prefs
    )) {
      if (typeof value === "undefined" || value === null) {
        if (branch === USER) {
          Assert.ok(
            !Services.prefs.prefHasUserValue(prefName),
            `${prefName} was cleared on the user branch`
          );
        } else if (prefValuesBeforeEnrollment[prefName] !== null) {
          // Can't clear the user branch.
          Assert.equal(
            PrefUtils.getPref(prefName, { branch }),
            prefValuesBeforeEnrollment
          );
        } else {
          Assert.equal(PrefUtils.getPref(prefName, { branch }), value);
        }
      } else {
        Assert.equal(PrefUtils.getPref(prefName, { branch }), value);
      }
    }

    if (expectedPrefs) {
      info("Checking expected prefs...");
      checkExpectedPrefs(expectedPrefs);
    }

    info("Unenrolling...");
    await cleanup();

    info("Checking prefs were restored after unenrollment...");
    // After unenrollment, the prefs should have been restored to their values
    // before enrollment.
    for (const [prefName, originalValue] of Object.entries(
      prefValuesBeforeEnrollment
    )) {
      // If the pref was set on the default branch, it won't be cleared. It will
      // persist until the next restart.
      const expectedValue =
        featureValue.prefs[prefName].branch === "default" &&
        originalValue === null
          ? featureValue.prefs[prefName].value
          : originalValue;
      Assert.equal(PrefUtils.getPref(prefName), expectedValue);
    }

    info("Cleaning up...");
    // Clear all the prefs we specified in `setPrefsBefore`.
    cleanupPrefs(setPrefsBefore);

    // Clear all prefs specified by the enrollment.
    for (const prefName of Object.keys(featureValue.prefs)) {
      Services.prefs.deleteBranch(prefName);
    }

    await assertEmptyStore(manager.store);
    assertNoObservers(manager);

    sandbox.restore();
  }
});

add_task(async function test_prefFlips_unenrollment() {
  const PREF = "nimbus.test-only.foo";
  const PREF2 = "nimbus.test-only.bar";

  const PREF_FLIPS_USER_1 = "pref-flips-user-1";
  const PREF_FLIPS_USER_2 = "pref-flips-user-2";
  const PREF_FLIPS_USER_MULTI = "pref-flips-user-multi";

  const PREF_FLIPS_DEFAULT_1 = "pref-flips-default-1";
  const PREF_FLIPS_DEFAULT_2 = "pref-flips-default-2";
  const PREF_FLIPS_DEFAULT_MULTI = "pref-flips-default-multi";

  const SET_PREF_USER_1 = "set-pref-user-1";
  const SET_PREF_USER_2 = "set-pref-user-2";

  const SET_PREF_DEFAULT_1 = "set-pref-default-1";
  const SET_PREF_DEFAULT_2 = "set-pref-default-2";

  const FEATURE_CONFIGS = {
    [PREF_FLIPS_USER_1]: {
      featureId: FEATURE_ID,
      value: {
        prefs: {
          [PREF]: {
            branch: USER,
            value: PREF_FLIPS_USER_1,
          },
        },
      },
    },
    [PREF_FLIPS_USER_2]: {
      featureId: FEATURE_ID,
      value: {
        prefs: {
          [PREF]: {
            branch: USER,
            value: PREF_FLIPS_USER_2,
          },
        },
      },
    },
    [PREF_FLIPS_USER_MULTI]: {
      featureId: FEATURE_ID,
      value: {
        prefs: {
          [PREF]: {
            branch: USER,
            value: PREF_FLIPS_USER_MULTI,
          },
          [PREF2]: {
            branch: USER,
            value: PREF_FLIPS_USER_MULTI,
          },
        },
      },
    },
    [PREF_FLIPS_DEFAULT_1]: {
      featureId: FEATURE_ID,
      value: {
        prefs: {
          [PREF]: {
            branch: DEFAULT,
            value: PREF_FLIPS_DEFAULT_1,
          },
        },
      },
    },
    [PREF_FLIPS_DEFAULT_2]: {
      featureId: FEATURE_ID,
      value: {
        prefs: {
          [PREF]: {
            branch: DEFAULT,
            value: PREF_FLIPS_DEFAULT_2,
          },
        },
      },
    },
    [PREF_FLIPS_DEFAULT_MULTI]: {
      featureId: FEATURE_ID,
      value: {
        prefs: {
          [PREF]: {
            branch: DEFAULT,
            value: PREF_FLIPS_DEFAULT_MULTI,
          },
          [PREF2]: {
            branch: DEFAULT,
            value: PREF_FLIPS_DEFAULT_MULTI,
          },
        },
      },
    },
    [SET_PREF_USER_1]: {
      featureId: PREF_FEATURES[USER].featureId,
      value: {
        foo: SET_PREF_USER_1,
      },
    },
    [SET_PREF_USER_2]: {
      featureId: PREF_FEATURES[USER].featureId,
      value: {
        foo: SET_PREF_USER_2,
      },
    },
    [SET_PREF_DEFAULT_1]: {
      featureId: PREF_FEATURES[DEFAULT].featureId,
      value: {
        foo: SET_PREF_DEFAULT_1,
      },
    },
    [SET_PREF_DEFAULT_2]: {
      featureId: PREF_FEATURES[DEFAULT].featureId,
      value: {
        foo: SET_PREF_DEFAULT_2,
      },
    },
  };

  const TEST_CASES = [
    // Single enrollment case (experiments)
    {
      name: "set pref on the user branch with a prefFlips experiment and change that pref on the user branch",
      enrollmentOrder: [{ slug: PREF_FLIPS_USER_1 }],
      setPrefsAfter: { [PREF]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [{ slug: PREF_FLIPS_USER_1 }],
      expectedPrefs: { [PREF]: USER_VALUE },
    },
    {
      name: "set pref on the user branch with a prefFlips experiment and change that pref on the default branch",
      enrollmentOrder: [{ slug: PREF_FLIPS_USER_1 }],
      setPrefsAfter: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedEnrollments: [{ slug: PREF_FLIPS_USER_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    {
      name: "set pref on the default branch with a prefFlips experiment and change that pref on the user branch",
      enrollmentOrder: [{ slug: PREF_FLIPS_USER_1 }],
      setPrefsAfter: { [PREF]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [{ slug: PREF_FLIPS_USER_1 }],
    },
    {
      name: "set pref on the default branch with a prefFlips experiment and change that pref on the default branch",
      enrollmentOrder: [{ slug: PREF_FLIPS_USER_1 }],
      setPrefsAfter: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedEnrollments: [{ slug: PREF_FLIPS_USER_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    // Single enrollment case, multiple prefs being reset
    {
      name: "set prefs on the user branch with a prefFlips experiment and change one pref on the user branch",
      setPrefsBefore: { [PREF]: { userBranchValue: SET_BEFORE_VALUE } },
      enrollmentOrder: [{ slug: PREF_FLIPS_USER_MULTI }],
      setPrefsAfter: { [PREF2]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [{ slug: PREF_FLIPS_USER_MULTI }],
      expectedPrefs: { [PREF]: SET_BEFORE_VALUE, [PREF2]: USER_VALUE },
    },
    {
      name: "set prefs on the user branch with a prefFlips experiment and change one pref on the default branch",
      setPrefsBefore: { [PREF]: { userBranchValue: SET_BEFORE_VALUE } },
      enrollmentOrder: [{ slug: PREF_FLIPS_USER_MULTI }],
      setPrefsAfter: { [PREF2]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedEnrollments: [{ slug: PREF_FLIPS_USER_MULTI }],
      expectedPrefs: {
        [PREF]: PREF_FLIPS_USER_MULTI,
        [PREF2]: PREF_FLIPS_USER_MULTI,
      },
    },
    {
      name: "set prefs on the default branch with a prefFlips experiment and change one pref on the user branch",
      setPrefsBefore: { [PREF]: { defaultBranchValue: SET_BEFORE_VALUE } },
      enrollmentOrder: [{ slug: PREF_FLIPS_DEFAULT_MULTI }],
      setPrefsAfter: { [PREF2]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [{ slug: PREF_FLIPS_DEFAULT_MULTI }],
      expectedPrefs: { [PREF]: SET_BEFORE_VALUE, [PREF2]: USER_VALUE },
    },
    {
      name: "set prefs on the default branch with a prefFlips experiment and change one pref on the default branch",
      setPrefsBefore: { [PREF]: { defaultBranchValue: SET_BEFORE_VALUE } },
      enrollmentOrder: [{ slug: PREF_FLIPS_DEFAULT_MULTI }],
      setPrefsAfter: { [PREF2]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedUnenrollments: [{ slug: PREF_FLIPS_DEFAULT_MULTI }],
      expectedPrefs: { [PREF]: SET_BEFORE_VALUE, [PREF2]: DEFAULT_VALUE },
    },
    // Multiple enrollment cases
    // * change pref that would be controlled by a rollout while an experiment is active
    {
      name: "set pref on the user branch with a prefFlips experiment and rollout and then change rollout pref on the user branch",
      setPrefsBefore: { [PREF]: { userBranchValue: SET_BEFORE_VALUE } },
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        // The rollout won't set any prefs because there is an active experiment.
        { slug: PREF_FLIPS_DEFAULT_MULTI, isRollout: true },
      ],
      setPrefsAfter: { [PREF2]: { userBranchValue: USER_VALUE } },
      expectedEnrollments: [
        { slug: PREF_FLIPS_USER_1 },
        // The rollout won't unenroll because the pref flipper doesn't know
        // about its prefs while the experiment is active.
        { slug: PREF_FLIPS_DEFAULT_MULTI, isRollout: true },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1, [PREF2]: USER_VALUE },
    },
    {
      name: "set pref on the user branch with a prefFlips experiment and rollout and then change rollout pref on the default branch",
      setPrefsBefore: { [PREF]: { userBranchValue: SET_BEFORE_VALUE } },
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_MULTI, isRollout: true },
      ],
      setPrefsAfter: { [PREF2]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedEnrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_MULTI, isRollout: true },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1, [PREF2]: DEFAULT_VALUE },
    },
    {
      name: "set pref on the default branch with a prefFlips experiment and rollout and then change rollout pref on the user branch",
      setPrefsBefore: { [PREF]: { defaultBranchValue: SET_BEFORE_VALUE } },
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_MULTI, isRollout: true },
      ],
      setPrefsAfter: { [PREF2]: { userBranchValue: USER_VALUE } },
      expectedEnrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_MULTI, isRollout: true },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1, [PREF2]: USER_VALUE },
    },
    {
      name: "set pref on the default branch with a prefFlips experiment and rollout and then change rollout pref on the default branch",
      setPrefsBefore: { [PREF]: { defaultBranchValue: SET_BEFORE_VALUE } },
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_MULTI, isRollout: true },
      ],
      setPrefsAfter: { [PREF2]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedEnrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_MULTI, isRollout: true },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1, [PREF2]: DEFAULT_VALUE },
    },
    // * prefFlips experiment (user) -> prefFlips rollout (user)
    {
      name: "set pref on the user branch with an experiment and then a rollout",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_USER_2, isRollout: true },
      ],
      expectedEnrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_USER_2, isRollout: true },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    {
      name: "set pref on the user branch with an experiment and then a rollout, then change that pref on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_USER_2, isRollout: true },
      ],
      setPrefsAfter: { [PREF]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_USER_2, isRollout: true },
      ],
      expectedPrefs: { [PREF]: USER_VALUE },
    },
    {
      name: "set pref on the user branch with an experiment and then a rollout, then change that pref on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_USER_2, isRollout: true },
      ],
      setPrefsAfter: { [PREF]: { defaultBranchvalue: DEFAULT_VALUE } },
      expectedEnrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_USER_2, isRollout: true },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    // * prefFlips rollout (user) -> prefFlips experiment (user)
    {
      name: "set pref on the user branch with a rollout and then an experiment",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
      ],
      expectedEnrollments: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_2 },
    },
    {
      name: "set pref on the user branch with a rollout and then an experiment, then change that pref on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
      ],
      setPrefsAfter: { [PREF]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
      ],
      expectedPrefs: { [PREF]: USER_VALUE },
    },
    {
      name: "set pref on the user branch with a rollout and then an experiment, then change that pref on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
      ],
      setPrefsAfter: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedEnrollments: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_2 },
    },
    // * prefFlips experiment (user) -> prefFlips rollout (default)
    {
      name: "set pref on the user branch with an experiment and on the default branch with a rollout",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
      ],
      expectedEnrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    {
      name: "set pref on the user branch with an experiment and on the default branch with a rollout, then change that pref on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
      ],
      setPrefsAfter: { [PREF]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
      ],
      expectedPrefs: { [PREF]: USER_VALUE },
    },
    {
      name: "set pref on the user branch with an experiment and on the default branch with a rollout, then change that pref on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
      ],
      setPrefsAfter: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedEnrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    // * prefFlips rollout (user) -> prefFlips experiment (default)
    {
      name: "set pref on the user branch with a rollout and on the default branch with an experiment",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      expectedEnrollments: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_DEFAULT_1 },
    },
    {
      name: "set pref on the user branch with a rollout and on the default branch with an experiment, then change that pref on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      setPrefsAfter: { [PREF]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      expectedPrefs: { [PREF]: USER_VALUE },
    },
    {
      name: "set pref on the user branch with a rollout and on the default branch with an experiment, then change that pref on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      setPrefsAfter: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      expectedPrefs: { [PREF]: DEFAULT_VALUE },
    },
    // * prefFlips experiment (default) -> prefFlips rollout (user)
    {
      name: "set pref on the default branch with an experiment and on the user branch with a rollout",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_USER_1, isRollout: true },
      ],
      expectedEnrollments: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_USER_1, isRollout: true },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_DEFAULT_1 },
    },
    {
      name: "set pref on the default branch with an experiment and on the user branch with a rollout, then change that pref on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_USER_1, isRollout: true },
      ],
      setPrefsAfter: { [PREF]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_USER_1, isRollout: true },
      ],
      expectedPrefs: { [PREF]: USER_VALUE },
    },
    {
      name: "set pref on the default branch with an experiment and on the user branch with a rollout, then change that pref on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_USER_1, isRollout: true },
      ],
      setPrefsAfter: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_USER_1, isRollout: true },
      ],
      expectedPrefs: { [PREF]: DEFAULT_VALUE },
    },
    // * prefFlips rollout (default) -> prefFlips experiment (user)
    {
      name: "set pref on the default branch with a rollout and on the user branch with an experiment",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
      ],
      expectedEnrollments: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    {
      name: "set pref on the default branch with a rollout and on the user branch with an experiment, then change that pref on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
      ],
      setPrefsAfter: { [PREF]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
      ],
      expectedPrefs: { [PREF]: USER_VALUE },
    },
    {
      name: "set pref on the default branch with a rollout and on the user branch with an experiment, then change that pref on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
      ],
      setPrefsAfter: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedEnrollments: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    // * prefFlips experiment (default) -> prefFlips rollout (default)
    {
      name: "set pref on the default branch with an experiment and then a rollout",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_DEFAULT_2, isRollout: true },
      ],
      expectedEnrollments: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_DEFAULT_2, isRollout: true },
      ],
      expectedPrefs: { [PREF]: PREF_FLIPS_DEFAULT_1 },
    },
    {
      name: "set pref on the default branch with an experiment and then a rollout, then change that pref on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_DEFAULT_2, isRollout: true },
      ],
      setPrefsAfter: { [PREF]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_DEFAULT_2, isRollout: true },
      ],
      expectedPrefs: { [PREF]: USER_VALUE },
    },
    {
      name: "set pref on the default branch with an experiment and then a rollout, then change that pref on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_DEFAULT_2, isRollout: true },
      ],
      setPrefsAfter: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_DEFAULT_2, isRollout: true },
      ],
      expectedPrefs: { [PREF]: DEFAULT_VALUE },
    },
    // * prefFlips rollout (default) -> prefFlips experiment (default)
    {
      name: "set pref on the default branch with a rollout and then an experiment",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_2 },
      ],
      expectedEnrollments: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_2 },
      ],
    },
    {
      name: "set pref on the default branch with a rollout and then an experiment, then change that pref on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_2 },
      ],
      setPrefsAfter: { [PREF]: { userBranchValue: USER_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_2 },
      ],
      expectedPrefs: { [PREF]: USER_VALUE },
    },
    {
      name: "set pref on the default branch with a rollout and then an experiment, then change that pref on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_2 },
      ],
      setPrefsAfter: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_2 },
      ],
      expectedPrefs: { [PREF]: DEFAULT_VALUE },
    },

    // Multiple enrollment cases (prefFlips -> setPref)

    // NB: We don't need to test setPref experiments/rollouts on both branches
    // for the same pref because that configuration is prohibited by
    // gen_feature_manifests.py

    // NB: prefFlip experiments/rollouts will stay enrolled over setPref
    // experiment/rollouts, no matter the enrollment order.

    // NB: If there is a prefFlips experiment/rollout controlling a pref and the
    // client would enroll in a setPref experiment for that same pref, the
    // setPref experiment will not be enrolled.

    // * prefFlip experiment -> setPref experiment

    // TODO: These need to be rewritten
    {
      name: "enroll in a prefFlips experiment on the user branch and then a setPref experiment on the user branch",
      enrollmentOrder: [{ slug: PREF_FLIPS_USER_1 }, { slug: SET_PREF_USER_1 }],
      expectedEnrollments: [{ slug: SET_PREF_USER_1 }],
      expectedUnenrollments: [{ slug: PREF_FLIPS_USER_1 }],
      expectedPrefs: { [PREF]: SET_PREF_USER_1 },
    },
    {
      name: "enroll in a prefFlips experiment on the user branch and then a setPref experiment on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: SET_PREF_DEFAULT_1 },
      ],
      expectedUnenrollments: [{ slug: PREF_FLIPS_USER_1 }],
      expectedEnrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedPrefs: { [PREF]: SET_PREF_DEFAULT_1 },
    },
    {
      name: "enroll in a prefFlips experiment on the default branch and then a setPref experiment on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: SET_PREF_USER_1 },
      ],
      expectedUnenrollments: [{ slug: PREF_FLIPS_DEFAULT_1 }],
      expectedEnrollments: [{ slug: SET_PREF_USER_1 }],
      expectedPrefs: { [PREF]: SET_PREF_USER_1 },
    },
    {
      name: "enroll in a prefFlips experiment on the default branch and then a setPref experiment on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: SET_PREF_DEFAULT_1 },
      ],
      expectedUnenrollments: [{ slug: PREF_FLIPS_DEFAULT_1 }],
      expectedEnrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedPrefs: { [PREF]: SET_PREF_DEFAULT_1 },
    },

    // * prefFlip experiment -> prefFlip rollout -> setPref experiment
    {
      name: "enroll in a prefFlips experiment on the user branch and rollout on the user branch and then a setPref experiment on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_USER_2, isRollout: true },
        { slug: SET_PREF_USER_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_USER_2, isRollout: true },
      ],
      expectedEnrollments: [{ slug: SET_PREF_USER_1 }],
      expectedPrefs: { [PREF]: SET_PREF_USER_1 },
    },
    {
      name: "enroll in a prefFlips experiment on the user branch and rollout on the user branch and then a setPref experiment on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_USER_2, isRollout: true },
        { slug: SET_PREF_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_USER_2, isRollout: true },
      ],
      expectedEnrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedPrefs: { [PREF]: SET_PREF_DEFAULT_1 },
    },
    {
      name: "enroll in a prefFlips experiment on the user branch and rollout on the default branch and then a setPref experiment on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: SET_PREF_USER_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
      ],
      expectedEnrollments: [{ slug: SET_PREF_USER_1 }],
      expectedPrefs: { [PREF]: SET_PREF_USER_1 },
    },
    {
      name: "enroll in a prefFlips experiment on the user branch and rollout on the default branch and then a setPref experiment on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: SET_PREF_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
      ],
      expectedEnrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedPrefs: { [PREF]: SET_PREF_DEFAULT_1 },
    },
    {
      name: "enroll in a prefFlips experiment on the default branch and rollout on the user branch and then a setPref experiment on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: SET_PREF_USER_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_USER_1, isRollout: true },
      ],
      expectedEnrollments: [{ slug: SET_PREF_USER_1 }],
      expectedPrefs: { [PREF]: SET_PREF_USER_1 },
    },
    {
      name: "enroll in a prefFlips experiment on the default branch and rollout on the user branch and then a setPref experiment on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: SET_PREF_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_USER_1, isRollout: true },
      ],
      expectedEnrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedPrefs: { [PREF]: SET_PREF_DEFAULT_1 },
    },
    {
      name: "enroll in a prefFlips experiment on the default branch and rollout on the default branch and then a setPref experiment on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_DEFAULT_2, isRollout: true },
        { slug: SET_PREF_USER_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_DEFAULT_2, isRollout: true },
      ],
      expectedEnrollments: [{ slug: SET_PREF_USER_1 }],
      expectedPrefs: { [PREF]: SET_PREF_USER_1 },
    },
    {
      name: "enroll in a prefFlips experiment on the default branch and rollout on the default branch and then a setPref experiment on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_DEFAULT_2, isRollout: true },
        { slug: SET_PREF_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: PREF_FLIPS_DEFAULT_2, isRollout: true },
      ],
      expectedEnrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedPrefs: { [PREF]: SET_PREF_DEFAULT_1 },
    },

    // * prefFlip rollout -> prefFlip experiment -> setPref experiment
    {
      name: "enroll in a prefFlips rollout on the user branch and experiment on the user branch and then a setPref experiment on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
        { slug: SET_PREF_USER_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
      ],
      expectedEnrollments: [{ slug: SET_PREF_USER_1 }],
      expectedPrefs: { [PREF]: SET_PREF_USER_1 },
    },
    {
      name: "enroll in a prefFlips rollout on the user branch and experiment on the user branch and then a setPref experiment on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
        { slug: SET_PREF_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
      ],
      expectedEnrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedPrefs: { [PREF]: SET_PREF_DEFAULT_1 },
    },
    {
      name: "enroll in a prefFlips rollout on the user branch and experiment on the default branch and then a setPref experiment on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
        { slug: SET_PREF_USER_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_USER_2 },
      ],
      expectedEnrollments: [{ slug: SET_PREF_USER_1 }],
      expectedPrefs: { [PREF]: SET_PREF_USER_1 },
    },
    {
      name: "enroll in a prefFlips rollout on the user branch and experiment on the default branch and then a setPref experiment on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_1 },
        { slug: SET_PREF_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_USER_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      expectedEnrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedPrefs: { [PREF]: SET_PREF_DEFAULT_1 },
    },
    {
      name: "enroll in a prefFlips rollout on the default branch and experiment on the user branch and then a setPref experiment on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
        { slug: SET_PREF_USER_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
      ],
      expectedEnrollments: [{ slug: SET_PREF_USER_1 }],
      expectedPrefs: { [PREF]: SET_PREF_USER_1 },
    },
    {
      name: "enroll in a prefFlips rollout on the default branch and experiment on the user branch and then a setPref experiment on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
        { slug: SET_PREF_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
      ],
      expectedEnrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedPrefs: { [PREF]: SET_PREF_DEFAULT_1 },
    },
    {
      name: "enroll in a prefFlips rollout on the default branch and experiment on the default branch and then a setPref experiment on the user branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_2 },
        { slug: SET_PREF_USER_1 },
      ],
      expectedUnnrollments: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_2 },
      ],
      expectedEnrollments: [{ slug: SET_PREF_USER_1 }],
      expectedPrefs: { [PREF]: SET_PREF_USER_1 },
    },
    {
      name: "enroll in a prefFlips rollout on the default branch and experiment on the default branch and then a setPref experiment on the default branch",
      enrollmentOrder: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_2 },
        { slug: SET_PREF_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: PREF_FLIPS_DEFAULT_1, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_2 },
      ],
      expectedEnrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedPrefs: { [PREF]: SET_PREF_DEFAULT_1 },
    },
    // Multiple enrollment cases (setPref -> prefFlips)
    // * setPref experiment -> prefFLip experiment:
    {
      name: "enroll in a setPref experiment on the user branch and then a prefFlip experiment on the user branch",
      enrollmentOrder: [{ slug: SET_PREF_USER_1 }, { slug: PREF_FLIPS_USER_1 }],
      expectedUnenrollments: [{ slug: SET_PREF_USER_1 }],
      expectedEnrollments: [{ slug: PREF_FLIPS_USER_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    {
      name: "enroll in a setPref experiment on the user branch and then a prefFlip experiment on the default branch",
      enrollmentOrder: [
        { slug: SET_PREF_USER_1 },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      expectedUnenrollments: [{ slug: SET_PREF_USER_1 }],
      expectedEnrollments: [{ slug: PREF_FLIPS_DEFAULT_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_DEFAULT_1 },
    },
    {
      name: "enroll in a setPref experiment on the default branch and then a prefFlip experiment on the user branch",
      enrollmentOrder: [
        { slug: SET_PREF_DEFAULT_1 },
        { slug: PREF_FLIPS_USER_1 },
      ],
      expectedUnenrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedEnrollments: [{ slug: PREF_FLIPS_USER_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    {
      name: "enroll in a setPref experiment on the default branch and then a prefFlip experiment on the default branch",
      enrollmentOrder: [
        { slug: SET_PREF_DEFAULT_1 },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      expectedUnenrollments: [{ slug: SET_PREF_DEFAULT_1 }],
      expectedEnrollments: [{ slug: PREF_FLIPS_DEFAULT_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_DEFAULT_1 },
    },
    // * setPref experiment -> setPref rollout -> prefFlip experiment
    {
      name: "enroll in a setPref experiment and rollout on the user branch and then a prefFlips experiment on the user branch",
      enrollmentOrder: [
        { slug: SET_PREF_USER_1 },
        { slug: SET_PREF_USER_2, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
      ],
      expectedUnenrollments: [
        { slug: SET_PREF_USER_1 },
        { slug: SET_PREF_USER_2, isRollout: true },
      ],
      expectedEnrollments: [{ slug: PREF_FLIPS_USER_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    {
      name: "enroll in a setPref experiment and rollout on the user branch and then a prefFlips experiment on the default branch",
      enrollmentOrder: [
        { slug: SET_PREF_USER_1 },
        { slug: SET_PREF_USER_2, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: SET_PREF_USER_1 },
        { slug: SET_PREF_USER_2, isRollout: true },
      ],
      expectedEnrollments: [{ slug: PREF_FLIPS_DEFAULT_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_DEFAULT_1 },
    },
    {
      name: "enroll in a setPref experiment and rollout on the default branch and then a prefFlips experiment on the user branch",
      enrollmentOrder: [
        { slug: SET_PREF_DEFAULT_1 },
        { slug: SET_PREF_DEFAULT_2, isRollout: true },
        { slug: PREF_FLIPS_USER_1 },
      ],
      expectedUnenrollments: [
        { slug: SET_PREF_DEFAULT_1 },
        { slug: SET_PREF_DEFAULT_2, isRollout: true },
      ],
      expectedEnrollments: [{ slug: PREF_FLIPS_USER_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    {
      name: "enroll in a setPref experiment and rollout on the default branch and then a prefFlips experiment on the default branch",
      enrollmentOrder: [
        { slug: SET_PREF_DEFAULT_1 },
        { slug: SET_PREF_DEFAULT_2, isRollout: true },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: SET_PREF_DEFAULT_1 },
        { slug: SET_PREF_DEFAULT_2, isRollout: true },
      ],
      expectedEnrollments: [{ slug: PREF_FLIPS_DEFAULT_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_DEFAULT_1 },
    },
    // * setPref rollout -> setPref experiment -> prefFlip experiment
    {
      name: "enroll in a setPref rollout on the user branch and experiment on the user branch and then a prefFlip experiment on the user branch",
      enrollmentOrder: [
        { slug: SET_PREF_USER_1, isRollout: true },
        { slug: SET_PREF_USER_2 },
        { slug: PREF_FLIPS_USER_1 },
      ],
      expectedUnenrollments: [
        { slug: SET_PREF_USER_1, isRollout: true },
        { slug: SET_PREF_USER_2 },
      ],
      expectedEnrollments: [{ slug: PREF_FLIPS_USER_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    {
      name: "enroll in a setPref rollout on the user branch and experiment on the user branch and then a prefFlip experiment on the default branch",
      enrollmentOrder: [
        { slug: SET_PREF_USER_1, isRollout: true },
        { slug: SET_PREF_USER_2 },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: SET_PREF_USER_1, isRollout: true },
        { slug: SET_PREF_USER_2 },
      ],
      expectedEnrollments: [{ slug: PREF_FLIPS_DEFAULT_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_DEFAULT_1 },
    },
    {
      name: "enroll in a setPref rollout on the default branch and experiment on the user branch and then a prefFlip experiment on the user branch",
      enrollmentOrder: [
        { slug: SET_PREF_DEFAULT_1, isRollout: true },
        { slug: SET_PREF_DEFAULT_2 },
        { slug: PREF_FLIPS_USER_1 },
      ],
      expectedUnenrollments: [
        { slug: SET_PREF_DEFAULT_1, isRollout: true },
        { slug: SET_PREF_DEFAULT_2 },
      ],
      expectedEnrollments: [{ slug: PREF_FLIPS_USER_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_USER_1 },
    },
    {
      name: "enroll in a setPref rollout on the default branch and experiment on the user branch and then a prefFlip experiment on the default branch",
      enrollmentOrder: [
        { slug: SET_PREF_DEFAULT_1, isRollout: true },
        { slug: SET_PREF_DEFAULT_2 },
        { slug: PREF_FLIPS_DEFAULT_1 },
      ],
      expectedUnenrollments: [
        { slug: SET_PREF_DEFAULT_1, isRollout: true },
        { slug: SET_PREF_DEFAULT_2 },
      ],
      expectedEnrollments: [{ slug: PREF_FLIPS_DEFAULT_1 }],
      expectedPrefs: { [PREF]: PREF_FLIPS_DEFAULT_1 },
    },
  ];

  for (const [i, { name, ...testCase }] of TEST_CASES.entries()) {
    info(`Running test case ${i}: ${name}`);

    const sandbox = sinon.createSandbox();

    const {
      // Prefs that should be set after enrollment. These will be undone after
      // each test case.
      setPrefsBefore = {},
      // The slugs to enroll in the order they should be enrolled in, and
      // whether or not they should enroll as rollouts.
      enrollmentOrder,
      // Prefs that should be set after enrollment. These will be undone
      // after each test case.
      setPrefsAfter = {},
      // The expected active enrollments after all enrollments have finished.
      expectedEnrollments = [],
      // The expected inactive enrollments after all enrollments have finished.
      expectedUnenrollments = [],
      // Prefs to check after enrollment. They will be checked on the user
      // branch.
      expectedPrefs,
    } = testCase;

    info("Setting prefs before enrollment...");
    setPrefs(setPrefsBefore);

    const manager = ExperimentFakes.manager();
    sandbox.stub(ExperimentAPI, "_store").get(() => manager.store);

    await manager.onStartup();

    info("Enrolling...");
    for (const { slug, isRollout = false } of enrollmentOrder) {
      await ExperimentFakes.enrollWithFeatureConfig(FEATURE_CONFIGS[slug], {
        slug: `${slug}-${isRollout ? "rollout" : "experiment"}`,
        manager,
        isRollout,
      });
    }

    info("Setting prefs after enrollment...");
    setPrefs(setPrefsAfter);

    info("Checking expected enrollments...");
    for (const { slug, isRollout = false } of expectedEnrollments) {
      const computedSlug = `${slug}-${isRollout ? "rollout" : "experiment"}`;
      const enrollment = manager.store.get(computedSlug);

      Assert.ok(
        enrollment !== null && typeof enrollment !== "undefined",
        `An enrollment for ${computedSlug} should exist`
      );
      Assert.ok(enrollment.active, `It should still be active`);
    }

    info("Checking expected unenrollments...");
    for (const { slug, isRollout = false } of expectedUnenrollments) {
      const computedSlug = `${slug}-${isRollout ? "rollout" : "experiment"}`;
      const enrollment = manager.store.get(computedSlug);

      Assert.ok(
        enrollment !== null,
        `An enrollment for ${computedSlug} should exist`
      );
      Assert.ok(!enrollment.active, "It should no longer be active");
    }

    if (expectedPrefs) {
      info("Checking expected prefs...");
      checkExpectedPrefs(expectedPrefs);
    }

    info("Unenrolling from active experiments...");
    for (const { slug, isRollout = false } of expectedEnrollments) {
      const computedSlug = `${slug}-${isRollout ? "rollout" : "experiment"}`;
      info(`Unenrolling from ${computedSlug}\n`);
      manager.unenroll(computedSlug, "cleanup");
    }
    await assertEmptyStore(manager.store);
    assertNoObservers(manager);

    info("Cleaning up prefs...");
    Services.prefs.deleteBranch(PREF);
    Services.prefs.deleteBranch(PREF2);

    sandbox.restore();
  }
});

add_task(async function test_prefFlip_setPref_restore() {
  const PREF = "nimbus.test-only.foo";

  const SET_PREF_USER = "set-pref-user";
  const SET_PREF_DEFAULT = "set-pref-default";
  const PREF_FLIPS_USER = "pref-flips-user";
  const PREF_FLIPS_DEFAULT = "pref-flips-default";

  const FEATURE_CONFIGS = {
    [SET_PREF_USER]: {
      featureId: PREF_FEATURES[USER].featureId,
      value: {
        foo: SET_PREF_USER,
      },
    },
    [SET_PREF_DEFAULT]: {
      featureId: PREF_FEATURES[DEFAULT].featureId,
      value: {
        foo: SET_PREF_DEFAULT,
      },
    },
    [PREF_FLIPS_USER]: {
      featureId: FEATURE_ID,
      value: {
        prefs: {
          [PREF]: {
            branch: USER,
            value: PREF_FLIPS_USER,
          },
        },
      },
    },
    [PREF_FLIPS_DEFAULT]: {
      featureId: FEATURE_ID,
      value: {
        prefs: {
          [PREF]: {
            branch: DEFAULT,
            value: PREF_FLIPS_DEFAULT,
          },
        },
      },
    },
  };

  const TEST_CASES = [
    // 1. No prefs set beforehand.
    // - setPref first
    {
      name: "enroll in setPref on user branch and prefFlips on user branch",
      enrollmentOrder: [SET_PREF_USER, PREF_FLIPS_USER],
      expectedPrefs: { [PREF]: {} },
    },
    {
      name: "enroll in setPref on user branch and prefFlips on default branch",
      enrollmentOrder: [SET_PREF_USER, PREF_FLIPS_DEFAULT],
      expectedPrefs: { [PREF]: { defaultBranchValue: PREF_FLIPS_DEFAULT } },
    },
    {
      name: "enroll in setPref on default branch and prefFlips on user branch",
      enrollmentOrder: [SET_PREF_DEFAULT, PREF_FLIPS_USER],
      expectedPrefs: { [PREF]: { defaultBranchValue: SET_PREF_DEFAULT } },
    },
    {
      name: "enroll in setPref on default branch and prefFlips on default branch",
      enrollmentOrder: [SET_PREF_DEFAULT, PREF_FLIPS_DEFAULT],
      expectedPrefs: { [PREF]: { defaultBranchValue: SET_PREF_DEFAULT } },
    },
    // - prefFlips first
    {
      name: "enroll in prefFlips on user branch and setPref on user branch",
      enrollmentOrder: [PREF_FLIPS_USER, SET_PREF_USER],
      expectedPrefs: { [PREF]: {} },
    },
    {
      name: "enroll in prefFlips on user branch and setPref on default branch",
      enrollmentOrder: [PREF_FLIPS_USER, SET_PREF_DEFAULT],
      expectedPrefs: { [PREF]: { defaultBranchValue: SET_PREF_DEFAULT } },
    },
    {
      name: "enroll in prefFlips on default branch and setPref on user branch",
      enrollmentOrder: [PREF_FLIPS_DEFAULT, SET_PREF_USER],
      expectedPrefs: { [PREF]: { defaultBranchValue: PREF_FLIPS_DEFAULT } },
    },
    {
      name: "enroll in prefFlips on default branch and setPref on default branch",
      enrollmentOrder: [PREF_FLIPS_DEFAULT, SET_PREF_DEFAULT],
      expectedPrefs: { [PREF]: { defaultBranchValue: SET_PREF_DEFAULT } },
    },
    // 2. User branch prefs set beforehand.
    // - setPref first
    {
      name: "set prefs on user branch and enroll in setPref on user branch and prefFlips on user branch",
      setPrefsBefore: { [PREF]: { userBranchValue: USER_VALUE } },
      enrollmentOrder: [SET_PREF_USER, PREF_FLIPS_USER],
      expectedPrefs: { [PREF]: { userBranchValue: USER_VALUE } },
    },
    {
      name: "set prefs on user branch and enroll in setPref on user branch and prefFlips on default branch",
      setPrefsBefore: { [PREF]: { userBranchValue: USER_VALUE } },
      enrollmentOrder: [SET_PREF_USER, PREF_FLIPS_DEFAULT],
      expectedPrefs: {
        [PREF]: {
          userBranchValue: USER_VALUE,
          defaultBranchValue: PREF_FLIPS_DEFAULT,
        },
      },
    },
    {
      name: "set prefs on user branch and enroll in setPref on default branch and prefFlips on user branch",
      setPrefsBefore: { [PREF]: { userBranchValue: USER_VALUE } },
      enrollmentOrder: [SET_PREF_DEFAULT, PREF_FLIPS_USER],
      expectedPrefs: {
        [PREF]: {
          userBranchValue: USER_VALUE,
          defaultBranchValue: SET_PREF_DEFAULT,
        },
      },
    },
    {
      name: "set prefs on user branch and enroll in setPref on default branch and prefFlips on default branch",
      setPrefsBefore: { [PREF]: { userBranchValue: USER_VALUE } },
      enrollmentOrder: [SET_PREF_DEFAULT, PREF_FLIPS_DEFAULT],
      expectedPrefs: {
        [PREF]: {
          userBranchValue: USER_VALUE,
          defaultBranchValue: SET_PREF_DEFAULT,
        },
      },
    },
    // - prefFlips first
    {
      name: "set prefs on user branch and enroll in prefFlips on user branch and setPref on user branch",
      setPrefsBefore: { [PREF]: { userBranchValue: USER_VALUE } },
      enrollmentOrder: [PREF_FLIPS_USER, SET_PREF_USER],
      expectedPrefs: { [PREF]: { userBranchValue: USER_VALUE } },
    },
    {
      name: "set prefs on user branch and enroll in prefFlips on user branch and setPref on default branch",
      setPrefsBefore: { [PREF]: { userBranchValue: USER_VALUE } },
      enrollmentOrder: [PREF_FLIPS_USER, SET_PREF_DEFAULT],
      expectedPrefs: {
        [PREF]: {
          userBranchValue: USER_VALUE,
          defaultBranchValue: SET_PREF_DEFAULT,
        },
      },
    },
    {
      name: "set prefs on user branch and enroll in prefFlips on default branch and setPref on user branch",
      setPrefsBefore: { [PREF]: { userBranchValue: USER_VALUE } },
      enrollmentOrder: [PREF_FLIPS_DEFAULT, SET_PREF_USER],
      expectedPrefs: {
        [PREF]: {
          userBranchValue: USER_VALUE,
          defaultBranchValue: PREF_FLIPS_DEFAULT,
        },
      },
    },
    {
      name: "set prefs on user branch and enroll in prefFlips on default branch and setPref on default branch",
      setPrefsBefore: { [PREF]: { userBranchValue: USER_VALUE } },
      enrollmentOrder: [PREF_FLIPS_DEFAULT, SET_PREF_DEFAULT],
      expectedPrefs: {
        [PREF]: {
          userBranchValue: USER_VALUE,
          defaultBranchValue: SET_PREF_DEFAULT,
        },
      },
    },
    // 3. Default branch prefs set beforehand.
    // - setPref first
    {
      setPrefsBefore: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      name: "set prefs on default branch and enroll branch in setPref on user branch and prefFlips on user branch",
      enrollmentOrder: [SET_PREF_USER, PREF_FLIPS_USER],
      expectedPrefs: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
    },
    {
      setPrefsBefore: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      name: "set prefs on default branch and enroll branch in setPref on user branch and prefFlips on default branch",
      enrollmentOrder: [SET_PREF_USER, PREF_FLIPS_DEFAULT],
      expectedPrefs: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
    },
    {
      setPrefsBefore: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      name: "set prefs on default branch and enroll branch in setPref on default branch and prefFlips on user branch",
      enrollmentOrder: [SET_PREF_DEFAULT, PREF_FLIPS_USER],
      expectedPrefs: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
    },
    {
      setPrefsBefore: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      name: "set prefs on default branch and enroll branch in setPref on default branch and prefFlips on default branch",
      enrollmentOrder: [SET_PREF_DEFAULT, PREF_FLIPS_DEFAULT],
      expectedPrefs: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
    },
    // - prefFlips first
    {
      setPrefsBefore: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      name: "set prefs on default branch and enroll branch in prefFlips on user branch and setPref on user branch",
      enrollmentOrder: [PREF_FLIPS_USER, SET_PREF_USER],
      expectedPrefs: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
    },
    {
      name: "set prefs on default branch and enroll branch in prefFlips on user branch and setPref on default branch",
      setPrefsBefore: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      enrollmentOrder: [PREF_FLIPS_USER, SET_PREF_DEFAULT],
      expectedPrefs: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
    },
    {
      name: "set prefs on default branch and enroll branch in prefFlips on default branch and setPref on user branch",
      setPrefsBefore: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      enrollmentOrder: [PREF_FLIPS_DEFAULT, SET_PREF_USER],
      expectedPrefs: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
    },
    {
      name: "set prefs on default branch and enroll branch in prefFlips on default branch and setPref on default branch",
      setPrefsBefore: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
      enrollmentOrder: [PREF_FLIPS_DEFAULT, SET_PREF_DEFAULT],
      expectedPrefs: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
    },
    {
      name: "set prefs on default branch and enroll branch in prefFlips on default branch and setPref on default branch, unenrolling in reverse order",
      setPrefsBefore: { [PREF]: { defaultBranchValue: DEFAULT_VALUE } },
--> --------------------

--> maximum size reached

--> --------------------

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

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