/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ // Tests the muxer's result groups composition logic: child groups, // `availableSpan`, `maxResultCount`, flex, etc. The purpose of this test is to // check the composition logic, not every possible result type or group. "use strict"; // The possible limit-related properties in result groups. const LIMIT_KEYS = ["availableSpan", "maxResultCount"]; // Most of this test adds tasks using `add_resultGroupsLimit_tasks`. It works // like this. Instead of defining `maxResultCount` or `availableSpan` in their // result groups, tasks define a `limit` property. The value of this property is // a number just like any of the values for the limit-related properties. At // runtime, `add_resultGroupsLimit_tasks` adds multiple tasks, one for each key // in `LIMIT_KEYS`. In each of these tasks, the `limit` property is replaced // with the actual limit key. This allows us to run checks against each of the // limit keys using essentially the same task. const RESULT_GROUPS_PREF = "browser.urlbar.resultGroups"; const MAX_RICH_RESULTS_PREF = "browser.urlbar.maxRichResults"; // For simplicity, most of the flex tests below assume that this is 10, so // you'll need to update them if you change this. const MAX_RESULTS = 10; add_task(async function setup() { // Set a specific maxRichResults for sanity's sake. Services.prefs.setIntPref(MAX_RICH_RESULTS_PREF, MAX_RESULTS); }); add_resultGroupsLimit_tasks({ testName: "empty root", resultGroups: {}, providerResults: [...makeHistoryResults(1)], expectedResultIndexes: [], }); add_resultGroupsLimit_tasks({ testName: "root with empty children", resultGroups: { children: [], }, providerResults: [...makeHistoryResults(1)], expectedResultIndexes: [], }); add_resultGroupsLimit_tasks({ testName: "root no match", resultGroups: { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, providerResults: [...makeHistoryResults(1)], expectedResultIndexes: [], }); add_resultGroupsLimit_tasks({ testName: "children no match", resultGroups: { children: [{ group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }], }, providerResults: [...makeHistoryResults(1)], expectedResultIndexes: [], }); add_resultGroupsLimit_tasks({ // The actual max result count on the root is always context.maxResults and // limit is ignored, so we expect the result in this case. testName: "root limit: 0", resultGroups: { limit: 0, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, providerResults: [...makeHistoryResults(1)], expectedResultIndexes: [0], }); add_resultGroupsLimit_tasks({ // The actual max result count on the root is always context.maxResults and // limit is ignored, so we expect the result in this case. testName: "root limit: 0 with children", resultGroups: { limit: 0, children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }], }, providerResults: [...makeHistoryResults(1)], expectedResultIndexes: [0], }); add_resultGroupsLimit_tasks({ testName: "child limit: 0", resultGroups: { children: [ { limit: 0, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, providerResults: [...makeHistoryResults(1)], expectedResultIndexes: [], }); add_resultGroupsLimit_tasks({ testName: "root group", resultGroups: { group: UrlbarUtils.RESULT_GROUP.GENERAL, }, providerResults: [...makeHistoryResults(1)], expectedResultIndexes: [...makeIndexRange(0, 1)], }); add_resultGroupsLimit_tasks({ testName: "root group multiple", resultGroups: { group: UrlbarUtils.RESULT_GROUP.GENERAL, }, providerResults: [...makeHistoryResults(2)], expectedResultIndexes: [...makeIndexRange(0, 2)], }); add_resultGroupsLimit_tasks({ testName: "child group multiple", resultGroups: { children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }], }, providerResults: [...makeHistoryResults(2)], expectedResultIndexes: [0, 1], }); add_resultGroupsLimit_tasks({ testName: "simple limit", resultGroups: { children: [ { limit: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, providerResults: [...makeHistoryResults(2)], expectedResultIndexes: [0], }); add_resultGroupsLimit_tasks({ testName: "limit siblings", resultGroups: { children: [ { limit: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { group: UrlbarUtils.RESULT_GROUP.GENERAL }, ], }, providerResults: [...makeHistoryResults(2)], expectedResultIndexes: [0, 1], }); add_resultGroupsLimit_tasks({ testName: "limit nested", resultGroups: { children: [ { limit: 1, children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }], }, ], }, providerResults: [...makeHistoryResults(2)], expectedResultIndexes: [0], }); add_resultGroupsLimit_tasks({ testName: "limit nested siblings", resultGroups: { children: [ { limit: 1, children: [ { group: UrlbarUtils.RESULT_GROUP.GENERAL }, { group: UrlbarUtils.RESULT_GROUP.GENERAL }, ], }, ], }, providerResults: [...makeHistoryResults(2)], expectedResultIndexes: [0], }); add_resultGroupsLimit_tasks({ testName: "limit nested uncle", resultGroups: { children: [ { limit: 1, children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }], }, { group: UrlbarUtils.RESULT_GROUP.GENERAL }, ], }, providerResults: [...makeHistoryResults(2)], expectedResultIndexes: [0, 1], }); add_resultGroupsLimit_tasks({ testName: "limit nested override bad", resultGroups: { children: [ { limit: 1, children: [ { limit: 99, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, ], }, providerResults: [...makeHistoryResults(2)], expectedResultIndexes: [0], }); add_resultGroupsLimit_tasks({ testName: "limit nested override good", resultGroups: { children: [ { limit: 99, children: [ { limit: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, ], }, providerResults: [...makeHistoryResults(2)], expectedResultIndexes: [0], }); add_resultGroupsLimit_tasks({ testName: "multiple groups", resultGroups: { children: [ { group: UrlbarUtils.RESULT_GROUP.GENERAL }, { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 2)], }); add_resultGroupsLimit_tasks({ testName: "multiple groups limit 1", resultGroups: { children: [ { limit: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [...makeIndexRange(2, 1), ...makeIndexRange(0, 2)], }); add_resultGroupsLimit_tasks({ testName: "multiple groups limit 2", resultGroups: { children: [ { group: UrlbarUtils.RESULT_GROUP.GENERAL }, { limit: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 1)], }); add_resultGroupsLimit_tasks({ testName: "multiple groups limit 3", resultGroups: { children: [ { limit: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }, { group: UrlbarUtils.RESULT_GROUP.GENERAL }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [ ...makeIndexRange(2, 1), ...makeIndexRange(0, 2), ...makeIndexRange(3, 1), ], }); add_resultGroupsLimit_tasks({ testName: "multiple groups limit 4", resultGroups: { children: [ { group: UrlbarUtils.RESULT_GROUP.GENERAL }, { limit: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, { group: UrlbarUtils.RESULT_GROUP.GENERAL }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 1)], }); add_resultGroupsLimit_tasks({ testName: "multiple groups nested 1", resultGroups: { children: [ { children: [ { group: UrlbarUtils.RESULT_GROUP.GENERAL }, { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }, ], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 2)], }); add_resultGroupsLimit_tasks({ testName: "multiple groups nested 2", resultGroups: { children: [ { children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }], }, { children: [{ group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 2)], }); add_resultGroupsLimit_tasks({ testName: "multiple groups nested limit 1", resultGroups: { children: [ { limit: 1, children: [ { group: UrlbarUtils.RESULT_GROUP.GENERAL }, { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }, ], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [...makeIndexRange(2, 1)], }); add_resultGroupsLimit_tasks({ testName: "multiple groups nested limit 2", resultGroups: { children: [ { children: [ { limit: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, { children: [{ group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [...makeIndexRange(2, 1), ...makeIndexRange(0, 2)], }); add_resultGroupsLimit_tasks({ testName: "multiple groups nested limit 3", resultGroups: { children: [ { children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }], }, { children: [ { limit: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 1)], }); add_resultGroupsLimit_tasks({ testName: "multiple groups nested limit 4", resultGroups: { children: [ { children: [ { limit: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, { children: [{ group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }], }, { children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [ ...makeIndexRange(2, 1), ...makeIndexRange(0, 2), ...makeIndexRange(3, 1), ], }); add_resultGroupsLimit_tasks({ testName: "multiple groups nested limit 5", resultGroups: { children: [ { children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }], }, { children: [ { limit: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, { children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 1)], }); add_resultGroupsLimit_tasks({ testName: "multiple groups nested limit 6", resultGroups: { children: [ { children: [ { limit: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }, { group: UrlbarUtils.RESULT_GROUP.GENERAL }, ], }, providerResults: [ ...makeRemoteSuggestionResults(2), ...makeHistoryResults(2), ], expectedResultIndexes: [ ...makeIndexRange(2, 1), ...makeIndexRange(0, 2), ...makeIndexRange(3, 1), ], }); add_resultGroupsLimit_tasks({ testName: "flex 1", resultGroups: { flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, providerResults: [ ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general/history: round(10 * (1 / (1 + 1))) = 5 ...makeIndexRange(MAX_RESULTS, 5), // remote suggestions: round(10 * (1 / (1 + 1))) = 5 ...makeIndexRange(0, 5), ], }); add_resultGroupsLimit_tasks({ testName: "flex 2", resultGroups: { flexChildren: true, children: [ { flex: 2, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, providerResults: [ ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general/history: round(10 * (2 / 3)) = 7 ...makeIndexRange(MAX_RESULTS, 7), // remote suggestions: round(10 * (1 / 3)) = 3 ...makeIndexRange(0, 3), ], }); add_resultGroupsLimit_tasks({ testName: "flex 3", resultGroups: { flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, providerResults: [ ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general/history: round(10 * (1 / 3)) = 3 ...makeIndexRange(MAX_RESULTS, 3), // remote suggestions: round(10 * (2 / 3)) = 7 ...makeIndexRange(0, 7), ], }); add_resultGroupsLimit_tasks({ testName: "flex 4", resultGroups: { flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, ], }, providerResults: [ ...makeFormHistoryResults(MAX_RESULTS), ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general/history: round(10 * (1 / 3)) = 3, and then incremented to 4 so // that the total result span is 10 instead of 9. This group is incremented // because the fractional part of its unrounded ideal max result count is // 0.33 (since 10 * (1 / 3) = 3.33), the same as the other two groups, and // this group is first. ...makeIndexRange(2 * MAX_RESULTS, 4), // remote suggestions: round(10 * (1 / 3)) = 3 ...makeIndexRange(MAX_RESULTS, 3), // form history: round(10 * (1 / 3)) = 3 // The first three form history results dupe the three remote suggestions, // so they should not be included. ...makeIndexRange(3, 3), ], }); add_resultGroupsLimit_tasks({ testName: "flex 5", resultGroups: { flexChildren: true, children: [ { flex: 2, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, ], }, providerResults: [ ...makeFormHistoryResults(MAX_RESULTS), ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general/history: round(10 * (2 / 4)) = 5 ...makeIndexRange(2 * MAX_RESULTS, 5), // remote suggestions: round(10 * (1 / 4)) = 3 ...makeIndexRange(MAX_RESULTS, 3), // form history: round(10 * (1 / 4)) = 3, but context.maxResults is 10, so 2 // The first three form history results dupe the three remote suggestions, // so they should not be included. ...makeIndexRange(3, 2), ], }); add_resultGroupsLimit_tasks({ testName: "flex 6", resultGroups: { flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, ], }, providerResults: [ ...makeFormHistoryResults(MAX_RESULTS), ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general/history: round(10 * (1 / 4)) = 3 ...makeIndexRange(2 * MAX_RESULTS, 3), // remote suggestions: round(10 * (2 / 4)) = 5 ...makeIndexRange(MAX_RESULTS, 5), // form history: round(10 * (1 / 4)) = 3, but context.maxResults is 10, so 2 // The first five form history results dupe the five remote suggestions, so // they should not be included. ...makeIndexRange(5, 2), ], }); add_resultGroupsLimit_tasks({ testName: "flex 7", resultGroups: { flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, ], }, providerResults: [ ...makeFormHistoryResults(MAX_RESULTS), ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general/history: round(10 * (1 / 4)) = 3 ...makeIndexRange(2 * MAX_RESULTS, 3), // remote suggestions: round(10 * (1 / 4)) = 3, and then decremented to 2 so // that the total result span is 10 instead of 11. This group is decremented // because the fractional part of its unrounded ideal max result count is // 0.5 (since 10 * (1 / 4) = 2.5), the same as the previous group, and the // next group's fractional part is zero. ...makeIndexRange(MAX_RESULTS, 2), // form history: round(10 * (2 / 4)) = 5 // The first 2 form history results dupe the three remote suggestions, so // they should not be included. ...makeIndexRange(2, 5), ], }); add_resultGroupsLimit_tasks({ testName: "flex overfill 1", resultGroups: { flexChildren: true, children: [ { flex: 2, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, ], }, providerResults: [ ...makeFormHistoryResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general/history: round(10 * (2 / (2 + 0 + 1))) = 7 ...makeIndexRange(MAX_RESULTS, 7), // form history: round(10 * (1 / (2 + 0 + 1))) = 3 ...makeIndexRange(0, 3), ], }); add_resultGroupsLimit_tasks({ testName: "flex overfill 2", resultGroups: { flexChildren: true, children: [ { flex: 2, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, ], }, providerResults: [ ...makeFormHistoryResults(MAX_RESULTS), ...makeRemoteSuggestionResults(1), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general/history: round(9 * (2 / (2 + 0 + 1))) = 6 ...makeIndexRange(MAX_RESULTS + 1, 6), // remote suggestions ...makeIndexRange(MAX_RESULTS, 1), // form history: round(9 * (1 / (2 + 0 + 1))) = 3 // The first form history result dupes the remote suggestion, so it should // not be included. ...makeIndexRange(1, 3), ], }); add_resultGroupsLimit_tasks({ testName: "flex nested limit 1", resultGroups: { children: [ { limit: 5, flexChildren: true, children: [ { flex: 2, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general/history: round(5 * (2 / (2 + 1))) = 3 ...makeIndexRange(MAX_RESULTS, 3), // remote suggestions: round(5 * (1 / (2 + 1))) = 2 ...makeIndexRange(0, 2), ], }); add_resultGroupsLimit_tasks({ testName: "flex nested limit 2", resultGroups: { children: [ { limit: 7, flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general: round(7 * (1 / (2 + 1))) = 2 ...makeIndexRange(MAX_RESULTS, 2), // remote suggestions: round(7 * (2 / (2 + 1))) = 5 ...makeIndexRange(0, 5), ], }); add_resultGroupsLimit_tasks({ testName: "flex nested limit 3", resultGroups: { children: [ { limit: 7, flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, { limit: 3, flexChildren: true, children: [ { flex: 2, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeFormHistoryResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general: round(7 * (1 / (2 + 1))) = 2 ...makeIndexRange(2 * MAX_RESULTS, 2), // remote suggestions: round(7 * (2 / (2 + 1))) = 5 ...makeIndexRange(0, 5), // form history: round(3 * (2 / (2 + 1))) = 2 // The first five form history results dupe the five remote suggestions, so // they should not be included. ...makeIndexRange(MAX_RESULTS + 5, 2), // general: round(3 * (1 / (2 + 1))) = 1 ...makeIndexRange(2 * MAX_RESULTS + 2, 1), ], }); add_resultGroupsLimit_tasks({ testName: "flex nested limit 4", resultGroups: { children: [ { limit: 7, flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, { limit: 3, children: [ { group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY }, { group: UrlbarUtils.RESULT_GROUP.GENERAL }, ], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeFormHistoryResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general: round(7 * (1 / (2 + 1))) = 2 ...makeIndexRange(2 * MAX_RESULTS, 2), // remote suggestions: round(7 * (2 / (2 + 1))) = 5 ...makeIndexRange(0, 5), // form history: round(3 * (2 / (2 + 1))) = 2 // The first five form history results dupe the five remote suggestions, so // they should not be included. ...makeIndexRange(MAX_RESULTS + 5, 3), ], }); add_resultGroupsLimit_tasks({ testName: "flex nested limit 5", resultGroups: { children: [ { limit: 7, flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, { limit: 3, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, ], }, providerResults: [ ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeFormHistoryResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general: round(7 * (1 / (2 + 1))) = 2 ...makeIndexRange(2 * MAX_RESULTS, 2), // remote suggestions: round(7 * (2 / (2 + 1))) = 5 ...makeIndexRange(0, 5), // form history: round(3 * (2 / (2 + 1))) = 2 // The first five form history results dupe the five remote suggestions, so // they should not be included. ...makeIndexRange(MAX_RESULTS + 5, 3), ], }); add_resultGroupsLimit_tasks({ testName: "flex nested", resultGroups: { flexChildren: true, children: [ { flex: 2, flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, { flex: 1, flexChildren: true, children: [ { flex: 2, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeFormHistoryResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // outer 1: general & remote suggestions: round(10 * (2 / (2 + 1))) = 7 // inner 1: general: round(7 * (1 / (2 + 1))) = 2 ...makeIndexRange(2 * MAX_RESULTS, 2), // inner 2: remote suggestions: round(7 * (2 / (2 + 1))) = 5 ...makeIndexRange(0, 5), // outer 2: form history & general: round(10 * (1 / (2 + 1))) = 3 // inner 1: form history: round(3 * (2 / (2 + 1))) = 2 // The first five form history results dupe the five remote suggestions, so // they should not be included. ...makeIndexRange(MAX_RESULTS + 5, 2), // inner 2: general: round(3 * (1 / (2 + 1))) = 1 ...makeIndexRange(2 * MAX_RESULTS + 2, 1), ], }); add_resultGroupsLimit_tasks({ testName: "flex nested overfill 1", resultGroups: { flexChildren: true, children: [ { flex: 2, flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, { flex: 1, flexChildren: true, children: [ { flex: 2, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, ], }, providerResults: [ ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeFormHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // outer 1: general & remote suggestions: round(10 * (2 / (2 + 1))) = 7 // inner 1: general: no results // inner 2: remote suggestions: round(7 * (2 / (2 + 0))) = 7 ...makeIndexRange(0, 7), // outer 2: form history & general: round(10 * (1 / (2 + 1))) = 3 // inner 1: form history: round(3 * (2 / (2 + 0))) = 3 // The first seven form history results dupe the seven remote suggestions, // so they should not be included. ...makeIndexRange(MAX_RESULTS + 7, 3), // inner 2: general: no results ], }); add_resultGroupsLimit_tasks({ testName: "flex nested overfill 2", resultGroups: { flexChildren: true, children: [ { flex: 2, flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, { flex: 1, flexChildren: true, children: [ { flex: 2, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, ], }, providerResults: [...makeFormHistoryResults(MAX_RESULTS)], expectedResultIndexes: [ // outer 1: general & remote suggestions: round(10 * (2 / (2 + 1))) = 7 // inner 1: general: no results // inner 2: remote suggestions: no results // outer 2: form history & general: round(10 * (1 / (0 + 1))) = 10 // inner 1: form history: round(10 * (2 / (2 + 0))) = 10 ...makeIndexRange(0, MAX_RESULTS), // inner 2: general: no results ], }); add_resultGroupsLimit_tasks({ testName: "flex nested overfill 3", resultGroups: { flexChildren: true, children: [ { flex: 2, flexChildren: true, children: [ { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 2, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, { flex: 1, flexChildren: true, children: [ { flex: 2, group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, ], }, providerResults: [...makeRemoteSuggestionResults(MAX_RESULTS)], expectedResultIndexes: [ // outer 1: general & remote suggestions: round(10 * (2 / (2 + 0))) = 10 // inner 1: general: no results // inner 2: remote suggestions: round(10 * (2 / (2 + 0))) = 10 ...makeIndexRange(0, MAX_RESULTS), // outer 2: form history & general: round(10 * (1 / (2 + 1))) = 3 // inner 1: form history: no results // inner 2: general: no results ], }); add_resultGroupsLimit_tasks({ testName: "limit ignored with flex", resultGroups: { flexChildren: true, children: [ { limit: 1, flex: 2, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { flex: 1, group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, providerResults: [ ...makeRemoteSuggestionResults(MAX_RESULTS), ...makeHistoryResults(MAX_RESULTS), ], expectedResultIndexes: [ // general/history: round(10 * (2 / (2 + 1))) = 7 -- limit ignored ...makeIndexRange(MAX_RESULTS, 7), // remote suggestions: round(10 * (1 / (2 + 1))) = 3 ...makeIndexRange(0, 3), ], }); add_resultGroupsLimit_tasks({ testName: "resultSpan = 3 followed by others", resultGroups: { children: [ { group: UrlbarUtils.RESULT_GROUP.GENERAL, }, { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION, }, ], }, providerResults: [ // max results remote suggestions ...makeRemoteSuggestionResults(MAX_RESULTS), // 1 history with resultSpan = 3 Object.assign(makeHistoryResults(1)[0], { resultSpan: 3 }), ], expectedResultIndexes: [ // general/history: 1 ...makeIndexRange(MAX_RESULTS, 1), // remote suggestions: maxResults - resultSpan of 3 = 10 - 3 = 7 ...makeIndexRange(0, 7), ], }); add_resultGroups_task({ testName: "maxResultCount: 1, availableSpan: 3", resultGroups: { children: [ { maxResultCount: 1, availableSpan: 3, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, providerResults: [...makeHistoryResults(MAX_RESULTS)], expectedResultIndexes: [0], }); add_resultGroups_task({ testName: "maxResultCount: 1, availableSpan: 3, resultSpan = 3", resultGroups: { children: [ { maxResultCount: 1, availableSpan: 3, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, providerResults: [ Object.assign(makeHistoryResults(1)[0], { resultSpan: 3 }), Object.assign(makeHistoryResults(1)[0], { resultSpan: 3 }), Object.assign(makeHistoryResults(1)[0], { resultSpan: 3 }), ], expectedResultIndexes: [0], }); add_resultGroups_task({ testName: "maxResultCount: 3, availableSpan: 1", resultGroups: { children: [ { maxResultCount: 3, availableSpan: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, providerResults: [...makeHistoryResults(MAX_RESULTS)], expectedResultIndexes: [0], }); add_resultGroups_task({ testName: "maxResultCount: 3, availableSpan: 1, resultSpan = 3", resultGroups: { children: [ { maxResultCount: 3, availableSpan: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, providerResults: [Object.assign(makeHistoryResults(1)[0], { resultSpan: 3 })], expectedResultIndexes: [], }); add_resultGroups_task({ testName: "availableSpan: 1", resultGroups: { children: [ { availableSpan: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, providerResults: [...makeHistoryResults(MAX_RESULTS)], expectedResultIndexes: [0], }); add_resultGroups_task({ testName: "availableSpan: 1, resultSpan = 3", resultGroups: { children: [ { availableSpan: 1, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, providerResults: [Object.assign(makeHistoryResults(1)[0], { resultSpan: 3 })], expectedResultIndexes: [], }); add_resultGroups_task({ testName: "availableSpan: 3, resultSpan = 2 and resultSpan = 1", resultGroups: { children: [ { availableSpan: 3, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, providerResults: [ makeHistoryResults(1)[0], Object.assign(makeHistoryResults(1)[0], { resultSpan: 2 }), makeHistoryResults(1)[0], ], expectedResultIndexes: [0, 1], }); add_resultGroups_task({ testName: "availableSpan: 3, resultSpan = 1 and resultSpan = 2", resultGroups: { children: [ { availableSpan: 3, group: UrlbarUtils.RESULT_GROUP.GENERAL, }, ], }, providerResults: [ Object.assign(makeHistoryResults(1)[0], { resultSpan: 2 }), makeHistoryResults(1)[0], makeHistoryResults(1)[0], ], expectedResultIndexes: [0, 1], }); /** * Adds a single test task. * * @param {object} options * The options for the test * @param {string} options.testName * This name is logged with `info` as the task starts. * @param {object} options.resultGroups * browser.urlbar.resultGroups is set to this value as the task starts. * @param {Array} options.providerResults * Array of result objects that the test provider will add. * @param {Array} options.expectedResultIndexes * Array of indexes in `providerResults` of the expected final results. */ function add_resultGroups_task({ testName, resultGroups, providerResults, expectedResultIndexes, }) { let func = async () => { info(`Running resultGroups test: ${testName}`); info(`Setting result groups: ` + JSON.stringify(resultGroups)); setResultGroups(resultGroups); let provider = registerBasicTestProvider(providerResults); let context = createContext("foo", { providers: [provider.name] }); let controller = UrlbarTestUtils.newMockController(); await UrlbarProvidersManager.startQuery(context, controller); UrlbarProvidersManager.unregisterProvider(provider); let expectedResults = expectedResultIndexes.map(i => providerResults[i]); Assert.deepEqual(context.results, expectedResults); setResultGroups(null); }; Object.defineProperty(func, "name", { value: testName }); add_task(func); } /** * Adds test tasks for each of the keys in `LIMIT_KEYS`. * * @param {object} options * The options for the test * @param {string} options.testName * The name of the test. * @param {object} options.resultGroups * The resultGroups object to set. * @param {Array} options.providerResults * The results to return from the test * @param {Array} options.expectedResultIndexes * Indexes of the expected results within {@link providerResults} */ function add_resultGroupsLimit_tasks({ testName, resultGroups, providerResults, expectedResultIndexes, }) { for (let key of LIMIT_KEYS) { add_resultGroups_task({ testName: `${testName} (limit: ${key})`, resultGroups: replaceLimitWithKey(resultGroups, key), providerResults, expectedResultIndexes, }); } } function replaceLimitWithKey(group, key) { group = { ...group }; if ("limit" in group) { group[key] = group.limit; delete group.limit; } for (let i = 0; i < group.children?.length; i++) { group.children[i] = replaceLimitWithKey(group.children[i], key); } return group; } function makeHistoryResults(count) { let results = []; for (let i = 0; i < count; i++) { results.push( new UrlbarResult( UrlbarUtils.RESULT_TYPE.URL, UrlbarUtils.RESULT_SOURCE.HISTORY, { url: "http://example.com/" + i } ) ); } return results; } function makeRemoteSuggestionResults(count) { let results = []; for (let i = 0; i < count; i++) { results.push( new UrlbarResult( UrlbarUtils.RESULT_TYPE.SEARCH, UrlbarUtils.RESULT_SOURCE.SEARCH, { engine: "test", query: "test", suggestion: "test " + i, lowerCaseSuggestion: "test " + i, } ) ); } return results; } function makeFormHistoryResults(count) { let results = []; for (let i = 0; i < count; i++) { results.push( new UrlbarResult( UrlbarUtils.RESULT_TYPE.SEARCH, UrlbarUtils.RESULT_SOURCE.HISTORY, { engine: "test", suggestion: "test " + i, lowerCaseSuggestion: "test " + i, } ) ); } return results; } function makeIndexRange(startIndex, count) { let indexes = []; for (let i = startIndex; i < startIndex + count; i++) { indexes.push(i); } return indexes; } function setResultGroups(resultGroups) { if (resultGroups) { Services.prefs.setCharPref( RESULT_GROUPS_PREF, JSON.stringify(resultGroups) ); } else { Services.prefs.clearUserPref(RESULT_GROUPS_PREF); } }