test_suggestedIndex.js (19057B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 // Tests results with suggestedIndex and resultSpan. 5 6 "use strict"; 7 8 const MAX_RESULTS = 10; 9 10 add_task(async function suggestedIndex() { 11 let tests = [ 12 // no result spans > 1 13 { 14 desc: "{ suggestedIndex: 0 }", 15 suggestedIndexes: [0], 16 expected: indexes([10, 1], [0, 9]), 17 }, 18 { 19 desc: "{ suggestedIndex: 1 }", 20 suggestedIndexes: [1], 21 expected: indexes([0, 1], [10, 1], [1, 8]), 22 }, 23 { 24 desc: "{ suggestedIndex: -1 }", 25 suggestedIndexes: [-1], 26 expected: indexes([0, 9], [10, 1]), 27 }, 28 { 29 desc: "{ suggestedIndex: -2 }", 30 suggestedIndexes: [-2], 31 expected: indexes([0, 8], [10, 1], [8, 1]), 32 }, 33 { 34 desc: "{ suggestedIndex: 0 }, { suggestedIndex: -1 }", 35 suggestedIndexes: [0, -1], 36 expected: indexes([10, 1], [0, 8], [11, 1]), 37 }, 38 { 39 desc: "{ suggestedIndex: 1 }, { suggestedIndex: -1 }", 40 suggestedIndexes: [1, -1], 41 expected: indexes([0, 1], [10, 1], [1, 7], [11, 1]), 42 }, 43 { 44 desc: "{ suggestedIndex: 1 }, { suggestedIndex: -2 }", 45 suggestedIndexes: [1, -2], 46 expected: indexes([0, 1], [10, 1], [1, 6], [11, 1], [7, 1]), 47 }, 48 { 49 desc: "{ suggestedIndex: 0 }, resultCount < max", 50 suggestedIndexes: [0], 51 resultCount: 5, 52 expected: indexes([5, 1], [0, 5]), 53 }, 54 { 55 desc: "{ suggestedIndex: 1 }, resultCount < max", 56 suggestedIndexes: [1], 57 resultCount: 5, 58 expected: indexes([0, 1], [5, 1], [1, 4]), 59 }, 60 { 61 desc: "{ suggestedIndex: -1 }, resultCount < max", 62 suggestedIndexes: [-1], 63 resultCount: 5, 64 expected: indexes([0, 5], [5, 1]), 65 }, 66 { 67 desc: "{ suggestedIndex: -2 }, resultCount < max", 68 suggestedIndexes: [-2], 69 resultCount: 5, 70 expected: indexes([0, 4], [5, 1], [4, 1]), 71 }, 72 { 73 desc: "{ suggestedIndex: 0 }, { suggestedIndex: -1 }, resultCount < max", 74 suggestedIndexes: [0, -1], 75 resultCount: 5, 76 expected: indexes([5, 1], [0, 5], [6, 1]), 77 }, 78 { 79 desc: "{ suggestedIndex: 1 }, { suggestedIndex: -1 }, resultCount < max", 80 suggestedIndexes: [1, -1], 81 resultCount: 5, 82 expected: indexes([0, 1], [5, 1], [1, 4], [6, 1]), 83 }, 84 { 85 desc: "{ suggestedIndex: 0 }, { suggestedIndex: -2 }, resultCount < max", 86 suggestedIndexes: [0, -2], 87 resultCount: 5, 88 expected: indexes([5, 1], [0, 4], [6, 1], [4, 1]), 89 }, 90 { 91 desc: "{ suggestedIndex: 1 }, { suggestedIndex: -2 }, resultCount < max", 92 suggestedIndexes: [1, -2], 93 resultCount: 5, 94 expected: indexes([0, 1], [5, 1], [1, 3], [6, 1], [4, 1]), 95 }, 96 97 // one suggestedIndex with result span > 1 98 { 99 desc: "{ suggestedIndex: 0, resultSpan: 2 }", 100 suggestedIndexes: [0], 101 spansByIndex: { 10: 2 }, 102 expected: indexes([10, 1], [0, 8]), 103 }, 104 { 105 desc: "{ suggestedIndex: 0, resultSpan: 3 }", 106 suggestedIndexes: [0], 107 spansByIndex: { 10: 3 }, 108 expected: indexes([10, 1], [0, 7]), 109 }, 110 { 111 desc: "{ suggestedIndex: 1, resultSpan: 2 }", 112 suggestedIndexes: [1], 113 spansByIndex: { 10: 2 }, 114 expected: indexes([0, 1], [10, 1], [1, 7]), 115 }, 116 { 117 desc: "suggestedIndex: 1, resultSpan:: 3 }", 118 suggestedIndexes: [1], 119 spansByIndex: { 10: 3 }, 120 expected: indexes([0, 1], [10, 1], [1, 6]), 121 }, 122 { 123 desc: "{ suggestedIndex: -1, resultSpan 2 }", 124 suggestedIndexes: [-1], 125 spansByIndex: { 10: 2 }, 126 expected: indexes([0, 8], [10, 1]), 127 }, 128 { 129 desc: "{ suggestedIndex: -1, resultSpan: 3 }", 130 suggestedIndexes: [-1], 131 spansByIndex: { 10: 3 }, 132 expected: indexes([0, 7], [10, 1]), 133 }, 134 { 135 desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -1 }", 136 suggestedIndexes: [0, -1], 137 spansByIndex: { 10: 2 }, 138 expected: indexes([10, 1], [0, 7], [11, 1]), 139 }, 140 { 141 desc: "{ suggestedIndex: 0, resultSpan: 3 }, { suggestedIndex: -1 }", 142 suggestedIndexes: [0, -1], 143 spansByIndex: { 10: 3 }, 144 expected: indexes([10, 1], [0, 6], [11, 1]), 145 }, 146 { 147 desc: "{ suggestedIndex: 0 }, { suggestedIndex: -1, resultSpan: 2 }", 148 suggestedIndexes: [0, -1], 149 spansByIndex: { 11: 2 }, 150 expected: indexes([10, 1], [0, 7], [11, 1]), 151 }, 152 { 153 desc: "{ suggestedIndex: 0 }, { suggestedIndex: -1, resultSpan: 3 }", 154 suggestedIndexes: [0, -1], 155 spansByIndex: { 11: 3 }, 156 expected: indexes([10, 1], [0, 6], [11, 1]), 157 }, 158 { 159 desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -1 }", 160 suggestedIndexes: [1, -1], 161 spansByIndex: { 10: 2 }, 162 expected: indexes([0, 1], [10, 1], [1, 6], [11, 1]), 163 }, 164 { 165 desc: "{ suggestedIndex: 1, resultSpan: 3 }, { suggestedIndex: -1 }", 166 suggestedIndexes: [1, -1], 167 spansByIndex: { 10: 3 }, 168 expected: indexes([0, 1], [10, 1], [1, 5], [11, 1]), 169 }, 170 { 171 desc: "{ suggestedIndex: 1 }, { suggestedIndex: -1, resultSpan: 2 }", 172 suggestedIndexes: [1, -1], 173 spansByIndex: { 11: 2 }, 174 expected: indexes([0, 1], [10, 1], [1, 6], [11, 1]), 175 }, 176 { 177 desc: "{ suggestedIndex: 1 }, { suggestedIndex: -1, resultSpan: 3 }", 178 suggestedIndexes: [1, -1], 179 spansByIndex: { 11: 3 }, 180 expected: indexes([0, 1], [10, 1], [1, 5], [11, 1]), 181 }, 182 { 183 desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -2 }", 184 suggestedIndexes: [0, -2], 185 spansByIndex: { 10: 2 }, 186 expected: indexes([10, 1], [0, 6], [11, 1], [6, 1]), 187 }, 188 { 189 desc: "{ suggestedIndex: 0, resultSpan: 3 }, { suggestedIndex: -2 }", 190 suggestedIndexes: [0, -2], 191 spansByIndex: { 10: 3 }, 192 expected: indexes([10, 1], [0, 5], [11, 1], [5, 1]), 193 }, 194 { 195 desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -2 }", 196 suggestedIndexes: [1, -2], 197 spansByIndex: { 10: 2 }, 198 expected: indexes([0, 1], [10, 1], [1, 5], [11, 1], [6, 1]), 199 }, 200 { 201 desc: "{ suggestedIndex: 1, resultSpan: 3 }, { suggestedIndex: -2 }", 202 suggestedIndexes: [1, -2], 203 spansByIndex: { 10: 3 }, 204 expected: indexes([0, 1], [10, 1], [1, 4], [11, 1], [5, 1]), 205 }, 206 { 207 desc: "{ suggestedIndex: 0 }, { suggestedIndex: -2, resultSpan: 2 }", 208 suggestedIndexes: [0, -2], 209 spansByIndex: { 11: 2 }, 210 expected: indexes([10, 1], [0, 6], [11, 1], [6, 1]), 211 }, 212 { 213 desc: "{ suggestedIndex: 0 }, { suggestedIndex: -2, resultSpan: 3 }", 214 suggestedIndexes: [0, -2], 215 spansByIndex: { 11: 3 }, 216 expected: indexes([10, 1], [0, 5], [11, 1], [5, 1]), 217 }, 218 { 219 desc: "{ suggestedIndex: 1 }, { suggestedIndex: -2, resultSpan: 2 }", 220 suggestedIndexes: [1, -2], 221 spansByIndex: { 11: 2 }, 222 expected: indexes([0, 1], [10, 1], [1, 5], [11, 1], [6, 1]), 223 }, 224 { 225 desc: "{ suggestedIndex: 1 }, { suggestedIndex: -2, resultSpan: 3 }", 226 suggestedIndexes: [1, -2], 227 spansByIndex: { 11: 3 }, 228 expected: indexes([0, 1], [10, 1], [1, 4], [11, 1], [5, 1]), 229 }, 230 { 231 desc: "{ suggestedIndex: 0, resultSpan: 2 }, resultCount < max", 232 suggestedIndexes: [0], 233 spansByIndex: { 5: 2 }, 234 resultCount: 5, 235 expected: indexes([5, 1], [0, 5]), 236 }, 237 { 238 desc: "{ suggestedIndex: 1, resultSpan: 2 }, resultCount < max", 239 suggestedIndexes: [1], 240 spansByIndex: { 5: 2 }, 241 resultCount: 5, 242 expected: indexes([0, 1], [5, 1], [1, 4]), 243 }, 244 { 245 desc: "{ suggestedIndex: -1, resultSpan: 2 }, resultCount < max", 246 suggestedIndexes: [-1], 247 spansByIndex: { 5: 2 }, 248 resultCount: 5, 249 expected: indexes([0, 5], [5, 1]), 250 }, 251 { 252 desc: "{ suggestedIndex: -2, resultSpan: 2 }, resultCount < max", 253 suggestedIndexes: [-2], 254 spansByIndex: { 5: 2 }, 255 resultCount: 5, 256 expected: indexes([0, 4], [5, 1], [4, 1]), 257 }, 258 { 259 desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -1 }, resultCount < max", 260 suggestedIndexes: [0, -1], 261 spansByIndex: { 5: 2 }, 262 resultCount: 5, 263 expected: indexes([5, 1], [0, 5], [6, 1]), 264 }, 265 { 266 desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -1 }, resultCount < max", 267 suggestedIndexes: [1, -1], 268 spansByIndex: { 5: 2 }, 269 resultCount: 5, 270 expected: indexes([0, 1], [5, 1], [1, 4], [6, 1]), 271 }, 272 { 273 desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -2 }, resultCount < max", 274 suggestedIndexes: [0, -2], 275 spansByIndex: { 5: 2 }, 276 resultCount: 5, 277 expected: indexes([5, 1], [0, 4], [6, 1], [4, 1]), 278 }, 279 { 280 desc: "{ suggestedIndex: 0 }, { suggestedIndex: -1, resultSpan: 2 }, resultCount < max", 281 suggestedIndexes: [0, -1], 282 spansByIndex: { 6: 2 }, 283 resultCount: 5, 284 expected: indexes([5, 1], [0, 5], [6, 1]), 285 }, 286 { 287 desc: "{ suggestedIndex: 0 }, { suggestedIndex: -2, resultSpan: 2 }, resultCount < max", 288 suggestedIndexes: [0, -2], 289 spansByIndex: { 6: 2 }, 290 resultCount: 5, 291 expected: indexes([5, 1], [0, 4], [6, 1], [4, 1]), 292 }, 293 294 // two suggestedIndexes with result span > 1 295 { 296 desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 2 }", 297 suggestedIndexes: [0, -1], 298 spansByIndex: { 10: 2, 11: 2 }, 299 expected: indexes([10, 1], [0, 6], [11, 1]), 300 }, 301 { 302 desc: "{ suggestedIndex: 0, resultSpan: 3 }, { suggestedIndex: -1, resultSpan: 2 }", 303 suggestedIndexes: [0, -1], 304 spansByIndex: { 10: 3, 11: 2 }, 305 expected: indexes([10, 1], [0, 5], [11, 1]), 306 }, 307 { 308 desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 3 }", 309 suggestedIndexes: [0, -1], 310 spansByIndex: { 10: 2, 11: 3 }, 311 expected: indexes([10, 1], [0, 5], [11, 1]), 312 }, 313 { 314 desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 2 }", 315 suggestedIndexes: [1, -1], 316 spansByIndex: { 10: 2, 11: 2 }, 317 expected: indexes([0, 1], [10, 1], [1, 5], [11, 1]), 318 }, 319 { 320 desc: "{ suggestedIndex: 1, resultSpan: 3 }, { suggestedIndex: -1, resultSpan: 2 }", 321 suggestedIndexes: [1, -1], 322 spansByIndex: { 10: 3, 11: 2 }, 323 expected: indexes([0, 1], [10, 1], [1, 4], [11, 1]), 324 }, 325 { 326 desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 3 }", 327 suggestedIndexes: [1, -1], 328 spansByIndex: { 10: 2, 11: 3 }, 329 expected: indexes([0, 1], [10, 1], [1, 4], [11, 1]), 330 }, 331 { 332 desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -2, resultSpan: 2 }", 333 suggestedIndexes: [0, -2], 334 spansByIndex: { 10: 2, 11: 2 }, 335 expected: indexes([10, 1], [0, 5], [11, 1], [5, 1]), 336 }, 337 { 338 desc: "{ suggestedIndex: 0, resultSpan: 3 }, { suggestedIndex: -2, resultSpan: 2 }", 339 suggestedIndexes: [0, -2], 340 spansByIndex: { 10: 3, 11: 2 }, 341 expected: indexes([10, 1], [0, 4], [11, 1], [4, 1]), 342 }, 343 { 344 desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -2, resultSpan: 3 }", 345 suggestedIndexes: [0, -2], 346 spansByIndex: { 10: 2, 11: 3 }, 347 expected: indexes([10, 1], [0, 4], [11, 1], [4, 1]), 348 }, 349 { 350 desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -2, resultSpan: 2 }", 351 suggestedIndexes: [1, -2], 352 spansByIndex: { 10: 2, 11: 2 }, 353 expected: indexes([0, 1], [10, 1], [1, 4], [11, 1], [5, 1]), 354 }, 355 { 356 desc: "{ suggestedIndex: 1, resultSpan: 3 }, { suggestedIndex: -2, resultSpan: 2 }", 357 suggestedIndexes: [1, -2], 358 spansByIndex: { 10: 3, 11: 2 }, 359 expected: indexes([0, 1], [10, 1], [1, 3], [11, 1], [4, 1]), 360 }, 361 { 362 desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -2, resultSpan: 3 }", 363 suggestedIndexes: [1, -2], 364 spansByIndex: { 10: 2, 11: 3 }, 365 expected: indexes([0, 1], [10, 1], [1, 3], [11, 1], [4, 1]), 366 }, 367 { 368 desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 2 }, resultCount < max", 369 suggestedIndexes: [0, -1], 370 spansByIndex: { 5: 2, 6: 2 }, 371 resultCount: 5, 372 expected: indexes([5, 1], [0, 5], [6, 1]), 373 }, 374 { 375 desc: "{ suggestedIndex: 1, resultSpan: 2 }, { suggestedIndex: -1, resultSpan: 2 }, resultCount < max", 376 suggestedIndexes: [1, -1], 377 spansByIndex: { 5: 2, 6: 2 }, 378 resultCount: 5, 379 expected: indexes([0, 1], [5, 1], [1, 4], [6, 1]), 380 }, 381 { 382 desc: "{ suggestedIndex: 0, resultSpan: 2 }, { suggestedIndex: -2, resultSpan: 2 }, resultCount < max", 383 suggestedIndexes: [0, -2], 384 spansByIndex: { 5: 2, 6: 2 }, 385 resultCount: 5, 386 expected: indexes([5, 1], [0, 4], [6, 1], [4, 1]), 387 }, 388 389 // one suggestedIndex plus other result with resultSpan > 1 390 { 391 desc: "{ suggestedIndex: 0 }, { resultSpan: 2 } A", 392 suggestedIndexes: [0], 393 spansByIndex: { 0: 2 }, 394 expected: indexes([10, 1], [0, 8]), 395 }, 396 { 397 desc: "{ suggestedIndex: 0 }, { resultSpan: 2 } B", 398 suggestedIndexes: [0], 399 spansByIndex: { 8: 2 }, 400 expected: indexes([10, 1], [0, 8]), 401 }, 402 { 403 desc: "{ suggestedIndex: 0 }, { resultSpan: 2 } C", 404 suggestedIndexes: [0], 405 spansByIndex: { 9: 2 }, 406 expected: indexes([10, 1], [0, 9]), 407 }, 408 { 409 desc: "{ suggestedIndex: 1 }, { resultSpan: 2 } A", 410 suggestedIndexes: [1], 411 spansByIndex: { 0: 2 }, 412 expected: indexes([0, 1], [10, 1], [1, 7]), 413 }, 414 { 415 desc: "{ suggestedIndex: 1 }, { resultSpan: 2 } B", 416 suggestedIndexes: [1], 417 spansByIndex: { 8: 2 }, 418 expected: indexes([0, 1], [10, 1], [1, 7]), 419 }, 420 { 421 desc: "{ suggestedIndex: -1 }, { resultSpan: 2 }", 422 suggestedIndexes: [-1], 423 spansByIndex: { 0: 2 }, 424 expected: indexes([0, 8], [10, 1]), 425 }, 426 { 427 desc: "{ suggestedIndex: -2 }, { resultSpan: 2 }", 428 suggestedIndexes: [-2], 429 spansByIndex: { 0: 2 }, 430 expected: indexes([0, 7], [10, 1], [7, 1]), 431 }, 432 433 // miscellaneous 434 { 435 desc: "no suggestedIndex, last result has resultSpan = 2", 436 suggestedIndexes: [], 437 spansByIndex: { 9: 2 }, 438 expected: indexes([0, 9]), 439 }, 440 { 441 desc: "{ suggestedIndex: -1 }, last result has resultSpan = 2", 442 suggestedIndexes: [-1], 443 spansByIndex: { 9: 2 }, 444 expected: indexes([0, 9], [10, 1]), 445 }, 446 { 447 desc: "no suggestedIndex, index 8 result has resultSpan = 2", 448 suggestedIndexes: [], 449 spansByIndex: { 8: 2 }, 450 expected: indexes([0, 9]), 451 }, 452 { 453 desc: "{ suggestedIndex: -1 }, index 8 result has resultSpan = 2", 454 suggestedIndexes: [-1], 455 spansByIndex: { 8: 2 }, 456 expected: indexes([0, 8], [10, 1]), 457 }, 458 { 459 desc: "{ suggestedIndex: 0, maxRichResults: 0 }", 460 maxRichResults: 0, 461 suggestedIndexes: [0], 462 expected: [], 463 }, 464 { 465 desc: "{ suggestedIndex: 1, maxRichResults: 0 }", 466 maxRichResults: 0, 467 suggestedIndexes: [1], 468 expected: [], 469 }, 470 { 471 desc: "{ suggestedIndex: -1, maxRichResults: 0 }", 472 maxRichResults: 0, 473 suggestedIndexes: [-1], 474 expected: [], 475 }, 476 { 477 desc: "{ suggestedIndex: 0, maxRichResults: 1 }", 478 maxRichResults: 1, 479 suggestedIndexes: [0], 480 expected: indexes([10, 1]), 481 }, 482 { 483 desc: "{ suggestedIndex: 1, maxRichResults: 1 }", 484 maxRichResults: 1, 485 suggestedIndexes: [1], 486 expected: indexes([10, 1]), 487 }, 488 { 489 desc: "{ suggestedIndex: -1, maxRichResults: 1 }", 490 maxRichResults: 1, 491 suggestedIndexes: [-1], 492 expected: indexes([10, 1]), 493 }, 494 ]; 495 496 for (let test of tests) { 497 info("Running test: " + JSON.stringify(test)); 498 await doSuggestedIndexTest(test); 499 } 500 }); 501 502 /** 503 * Sets up a provider with some results with suggested indexes and result spans, 504 * performs a search, and then checks the results. 505 * 506 * @param {object} options 507 * Options for the test. 508 * @param {Array} options.suggestedIndexes 509 * For each of the indexes in this array, a new result with the given 510 * suggestedIndex will be returned by the provider. 511 * @param {Array} options.expected 512 * The indexes of the expected results within the array of results returned by 513 * the provider. 514 * @param {object} [options.spansByIndex] 515 * Maps indexes within the array of results returned by the provider to result 516 * spans to set on those results. 517 * @param {number} [options.resultCount] 518 * Aside from the results with suggested indexes, this is the number of 519 * results that the provider will return. 520 * @param {number} [options.maxRichResults] 521 * The `maxRichResults` pref will be set to this value. 522 */ 523 async function doSuggestedIndexTest({ 524 suggestedIndexes, 525 expected, 526 spansByIndex = {}, 527 resultCount = MAX_RESULTS, 528 maxRichResults = MAX_RESULTS, 529 }) { 530 // Make resultCount history results. 531 let results = []; 532 for (let i = 0; i < resultCount; i++) { 533 results.push( 534 new UrlbarResult({ 535 type: UrlbarUtils.RESULT_TYPE.URL, 536 source: UrlbarUtils.RESULT_SOURCE.HISTORY, 537 resultSpan: spansByIndex[results.length], 538 payload: { 539 url: "http://example.com/" + i, 540 }, 541 }) 542 ); 543 } 544 545 // Make the suggested-index results. 546 for (let suggestedIndex of suggestedIndexes) { 547 results.push( 548 new UrlbarResult({ 549 type: UrlbarUtils.RESULT_TYPE.URL, 550 source: UrlbarUtils.RESULT_SOURCE.HISTORY, 551 suggestedIndex, 552 resultSpan: spansByIndex[results.length], 553 payload: { 554 url: "http://example.com/si " + suggestedIndex, 555 }, 556 }) 557 ); 558 } 559 560 // Set up the provider, etc. 561 UrlbarPrefs.set("maxRichResults", maxRichResults); 562 let provider = registerBasicTestProvider(results); 563 let context = createContext(undefined, { providers: [provider.name] }); 564 let controller = UrlbarTestUtils.newMockController(); 565 566 // Finally, search and check the results. 567 let expectedResults = expected.map(i => results[i]); 568 await UrlbarProvidersManager.startQuery(context, controller); 569 Assert.deepEqual(context.results, expectedResults); 570 } 571 572 /** 573 * Helper that generates an array of indexes. Pass in [index, length] tuples. 574 * Each tuple will produce the indexes starting from `index` to `index + length` 575 * (not including the index at `index + length`). 576 * 577 * Examples: 578 * 579 * indexes([0, 5]) => [0, 1, 2, 3, 4] 580 * indexes([0, 1], [4, 3], [8, 2]) => [0, 4, 5, 6, 8, 9] 581 * 582 * @param {Array} pairs 583 * [index, length] tuples as described above. 584 * @returns {Array} 585 * An array of indexes. 586 */ 587 function indexes(...pairs) { 588 return pairs.reduce((indexesArray, [start, len]) => { 589 for (let i = start; i < start + len; i++) { 590 indexesArray.push(i); 591 } 592 return indexesArray; 593 }, []); 594 }