/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ // Tests results with suggestedIndex and resultSpan. "use strict"; const MAX_RESULTS = 10; add_task(async function suggestedIndex() { // Initialize maxRichResults for sanity. UrlbarPrefs.set("maxRichResults", MAX_RESULTS); let tests = [ // no result spans > 1 { desc: "{ suggestedIndex: 0 }", suggestedIndexes: [0], expected: indexes([10, 1], [0, 9]), }, { desc: "{ suggestedIndex: 1 }", suggestedIndexes: [1], expected: indexes([0, 1], [10, 1], [1, 8]), }, { desc: "{ suggestedIndex: -1 }", suggestedIndexes: [-1], expected: indexes([0, 9], [10, 1]), }, { desc: "{ suggestedIndex: -2 }", suggestedIndexes: [-2], expected: indexes([0, 8], [10, 1], [8, 1]), }, { desc: "{ suggestedIndex: 0 }, { suggestedIndex: -1 }", suggestedIndexes: [0, -1], expected: indexes([10, 1], [0, 8], [11, 1]), }, { desc: "{ suggestedIndex: 1 }, { suggestedIndex: -1 }", suggestedIndexes: [1, -1], expected: indexes([0, 1], [10, 1], [1, 7], [11, 1]), }, { desc: "{ suggestedIndex: 1 }, { suggestedIndex: -2 }", suggestedIndexes: [1, -2], expected: indexes([0, 1], [10, 1], [1, 6], [11, 1], [7, 1]), }, { desc: "{ suggestedIndex: 0 }, resultCount < max", suggestedIndexes: [0], resultCount: 5, expected: indexes([5, 1], [0, 5]), }, { desc: "{ suggestedIndex: 1 }, resultCount < max", suggestedIndexes: [1], resultCount: 5, expected: indexes([0, 1], [5, 1], [1, 4]), }, { desc: "{ suggestedIndex: -1 }, resultCount < max", suggestedIndexes: [-1], resultCount: 5, expected: indexes([0, 5], [5, 1]), }, { desc: "{ suggestedIndex: -2 }, resultCount < max", suggestedIndexes: [-2], resultCount: 5, expected: indexes([0, 4], [5, 1], [4, 1]), }, { desc: "{ suggestedIndex: 0 }, { suggestedIndex: -1 }, resultCount < max", suggestedIndexes: [0, -1], resultCount: 5, expected: indexes([5, 1], [0, 5], [6, 1]), }, { desc: "{ suggestedIndex: 1 }, { suggestedIndex: -1 }, resultCount < max", suggestedIndexes: [1, -1], resultCount: 5, expected: indexes([0, 1], [5, 1], [1, 4], [6, 1]), }, { desc: "{ suggestedIndex: 0 }, { suggestedIndex: -2 }, resultCount < max", suggestedIndexes: [0, -2], resultCount: 5, expected: indexes([5, 1], [0, 4], [6, 1], [4, 1]), }, { desc: "{ suggestedIndex: 1 }, { suggestedIndex: -2 }, resultCount < max", suggestedIndexes: [1, -2], resultCount: 5, expected: indexes([0, 1], [5, 1], [1, 3], [6, 1], [4, 1]), }, // one suggestedIndex with result span > 1 { desc: "{ suggestedIndex: 0, resultSpan: 2 }", suggestedIndexes: [0], spansByIndex: { 10: 2 }, expected: indexes([10, 1], [0, 8]), }, { desc: "{ suggestedIndex: 0, resultSpan: 3 }", suggestedIndexes: [0], spansByIndex: { 10: 3 }, expected: indexes([10, 1], [0, 7]), }, { desc: "{ suggestedIndex: 1, resultSpan: 2 }", suggestedIndexes: [1], spansByIndex: { 10: 2 }, expected: indexes([0, 1], [10, 1], [1, 7]), }, { desc: "suggestedIndex: 1, resultSpan:: 3 }", suggestedIndexes: [1], spansByIndex: { 10: 3 }, expected: indexes([0, 1], [10, 1], [1, 6]), }, { desc: "{ suggestedIndex: -1, resultSpan 2 }", suggestedIndexes: [-1], spansByIndex: { 10: 2 }, expected: indexes([0, 8], [10, 1]), }, { desc: "{ suggestedIndex: -1, resultSpan: 3 }", suggestedIndexes: [-1], spansByIndex: { 10: 3 }, expected: indexes([0, 7], [10, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -1 }", suggestedIndexes: [0, -1], spansByIndex: { 10: 2 }, expected: indexes([10, 1], [0, 7], [11, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 3 }, { suggestedIndex: -1 }", suggestedIndexes: [0, -1], spansByIndex: { 10: 3 }, expected: indexes([10, 1], [0, 6], [11, 1]), }, { desc: "{ suggestedIndex: 0 }, { suggestedIndex: -1, resultSpan: 2 }", suggestedIndexes: [0, -1], spansByIndex: { 11: 2 }, expected: indexes([10, 1], [0, 7], [11, 1]), }, { desc: "{ suggestedIndex: 0 }, { suggestedIndex: -1, resultSpan: 3 }", suggestedIndexes: [0, -1], spansByIndex: { 11: 3 }, expected: indexes([10, 1], [0, 6], [11, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -1 }", suggestedIndexes: [1, -1], spansByIndex: { 10: 2 }, expected: indexes([0, 1], [10, 1], [1, 6], [11, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 3 }, { suggestedIndex: -1 }", suggestedIndexes: [1, -1], spansByIndex: { 10: 3 }, expected: indexes([0, 1], [10, 1], [1, 5], [11, 1]), }, { desc: "{ suggestedIndex: 1 }, { suggestedIndex: -1, resultSpan: 2 }", suggestedIndexes: [1, -1], spansByIndex: { 11: 2 }, expected: indexes([0, 1], [10, 1], [1, 6], [11, 1]), }, { desc: "{ suggestedIndex: 1 }, { suggestedIndex: -1, resultSpan: 3 }", suggestedIndexes: [1, -1], spansByIndex: { 11: 3 }, expected: indexes([0, 1], [10, 1], [1, 5], [11, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -2 }", suggestedIndexes: [0, -2], spansByIndex: { 10: 2 }, expected: indexes([10, 1], [0, 6], [11, 1], [6, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 3 }, { suggestedIndex: -2 }", suggestedIndexes: [0, -2], spansByIndex: { 10: 3 }, expected: indexes([10, 1], [0, 5], [11, 1], [5, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -2 }", suggestedIndexes: [1, -2], spansByIndex: { 10: 2 }, expected: indexes([0, 1], [10, 1], [1, 5], [11, 1], [6, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 3 }, { suggestedIndex: -2 }", suggestedIndexes: [1, -2], spansByIndex: { 10: 3 }, expected: indexes([0, 1], [10, 1], [1, 4], [11, 1], [5, 1]), }, { desc: "{ suggestedIndex: 0 }, { suggestedIndex: -2, resultSpan: 2 }", suggestedIndexes: [0, -2], spansByIndex: { 11: 2 }, expected: indexes([10, 1], [0, 6], [11, 1], [6, 1]), }, { desc: "{ suggestedIndex: 0 }, { suggestedIndex: -2, resultSpan: 3 }", suggestedIndexes: [0, -2], spansByIndex: { 11: 3 }, expected: indexes([10, 1], [0, 5], [11, 1], [5, 1]), }, { desc: "{ suggestedIndex: 1 }, { suggestedIndex: -2, resultSpan: 2 }", suggestedIndexes: [1, -2], spansByIndex: { 11: 2 }, expected: indexes([0, 1], [10, 1], [1, 5], [11, 1], [6, 1]), }, { desc: "{ suggestedIndex: 1 }, { suggestedIndex: -2, resultSpan: 3 }", suggestedIndexes: [1, -2], spansByIndex: { 11: 3 }, expected: indexes([0, 1], [10, 1], [1, 4], [11, 1], [5, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 2 }, resultCount < max", suggestedIndexes: [0], spansByIndex: { 5: 2 }, resultCount: 5, expected: indexes([5, 1], [0, 5]), }, { desc: "{ suggestedIndex: 1, resultSpan: 2 }, resultCount < max", suggestedIndexes: [1], spansByIndex: { 5: 2 }, resultCount: 5, expected: indexes([0, 1], [5, 1], [1, 4]), }, { desc: "{ suggestedIndex: -1, resultSpan: 2 }, resultCount < max", suggestedIndexes: [-1], spansByIndex: { 5: 2 }, resultCount: 5, expected: indexes([0, 5], [5, 1]), }, { desc: "{ suggestedIndex: -2, resultSpan: 2 }, resultCount < max", suggestedIndexes: [-2], spansByIndex: { 5: 2 }, resultCount: 5, expected: indexes([0, 4], [5, 1], [4, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -1 }, resultCount < max", suggestedIndexes: [0, -1], spansByIndex: { 5: 2 }, resultCount: 5, expected: indexes([5, 1], [0, 5], [6, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -1 }, resultCount < max", suggestedIndexes: [1, -1], spansByIndex: { 5: 2 }, resultCount: 5, expected: indexes([0, 1], [5, 1], [1, 4], [6, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -2 }, resultCount < max", suggestedIndexes: [0, -2], spansByIndex: { 5: 2 }, resultCount: 5, expected: indexes([5, 1], [0, 4], [6, 1], [4, 1]), }, { desc: "{ suggestedIndex: 0 }, { suggestedIndex: -1, resultSpan: 2 }, resultCount < max", suggestedIndexes: [0, -1], spansByIndex: { 6: 2 }, resultCount: 5, expected: indexes([5, 1], [0, 5], [6, 1]), }, { desc: "{ suggestedIndex: 0 }, { suggestedIndex: -2, resultSpan: 2 }, resultCount < max", suggestedIndexes: [0, -2], spansByIndex: { 6: 2 }, resultCount: 5, expected: indexes([5, 1], [0, 4], [6, 1], [4, 1]), }, // two suggestedIndexes with result span > 1 { desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 2 }", suggestedIndexes: [0, -1], spansByIndex: { 10: 2, 11: 2 }, expected: indexes([10, 1], [0, 6], [11, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 3 }, { suggestedIndex: -1, resultSpan: 2 }", suggestedIndexes: [0, -1], spansByIndex: { 10: 3, 11: 2 }, expected: indexes([10, 1], [0, 5], [11, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 3 }", suggestedIndexes: [0, -1], spansByIndex: { 10: 2, 11: 3 }, expected: indexes([10, 1], [0, 5], [11, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 2 }", suggestedIndexes: [1, -1], spansByIndex: { 10: 2, 11: 2 }, expected: indexes([0, 1], [10, 1], [1, 5], [11, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 3 }, { suggestedIndex: -1, resultSpan: 2 }", suggestedIndexes: [1, -1], spansByIndex: { 10: 3, 11: 2 }, expected: indexes([0, 1], [10, 1], [1, 4], [11, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 3 }", suggestedIndexes: [1, -1], spansByIndex: { 10: 2, 11: 3 }, expected: indexes([0, 1], [10, 1], [1, 4], [11, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -2, resultSpan: 2 }", suggestedIndexes: [0, -2], spansByIndex: { 10: 2, 11: 2 }, expected: indexes([10, 1], [0, 5], [11, 1], [5, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 3 }, { suggestedIndex: -2, resultSpan: 2 }", suggestedIndexes: [0, -2], spansByIndex: { 10: 3, 11: 2 }, expected: indexes([10, 1], [0, 4], [11, 1], [4, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -2, resultSpan: 3 }", suggestedIndexes: [0, -2], spansByIndex: { 10: 2, 11: 3 }, expected: indexes([10, 1], [0, 4], [11, 1], [4, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -2, resultSpan: 2 }", suggestedIndexes: [1, -2], spansByIndex: { 10: 2, 11: 2 }, expected: indexes([0, 1], [10, 1], [1, 4], [11, 1], [5, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 3 }, { suggestedIndex: -2, resultSpan: 2 }", suggestedIndexes: [1, -2], spansByIndex: { 10: 3, 11: 2 }, expected: indexes([0, 1], [10, 1], [1, 3], [11, 1], [4, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -2, resultSpan: 3 }", suggestedIndexes: [1, -2], spansByIndex: { 10: 2, 11: 3 }, expected: indexes([0, 1], [10, 1], [1, 3], [11, 1], [4, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 2 }, resultCount < max", suggestedIndexes: [0, -1], spansByIndex: { 5: 2, 6: 2 }, resultCount: 5, expected: indexes([5, 1], [0, 5], [6, 1]), }, { desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 2 }, resultCount < max", suggestedIndexes: [1, -1], spansByIndex: { 5: 2, 6: 2 }, resultCount: 5, expected: indexes([0, 1], [5, 1], [1, 4], [6, 1]), }, { desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -2, resultSpan: 2 }, resultCount < max", suggestedIndexes: [0, -2], spansByIndex: { 5: 2, 6: 2 }, resultCount: 5, expected: indexes([5, 1], [0, 4], [6, 1], [4, 1]), }, // one suggestedIndex plus other result with resultSpan > 1 { desc: "{ suggestedIndex: 0 }, { resultSpan: 2 } A", suggestedIndexes: [0], spansByIndex: { 0: 2 }, expected: indexes([10, 1], [0, 8]), }, { desc: "{ suggestedIndex: 0 }, { resultSpan: 2 } B", suggestedIndexes: [0], spansByIndex: { 8: 2 }, expected: indexes([10, 1], [0, 8]), }, { desc: "{ suggestedIndex: 0 }, { resultSpan: 2 } C", suggestedIndexes: [0], spansByIndex: { 9: 2 }, expected: indexes([10, 1], [0, 9]), }, { desc: "{ suggestedIndex: 1 }, { resultSpan: 2 } A", suggestedIndexes: [1], spansByIndex: { 0: 2 }, expected: indexes([0, 1], [10, 1], [1, 7]), }, { desc: "{ suggestedIndex: 1 }, { resultSpan: 2 } B", suggestedIndexes: [1], spansByIndex: { 8: 2 }, expected: indexes([0, 1], [10, 1], [1, 7]), }, { desc: "{ suggestedIndex: -1 }, { resultSpan: 2 }", suggestedIndexes: [-1], spansByIndex: { 0: 2 }, expected: indexes([0, 8], [10, 1]), }, { desc: "{ suggestedIndex: -2 }, { resultSpan: 2 }", suggestedIndexes: [-2], spansByIndex: { 0: 2 }, expected: indexes([0, 7], [10, 1], [7, 1]), }, // miscellaneous { desc: "no suggestedIndex, last result has resultSpan = 2", suggestedIndexes: [], spansByIndex: { 9: 2 }, expected: indexes([0, 9]), }, { desc: "{ suggestedIndex: -1 }, last result has resultSpan = 2", suggestedIndexes: [-1], spansByIndex: { 9: 2 }, expected: indexes([0, 9], [10, 1]), }, { desc: "no suggestedIndex, index 8 result has resultSpan = 2", suggestedIndexes: [], spansByIndex: { 8: 2 }, expected: indexes([0, 9]), }, { desc: "{ suggestedIndex: -1 }, index 8 result has resultSpan = 2", suggestedIndexes: [-1], spansByIndex: { 8: 2 }, expected: indexes([0, 8], [10, 1]), }, ]; for (let test of tests) { info("Running test: " + JSON.stringify(test)); await doSuggestedIndexTest(test); } }); /** * Sets up a provider with some results with suggested indexes and result spans, * performs a search, and then checks the results. * * @param {object} options * Options for the test. * @param {Array} options.suggestedIndexes * For each of the indexes in this array, a new result with the given * suggestedIndex will be returned by the provider. * @param {Array} options.expected * The indexes of the expected results within the array of results returned by * the provider. * @param {object} [options.spansByIndex] * Maps indexes within the array of results returned by the provider to result * spans to set on those results. * @param {number} [options.resultCount] * Aside from the results with suggested indexes, this is the number of * results that the provider will return. */ async function doSuggestedIndexTest({ suggestedIndexes, expected, spansByIndex = {}, resultCount = MAX_RESULTS, }) { // Make resultCount history results. let results = []; for (let i = 0; i < resultCount; i++) { results.push( new UrlbarResult( UrlbarUtils.RESULT_TYPE.URL, UrlbarUtils.RESULT_SOURCE.HISTORY, { url: "http://example.com/" + i, } ) ); } // Make the suggested-index results. for (let suggestedIndex of suggestedIndexes) { results.push( Object.assign( new UrlbarResult( UrlbarUtils.RESULT_TYPE.URL, UrlbarUtils.RESULT_SOURCE.HISTORY, { url: "http://example.com/si " + suggestedIndex, } ), { suggestedIndex } ) ); } // Set resultSpan on each result as indicated by spansByIndex. for (let [index, span] of Object.entries(spansByIndex)) { results[index].resultSpan = span; } // Set up the provider, etc. let provider = registerBasicTestProvider(results); let context = createContext(undefined, { providers: [provider.name] }); let controller = UrlbarTestUtils.newMockController(); // Finally, search and check the results. let expectedResults = expected.map(i => results[i]); await UrlbarProvidersManager.startQuery(context, controller); Assert.deepEqual(context.results, expectedResults); } /** * Helper that generates an array of indexes. Pass in [index, length] tuples. * Each tuple will produce the indexes starting from `index` to `index + length` * (not including the index at `index + length`). * * Examples: * * indexes([0, 5]) => [0, 1, 2, 3, 4] * indexes([0, 1], [4, 3], [8, 2]) => [0, 4, 5, 6, 8, 9] * * @param {Array} pairs * [index, length] tuples as described above. * @returns {Array} * An array of indexes. */ function indexes(...pairs) { return pairs.reduce((indexesArray, [start, len]) => { for (let i = start; i < start + len; i++) { indexesArray.push(i); } return indexesArray; }, []); }