Global Metrics

path: .metrics.halstead.bugs
old: 4.566575196351224
new: 4.5708066528261595

path: .metrics.halstead.difficulty
old: 81.15116279069767
new: 81.23255813953489

path: .metrics.halstead.level
old: 0.012322682332712423
new: 0.012310334955625536

path: .metrics.halstead.length
old: 2585.0
new: 2586.0

path: .metrics.halstead.purity_ratio
old: 0.5461986366059473
new: 0.5459874229026966

path: .metrics.halstead.effort
old: 1603495.7095431597
new: 1605724.9602070637

path: .metrics.halstead.time
old: 89083.09497461998
new: 89206.94223372574

path: .metrics.halstead.N2
old: 997.0
new: 998.0

path: .metrics.halstead.volume
old: 19759.368250567662
new: 19767.012106757436

path: .metrics.mi.mi_sei
old: -58.41335855548763
new: -58.41626012744902

path: .metrics.mi.mi_original
old: -3.4768705709522294
new: -3.4788817873764515

Spaces Data

Minimal test - lines (278, 930)

path: .spaces[1].metrics.halstead.volume
old: 11778.825024881426
new: 11785.933549338204

path: .spaces[1].metrics.halstead.bugs
old: 2.645487189337893
new: 2.6493380277836787

path: .spaces[1].metrics.halstead.difficulty
old: 60.02586206896552
new: 60.12068965517241

path: .spaces[1].metrics.halstead.time
old: 39279.67368211176
new: 39365.46962312482

path: .spaces[1].metrics.halstead.level
old: 0.01665948585379865
new: 0.016633209062231143

path: .spaces[1].metrics.halstead.effort
old: 707034.1262780117
new: 708578.4532162468

path: .spaces[1].metrics.halstead.N2
old: 633.0
new: 634.0

path: .spaces[1].metrics.halstead.purity_ratio
old: 0.5393079607995286
new: 0.5389826845867424

path: .spaces[1].metrics.halstead.length
old: 1657.0
new: 1658.0

path: .spaces[1].metrics.mi.mi_original
old: 11.503345218859437
new: 11.500207963862309

path: .spaces[1].metrics.mi.mi_visual_studio
old: 6.727102467169261
new: 6.725267815124157

path: .spaces[1].metrics.mi.mi_sei
old: -41.34822162047297
new: -41.352747722699334

Code

add_task(async function test_privacy_other_prefs() {
  registerCleanupFunction(() => {
    Services.prefs.clearUserPref("security.tls.version.min");
    Services.prefs.clearUserPref("security.tls.version.max");
  });

  const cookieSvc = Ci.nsICookieService;

  // Create an object to hold the values to which we will initialize the prefs.
  const SETTINGS = {
    "network.webRTCIPHandlingPolicy": {
      "media.peerconnection.ice.default_address_only": false,
      "media.peerconnection.ice.no_host": false,
      "media.peerconnection.ice.proxy_only_if_behind_proxy": false,
      "media.peerconnection.ice.proxy_only": false,
    },
    "network.tlsVersionRestriction": {
      "security.tls.version.min": tlsMinPref,
      "security.tls.version.max": 4,
    },
    "network.peerConnectionEnabled": {
      "media.peerconnection.enabled": true,
    },
    "services.passwordSavingEnabled": {
      "signon.rememberSignons": true,
    },
    "websites.referrersEnabled": {
      "network.http.sendRefererHeader": 2,
    },
    "websites.resistFingerprinting": {
      "privacy.resistFingerprinting": true,
    },
    "websites.firstPartyIsolate": {
      "privacy.firstparty.isolate": false,
    },
    "websites.cookieConfig": {
      "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_ACCEPT,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY,
    },
  };

  let defaultPrefs = new Preferences({ defaultBranch: true });
  let defaultCookieBehavior = defaultPrefs.get("network.cookie.cookieBehavior");
  let defaultBehavior;
  switch (defaultCookieBehavior) {
    case cookieSvc.BEHAVIOR_ACCEPT:
      defaultBehavior = "allow_all";
      break;
    case cookieSvc.BEHAVIOR_REJECT_FOREIGN:
      defaultBehavior = "reject_third_party";
      break;
    case cookieSvc.BEHAVIOR_REJECT:
      defaultBehavior = "reject_all";
      break;
    case cookieSvc.BEHAVIOR_LIMIT_FOREIGN:
      defaultBehavior = "allow_visited";
      break;
    case cookieSvc.BEHAVIOR_REJECT_TRACKER:
      defaultBehavior = "reject_trackers";
      break;
    case cookieSvc.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN:
      defaultBehavior = "reject_trackers_and_partition_foreign";
      break;
    default:
      ok(
        false,
        `Unexpected cookie behavior encountered: ${defaultCookieBehavior}`
      );
      break;
  }

  async function background() {
    browser.test.onMessage.addListener(async (msg, ...args) => {
      let data = args[0];
      // The second argument is the end of the api name,
      // e.g., "network.webRTCIPHandlingPolicy".
      let apiObj = args[1].split(".").reduce((o, i) => o[i], browser.privacy);
      let settingData;
      switch (msg) {
        case "set":
          try {
            await apiObj.set(data);
          } catch (e) {
            browser.test.sendMessage("settingThrowsException", {
              message: e.message,
            });
            break;
          }
          settingData = await apiObj.get({});
          browser.test.sendMessage("settingData", settingData);
          break;
        case "get":
          settingData = await apiObj.get({});
          browser.test.sendMessage("gettingData", settingData);
          break;
      }
    });
  }

  // Set prefs to our initial values.
  for (let setting in SETTINGS) {
    for (let pref in SETTINGS[setting]) {
      Preferences.set(pref, SETTINGS[setting][pref]);
    }
  }

  registerCleanupFunction(() => {
    // Reset the prefs.
    for (let setting in SETTINGS) {
      for (let pref in SETTINGS[setting]) {
        Preferences.reset(pref);
      }
    }
  });

  await promiseStartupManager();

  let extension = ExtensionTestUtils.loadExtension({
    background,
    manifest: {
      permissions: ["privacy"],
    },
    useAddonManager: "temporary",
  });

  await extension.startup();

  async function testSetting(setting, value, expected, expectedValue = value) {
    extension.sendMessage("set", { value: value }, setting);
    let data = await extension.awaitMessage("settingData");
    deepEqual(
      data.value,
      expectedValue,
      `Got expected result on setting ${setting} to ${uneval(value)}`
    );
    for (let pref in expected) {
      equal(
        Preferences.get(pref),
        expected[pref],
        `${pref} set correctly for ${expected[pref]}`
      );
    }
  }

  async function testSettingException(setting, value, expected) {
    extension.sendMessage("set", { value: value }, setting);
    let data = await extension.awaitMessage("settingThrowsException");
    equal(data.message, expected);
  }

  async function testGetting(getting, expected, expectedValue) {
    extension.sendMessage("get", null, getting);
    let data = await extension.awaitMessage("gettingData");
    deepEqual(
      data.value,
      expectedValue,
      `Got expected result on getting ${getting}`
    );
    for (let pref in expected) {
      equal(
        Preferences.get(pref),
        expected[pref],
        `${pref} get correctly for ${expected[pref]}`
      );
    }
  }

  await testSetting(
    "network.webRTCIPHandlingPolicy",
    "default_public_and_private_interfaces",
    {
      "media.peerconnection.ice.default_address_only": true,
      "media.peerconnection.ice.no_host": false,
      "media.peerconnection.ice.proxy_only_if_behind_proxy": false,
      "media.peerconnection.ice.proxy_only": false,
    }
  );
  await testSetting(
    "network.webRTCIPHandlingPolicy",
    "default_public_interface_only",
    {
      "media.peerconnection.ice.default_address_only": true,
      "media.peerconnection.ice.no_host": true,
      "media.peerconnection.ice.proxy_only_if_behind_proxy": false,
      "media.peerconnection.ice.proxy_only": false,
    }
  );
  await testSetting(
    "network.webRTCIPHandlingPolicy",
    "disable_non_proxied_udp",
    {
      "media.peerconnection.ice.default_address_only": true,
      "media.peerconnection.ice.no_host": true,
      "media.peerconnection.ice.proxy_only_if_behind_proxy": true,
      "media.peerconnection.ice.proxy_only": false,
    }
  );
  await testSetting("network.webRTCIPHandlingPolicy", "proxy_only", {
    "media.peerconnection.ice.default_address_only": false,
    "media.peerconnection.ice.no_host": false,
    "media.peerconnection.ice.proxy_only_if_behind_proxy": false,
    "media.peerconnection.ice.proxy_only": true,
  });
  await testSetting("network.webRTCIPHandlingPolicy", "default", {
    "media.peerconnection.ice.default_address_only": false,
    "media.peerconnection.ice.no_host": false,
    "media.peerconnection.ice.proxy_only_if_behind_proxy": false,
    "media.peerconnection.ice.proxy_only": false,
  });

  await testSetting("network.peerConnectionEnabled", false, {
    "media.peerconnection.enabled": false,
  });
  await testSetting("network.peerConnectionEnabled", true, {
    "media.peerconnection.enabled": true,
  });

  await testSetting("websites.referrersEnabled", false, {
    "network.http.sendRefererHeader": 0,
  });
  await testSetting("websites.referrersEnabled", true, {
    "network.http.sendRefererHeader": 2,
  });

  await testSetting("websites.resistFingerprinting", false, {
    "privacy.resistFingerprinting": false,
  });
  await testSetting("websites.resistFingerprinting", true, {
    "privacy.resistFingerprinting": true,
  });

  await testSetting("websites.trackingProtectionMode", "always", {
    "privacy.trackingprotection.enabled": true,
    "privacy.trackingprotection.pbmode.enabled": true,
  });
  await testSetting("websites.trackingProtectionMode", "never", {
    "privacy.trackingprotection.enabled": false,
    "privacy.trackingprotection.pbmode.enabled": false,
  });
  await testSetting("websites.trackingProtectionMode", "private_browsing", {
    "privacy.trackingprotection.enabled": false,
    "privacy.trackingprotection.pbmode.enabled": true,
  });

  await testSetting("services.passwordSavingEnabled", false, {
    "signon.rememberSignons": false,
  });
  await testSetting("services.passwordSavingEnabled", true, {
    "signon.rememberSignons": true,
  });

  await testSetting(
    "websites.cookieConfig",
    { behavior: "reject_third_party", nonPersistentCookies: true },
    {
      "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT_FOREIGN,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_SESSION,
    }
  );
  // A missing nonPersistentCookies property should default to false.
  await testSetting(
    "websites.cookieConfig",
    { behavior: "reject_third_party" },
    {
      "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT_FOREIGN,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY,
    },
    { behavior: "reject_third_party", nonPersistentCookies: false }
  );
  // A missing behavior property should reset the pref.
  await testSetting(
    "websites.cookieConfig",
    { nonPersistentCookies: true },
    {
      "network.cookie.cookieBehavior": defaultCookieBehavior,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_SESSION,
    },
    { behavior: defaultBehavior, nonPersistentCookies: true }
  );
  await testSetting(
    "websites.cookieConfig",
    { behavior: "reject_all" },
    {
      "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY,
    },
    { behavior: "reject_all", nonPersistentCookies: false }
  );
  await testSetting(
    "websites.cookieConfig",
    { behavior: "allow_visited" },
    {
      "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_LIMIT_FOREIGN,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY,
    },
    { behavior: "allow_visited", nonPersistentCookies: false }
  );
  await testSetting(
    "websites.cookieConfig",
    { behavior: "allow_all" },
    {
      "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_ACCEPT,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY,
    },
    { behavior: "allow_all", nonPersistentCookies: false }
  );
  await testSetting(
    "websites.cookieConfig",
    { nonPersistentCookies: true },
    {
      "network.cookie.cookieBehavior": defaultCookieBehavior,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_SESSION,
    },
    { behavior: defaultBehavior, nonPersistentCookies: true }
  );
  await testSetting(
    "websites.cookieConfig",
    { nonPersistentCookies: false },
    {
      "network.cookie.cookieBehavior": defaultCookieBehavior,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY,
    },
    { behavior: defaultBehavior, nonPersistentCookies: false }
  );
  await testSetting(
    "websites.cookieConfig",
    { behavior: "reject_trackers" },
    {
      "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT_TRACKER,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY,
    },
    { behavior: "reject_trackers", nonPersistentCookies: false }
  );
  await testSetting(
    "websites.cookieConfig",
    { behavior: "reject_trackers_and_partition_foreign" },
    {
      "network.cookie.cookieBehavior":
        cookieSvc.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY,
    },
    {
      behavior: "reject_trackers_and_partition_foreign",
      nonPersistentCookies: false,
    }
  );

  // 1. Can't enable FPI when cookie behavior is "reject_trackers_and_partition_foreign"
  await testSettingException(
    "websites.firstPartyIsolate",
    true,
    "Can't enable firstPartyIsolate when cookieBehavior is 'reject_trackers_and_partition_foreign'"
  );

  // 2. Change cookieConfig to reject_trackers should work normally.
  await testSetting(
    "websites.cookieConfig",
    { behavior: "reject_trackers" },
    {
      "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT_TRACKER,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY,
    },
    { behavior: "reject_trackers", nonPersistentCookies: false }
  );

  // 3. Enable FPI
  await testSetting("websites.firstPartyIsolate", true, {
    "privacy.firstparty.isolate": true,
  });

  // 4. When FPI is enabled, change setting to "reject_trackers_and_partition_foreign" is invalid
  await testSettingException(
    "websites.cookieConfig",
    { behavior: "reject_trackers_and_partition_foreign" },
    "Invalid cookieConfig 'reject_trackers_and_partition_foreign' when firstPartyIsolate is enabled"
  );

  // 5. Set conflict settings manually and check prefs.
  Preferences.set("network.cookie.cookieBehavior", 5);
  await testGetting(
    "websites.firstPartyIsolate",
    { "privacy.firstparty.isolate": true },
    true
  );
  await testGetting(
    "websites.cookieConfig",
    {
      "network.cookie.cookieBehavior":
        cookieSvc.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY,
    },
    {
      behavior: "reject_trackers_and_partition_foreign",
      nonPersistentCookies: false,
    }
  );

  // 6. It is okay to set current saved value.
  await testSetting("websites.firstPartyIsolate", true, {
    "privacy.firstparty.isolate": true,
  });
  await testSetting(
    "websites.cookieConfig",
    { behavior: "reject_trackers_and_partition_foreign" },
    {
      "network.cookie.cookieBehavior":
        cookieSvc.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
      "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY,
    },
    {
      behavior: "reject_trackers_and_partition_foreign",
      nonPersistentCookies: false,
    }
  );

  await testSetting("websites.firstPartyIsolate", false, {
    "privacy.firstparty.isolate": false,
  });

  await testSetting(
    "network.tlsVersionRestriction",
    {
      minimum: "TLSv1.2",
      maximum: "TLSv1.3",
    },
    {
      "security.tls.version.min": 3,
      "security.tls.version.max": 4,
    }
  );

  // Single values
  await testSetting(
    "network.tlsVersionRestriction",
    {
      minimum: "TLSv1.3",
    },
    {
      "security.tls.version.min": 4,
      "security.tls.version.max": 4,
    },
    {
      minimum: "TLSv1.3",
      maximum: "TLSv1.3",
    }
  );

  // Single values
  await testSetting(
    "network.tlsVersionRestriction",
    {
      minimum: "TLSv1.3",
    },
    {
      "security.tls.version.min": 4,
      "security.tls.version.max": 4,
    },
    {
      minimum: "TLSv1.3",
      maximum: "TLSv1.3",
    }
  );

  // Invalid values.
  await testSettingException(
    "network.tlsVersionRestriction",
    {
      minimum: "invalid",
      maximum: "invalid",
    },
    "Setting TLS version invalid is not allowed for security reasons."
  );

  // Invalid values.
  await testSettingException(
    "network.tlsVersionRestriction",
    {
      minimum: "invalid2",
    },
    "Setting TLS version invalid2 is not allowed for security reasons."
  );

  // Invalid values.
  await testSettingException(
    "network.tlsVersionRestriction",
    {
      maximum: "invalid3",
    },
    "Setting TLS version invalid3 is not allowed for security reasons."
  );

  await testSetting(
    "network.tlsVersionRestriction",
    {
      minimum: "TLSv1.2",
    },
    {
      "security.tls.version.min": 3,
      "security.tls.version.max": 4,
    },
    {
      minimum: "TLSv1.2",
      maximum: "TLSv1.3",
    }
  );

  await testSetting(
    "network.tlsVersionRestriction",
    {
      maximum: "TLSv1.2",
    },
    {
      "security.tls.version.min": tlsMinPref,
      "security.tls.version.max": 3,
    },
    {
      minimum: tlsMinVer,
      maximum: "TLSv1.2",
    }
  );

  // Not supported version.
  if (tlsMinPref === 3) {
    await testSettingException(
      "network.tlsVersionRestriction",
      {
        minimum: "TLSv1",
      },
      "Setting TLS version TLSv1 is not allowed for security reasons."
    );

    await testSettingException(
      "network.tlsVersionRestriction",
      {
        minimum: "TLSv1.1",
      },
      "Setting TLS version TLSv1.1 is not allowed for security reasons."
    );

    await testSettingException(
      "network.tlsVersionRestriction",
      {
        maximum: "TLSv1",
      },
      "Setting TLS version TLSv1 is not allowed for security reasons."
    );

    await testSettingException(
      "network.tlsVersionRestriction",
      {
        maximum: "TLSv1.1",
      },
      "Setting TLS version TLSv1.1 is not allowed for security reasons."
    );
  }

  // Min vs Max
  await testSettingException(
    "network.tlsVersionRestriction",
    {
      minimum: "TLSv1.3",
      maximum: "TLSv1.2",
    },
    "Setting TLS min version grater than the max version is not allowed."
  );

  // Min vs Max (with default max)
  await testSetting(
    "network.tlsVersionRestriction",
    {
      minimum: "TLSv1.2",
      maximum: "TLSv1.2",
    },
    {
      "security.tls.version.min": 3,
      "security.tls.version.max": 3,
    }
  );
  await testSettingException(
    "network.tlsVersionRestriction",
    {
      minimum: "TLSv1.3",
    },
    "Setting TLS min version grater than the max version is not allowed."
  );

  // Max vs Min
  await testSetting(
    "network.tlsVersionRestriction",
    {
      minimum: "TLSv1.3",
      maximum: "TLSv1.3",
    },
    {
      "security.tls.version.min": 4,
      "security.tls.version.max": 4,
    }
  );
  await testSettingException(
    "network.tlsVersionRestriction",
    {
      maximum: "TLSv1.2",
    },
    "Setting TLS max version lower than the min version is not allowed."
  );

  // Empty value.
  await testSetting(
    "network.tlsVersionRestriction",
    {},
    {
      "security.tls.version.min": tlsMinPref,
      "security.tls.version.max": 4,
    },
    {
      minimum: tlsMinVer,
      maximum: "TLSv1.3",
    }
  );

  const HTTPS_ONLY_PREF_NAME = "dom.security.https_only_mode";
  const HTTPS_ONLY_PBM_PREF_NAME = "dom.security.https_only_mode_pbm";

  Preferences.set(HTTPS_ONLY_PREF_NAME, false);
  Preferences.set(HTTPS_ONLY_PBM_PREF_NAME, false);
  await testGetting("network.httpsOnlyMode", {}, "never");

  Preferences.set(HTTPS_ONLY_PREF_NAME, true);
  Preferences.set(HTTPS_ONLY_PBM_PREF_NAME, false);
  await testGetting("network.httpsOnlyMode", {}, "always");

  Preferences.set(HTTPS_ONLY_PREF_NAME, false);
  Preferences.set(HTTPS_ONLY_PBM_PREF_NAME, true);
  await testGetting("network.httpsOnlyMode", {}, "private_browsing");

  // Please note that if https_only_mode = true, then
  // https_only_mode_pbm has no effect.
  Preferences.set(HTTPS_ONLY_PREF_NAME, true);
  Preferences.set(HTTPS_ONLY_PBM_PREF_NAME, true);
  await testGetting("network.httpsOnlyMode", {}, "always");

  // trying to "set" should have no effect when readonly!
  extension.sendMessage("set", { value: "never" }, "network.httpsOnlyMode");
  let readOnlyData = await extension.awaitMessage("settingData");
  equal(readOnlyData.value, "always");

  equal(Preferences.get(HTTPS_ONLY_PREF_NAME), true);
  equal(Preferences.get(HTTPS_ONLY_PBM_PREF_NAME), true);

  await extension.unload();

  await promiseShutdownManager();
});

Minimal test - lines (405, 420)

path: .spaces[1].spaces[3].metrics.halstead.difficulty
old: 12.0
new: 12.428571428571429

path: .spaces[1].spaces[3].metrics.halstead.purity_ratio
old: 1.5289288717057194
new: 1.5050393580853176

path: .spaces[1].spaces[3].metrics.halstead.N2
old: 28.0
new: 29.0

path: .spaces[1].spaces[3].metrics.halstead.volume
old: 296.1277022428888
new: 300.82814196102987

path: .spaces[1].spaces[3].metrics.halstead.time
old: 197.4184681619259
new: 207.71466944928252

path: .spaces[1].spaces[3].metrics.halstead.effort
old: 3553.532426914666
new: 3738.8640500870856

path: .spaces[1].spaces[3].metrics.halstead.length
old: 63.0
new: 64.0

path: .spaces[1].spaces[3].metrics.halstead.bugs
old: 0.07762213797699279
new: 0.08029808620179398

path: .spaces[1].spaces[3].metrics.halstead.level
old: 0.08333333333333333
new: 0.08045977011494253

path: .spaces[1].spaces[3].metrics.mi.mi_sei
old: 63.047606628992725
new: 62.929462231192275

path: .spaces[1].spaces[3].metrics.mi.mi_visual_studio
old: 56.15903544049458
new: 56.11114570000667

path: .spaces[1].spaces[3].metrics.mi.mi_original
old: 96.03195060324572
new: 95.9500591470114

Code

  async function testSetting(setting, value, expected, expectedValue = value) {
    extension.sendMessage("set", { value: value }, setting);
    let data = await extension.awaitMessage("settingData");
    deepEqual(
      data.value,
      expectedValue,
      `Got expected result on setting ${setting} to ${uneval(value)}`
    );
    for (let pref in expected) {
      equal(
        Preferences.get(pref),
        expected[pref],
        `${pref} set correctly for ${expected[pref]}`
      );
    }
  }