tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_resultGroups.js (40004B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 // Tests the muxer's result groups composition logic: child groups,
      5 // `availableSpan`, `maxResultCount`, flex, etc. The purpose of this test is to
      6 // check the composition logic, not every possible result type or group.
      7 
      8 "use strict";
      9 
     10 const lazy = {};
     11 
     12 ChromeUtils.defineESModuleGetters(lazy, {
     13  sinon: "resource://testing-common/Sinon.sys.mjs",
     14 });
     15 
     16 // The possible limit-related properties in result groups.
     17 const LIMIT_KEYS = ["availableSpan", "maxResultCount"];
     18 
     19 // Most of this test adds tasks using `add_resultGroupsLimit_tasks`. It works
     20 // like this. Instead of defining `maxResultCount` or `availableSpan` in their
     21 // result groups, tasks define a `limit` property. The value of this property is
     22 // a number just like any of the values for the limit-related properties. At
     23 // runtime, `add_resultGroupsLimit_tasks` adds multiple tasks, one for each key
     24 // in `LIMIT_KEYS`. In each of these tasks, the `limit` property is replaced
     25 // with the actual limit key. This allows us to run checks against each of the
     26 // limit keys using essentially the same task.
     27 
     28 const MAX_RICH_RESULTS_PREF = "browser.urlbar.maxRichResults";
     29 
     30 // For simplicity, most of the flex tests below assume that this is 10, so
     31 // you'll need to update them if you change this.
     32 const MAX_RESULTS = 10;
     33 
     34 let sandbox;
     35 
     36 add_setup(async function () {
     37  // Set a specific maxRichResults for sanity's sake.
     38  Services.prefs.setIntPref(MAX_RICH_RESULTS_PREF, MAX_RESULTS);
     39 
     40  sandbox = lazy.sinon.createSandbox();
     41  registerCleanupFunction(() => {
     42    sandbox.restore();
     43  });
     44 });
     45 
     46 add_resultGroupsLimit_tasks({
     47  testName: "empty root",
     48  resultGroups: {},
     49  providerResults: [...makeHistoryResults(1)],
     50  expectedResultIndexes: [],
     51 });
     52 
     53 add_resultGroupsLimit_tasks({
     54  testName: "root with empty children",
     55  resultGroups: {
     56    children: [],
     57  },
     58  providerResults: [...makeHistoryResults(1)],
     59  expectedResultIndexes: [],
     60 });
     61 
     62 add_resultGroupsLimit_tasks({
     63  testName: "root no match",
     64  resultGroups: {
     65    group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
     66  },
     67  providerResults: [...makeHistoryResults(1)],
     68  expectedResultIndexes: [],
     69 });
     70 
     71 add_resultGroupsLimit_tasks({
     72  testName: "children no match",
     73  resultGroups: {
     74    children: [{ group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }],
     75  },
     76  providerResults: [...makeHistoryResults(1)],
     77  expectedResultIndexes: [],
     78 });
     79 
     80 add_resultGroupsLimit_tasks({
     81  // The actual max result count on the root is always context.maxResults and
     82  // limit is ignored, so we expect the result in this case.
     83  testName: "root limit: 0",
     84  resultGroups: {
     85    limit: 0,
     86    group: UrlbarUtils.RESULT_GROUP.GENERAL,
     87  },
     88  providerResults: [...makeHistoryResults(1)],
     89  expectedResultIndexes: [0],
     90 });
     91 
     92 add_resultGroupsLimit_tasks({
     93  // The actual max result count on the root is always context.maxResults and
     94  // limit is ignored, so we expect the result in this case.
     95  testName: "root limit: 0 with children",
     96  resultGroups: {
     97    limit: 0,
     98    children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }],
     99  },
    100  providerResults: [...makeHistoryResults(1)],
    101  expectedResultIndexes: [0],
    102 });
    103 
    104 add_resultGroupsLimit_tasks({
    105  testName: "child limit: 0",
    106  resultGroups: {
    107    children: [
    108      {
    109        limit: 0,
    110        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    111      },
    112    ],
    113  },
    114  providerResults: [...makeHistoryResults(1)],
    115  expectedResultIndexes: [],
    116 });
    117 
    118 add_resultGroupsLimit_tasks({
    119  testName: "root group",
    120  resultGroups: {
    121    group: UrlbarUtils.RESULT_GROUP.GENERAL,
    122  },
    123  providerResults: [...makeHistoryResults(1)],
    124  expectedResultIndexes: [...makeIndexRange(0, 1)],
    125 });
    126 
    127 add_resultGroupsLimit_tasks({
    128  testName: "root group multiple",
    129  resultGroups: {
    130    group: UrlbarUtils.RESULT_GROUP.GENERAL,
    131  },
    132  providerResults: [...makeHistoryResults(2)],
    133  expectedResultIndexes: [...makeIndexRange(0, 2)],
    134 });
    135 
    136 add_resultGroupsLimit_tasks({
    137  testName: "child group multiple",
    138  resultGroups: {
    139    children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }],
    140  },
    141  providerResults: [...makeHistoryResults(2)],
    142  expectedResultIndexes: [0, 1],
    143 });
    144 
    145 add_resultGroupsLimit_tasks({
    146  testName: "simple limit",
    147  resultGroups: {
    148    children: [
    149      {
    150        limit: 1,
    151        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    152      },
    153    ],
    154  },
    155  providerResults: [...makeHistoryResults(2)],
    156  expectedResultIndexes: [0],
    157 });
    158 
    159 add_resultGroupsLimit_tasks({
    160  testName: "limit siblings",
    161  resultGroups: {
    162    children: [
    163      {
    164        limit: 1,
    165        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    166      },
    167      { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    168    ],
    169  },
    170  providerResults: [...makeHistoryResults(2)],
    171  expectedResultIndexes: [0, 1],
    172 });
    173 
    174 add_resultGroupsLimit_tasks({
    175  testName: "limit nested",
    176  resultGroups: {
    177    children: [
    178      {
    179        limit: 1,
    180        children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }],
    181      },
    182    ],
    183  },
    184  providerResults: [...makeHistoryResults(2)],
    185  expectedResultIndexes: [0],
    186 });
    187 
    188 add_resultGroupsLimit_tasks({
    189  testName: "limit nested siblings",
    190  resultGroups: {
    191    children: [
    192      {
    193        limit: 1,
    194        children: [
    195          { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    196          { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    197        ],
    198      },
    199    ],
    200  },
    201  providerResults: [...makeHistoryResults(2)],
    202  expectedResultIndexes: [0],
    203 });
    204 
    205 add_resultGroupsLimit_tasks({
    206  testName: "limit nested uncle",
    207  resultGroups: {
    208    children: [
    209      {
    210        limit: 1,
    211        children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }],
    212      },
    213      { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    214    ],
    215  },
    216  providerResults: [...makeHistoryResults(2)],
    217  expectedResultIndexes: [0, 1],
    218 });
    219 
    220 add_resultGroupsLimit_tasks({
    221  testName: "limit nested override bad",
    222  resultGroups: {
    223    children: [
    224      {
    225        limit: 1,
    226        children: [
    227          {
    228            limit: 99,
    229            group: UrlbarUtils.RESULT_GROUP.GENERAL,
    230          },
    231        ],
    232      },
    233    ],
    234  },
    235  providerResults: [...makeHistoryResults(2)],
    236  expectedResultIndexes: [0],
    237 });
    238 
    239 add_resultGroupsLimit_tasks({
    240  testName: "limit nested override good",
    241  resultGroups: {
    242    children: [
    243      {
    244        limit: 99,
    245        children: [
    246          {
    247            limit: 1,
    248            group: UrlbarUtils.RESULT_GROUP.GENERAL,
    249          },
    250        ],
    251      },
    252    ],
    253  },
    254  providerResults: [...makeHistoryResults(2)],
    255  expectedResultIndexes: [0],
    256 });
    257 
    258 add_resultGroupsLimit_tasks({
    259  testName: "multiple groups",
    260  resultGroups: {
    261    children: [
    262      { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    263      { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION },
    264    ],
    265  },
    266  providerResults: [
    267    ...makeRemoteSuggestionResults(2),
    268    ...makeHistoryResults(2),
    269  ],
    270  expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 2)],
    271 });
    272 
    273 add_resultGroupsLimit_tasks({
    274  testName: "multiple groups limit 1",
    275  resultGroups: {
    276    children: [
    277      {
    278        limit: 1,
    279        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    280      },
    281      { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION },
    282    ],
    283  },
    284  providerResults: [
    285    ...makeRemoteSuggestionResults(2),
    286    ...makeHistoryResults(2),
    287  ],
    288  expectedResultIndexes: [...makeIndexRange(2, 1), ...makeIndexRange(0, 2)],
    289 });
    290 
    291 add_resultGroupsLimit_tasks({
    292  testName: "multiple groups limit 2",
    293  resultGroups: {
    294    children: [
    295      { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    296      {
    297        limit: 1,
    298        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    299      },
    300    ],
    301  },
    302  providerResults: [
    303    ...makeRemoteSuggestionResults(2),
    304    ...makeHistoryResults(2),
    305  ],
    306  expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 1)],
    307 });
    308 
    309 add_resultGroupsLimit_tasks({
    310  testName: "multiple groups limit 3",
    311  resultGroups: {
    312    children: [
    313      {
    314        limit: 1,
    315        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    316      },
    317      { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION },
    318      { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    319    ],
    320  },
    321  providerResults: [
    322    ...makeRemoteSuggestionResults(2),
    323    ...makeHistoryResults(2),
    324  ],
    325  expectedResultIndexes: [
    326    ...makeIndexRange(2, 1),
    327    ...makeIndexRange(0, 2),
    328    ...makeIndexRange(3, 1),
    329  ],
    330 });
    331 
    332 add_resultGroupsLimit_tasks({
    333  testName: "multiple groups limit 4",
    334  resultGroups: {
    335    children: [
    336      { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    337      {
    338        limit: 1,
    339        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    340      },
    341      { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    342    ],
    343  },
    344  providerResults: [
    345    ...makeRemoteSuggestionResults(2),
    346    ...makeHistoryResults(2),
    347  ],
    348  expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 1)],
    349 });
    350 
    351 add_resultGroupsLimit_tasks({
    352  testName: "multiple groups nested 1",
    353  resultGroups: {
    354    children: [
    355      {
    356        children: [
    357          { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    358          { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION },
    359        ],
    360      },
    361    ],
    362  },
    363  providerResults: [
    364    ...makeRemoteSuggestionResults(2),
    365    ...makeHistoryResults(2),
    366  ],
    367  expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 2)],
    368 });
    369 
    370 add_resultGroupsLimit_tasks({
    371  testName: "multiple groups nested 2",
    372  resultGroups: {
    373    children: [
    374      {
    375        children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }],
    376      },
    377      {
    378        children: [{ group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }],
    379      },
    380    ],
    381  },
    382  providerResults: [
    383    ...makeRemoteSuggestionResults(2),
    384    ...makeHistoryResults(2),
    385  ],
    386  expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 2)],
    387 });
    388 
    389 add_resultGroupsLimit_tasks({
    390  testName: "multiple groups nested limit 1",
    391  resultGroups: {
    392    children: [
    393      {
    394        limit: 1,
    395        children: [
    396          { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    397          { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION },
    398        ],
    399      },
    400    ],
    401  },
    402  providerResults: [
    403    ...makeRemoteSuggestionResults(2),
    404    ...makeHistoryResults(2),
    405  ],
    406  expectedResultIndexes: [...makeIndexRange(2, 1)],
    407 });
    408 
    409 add_resultGroupsLimit_tasks({
    410  testName: "multiple groups nested limit 2",
    411  resultGroups: {
    412    children: [
    413      {
    414        children: [
    415          {
    416            limit: 1,
    417            group: UrlbarUtils.RESULT_GROUP.GENERAL,
    418          },
    419        ],
    420      },
    421      {
    422        children: [{ group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }],
    423      },
    424    ],
    425  },
    426  providerResults: [
    427    ...makeRemoteSuggestionResults(2),
    428    ...makeHistoryResults(2),
    429  ],
    430  expectedResultIndexes: [...makeIndexRange(2, 1), ...makeIndexRange(0, 2)],
    431 });
    432 
    433 add_resultGroupsLimit_tasks({
    434  testName: "multiple groups nested limit 3",
    435  resultGroups: {
    436    children: [
    437      {
    438        children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }],
    439      },
    440      {
    441        children: [
    442          {
    443            limit: 1,
    444            group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    445          },
    446        ],
    447      },
    448    ],
    449  },
    450  providerResults: [
    451    ...makeRemoteSuggestionResults(2),
    452    ...makeHistoryResults(2),
    453  ],
    454  expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 1)],
    455 });
    456 
    457 add_resultGroupsLimit_tasks({
    458  testName: "multiple groups nested limit 4",
    459  resultGroups: {
    460    children: [
    461      {
    462        children: [
    463          {
    464            limit: 1,
    465            group: UrlbarUtils.RESULT_GROUP.GENERAL,
    466          },
    467        ],
    468      },
    469      {
    470        children: [{ group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION }],
    471      },
    472      {
    473        children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }],
    474      },
    475    ],
    476  },
    477  providerResults: [
    478    ...makeRemoteSuggestionResults(2),
    479    ...makeHistoryResults(2),
    480  ],
    481  expectedResultIndexes: [
    482    ...makeIndexRange(2, 1),
    483    ...makeIndexRange(0, 2),
    484    ...makeIndexRange(3, 1),
    485  ],
    486 });
    487 
    488 add_resultGroupsLimit_tasks({
    489  testName: "multiple groups nested limit 5",
    490  resultGroups: {
    491    children: [
    492      {
    493        children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }],
    494      },
    495      {
    496        children: [
    497          {
    498            limit: 1,
    499            group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    500          },
    501        ],
    502      },
    503      {
    504        children: [{ group: UrlbarUtils.RESULT_GROUP.GENERAL }],
    505      },
    506    ],
    507  },
    508  providerResults: [
    509    ...makeRemoteSuggestionResults(2),
    510    ...makeHistoryResults(2),
    511  ],
    512  expectedResultIndexes: [...makeIndexRange(2, 2), ...makeIndexRange(0, 1)],
    513 });
    514 
    515 add_resultGroupsLimit_tasks({
    516  testName: "multiple groups nested limit 6",
    517  resultGroups: {
    518    children: [
    519      {
    520        children: [
    521          {
    522            limit: 1,
    523            group: UrlbarUtils.RESULT_GROUP.GENERAL,
    524          },
    525        ],
    526      },
    527      { group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION },
    528      { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    529    ],
    530  },
    531  providerResults: [
    532    ...makeRemoteSuggestionResults(2),
    533    ...makeHistoryResults(2),
    534  ],
    535  expectedResultIndexes: [
    536    ...makeIndexRange(2, 1),
    537    ...makeIndexRange(0, 2),
    538    ...makeIndexRange(3, 1),
    539  ],
    540 });
    541 
    542 add_resultGroupsLimit_tasks({
    543  testName: "flex 1",
    544  resultGroups: {
    545    flexChildren: true,
    546    children: [
    547      {
    548        flex: 1,
    549        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    550      },
    551      {
    552        flex: 1,
    553        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    554      },
    555    ],
    556  },
    557  providerResults: [
    558    ...makeRemoteSuggestionResults(MAX_RESULTS),
    559    ...makeHistoryResults(MAX_RESULTS),
    560  ],
    561  expectedResultIndexes: [
    562    // general/history: round(10 * (1 / (1 + 1))) = 5
    563    ...makeIndexRange(MAX_RESULTS, 5),
    564    // remote suggestions: round(10 * (1 / (1 + 1))) = 5
    565    ...makeIndexRange(0, 5),
    566  ],
    567 });
    568 
    569 add_resultGroupsLimit_tasks({
    570  testName: "flex 2",
    571  resultGroups: {
    572    flexChildren: true,
    573    children: [
    574      {
    575        flex: 2,
    576        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    577      },
    578      {
    579        flex: 1,
    580        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    581      },
    582    ],
    583  },
    584  providerResults: [
    585    ...makeRemoteSuggestionResults(MAX_RESULTS),
    586    ...makeHistoryResults(MAX_RESULTS),
    587  ],
    588  expectedResultIndexes: [
    589    // general/history: round(10 * (2 / 3)) = 7
    590    ...makeIndexRange(MAX_RESULTS, 7),
    591    // remote suggestions: round(10 * (1 / 3)) = 3
    592    ...makeIndexRange(0, 3),
    593  ],
    594 });
    595 
    596 add_resultGroupsLimit_tasks({
    597  testName: "flex 3",
    598  resultGroups: {
    599    flexChildren: true,
    600    children: [
    601      {
    602        flex: 1,
    603        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    604      },
    605      {
    606        flex: 2,
    607        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    608      },
    609    ],
    610  },
    611  providerResults: [
    612    ...makeRemoteSuggestionResults(MAX_RESULTS),
    613    ...makeHistoryResults(MAX_RESULTS),
    614  ],
    615  expectedResultIndexes: [
    616    // general/history: round(10 * (1 / 3)) = 3
    617    ...makeIndexRange(MAX_RESULTS, 3),
    618    // remote suggestions: round(10 * (2 / 3)) = 7
    619    ...makeIndexRange(0, 7),
    620  ],
    621 });
    622 
    623 add_resultGroupsLimit_tasks({
    624  testName: "flex 4",
    625  resultGroups: {
    626    flexChildren: true,
    627    children: [
    628      {
    629        flex: 1,
    630        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    631      },
    632      {
    633        flex: 1,
    634        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    635      },
    636      {
    637        flex: 1,
    638        group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
    639      },
    640    ],
    641  },
    642  providerResults: [
    643    ...makeFormHistoryResults(MAX_RESULTS),
    644    ...makeRemoteSuggestionResults(MAX_RESULTS),
    645    ...makeHistoryResults(MAX_RESULTS),
    646  ],
    647  expectedResultIndexes: [
    648    // general/history: round(10 * (1 / 3)) = 3, and then incremented to 4 so
    649    // that the total result span is 10 instead of 9. This group is incremented
    650    // because the fractional part of its unrounded ideal max result count is
    651    // 0.33 (since 10 * (1 / 3) = 3.33), the same as the other two groups, and
    652    // this group is first.
    653    ...makeIndexRange(2 * MAX_RESULTS, 4),
    654    // remote suggestions: round(10 * (1 / 3)) = 3
    655    ...makeIndexRange(MAX_RESULTS, 3),
    656    // form history: round(10 * (1 / 3)) = 3
    657    // The first three form history results dupe the three remote suggestions,
    658    // so they should not be included.
    659    ...makeIndexRange(3, 3),
    660  ],
    661 });
    662 
    663 add_resultGroupsLimit_tasks({
    664  testName: "flex 5",
    665  resultGroups: {
    666    flexChildren: true,
    667    children: [
    668      {
    669        flex: 2,
    670        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    671      },
    672      {
    673        flex: 1,
    674        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    675      },
    676      {
    677        flex: 1,
    678        group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
    679      },
    680    ],
    681  },
    682  providerResults: [
    683    ...makeFormHistoryResults(MAX_RESULTS),
    684    ...makeRemoteSuggestionResults(MAX_RESULTS),
    685    ...makeHistoryResults(MAX_RESULTS),
    686  ],
    687  expectedResultIndexes: [
    688    // general/history: round(10 * (2 / 4)) = 5
    689    ...makeIndexRange(2 * MAX_RESULTS, 5),
    690    // remote suggestions: round(10 * (1 / 4)) = 3
    691    ...makeIndexRange(MAX_RESULTS, 3),
    692    // form history: round(10 * (1 / 4)) = 3, but context.maxResults is 10, so 2
    693    // The first three form history results dupe the three remote suggestions,
    694    // so they should not be included.
    695    ...makeIndexRange(3, 2),
    696  ],
    697 });
    698 
    699 add_resultGroupsLimit_tasks({
    700  testName: "flex 6",
    701  resultGroups: {
    702    flexChildren: true,
    703    children: [
    704      {
    705        flex: 1,
    706        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    707      },
    708      {
    709        flex: 2,
    710        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    711      },
    712      {
    713        flex: 1,
    714        group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
    715      },
    716    ],
    717  },
    718  providerResults: [
    719    ...makeFormHistoryResults(MAX_RESULTS),
    720    ...makeRemoteSuggestionResults(MAX_RESULTS),
    721    ...makeHistoryResults(MAX_RESULTS),
    722  ],
    723  expectedResultIndexes: [
    724    // general/history: round(10 * (1 / 4)) = 3
    725    ...makeIndexRange(2 * MAX_RESULTS, 3),
    726    // remote suggestions: round(10 * (2 / 4)) = 5
    727    ...makeIndexRange(MAX_RESULTS, 5),
    728    // form history: round(10 * (1 / 4)) = 3, but context.maxResults is 10, so 2
    729    // The first five form history results dupe the five remote suggestions, so
    730    // they should not be included.
    731    ...makeIndexRange(5, 2),
    732  ],
    733 });
    734 
    735 add_resultGroupsLimit_tasks({
    736  testName: "flex 7",
    737  resultGroups: {
    738    flexChildren: true,
    739    children: [
    740      {
    741        flex: 1,
    742        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    743      },
    744      {
    745        flex: 1,
    746        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    747      },
    748      {
    749        flex: 2,
    750        group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
    751      },
    752    ],
    753  },
    754  providerResults: [
    755    ...makeFormHistoryResults(MAX_RESULTS),
    756    ...makeRemoteSuggestionResults(MAX_RESULTS),
    757    ...makeHistoryResults(MAX_RESULTS),
    758  ],
    759  expectedResultIndexes: [
    760    // general/history: round(10 * (1 / 4)) = 3
    761    ...makeIndexRange(2 * MAX_RESULTS, 3),
    762    // remote suggestions: round(10 * (1 / 4)) = 3, and then decremented to 2 so
    763    // that the total result span is 10 instead of 11. This group is decremented
    764    // because the fractional part of its unrounded ideal max result count is
    765    // 0.5 (since 10 * (1 / 4) = 2.5), the same as the previous group, and the
    766    // next group's fractional part is zero.
    767    ...makeIndexRange(MAX_RESULTS, 2),
    768    // form history: round(10 * (2 / 4)) = 5
    769    // The first 2 form history results dupe the three remote suggestions, so
    770    // they should not be included.
    771    ...makeIndexRange(2, 5),
    772  ],
    773 });
    774 
    775 add_resultGroupsLimit_tasks({
    776  testName: "flex overfill 1",
    777  resultGroups: {
    778    flexChildren: true,
    779    children: [
    780      {
    781        flex: 2,
    782        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    783      },
    784      {
    785        flex: 1,
    786        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    787      },
    788      {
    789        flex: 1,
    790        group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
    791      },
    792    ],
    793  },
    794  providerResults: [
    795    ...makeFormHistoryResults(MAX_RESULTS),
    796    ...makeHistoryResults(MAX_RESULTS),
    797  ],
    798  expectedResultIndexes: [
    799    // general/history: round(10 * (2 / (2 + 0 + 1))) = 7
    800    ...makeIndexRange(MAX_RESULTS, 7),
    801    // form history: round(10 * (1 / (2 + 0 + 1))) = 3
    802    ...makeIndexRange(0, 3),
    803  ],
    804 });
    805 
    806 add_resultGroupsLimit_tasks({
    807  testName: "flex overfill 2",
    808  resultGroups: {
    809    flexChildren: true,
    810    children: [
    811      {
    812        flex: 2,
    813        group: UrlbarUtils.RESULT_GROUP.GENERAL,
    814      },
    815      {
    816        flex: 2,
    817        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    818      },
    819      {
    820        flex: 1,
    821        group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
    822      },
    823    ],
    824  },
    825  providerResults: [
    826    ...makeFormHistoryResults(MAX_RESULTS),
    827    ...makeRemoteSuggestionResults(1),
    828    ...makeHistoryResults(MAX_RESULTS),
    829  ],
    830  expectedResultIndexes: [
    831    // general/history: round(9 * (2 / (2 + 0 + 1))) = 6
    832    ...makeIndexRange(MAX_RESULTS + 1, 6),
    833    // remote suggestions
    834    ...makeIndexRange(MAX_RESULTS, 1),
    835    // form history: round(9 * (1 / (2 + 0 + 1))) = 3
    836    // The first form history result dupes the remote suggestion, so it should
    837    // not be included.
    838    ...makeIndexRange(1, 3),
    839  ],
    840 });
    841 
    842 add_resultGroupsLimit_tasks({
    843  testName: "flex nested limit 1",
    844  resultGroups: {
    845    children: [
    846      {
    847        limit: 5,
    848        flexChildren: true,
    849        children: [
    850          {
    851            flex: 2,
    852            group: UrlbarUtils.RESULT_GROUP.GENERAL,
    853          },
    854          {
    855            flex: 1,
    856            group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    857          },
    858        ],
    859      },
    860    ],
    861  },
    862  providerResults: [
    863    ...makeRemoteSuggestionResults(MAX_RESULTS),
    864    ...makeHistoryResults(MAX_RESULTS),
    865  ],
    866  expectedResultIndexes: [
    867    // general/history: round(5 * (2 / (2 + 1))) = 3
    868    ...makeIndexRange(MAX_RESULTS, 3),
    869    // remote suggestions: round(5 * (1 / (2 + 1))) = 2
    870    ...makeIndexRange(0, 2),
    871  ],
    872 });
    873 
    874 add_resultGroupsLimit_tasks({
    875  testName: "flex nested limit 2",
    876  resultGroups: {
    877    children: [
    878      {
    879        limit: 7,
    880        flexChildren: true,
    881        children: [
    882          {
    883            flex: 1,
    884            group: UrlbarUtils.RESULT_GROUP.GENERAL,
    885          },
    886          {
    887            flex: 2,
    888            group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    889          },
    890        ],
    891      },
    892    ],
    893  },
    894  providerResults: [
    895    ...makeRemoteSuggestionResults(MAX_RESULTS),
    896    ...makeHistoryResults(MAX_RESULTS),
    897  ],
    898  expectedResultIndexes: [
    899    // general: round(7 * (1 / (2 + 1))) = 2
    900    ...makeIndexRange(MAX_RESULTS, 2),
    901    // remote suggestions: round(7 * (2 / (2 + 1))) = 5
    902    ...makeIndexRange(0, 5),
    903  ],
    904 });
    905 
    906 add_resultGroupsLimit_tasks({
    907  testName: "flex nested limit 3",
    908  resultGroups: {
    909    children: [
    910      {
    911        limit: 7,
    912        flexChildren: true,
    913        children: [
    914          {
    915            flex: 1,
    916            group: UrlbarUtils.RESULT_GROUP.GENERAL,
    917          },
    918          {
    919            flex: 2,
    920            group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    921          },
    922        ],
    923      },
    924      {
    925        limit: 3,
    926        flexChildren: true,
    927        children: [
    928          {
    929            flex: 2,
    930            group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
    931          },
    932          {
    933            flex: 1,
    934            group: UrlbarUtils.RESULT_GROUP.GENERAL,
    935          },
    936        ],
    937      },
    938    ],
    939  },
    940  providerResults: [
    941    ...makeRemoteSuggestionResults(MAX_RESULTS),
    942    ...makeFormHistoryResults(MAX_RESULTS),
    943    ...makeHistoryResults(MAX_RESULTS),
    944  ],
    945  expectedResultIndexes: [
    946    // general: round(7 * (1 / (2 + 1))) = 2
    947    ...makeIndexRange(2 * MAX_RESULTS, 2),
    948    // remote suggestions: round(7 * (2 / (2 + 1))) = 5
    949    ...makeIndexRange(0, 5),
    950    // form history: round(3 * (2 / (2 + 1))) = 2
    951    // The first five form history results dupe the five remote suggestions, so
    952    // they should not be included.
    953    ...makeIndexRange(MAX_RESULTS + 5, 2),
    954    // general: round(3 * (1 / (2 + 1))) = 1
    955    ...makeIndexRange(2 * MAX_RESULTS + 2, 1),
    956  ],
    957 });
    958 
    959 add_resultGroupsLimit_tasks({
    960  testName: "flex nested limit 4",
    961  resultGroups: {
    962    children: [
    963      {
    964        limit: 7,
    965        flexChildren: true,
    966        children: [
    967          {
    968            flex: 1,
    969            group: UrlbarUtils.RESULT_GROUP.GENERAL,
    970          },
    971          {
    972            flex: 2,
    973            group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
    974          },
    975        ],
    976      },
    977      {
    978        limit: 3,
    979        children: [
    980          { group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY },
    981          { group: UrlbarUtils.RESULT_GROUP.GENERAL },
    982        ],
    983      },
    984    ],
    985  },
    986  providerResults: [
    987    ...makeRemoteSuggestionResults(MAX_RESULTS),
    988    ...makeFormHistoryResults(MAX_RESULTS),
    989    ...makeHistoryResults(MAX_RESULTS),
    990  ],
    991  expectedResultIndexes: [
    992    // general: round(7 * (1 / (2 + 1))) = 2
    993    ...makeIndexRange(2 * MAX_RESULTS, 2),
    994    // remote suggestions: round(7 * (2 / (2 + 1))) = 5
    995    ...makeIndexRange(0, 5),
    996    // form history: round(3 * (2 / (2 + 1))) = 2
    997    // The first five form history results dupe the five remote suggestions, so
    998    // they should not be included.
    999    ...makeIndexRange(MAX_RESULTS + 5, 3),
   1000  ],
   1001 });
   1002 
   1003 add_resultGroupsLimit_tasks({
   1004  testName: "flex nested limit 5",
   1005  resultGroups: {
   1006    children: [
   1007      {
   1008        limit: 7,
   1009        flexChildren: true,
   1010        children: [
   1011          {
   1012            flex: 1,
   1013            group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1014          },
   1015          {
   1016            flex: 2,
   1017            group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
   1018          },
   1019        ],
   1020      },
   1021      {
   1022        limit: 3,
   1023        group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
   1024      },
   1025    ],
   1026  },
   1027  providerResults: [
   1028    ...makeRemoteSuggestionResults(MAX_RESULTS),
   1029    ...makeFormHistoryResults(MAX_RESULTS),
   1030    ...makeHistoryResults(MAX_RESULTS),
   1031  ],
   1032  expectedResultIndexes: [
   1033    // general: round(7 * (1 / (2 + 1))) = 2
   1034    ...makeIndexRange(2 * MAX_RESULTS, 2),
   1035    // remote suggestions: round(7 * (2 / (2 + 1))) = 5
   1036    ...makeIndexRange(0, 5),
   1037    // form history: round(3 * (2 / (2 + 1))) = 2
   1038    // The first five form history results dupe the five remote suggestions, so
   1039    // they should not be included.
   1040    ...makeIndexRange(MAX_RESULTS + 5, 3),
   1041  ],
   1042 });
   1043 
   1044 add_resultGroupsLimit_tasks({
   1045  testName: "flex nested",
   1046  resultGroups: {
   1047    flexChildren: true,
   1048    children: [
   1049      {
   1050        flex: 2,
   1051        flexChildren: true,
   1052        children: [
   1053          {
   1054            flex: 1,
   1055            group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1056          },
   1057          {
   1058            flex: 2,
   1059            group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
   1060          },
   1061        ],
   1062      },
   1063      {
   1064        flex: 1,
   1065        flexChildren: true,
   1066        children: [
   1067          {
   1068            flex: 2,
   1069            group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
   1070          },
   1071          {
   1072            flex: 1,
   1073            group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1074          },
   1075        ],
   1076      },
   1077    ],
   1078  },
   1079  providerResults: [
   1080    ...makeRemoteSuggestionResults(MAX_RESULTS),
   1081    ...makeFormHistoryResults(MAX_RESULTS),
   1082    ...makeHistoryResults(MAX_RESULTS),
   1083  ],
   1084  expectedResultIndexes: [
   1085    // outer 1: general & remote suggestions: round(10 * (2 / (2 + 1))) = 7
   1086    // inner 1: general: round(7 * (1 / (2 + 1))) = 2
   1087    ...makeIndexRange(2 * MAX_RESULTS, 2),
   1088    // inner 2: remote suggestions: round(7 * (2 / (2 + 1))) = 5
   1089    ...makeIndexRange(0, 5),
   1090 
   1091    // outer 2: form history & general: round(10 * (1 / (2 + 1))) = 3
   1092    // inner 1: form history: round(3 * (2 / (2 + 1))) = 2
   1093    // The first five form history results dupe the five remote suggestions, so
   1094    // they should not be included.
   1095    ...makeIndexRange(MAX_RESULTS + 5, 2),
   1096    // inner 2: general: round(3 * (1 / (2 + 1))) = 1
   1097    ...makeIndexRange(2 * MAX_RESULTS + 2, 1),
   1098  ],
   1099 });
   1100 
   1101 add_resultGroupsLimit_tasks({
   1102  testName: "flex nested overfill 1",
   1103  resultGroups: {
   1104    flexChildren: true,
   1105    children: [
   1106      {
   1107        flex: 2,
   1108        flexChildren: true,
   1109        children: [
   1110          {
   1111            flex: 1,
   1112            group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1113          },
   1114          {
   1115            flex: 2,
   1116            group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
   1117          },
   1118        ],
   1119      },
   1120      {
   1121        flex: 1,
   1122        flexChildren: true,
   1123        children: [
   1124          {
   1125            flex: 2,
   1126            group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
   1127          },
   1128          {
   1129            flex: 1,
   1130            group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1131          },
   1132        ],
   1133      },
   1134    ],
   1135  },
   1136  providerResults: [
   1137    ...makeRemoteSuggestionResults(MAX_RESULTS),
   1138    ...makeFormHistoryResults(MAX_RESULTS),
   1139  ],
   1140  expectedResultIndexes: [
   1141    // outer 1: general & remote suggestions: round(10 * (2 / (2 + 1))) = 7
   1142    // inner 1: general: no results
   1143    // inner 2: remote suggestions: round(7 * (2 / (2 + 0))) = 7
   1144    ...makeIndexRange(0, 7),
   1145 
   1146    // outer 2: form history & general: round(10 * (1 / (2 + 1))) = 3
   1147    // inner 1: form history: round(3 * (2 / (2 + 0))) = 3
   1148    // The first seven form history results dupe the seven remote suggestions,
   1149    // so they should not be included.
   1150    ...makeIndexRange(MAX_RESULTS + 7, 3),
   1151    // inner 2: general: no results
   1152  ],
   1153 });
   1154 
   1155 add_resultGroupsLimit_tasks({
   1156  testName: "flex nested overfill 2",
   1157  resultGroups: {
   1158    flexChildren: true,
   1159    children: [
   1160      {
   1161        flex: 2,
   1162        flexChildren: true,
   1163        children: [
   1164          {
   1165            flex: 1,
   1166            group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1167          },
   1168          {
   1169            flex: 2,
   1170            group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
   1171          },
   1172        ],
   1173      },
   1174      {
   1175        flex: 1,
   1176        flexChildren: true,
   1177        children: [
   1178          {
   1179            flex: 2,
   1180            group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
   1181          },
   1182          {
   1183            flex: 1,
   1184            group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1185          },
   1186        ],
   1187      },
   1188    ],
   1189  },
   1190  providerResults: [...makeFormHistoryResults(MAX_RESULTS)],
   1191  expectedResultIndexes: [
   1192    // outer 1: general & remote suggestions: round(10 * (2 / (2 + 1))) = 7
   1193    // inner 1: general: no results
   1194    // inner 2: remote suggestions: no results
   1195 
   1196    // outer 2: form history & general: round(10 * (1 / (0 + 1))) = 10
   1197    // inner 1: form history: round(10 * (2 / (2 + 0))) = 10
   1198    ...makeIndexRange(0, MAX_RESULTS),
   1199    // inner 2: general: no results
   1200  ],
   1201 });
   1202 
   1203 add_resultGroupsLimit_tasks({
   1204  testName: "flex nested overfill 3",
   1205  resultGroups: {
   1206    flexChildren: true,
   1207    children: [
   1208      {
   1209        flex: 2,
   1210        flexChildren: true,
   1211        children: [
   1212          {
   1213            flex: 1,
   1214            group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1215          },
   1216          {
   1217            flex: 2,
   1218            group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
   1219          },
   1220        ],
   1221      },
   1222      {
   1223        flex: 1,
   1224        flexChildren: true,
   1225        children: [
   1226          {
   1227            flex: 2,
   1228            group: UrlbarUtils.RESULT_GROUP.FORM_HISTORY,
   1229          },
   1230          {
   1231            flex: 1,
   1232            group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1233          },
   1234        ],
   1235      },
   1236    ],
   1237  },
   1238  providerResults: [...makeRemoteSuggestionResults(MAX_RESULTS)],
   1239  expectedResultIndexes: [
   1240    // outer 1: general & remote suggestions: round(10 * (2 / (2 + 0))) = 10
   1241    // inner 1: general: no results
   1242    // inner 2: remote suggestions: round(10 * (2 / (2 + 0))) = 10
   1243    ...makeIndexRange(0, MAX_RESULTS),
   1244 
   1245    // outer 2: form history & general: round(10 * (1 / (2 + 1))) = 3
   1246    // inner 1: form history: no results
   1247    // inner 2: general: no results
   1248  ],
   1249 });
   1250 
   1251 add_resultGroupsLimit_tasks({
   1252  testName: "limit ignored with flex",
   1253  resultGroups: {
   1254    flexChildren: true,
   1255    children: [
   1256      {
   1257        limit: 1,
   1258        flex: 2,
   1259        group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1260      },
   1261      {
   1262        flex: 1,
   1263        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
   1264      },
   1265    ],
   1266  },
   1267  providerResults: [
   1268    ...makeRemoteSuggestionResults(MAX_RESULTS),
   1269    ...makeHistoryResults(MAX_RESULTS),
   1270  ],
   1271  expectedResultIndexes: [
   1272    // general/history: round(10 * (2 / (2 + 1))) = 7 -- limit ignored
   1273    ...makeIndexRange(MAX_RESULTS, 7),
   1274    // remote suggestions: round(10 * (1 / (2 + 1))) = 3
   1275    ...makeIndexRange(0, 3),
   1276  ],
   1277 });
   1278 
   1279 add_resultGroupsLimit_tasks({
   1280  testName: "resultSpan = 3 followed by others",
   1281  resultGroups: {
   1282    children: [
   1283      {
   1284        group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1285      },
   1286      {
   1287        group: UrlbarUtils.RESULT_GROUP.REMOTE_SUGGESTION,
   1288      },
   1289    ],
   1290  },
   1291  providerResults: [
   1292    // max results remote suggestions
   1293    ...makeRemoteSuggestionResults(MAX_RESULTS),
   1294    // 1 history with resultSpan = 3
   1295    ...makeHistoryResults(1, { resultSpan: 3 }),
   1296  ],
   1297  expectedResultIndexes: [
   1298    // general/history: 1
   1299    ...makeIndexRange(MAX_RESULTS, 1),
   1300    // remote suggestions: maxResults - resultSpan of 3 = 10 - 3 = 7
   1301    ...makeIndexRange(0, 7),
   1302  ],
   1303 });
   1304 
   1305 add_resultGroups_task({
   1306  testName: "maxResultCount: 1, availableSpan: 3",
   1307  resultGroups: {
   1308    children: [
   1309      {
   1310        maxResultCount: 1,
   1311        availableSpan: 3,
   1312        group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1313      },
   1314    ],
   1315  },
   1316  providerResults: [...makeHistoryResults(MAX_RESULTS)],
   1317  expectedResultIndexes: [0],
   1318 });
   1319 
   1320 add_resultGroups_task({
   1321  testName: "maxResultCount: 1, availableSpan: 3, resultSpan = 3",
   1322  resultGroups: {
   1323    children: [
   1324      {
   1325        maxResultCount: 1,
   1326        availableSpan: 3,
   1327        group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1328      },
   1329    ],
   1330  },
   1331  providerResults: [
   1332    ...makeHistoryResults(1, { resultSpan: 3 }),
   1333    ...makeHistoryResults(1, { resultSpan: 3 }),
   1334    ...makeHistoryResults(1, { resultSpan: 3 }),
   1335  ],
   1336  expectedResultIndexes: [0],
   1337 });
   1338 
   1339 add_resultGroups_task({
   1340  testName: "maxResultCount: 3, availableSpan: 1",
   1341  resultGroups: {
   1342    children: [
   1343      {
   1344        maxResultCount: 3,
   1345        availableSpan: 1,
   1346        group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1347      },
   1348    ],
   1349  },
   1350  providerResults: [...makeHistoryResults(MAX_RESULTS)],
   1351  expectedResultIndexes: [0],
   1352 });
   1353 
   1354 add_resultGroups_task({
   1355  testName: "maxResultCount: 3, availableSpan: 1, resultSpan = 3",
   1356  resultGroups: {
   1357    children: [
   1358      {
   1359        maxResultCount: 3,
   1360        availableSpan: 1,
   1361        group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1362      },
   1363    ],
   1364  },
   1365  providerResults: makeHistoryResults(1, { resultSpan: 3 }),
   1366  expectedResultIndexes: [],
   1367 });
   1368 
   1369 add_resultGroups_task({
   1370  testName: "availableSpan: 1",
   1371  resultGroups: {
   1372    children: [
   1373      {
   1374        availableSpan: 1,
   1375        group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1376      },
   1377    ],
   1378  },
   1379  providerResults: [...makeHistoryResults(MAX_RESULTS)],
   1380  expectedResultIndexes: [0],
   1381 });
   1382 
   1383 add_resultGroups_task({
   1384  testName: "availableSpan: 1, resultSpan = 3",
   1385  resultGroups: {
   1386    children: [
   1387      {
   1388        availableSpan: 1,
   1389        group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1390      },
   1391    ],
   1392  },
   1393  providerResults: makeHistoryResults(1, { resultSpan: 3 }),
   1394  expectedResultIndexes: [],
   1395 });
   1396 
   1397 add_resultGroups_task({
   1398  testName: "availableSpan: 3, resultSpan = 2 and resultSpan = 1",
   1399  resultGroups: {
   1400    children: [
   1401      {
   1402        availableSpan: 3,
   1403        group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1404      },
   1405    ],
   1406  },
   1407  providerResults: [
   1408    makeHistoryResults(1)[0],
   1409    ...makeHistoryResults(1, { resultSpan: 2 }),
   1410    makeHistoryResults(1)[0],
   1411  ],
   1412  expectedResultIndexes: [0, 1],
   1413 });
   1414 
   1415 add_resultGroups_task({
   1416  testName: "availableSpan: 3, resultSpan = 1 and resultSpan = 2",
   1417  resultGroups: {
   1418    children: [
   1419      {
   1420        availableSpan: 3,
   1421        group: UrlbarUtils.RESULT_GROUP.GENERAL,
   1422      },
   1423    ],
   1424  },
   1425  providerResults: [
   1426    ...makeHistoryResults(1, { resultSpan: 2 }),
   1427    makeHistoryResults(1)[0],
   1428    makeHistoryResults(1)[0],
   1429  ],
   1430  expectedResultIndexes: [0, 1],
   1431 });
   1432 
   1433 /**
   1434 * Adds a single test task.
   1435 *
   1436 * @param {object} options
   1437 *   The options for the test
   1438 * @param {string} options.testName
   1439 *   This name is logged with `info` as the task starts.
   1440 * @param {object} options.resultGroups
   1441 *   browser.urlbar.resultGroups is set to this value as the task starts.
   1442 * @param {Array} options.providerResults
   1443 *   Array of result objects that the test provider will add.
   1444 * @param {Array} options.expectedResultIndexes
   1445 *   Array of indexes in `providerResults` of the expected final results.
   1446 */
   1447 function add_resultGroups_task({
   1448  testName,
   1449  resultGroups,
   1450  providerResults,
   1451  expectedResultIndexes,
   1452 }) {
   1453  let func = async () => {
   1454    info(`Running resultGroups test: ${testName}`);
   1455    info(`Setting result groups: ` + JSON.stringify(resultGroups));
   1456    setResultGroups(resultGroups);
   1457    let provider = registerBasicTestProvider(providerResults);
   1458    let context = createContext("foo", { providers: [provider.name] });
   1459    let controller = UrlbarTestUtils.newMockController();
   1460    await UrlbarProvidersManager.startQuery(context, controller);
   1461    UrlbarProvidersManager.unregisterProvider(provider);
   1462    let expectedResults = expectedResultIndexes.map(i => providerResults[i]);
   1463    Assert.deepEqual(context.results, expectedResults);
   1464    setResultGroups(null);
   1465  };
   1466  Object.defineProperty(func, "name", { value: testName });
   1467  add_task(func);
   1468 }
   1469 
   1470 /**
   1471 * Adds test tasks for each of the keys in `LIMIT_KEYS`.
   1472 *
   1473 * @param {object} options
   1474 *   The options for the test
   1475 * @param {string} options.testName
   1476 *   The name of the test.
   1477 * @param {object} options.resultGroups
   1478 *   The resultGroups object to set.
   1479 * @param {Array} options.providerResults
   1480 *   The results to return from the test
   1481 * @param {Array} options.expectedResultIndexes
   1482 *   Indexes of the expected results within {@link providerResults}
   1483 */
   1484 function add_resultGroupsLimit_tasks({
   1485  testName,
   1486  resultGroups,
   1487  providerResults,
   1488  expectedResultIndexes,
   1489 }) {
   1490  for (let key of LIMIT_KEYS) {
   1491    add_resultGroups_task({
   1492      testName: `${testName} (limit: ${key})`,
   1493      resultGroups: replaceLimitWithKey(resultGroups, key),
   1494      providerResults,
   1495      expectedResultIndexes,
   1496    });
   1497  }
   1498 }
   1499 
   1500 function replaceLimitWithKey(group, key) {
   1501  group = { ...group };
   1502  if ("limit" in group) {
   1503    group[key] = group.limit;
   1504    delete group.limit;
   1505  }
   1506  for (let i = 0; i < group.children?.length; i++) {
   1507    group.children[i] = replaceLimitWithKey(group.children[i], key);
   1508  }
   1509  return group;
   1510 }
   1511 
   1512 function makeHistoryResults(count, { resultSpan } = {}) {
   1513  let results = [];
   1514  for (let i = 0; i < count; i++) {
   1515    results.push(
   1516      new UrlbarResult({
   1517        type: UrlbarUtils.RESULT_TYPE.URL,
   1518        source: UrlbarUtils.RESULT_SOURCE.HISTORY,
   1519        resultSpan: resultSpan && i == 0 ? resultSpan : undefined,
   1520        payload: { url: "http://example.com/" + i },
   1521      })
   1522    );
   1523  }
   1524  return results;
   1525 }
   1526 
   1527 function makeRemoteSuggestionResults(count) {
   1528  let results = [];
   1529  for (let i = 0; i < count; i++) {
   1530    results.push(
   1531      new UrlbarResult({
   1532        type: UrlbarUtils.RESULT_TYPE.SEARCH,
   1533        source: UrlbarUtils.RESULT_SOURCE.SEARCH,
   1534        payload: {
   1535          engine: "test",
   1536          query: "test",
   1537          suggestion: "test " + i,
   1538          lowerCaseSuggestion: "test " + i,
   1539        },
   1540      })
   1541    );
   1542  }
   1543  return results;
   1544 }
   1545 
   1546 function makeFormHistoryResults(count) {
   1547  let results = [];
   1548  for (let i = 0; i < count; i++) {
   1549    results.push(
   1550      new UrlbarResult({
   1551        type: UrlbarUtils.RESULT_TYPE.SEARCH,
   1552        source: UrlbarUtils.RESULT_SOURCE.HISTORY,
   1553        payload: {
   1554          engine: "test",
   1555          suggestion: "test " + i,
   1556          lowerCaseSuggestion: "test " + i,
   1557        },
   1558      })
   1559    );
   1560  }
   1561  return results;
   1562 }
   1563 
   1564 function makeIndexRange(startIndex, count) {
   1565  let indexes = [];
   1566  for (let i = startIndex; i < startIndex + count; i++) {
   1567    indexes.push(i);
   1568  }
   1569  return indexes;
   1570 }
   1571 
   1572 function setResultGroups(resultGroups) {
   1573  sandbox.restore();
   1574  if (resultGroups) {
   1575    sandbox.stub(UrlbarPrefs, "getResultGroups").returns(resultGroups);
   1576  }
   1577 }