Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/browser/components/urlbar/tests/unit/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 32 kB image not shown  

Quelle  test_muxer.js

  Sprache: JAVA
 

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


"use strict";

const lazy = {};

ChromeUtils.defineESModuleGetters(lazy, {
  sinon: "resource://testing-common/Sinon.sys.mjs",
});

let sandbox;

add_setup(async function () {
  sandbox = lazy.sinon.createSandbox();
  registerCleanupFunction(() => {
    sandbox.restore();
  });
});

add_task(async function test_muxer() {
  let providersManager = ProvidersManager.getInstanceForSap("urlbar");
  Assert.throws(
    () => providersManager.registerMuxer(),
    /invalid muxer/,
    "Should throw with no arguments"
  );
  Assert.throws(
    () => providersManager.registerMuxer({}),
    /invalid muxer/,
    "Should throw with empty object"
  );
  Assert.throws(
    () =>
      providersManager.registerMuxer({
        name: "",
      }),
    /invalid muxer/,
    "Should throw with empty name"
  );
  Assert.throws(
    () =>
      providersManager.registerMuxer({
        name: "test",
        sort: "no",
      }),
    /invalid muxer/,
    "Should throw with invalid sort"
  );

  let matches = [
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
      source: UrlbarUtils.RESULT_SOURCE.TABS,
      payload: { url: "http://mozilla.org/tab/" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
      payload: { url: "http://mozilla.org/bookmark/" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://mozilla.org/history/" },
    }),
  ];

  let provider = registerBasicTestProvider(matches);
  let context = createContext(undefined, { providers: [provider.name] });
  let controller = UrlbarTestUtils.newMockController();
  /**
   * A test muxer.
   */

  class TestMuxer extends UrlbarMuxer {
    get name() {
      return "TestMuxer";
    }
    sort(queryContext, unsortedResults) {
      queryContext.results = [...unsortedResults].sort((a, b) => {
        if (b.source == UrlbarUtils.RESULT_SOURCE.TABS) {
          return -1;
        }
        if (b.source == UrlbarUtils.RESULT_SOURCE.BOOKMARKS) {
          return 1;
        }
        return a.source == UrlbarUtils.RESULT_SOURCE.BOOKMARKS ? -1 : 1;
      });
    }
  }
  let muxer = new TestMuxer();

  providersManager.registerMuxer(muxer);
  context.muxer = "TestMuxer";

  info("Check results, the order should be: bookmark, history, tab");
  await providersManager.startQuery(context, controller);
  Assert.deepEqual(context.results, [matches[1], matches[2], matches[0]]);

  // Sanity check, should not throw.
  providersManager.unregisterMuxer(muxer);
  providersManager.unregisterMuxer("TestMuxer"); // no-op.
});

add_task(async function test_preselectedHeuristic_singleProvider() {
  let matches = [
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://mozilla.org/a" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      heuristic: true,
      payload: { url: "http://mozilla.org/b" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://mozilla.org/c" },
    }),
  ];

  let provider = registerBasicTestProvider(matches);
  let context = createContext(undefined, {
    providers: [provider.name],
  });
  let controller = UrlbarTestUtils.newMockController();

  info("Check results, the order should be: b (heuristic), a, c");
  await ProvidersManager.getInstanceForSap("urlbar").startQuery(
    context,
    controller
  );
  Assert.deepEqual(context.results, [matches[1], matches[0], matches[2]]);
});

add_task(async function test_preselectedHeuristic_multiProviders() {
  let matches1 = [
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://mozilla.org/a" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://mozilla.org/b" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://mozilla.org/c" },
    }),
  ];

  let matches2 = [
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://mozilla.org/d" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      heuristic: true,
      payload: { url: "http://mozilla.org/e" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://mozilla.org/f" },
    }),
  ];

  let provider1 = registerBasicTestProvider(matches1);
  let provider2 = registerBasicTestProvider(matches2);

  let context = createContext(undefined, {
    providers: [provider1.name, provider2.name],
  });
  let controller = UrlbarTestUtils.newMockController();

  info("Check results, the order should be: e (heuristic), a, b, c, d, f");
  await ProvidersManager.getInstanceForSap("urlbar").startQuery(
    context,
    controller
  );
  Assert.deepEqual(context.results, [
    matches2[1],
    ...matches1,
    matches2[0],
    matches2[2],
  ]);
});

add_task(async function test_suggestions() {
  Services.prefs.setIntPref("browser.urlbar.maxHistoricalSearchSuggestions"1);

  let matches = [
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://mozilla.org/a" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://mozilla.org/b" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.SEARCH,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: {
        engine: "mozSearch",
        query: "moz",
        suggestion: "mozzarella",
        lowerCaseSuggestion: "mozzarella",
      },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.SEARCH,
      source: UrlbarUtils.RESULT_SOURCE.SEARCH,
      payload: {
        engine: "mozSearch",
        query: "moz",
        suggestion: "mozilla",
        lowerCaseSuggestion: "mozilla",
      },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.SEARCH,
      source: UrlbarUtils.RESULT_SOURCE.SEARCH,
      payload: {
        engine: "mozSearch",
        query: "moz",
        providesSearchMode: true,
        keyword: "@moz",
      },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://mozilla.org/c" },
    }),
  ];

  let provider = registerBasicTestProvider(matches);

  let context = createContext(undefined, {
    providers: [provider.name],
  });
  let controller = UrlbarTestUtils.newMockController();

  info("Check results, the order should be: mozzarella, moz, a, b, @moz, c");
  await ProvidersManager.getInstanceForSap("urlbar").startQuery(
    context,
    controller
  );
  Assert.deepEqual(context.results, [
    matches[2],
    matches[3],
    matches[0],
    matches[1],
    matches[4],
    matches[5],
  ]);

  Services.prefs.clearUserPref("browser.urlbar.maxHistoricalSearchSuggestions");
});

add_task(async function test_deduplicate_for_unitConversion() {
  const searchSuggestion = new UrlbarResult({
    type: UrlbarUtils.RESULT_TYPE.SEARCH,
    source: UrlbarUtils.RESULT_SOURCE.SEARCH,
    payload: {
      engine: "Google",
      query: "10cm to m",
      suggestion: "= 0.1 meters",
    },
  });
  const searchProvider = registerBasicTestProvider(
    [searchSuggestion],
    null,
    UrlbarUtils.PROVIDER_TYPE.PROFILE
  );

  const unitConversionSuggestion = new UrlbarResult({
    type: UrlbarUtils.RESULT_TYPE.DYNAMIC,
    source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
    suggestedIndex: 1,
    payload: {
      dynamicType: "unitConversion",
      output: "0.1 m",
      input: "10cm to m",
    },
  });

  const unitConversion = registerBasicTestProvider(
    [unitConversionSuggestion],
    null,
    UrlbarUtils.PROVIDER_TYPE.PROFILE,
    "UrlbarProviderUnitConversion"
  );

  const context = createContext(undefined, {
    providers: [searchProvider.name, unitConversion.name],
  });
  const controller = UrlbarTestUtils.newMockController();
  await ProvidersManager.getInstanceForSap("urlbar").startQuery(
    context,
    controller
  );
  Assert.deepEqual(context.results, [unitConversionSuggestion]);
});

// These results are used in the badHeuristicGroups tests below.  The order of
// the results in the array isn't important because they all get added at the
// same time.  It's the resultGroups in each test that is important.
const BAD_HEURISTIC_RESULTS = [
  // heuristic
  new UrlbarResult({
    type: UrlbarUtils.RESULT_TYPE.URL,
    source: UrlbarUtils.RESULT_SOURCE.HISTORY,
    heuristic: true,
    payload: { url: "http://mozilla.org/heuristic-0" },
  }),
  // heuristic
  new UrlbarResult({
    type: UrlbarUtils.RESULT_TYPE.URL,
    source: UrlbarUtils.RESULT_SOURCE.HISTORY,
    heuristic: true,
    payload: { url: "http://mozilla.org/heuristic-1" },
  }),
  // non-heuristic
  new UrlbarResult({
    type: UrlbarUtils.RESULT_TYPE.URL,
    source: UrlbarUtils.RESULT_SOURCE.HISTORY,
    payload: { url: "http://mozilla.org/non-heuristic-0" },
  }),
  // non-heuristic
  new UrlbarResult({
    type: UrlbarUtils.RESULT_TYPE.URL,
    source: UrlbarUtils.RESULT_SOURCE.HISTORY,
    payload: { url: "http://mozilla.org/non-heuristic-1" },
  }),
];

const BAD_HEURISTIC_RESULTS_FIRST_HEURISTIC = BAD_HEURISTIC_RESULTS[0];
const BAD_HEURISTIC_RESULTS_GENERAL = [
  BAD_HEURISTIC_RESULTS[2],
  BAD_HEURISTIC_RESULTS[3],
];

add_task(async function test_badHeuristicGroups_multiple_0() {
  await doBadHeuristicGroupsTest(
    [
      // 2 heuristics with child groups
      {
        maxResultCount: 2,
        children: [{ group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST }],
      },
      // infinite general
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
    ],
    [BAD_HEURISTIC_RESULTS_FIRST_HEURISTIC, ...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicGroups_multiple_1() {
  await doBadHeuristicGroupsTest(
    [
      // infinite heuristics with child groups
      {
        children: [{ group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST }],
      },
      // infinite general
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
    ],
    [BAD_HEURISTIC_RESULTS_FIRST_HEURISTIC, ...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicGroups_multiple_2() {
  await doBadHeuristicGroupsTest(
    [
      // 2 heuristics
      {
        maxResultCount: 2,
        group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST,
      },
      // infinite general
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
    ],
    [BAD_HEURISTIC_RESULTS_FIRST_HEURISTIC, ...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicGroups_multiple_3() {
  await doBadHeuristicGroupsTest(
    [
      // infinite heuristics
      {
        group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST,
      },
      // infinite general
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
    ],
    [BAD_HEURISTIC_RESULTS_FIRST_HEURISTIC, ...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicGroups_multiple_4() {
  await doBadHeuristicGroupsTest(
    [
      // 1 heuristic with child groups
      {
        maxResultCount: 1,
        children: [{ group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST }],
      },
      // infinite general
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
      // 1 heuristic with child groups
      {
        maxResultCount: 1,
        children: [{ group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST }],
      },
    ],
    [BAD_HEURISTIC_RESULTS_FIRST_HEURISTIC, ...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicGroups_multiple_5() {
  await doBadHeuristicGroupsTest(
    [
      // infinite heuristics with child groups
      {
        children: [{ group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST }],
      },
      // infinite general
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
      // infinite heuristics with child groups
      {
        children: [{ group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST }],
      },
    ],
    [BAD_HEURISTIC_RESULTS_FIRST_HEURISTIC, ...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicGroups_multiple_6() {
  await doBadHeuristicGroupsTest(
    [
      // 1 heuristic
      {
        maxResultCount: 1,
        group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST,
      },
      // infinite general
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
      // 1 heuristic
      {
        maxResultCount: 1,
        group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST,
      },
    ],
    [BAD_HEURISTIC_RESULTS_FIRST_HEURISTIC, ...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicGroups_multiple_7() {
  await doBadHeuristicGroupsTest(
    [
      // infinite heuristics
      {
        group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST,
      },
      // infinite general
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
      // infinite heuristics
      {
        group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST,
      },
    ],
    [BAD_HEURISTIC_RESULTS_FIRST_HEURISTIC, ...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicsGroups_notFirst_0() {
  await doBadHeuristicGroupsTest(
    [
      // infinite general first
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
      // 1 heuristic with child groups second
      {
        maxResultCount: 1,
        children: [{ group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST }],
      },
    ],
    [...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicsGroups_notFirst_1() {
  await doBadHeuristicGroupsTest(
    [
      // infinite general first
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
      // infinite heuristics with child groups second
      {
        children: [{ group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST }],
      },
    ],
    [...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicsGroups_notFirst_2() {
  await doBadHeuristicGroupsTest(
    [
      // infinite general first
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
      // 1 heuristic second
      {
        maxResultCount: 1,
        group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST,
      },
    ],
    [...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicsGroups_notFirst_3() {
  await doBadHeuristicGroupsTest(
    [
      // infinite general first
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
      // infinite heuristics second
      {
        group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST,
      },
    ],
    [...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

add_task(async function test_badHeuristicsGroups_notFirst_4() {
  await doBadHeuristicGroupsTest(
    [
      // 1 general first
      {
        maxResultCount: 1,
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
      // infinite heuristics second
      {
        group: UrlbarUtils.RESULT_GROUP.HEURISTIC_TEST,
      },
      // infinite general third
      {
        group: UrlbarUtils.RESULT_GROUP.GENERAL,
      },
    ],
    [...BAD_HEURISTIC_RESULTS_GENERAL]
  );
});

/**
 * Sets the resultGroups pref, performs a search, and then checks the results.
 * Regardless of the groups, the muxer should include at most one heuristic in
 * its results and it should always be the first result.
 *
 * @param {Array} resultGroups
 *   The result groups.
 * @param {Array} expectedResults
 *   The expected results.
 */

async function doBadHeuristicGroupsTest(resultGroups, expectedResults) {
  sandbox
    .stub(UrlbarPrefs, "getResultGroups")
    .returns({ children: resultGroups });

  let provider = registerBasicTestProvider(BAD_HEURISTIC_RESULTS);
  let context = createContext("foo", { providers: [provider.name] });
  let controller = UrlbarTestUtils.newMockController();
  await ProvidersManager.getInstanceForSap("urlbar").startQuery(
    context,
    controller
  );
  Assert.deepEqual(context.results, expectedResults);

  sandbox.restore();
}

// When `maxRichResults` is positive and taken up by suggested-index result(s),
// both the heuristic and suggested-index results should be included because we
// (a) make room for the heuristic and (b) assume all suggested-index results
// should be included even if it means exceeding `maxRichResults`. The specified
// `maxRichResults` span will be exceeded in this case.
add_task(async function roomForHeuristic_suggestedIndex() {
  let results = [
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      heuristic: true,
      payload: { url: "http://example.com/heuristic" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      suggestedIndex: 1,
      payload: { url: "http://example.com/suggestedIndex" },
    }),
  ];

  UrlbarPrefs.set("maxRichResults"1);

  let provider = registerBasicTestProvider(results);
  let context = createContext(undefined, { providers: [provider.name] });
  await check_results({
    context,
    matches: results,
  });

  UrlbarPrefs.clear("maxRichResults");
});

// When `maxRichResults` is positive but less than the heuristic's result span,
// the heuristic should be included because we make room for it even if it means
// exceeding `maxRichResults`. The specified `maxRichResults` span will be
// exceeded in this case.
add_task(async function roomForHeuristic_largeResultSpan() {
  let results = [
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      heuristic: true,
      resultSpan: 2,
      payload: { url: "http://example.com/heuristic" },
    }),
  ];

  UrlbarPrefs.set("maxRichResults"1);

  let provider = registerBasicTestProvider(results);
  let context = createContext(undefined, { providers: [provider.name] });
  await check_results({
    context,
    matches: results,
  });

  UrlbarPrefs.clear("maxRichResults");
});

// When `maxRichResults` is zero and there are no suggested-index results, the
// heuristic should not be included.
add_task(async function roomForHeuristic_maxRichResultsZero() {
  let results = [
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      heuristic: true,
      payload: { url: "http://example.com/heuristic" },
    }),
  ];

  UrlbarPrefs.set("maxRichResults"0);

  let provider = registerBasicTestProvider(results);
  let context = createContext(undefined, { providers: [provider.name] });
  await check_results({
    context,
    matches: [],
  });

  UrlbarPrefs.clear("maxRichResults");
});

// When `maxRichResults` is zero and suggested-index results are present,
// neither the heuristic nor the suggested-index results should be included.
add_task(async function roomForHeuristic_maxRichResultsZero_suggestedIndex() {
  let results = [
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      heuristic: true,
      payload: { url: "http://example.com/heuristic" },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      suggestedIndex: 1,
      payload: { url: "http://example.com/suggestedIndex" },
    }),
  ];

  UrlbarPrefs.set("maxRichResults"0);

  let provider = registerBasicTestProvider(results);
  let context = createContext(undefined, { providers: [provider.name] });
  await check_results({
    context,
    matches: [],
  });

  UrlbarPrefs.clear("maxRichResults");
});

add_task(async function test_orderBy() {
  // The GENERAL groups has an orderBy property, so let's just add to history.
  let results1 = [
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://example.com/test1", frecency: 10 },
    }),
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://example.com/test2", frecency: 1000 },
    }),
  ];
  let provider1 = registerBasicTestProvider(results1);
  let results2 = [
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url: "http://example.com/test3", frecency: 100 },
    }),
  ];
  let provider2 = registerBasicTestProvider(results2);

  let context = createContext(undefined, {
    providers: [provider1.name, provider2.name],
  });
  await check_results({
    context,
    matches: [
      results1[1], // 1000
      results2[0], // 100
      results1[0], // 10
    ],
  });
});

// A result returned by both the semantic history provider and a non-semantic
// provider for the same page should be deduped down to the non-semantic
// result, regardless of which provider's result is added first and regardless
// of scheme/www differences or result type (URL vs switch-to-tab).
async function checkSemanticDedupe({
  semanticFirst,
  semanticUrl = "https://example.com/foo/",
  nonSemanticUrl = "https://example.com/foo/",
  semanticType = UrlbarUtils.RESULT_TYPE.URL,
  nonSemanticType = UrlbarUtils.RESULT_TYPE.URL,
  description = "",
}) {
  let makeMatch = (type, url) =>
    new UrlbarResult({
      type,
      source:
        type == UrlbarUtils.RESULT_TYPE.TAB_SWITCH
          ? UrlbarUtils.RESULT_SOURCE.TABS
          : UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url, title: "Example Page" },
    });
  let semanticMatch = makeMatch(semanticType, semanticUrl);
  let nonSemanticMatch = makeMatch(nonSemanticType, nonSemanticUrl);

  let providersManager = ProvidersManager.getInstanceForSap("urlbar");
  // `unregisterProvider` matches by name, so clear any strays left under the
  // semantic name by a previous run for a clean slate.
  for (let p of [...providersManager.providers]) {
    if (p.name == "UrlbarProviderSemanticHistorySearch") {
      providersManager.unregisterProvider(p);
    }
  }

  // Register the providers in the order under test so the matching result is
  // processed first by the muxer.
  let semanticProvider, nonSemanticProvider;
  let registerSemantic = () =>
    (semanticProvider = registerBasicTestProvider(
      [semanticMatch],
      undefined,
      undefined,
      "UrlbarProviderSemanticHistorySearch"
    ));
  let registerNonSemantic = () =>
    (nonSemanticProvider = registerBasicTestProvider([nonSemanticMatch]));
  if (semanticFirst) {
    registerSemantic();
    registerNonSemantic();
  } else {
    registerNonSemantic();
    registerSemantic();
  }

  let context = createContext(undefined, {
    providers: semanticFirst
      ? [semanticProvider.name, nonSemanticProvider.name]
      : [nonSemanticProvider.name, semanticProvider.name],
  });
  let controller = UrlbarTestUtils.newMockController();
  await ProvidersManager.getInstanceForSap("urlbar").startQuery(
    context,
    controller
  );

  Assert.deepEqual(
    context.results,
    [nonSemanticMatch],
    `Only the non-semantic result should survive (${description}semanticFirst=${semanticFirst})`
  );

  providersManager.unregisterProvider(semanticProvider);
  providersManager.unregisterProvider(nonSemanticProvider);
}

add_task(async function test_dedupe_semantic_seen_first() {
  await checkSemanticDedupe({ semanticFirst: true });
});

add_task(async function test_dedupe_nonSemantic_seen_first() {
  await checkSemanticDedupe({ semanticFirst: false });
});

// The semantic and non-semantic results may have the same stripped URL but
// different schemes (http vs https). The non-semantic result should still win.
add_task(async function test_dedupe_semantic_scheme_mismatch() {
  for (let semanticFirst of [truefalse]) {
    await checkSemanticDedupe({
      semanticFirst,
      semanticUrl: "https://example.com/foo/",
      nonSemanticUrl: "http://example.com/foo/",
      description: "scheme mismatch, ",
    });
  }
});

// Same as above but the prefixes differ by www. The non-semantic result wins.
add_task(async function test_dedupe_semantic_www_mismatch() {
  for (let semanticFirst of [truefalse]) {
    await checkSemanticDedupe({
      semanticFirst,
      semanticUrl: "https://www.example.com/foo/",
      nonSemanticUrl: "https://example.com/foo/",
      description: "www mismatch, ",
    });
  }
});

// A semantic switch-to-tab result that dupes a non-semantic switch-to-tab
// result for the same open tab should be deduped to the non-semantic one.
add_task(async function test_dedupe_semantic_tab_switch() {
  for (let semanticFirst of [truefalse]) {
    await checkSemanticDedupe({
      semanticFirst,
      semanticUrl: "https://example.com/tab/",
      nonSemanticUrl: "https://example.com/tab/",
      semanticType: UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
      nonSemanticType: UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
      description: "tab switch, ",
    });
  }
});

// A semantic result with no non-semantic counterpart must not be suppressed,
// whether it's a plain URL or a switch-to-tab result.
add_task(async function test_semantic_only_survives() {
  let providersManager = ProvidersManager.getInstanceForSap("urlbar");
  for (let p of [...providersManager.providers]) {
    if (p.name == "UrlbarProviderSemanticHistorySearch") {
      providersManager.unregisterProvider(p);
    }
  }

  let urlMatch = new UrlbarResult({
    type: UrlbarUtils.RESULT_TYPE.URL,
    source: UrlbarUtils.RESULT_SOURCE.HISTORY,
    payload: { url: "https://semantic-only.example.com/page/", title: "Page" },
  });
  let tabMatch = new UrlbarResult({
    type: UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
    source: UrlbarUtils.RESULT_SOURCE.TABS,
    payload: { url: "https://semantic-only.example.com/tab/", title: "Tab" },
  });
  let semanticProvider = registerBasicTestProvider(
    [tabMatch, urlMatch],
    undefined,
    undefined,
    "UrlbarProviderSemanticHistorySearch"
  );

  let context = createContext(undefined, {
    providers: [semanticProvider.name],
  });
  await ProvidersManager.getInstanceForSap("urlbar").startQuery(
    context,
    UrlbarTestUtils.newMockController()
  );

  Assert.deepEqual(
    context.results.map(r => r.payload.url).sort(),
    [tabMatch.payload.url, urlMatch.payload.url].sort(),
    "Semantic results with no non-semantic counterpart are kept"
  );

  providersManager.unregisterProvider(semanticProvider);
});

// Two semantic results that are prefix variants of the same page (and have no
// non-semantic counterpart) should still be deduped to a single result by the
// normal prefix-rank logic, since only suppressed semantic dupes are excluded
// from that bookkeeping.
add_task(async function test_dedupe_two_semantic_prefixes() {
  let providersManager = ProvidersManager.getInstanceForSap("urlbar");
  for (let p of [...providersManager.providers]) {
    if (p.name == "UrlbarProviderSemanticHistorySearch") {
      providersManager.unregisterProvider(p);
    }
  }

  let httpsMatch = new UrlbarResult({
    type: UrlbarUtils.RESULT_TYPE.URL,
    source: UrlbarUtils.RESULT_SOURCE.HISTORY,
    payload: { url: "https://example.com/foo/", title: "Example Page" },
  });
  let httpMatch = new UrlbarResult({
    type: UrlbarUtils.RESULT_TYPE.URL,
    source: UrlbarUtils.RESULT_SOURCE.HISTORY,
    payload: { url: "http://example.com/foo/", title: "Example Page" },
  });
  let semanticProvider = registerBasicTestProvider(
    [httpsMatch, httpMatch],
    undefined,
    undefined,
    "UrlbarProviderSemanticHistorySearch"
  );

  let context = createContext(undefined, {
    providers: [semanticProvider.name],
  });
  await ProvidersManager.getInstanceForSap("urlbar").startQuery(
    context,
    UrlbarTestUtils.newMockController()
  );

  Assert.deepEqual(
    context.results,
    [httpsMatch],
    "Only the highest-prefix-rank semantic variant should survive"
  );

  providersManager.unregisterProvider(semanticProvider);
});

// When the separateGroup setting is enabled with semantic seearch, semantic results
// share the general area with non-semantic history at a 9:1 ratio: at most ~1 in every
// 10 of these slots is semantic, semantic results are ordered by frecency, and
// they fill the remaining space (without evicting) when there's little other
// history.
//
// The ratio 9:1 ratio enables one sementic result to be visible in the history view
// when there are many semantic results.

add_task(async function test_semantic_history_separate_group_ratio() {
  // The separate semantic group only exists when this pref is enabled.
  UrlbarPrefs.set("suggest.semanticHistory.separateGroup"true);

  let providersManager = ProvidersManager.getInstanceForSap("urlbar");
  // `unregisterProvider` matches by name, and earlier tests register providers
  // under the same semantic name, so clear any strays for a clean slate.
  for (let p of [...providersManager.providers]) {
    if (p.name == "UrlbarProviderSemanticHistorySearch") {
      providersManager.unregisterProvider(p);
    }
  }

  let makeUrlResult = (url, frecency) =>
    new UrlbarResult({
      type: UrlbarUtils.RESULT_TYPE.URL,
      source: UrlbarUtils.RESULT_SOURCE.HISTORY,
      payload: { url, title: "Page", frecency },
    });
  let isSemantic = r => r.providerName == "UrlbarProviderSemanticHistorySearch";

  // 12 general results, frecency descending, distinct URLs so nothing dedupes.
  let exactMatches = Array.from({ length: 12 }, (_, i) =>
    makeUrlResult(`https://example.com/exact${i}`, 120 - i * 10)
  );
  let semanticMatches = [
    makeUrlResult("https://example.com/semantic1", 50),
    makeUrlResult("https://example.com/semantic2", 200),
    makeUrlResult("https://example.com/semantic3", 100),
  ];

  let exactProvider = registerBasicTestProvider(exactMatches);
  let semanticProvider = registerBasicTestProvider(
    semanticMatches,
    undefined,
    undefined,
    "UrlbarProviderSemanticHistorySearch"
  );

  // Typical search results with competing search engine resuls. Only room for 3 history related
  // results, so semantic results are supprressed to keep from evicting an exact match result
  let limitedResultsContext = createContext(undefined, {
    providers: [exactProvider.name, semanticProvider.name],
    maxResults: 3,
  });
  await providersManager.startQuery(
    limitedResultsContext,
    UrlbarTestUtils.newMockController()
  );
  Assert.equal(limitedResultsContext.results.length, 3"Fills the budget");
  Assert.equal(
    limitedResultsContext.results.filter(isSemantic).length,
    0,
    "At no semantic results are shown"
  );
  // History view with with lots of of competing history: the general area holds 10,
  //  so the 9:1 split yields 9 general + 1 semantic.
  let historyViewContext = createContext(undefined, {
    providers: [exactProvider.name, semanticProvider.name],
    maxResults: 10,
  });
  await providersManager.startQuery(
    historyViewContext,
    UrlbarTestUtils.newMockController()
  );
  Assert.equal(historyViewContext.results.length, 10"Fills the budget");
  Assert.equal(
    historyViewContext.results.filter(isSemantic).length,
    1,
    "At most 1 in 10 results is semantic"
  );
  Assert.deepEqual(
    historyViewContext.results.slice(09),
    exactMatches.slice(09),
    "The 9 highest-frecency general results are kept, ordered by frecency"
  );
  Assert.equal(
    historyViewContext.results[9],
    semanticMatches[1],
    "The shown semantic result is the highest-frecency one (sorted by frecency)"
  );

  // Little competing history: semantic fills the leftover space without
  // evicting the general results.
  let fewExactProvider = registerBasicTestProvider(exactMatches.slice(02));
  let sparseContext = createContext(undefined, {
    providers: [fewExactProvider.name, semanticProvider.name],
    maxResults: 10,
  });
  await providersManager.startQuery(
    sparseContext,
    UrlbarTestUtils.newMockController()
  );
  Assert.equal(
    sparseContext.results.filter(r => !isSemantic(r)).length,
    2,
    "Both general results are kept (not evicted)"
  );
  Assert.equal(
    sparseContext.results.filter(isSemantic).length,
    3,
    "Semantic results fill the leftover space"
  );
  Assert.deepEqual(
    sparseContext.results.filter(isSemantic),
    [semanticMatches[1], semanticMatches[2], semanticMatches[0]],
    "Multiple shown semantic results are ordered by frecency (descending)"
  );

  providersManager.unregisterProvider(exactProvider);
  providersManager.unregisterProvider(fewExactProvider);
  providersManager.unregisterProvider(semanticProvider);
  UrlbarPrefs.clear("suggest.semanticHistory.separateGroup");
});

Messung V0.5 in Prozent
C=84 H=97 G=90

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet am  2026-08-26) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

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.