Path: blob/main/src/vs/base/test/common/arrays.test.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4import assert from 'assert';5import * as arrays from '../../common/arrays.js';6import * as arraysFind from '../../common/arraysFind.js';7import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js';89suite('Arrays', () => {1011ensureNoDisposablesAreLeakedInTestSuite();1213test('removeFastWithoutKeepingOrder', () => {14const array = [1, 4, 5, 7, 55, 59, 60, 61, 64, 69];15arrays.removeFastWithoutKeepingOrder(array, 1);16assert.deepStrictEqual(array, [1, 69, 5, 7, 55, 59, 60, 61, 64]);1718arrays.removeFastWithoutKeepingOrder(array, 0);19assert.deepStrictEqual(array, [64, 69, 5, 7, 55, 59, 60, 61]);2021arrays.removeFastWithoutKeepingOrder(array, 7);22assert.deepStrictEqual(array, [64, 69, 5, 7, 55, 59, 60]);23});2425test('findFirst', () => {26const array = [1, 4, 5, 7, 55, 59, 60, 61, 64, 69];2728let idx = arraysFind.findFirstIdxMonotonousOrArrLen(array, e => e >= 0);29assert.strictEqual(array[idx], 1);3031idx = arraysFind.findFirstIdxMonotonousOrArrLen(array, e => e > 1);32assert.strictEqual(array[idx], 4);3334idx = arraysFind.findFirstIdxMonotonousOrArrLen(array, e => e >= 8);35assert.strictEqual(array[idx], 55);3637idx = arraysFind.findFirstIdxMonotonousOrArrLen(array, e => e >= 61);38assert.strictEqual(array[idx], 61);3940idx = arraysFind.findFirstIdxMonotonousOrArrLen(array, e => e >= 69);41assert.strictEqual(array[idx], 69);4243idx = arraysFind.findFirstIdxMonotonousOrArrLen(array, e => e >= 70);44assert.strictEqual(idx, array.length);4546idx = arraysFind.findFirstIdxMonotonousOrArrLen([], e => e >= 0);47assert.strictEqual(array[idx], 1);48});4950test('quickSelect', () => {5152function assertMedian(expexted: number, data: number[], nth: number = Math.floor(data.length / 2)) {53const compare = (a: number, b: number) => a - b;54const actual1 = arrays.quickSelect(nth, data, compare);55assert.strictEqual(actual1, expexted);5657const actual2 = data.slice().sort(compare)[nth];58assert.strictEqual(actual2, expexted);59}6061assertMedian(5, [9, 1, 0, 2, 3, 4, 6, 8, 7, 10, 5]);62assertMedian(8, [9, 1, 0, 2, 3, 4, 6, 8, 7, 10, 5], 8);63assertMedian(8, [13, 4, 8]);64assertMedian(4, [13, 4, 8, 4, 4]);65assertMedian(13, [13, 4, 8], 2);66});6768test('sortedDiff', () => {69function compare(a: number, b: number): number {70return a - b;71}7273let d = arrays.sortedDiff([1, 2, 4], [], compare);74assert.deepStrictEqual(d, [75{ start: 0, deleteCount: 3, toInsert: [] }76]);7778d = arrays.sortedDiff([], [1, 2, 4], compare);79assert.deepStrictEqual(d, [80{ start: 0, deleteCount: 0, toInsert: [1, 2, 4] }81]);8283d = arrays.sortedDiff([1, 2, 4], [1, 2, 4], compare);84assert.deepStrictEqual(d, []);8586d = arrays.sortedDiff([1, 2, 4], [2, 3, 4, 5], compare);87assert.deepStrictEqual(d, [88{ start: 0, deleteCount: 1, toInsert: [] },89{ start: 2, deleteCount: 0, toInsert: [3] },90{ start: 3, deleteCount: 0, toInsert: [5] },91]);9293d = arrays.sortedDiff([2, 3, 4, 5], [1, 2, 4], compare);94assert.deepStrictEqual(d, [95{ start: 0, deleteCount: 0, toInsert: [1] },96{ start: 1, deleteCount: 1, toInsert: [] },97{ start: 3, deleteCount: 1, toInsert: [] },98]);99100d = arrays.sortedDiff([1, 3, 5, 7], [5, 9, 11], compare);101assert.deepStrictEqual(d, [102{ start: 0, deleteCount: 2, toInsert: [] },103{ start: 3, deleteCount: 1, toInsert: [9, 11] }104]);105106d = arrays.sortedDiff([1, 3, 7], [5, 9, 11], compare);107assert.deepStrictEqual(d, [108{ start: 0, deleteCount: 3, toInsert: [5, 9, 11] }109]);110});111112test('delta sorted arrays', function () {113function compare(a: number, b: number): number {114return a - b;115}116117let d = arrays.delta([1, 2, 4], [], compare);118assert.deepStrictEqual(d.removed, [1, 2, 4]);119assert.deepStrictEqual(d.added, []);120121d = arrays.delta([], [1, 2, 4], compare);122assert.deepStrictEqual(d.removed, []);123assert.deepStrictEqual(d.added, [1, 2, 4]);124125d = arrays.delta([1, 2, 4], [1, 2, 4], compare);126assert.deepStrictEqual(d.removed, []);127assert.deepStrictEqual(d.added, []);128129d = arrays.delta([1, 2, 4], [2, 3, 4, 5], compare);130assert.deepStrictEqual(d.removed, [1]);131assert.deepStrictEqual(d.added, [3, 5]);132133d = arrays.delta([2, 3, 4, 5], [1, 2, 4], compare);134assert.deepStrictEqual(d.removed, [3, 5]);135assert.deepStrictEqual(d.added, [1]);136137d = arrays.delta([1, 3, 5, 7], [5, 9, 11], compare);138assert.deepStrictEqual(d.removed, [1, 3, 7]);139assert.deepStrictEqual(d.added, [9, 11]);140141d = arrays.delta([1, 3, 7], [5, 9, 11], compare);142assert.deepStrictEqual(d.removed, [1, 3, 7]);143assert.deepStrictEqual(d.added, [5, 9, 11]);144});145146test('binarySearch', () => {147function compare(a: number, b: number): number {148return a - b;149}150const array = [1, 4, 5, 7, 55, 59, 60, 61, 64, 69];151152assert.strictEqual(arrays.binarySearch(array, 1, compare), 0);153assert.strictEqual(arrays.binarySearch(array, 5, compare), 2);154155// insertion point156assert.strictEqual(arrays.binarySearch(array, 0, compare), ~0);157assert.strictEqual(arrays.binarySearch(array, 6, compare), ~3);158assert.strictEqual(arrays.binarySearch(array, 70, compare), ~10);159});160161test('binarySearch2', () => {162function compareTo(key: number) {163return (index: number) => {164return array[index] - key;165};166}167const array = [1, 4, 5, 7, 55, 59, 60, 61, 64, 69];168169assert.strictEqual(arrays.binarySearch2(10, compareTo(1)), 0);170assert.strictEqual(arrays.binarySearch2(10, compareTo(5)), 2);171172// insertion point173assert.strictEqual(arrays.binarySearch2(10, compareTo(0)), ~0);174assert.strictEqual(arrays.binarySearch2(10, compareTo(6)), ~3);175assert.strictEqual(arrays.binarySearch2(10, compareTo(70)), ~10);176assert.strictEqual(arrays.binarySearch2(2, compareTo(5)), ~2);177});178179test('distinct', () => {180function compare(a: string): string {181return a;182}183184assert.deepStrictEqual(arrays.distinct(['32', '4', '5'], compare), ['32', '4', '5']);185assert.deepStrictEqual(arrays.distinct(['32', '4', '5', '4'], compare), ['32', '4', '5']);186assert.deepStrictEqual(arrays.distinct(['32', 'constructor', '5', '1'], compare), ['32', 'constructor', '5', '1']);187assert.deepStrictEqual(arrays.distinct(['32', 'constructor', 'proto', 'proto', 'constructor'], compare), ['32', 'constructor', 'proto']);188assert.deepStrictEqual(arrays.distinct(['32', '4', '5', '32', '4', '5', '32', '4', '5', '5'], compare), ['32', '4', '5']);189});190191test('top', () => {192const cmp = (a: number, b: number) => {193assert.strictEqual(typeof a, 'number', 'typeof a');194assert.strictEqual(typeof b, 'number', 'typeof b');195return a - b;196};197198assert.deepStrictEqual(arrays.top([], cmp, 1), []);199assert.deepStrictEqual(arrays.top([1], cmp, 0), []);200assert.deepStrictEqual(arrays.top([1, 2], cmp, 1), [1]);201assert.deepStrictEqual(arrays.top([2, 1], cmp, 1), [1]);202assert.deepStrictEqual(arrays.top([1, 3, 2], cmp, 2), [1, 2]);203assert.deepStrictEqual(arrays.top([3, 2, 1], cmp, 3), [1, 2, 3]);204assert.deepStrictEqual(arrays.top([4, 6, 2, 7, 8, 3, 5, 1], cmp, 3), [1, 2, 3]);205});206207test('topAsync', async () => {208const cmp = (a: number, b: number) => {209assert.strictEqual(typeof a, 'number', 'typeof a');210assert.strictEqual(typeof b, 'number', 'typeof b');211return a - b;212};213214await testTopAsync(cmp, 1);215return testTopAsync(cmp, 2);216});217218async function testTopAsync(cmp: any, m: number) {219{220const result = await arrays.topAsync([], cmp, 1, m);221assert.deepStrictEqual(result, []);222}223{224const result = await arrays.topAsync([1], cmp, 0, m);225assert.deepStrictEqual(result, []);226}227{228const result = await arrays.topAsync([1, 2], cmp, 1, m);229assert.deepStrictEqual(result, [1]);230}231{232const result = await arrays.topAsync([2, 1], cmp, 1, m);233assert.deepStrictEqual(result, [1]);234}235{236const result = await arrays.topAsync([1, 3, 2], cmp, 2, m);237assert.deepStrictEqual(result, [1, 2]);238}239{240const result = await arrays.topAsync([3, 2, 1], cmp, 3, m);241assert.deepStrictEqual(result, [1, 2, 3]);242}243{244const result = await arrays.topAsync([4, 6, 2, 7, 8, 3, 5, 1], cmp, 3, m);245assert.deepStrictEqual(result, [1, 2, 3]);246}247}248249test('coalesce', () => {250const a: Array<number | null> = arrays.coalesce([null, 1, null, 2, 3]);251assert.strictEqual(a.length, 3);252assert.strictEqual(a[0], 1);253assert.strictEqual(a[1], 2);254assert.strictEqual(a[2], 3);255256arrays.coalesce([null, 1, null, undefined, undefined, 2, 3]);257assert.strictEqual(a.length, 3);258assert.strictEqual(a[0], 1);259assert.strictEqual(a[1], 2);260assert.strictEqual(a[2], 3);261262let b: number[] = [];263b[10] = 1;264b[20] = 2;265b[30] = 3;266b = arrays.coalesce(b);267assert.strictEqual(b.length, 3);268assert.strictEqual(b[0], 1);269assert.strictEqual(b[1], 2);270assert.strictEqual(b[2], 3);271272let sparse: number[] = [];273sparse[0] = 1;274sparse[1] = 1;275sparse[17] = 1;276sparse[1000] = 1;277sparse[1001] = 1;278279assert.strictEqual(sparse.length, 1002);280281sparse = arrays.coalesce(sparse);282assert.strictEqual(sparse.length, 5);283});284285test('coalesce - inplace', function () {286let a: Array<number | null> = [null, 1, null, 2, 3];287arrays.coalesceInPlace(a);288assert.strictEqual(a.length, 3);289assert.strictEqual(a[0], 1);290assert.strictEqual(a[1], 2);291assert.strictEqual(a[2], 3);292293a = [null, 1, null, undefined!, undefined!, 2, 3];294arrays.coalesceInPlace(a);295assert.strictEqual(a.length, 3);296assert.strictEqual(a[0], 1);297assert.strictEqual(a[1], 2);298assert.strictEqual(a[2], 3);299300const b: number[] = [];301b[10] = 1;302b[20] = 2;303b[30] = 3;304arrays.coalesceInPlace(b);305assert.strictEqual(b.length, 3);306assert.strictEqual(b[0], 1);307assert.strictEqual(b[1], 2);308assert.strictEqual(b[2], 3);309310const sparse: number[] = [];311sparse[0] = 1;312sparse[1] = 1;313sparse[17] = 1;314sparse[1000] = 1;315sparse[1001] = 1;316317assert.strictEqual(sparse.length, 1002);318319arrays.coalesceInPlace(sparse);320assert.strictEqual(sparse.length, 5);321});322323test('insert, remove', function () {324const array: string[] = [];325const remove = arrays.insert(array, 'foo');326assert.strictEqual(array[0], 'foo');327328remove();329assert.strictEqual(array.length, 0);330});331332test('splice', function () {333// negative start index, absolute value greater than the length334let array = [1, 2, 3, 4, 5];335arrays.splice(array, -6, 3, [6, 7]);336assert.strictEqual(array.length, 4);337assert.strictEqual(array[0], 6);338assert.strictEqual(array[1], 7);339assert.strictEqual(array[2], 4);340assert.strictEqual(array[3], 5);341342// negative start index, absolute value less than the length343array = [1, 2, 3, 4, 5];344arrays.splice(array, -3, 3, [6, 7]);345assert.strictEqual(array.length, 4);346assert.strictEqual(array[0], 1);347assert.strictEqual(array[1], 2);348assert.strictEqual(array[2], 6);349assert.strictEqual(array[3], 7);350351// Start index less than the length352array = [1, 2, 3, 4, 5];353arrays.splice(array, 3, 3, [6, 7]);354assert.strictEqual(array.length, 5);355assert.strictEqual(array[0], 1);356assert.strictEqual(array[1], 2);357assert.strictEqual(array[2], 3);358assert.strictEqual(array[3], 6);359assert.strictEqual(array[4], 7);360361// Start index greater than the length362array = [1, 2, 3, 4, 5];363arrays.splice(array, 6, 3, [6, 7]);364assert.strictEqual(array.length, 7);365assert.strictEqual(array[0], 1);366assert.strictEqual(array[1], 2);367assert.strictEqual(array[2], 3);368assert.strictEqual(array[3], 4);369assert.strictEqual(array[4], 5);370assert.strictEqual(array[5], 6);371assert.strictEqual(array[6], 7);372});373374test('findMaxBy', () => {375const array = [{ v: 3 }, { v: 5 }, { v: 2 }, { v: 2 }, { v: 2 }, { v: 5 }];376377assert.strictEqual(378array.indexOf(arraysFind.findFirstMax(array, arrays.compareBy(v => v.v, arrays.numberComparator))!),3791380);381});382383test('findLastMaxBy', () => {384const array = [{ v: 3 }, { v: 5 }, { v: 2 }, { v: 2 }, { v: 2 }, { v: 5 }];385386assert.strictEqual(387array.indexOf(arraysFind.findLastMax(array, arrays.compareBy(v => v.v, arrays.numberComparator))!),3885389);390});391392test('findMinBy', () => {393const array = [{ v: 3 }, { v: 5 }, { v: 2 }, { v: 2 }, { v: 2 }, { v: 5 }];394395assert.strictEqual(396array.indexOf(arraysFind.findFirstMin(array, arrays.compareBy(v => v.v, arrays.numberComparator))!),3972398);399});400401402403suite('ArrayQueue', () => {404suite('takeWhile/takeFromEndWhile', () => {405test('TakeWhile 1', () => {406const queue1 = new arrays.ArrayQueue([9, 8, 1, 7, 6]);407assert.deepStrictEqual(queue1.takeWhile(x => x > 5), [9, 8]);408assert.deepStrictEqual(queue1.takeWhile(x => x < 7), [1]);409assert.deepStrictEqual(queue1.takeWhile(x => true), [7, 6]);410});411412test('TakeFromEndWhile 1', () => {413const queue1 = new arrays.ArrayQueue([9, 8, 1, 7, 6]);414assert.deepStrictEqual(queue1.takeFromEndWhile(x => x > 5), [7, 6]);415assert.deepStrictEqual(queue1.takeFromEndWhile(x => x < 2), [1]);416assert.deepStrictEqual(queue1.takeFromEndWhile(x => true), [9, 8]);417});418});419420suite('takeWhile/takeFromEndWhile monotonous', () => {421function testMonotonous(array: number[], predicate: (a: number) => boolean) {422function normalize(arr: number[]): number[] | null {423if (arr.length === 0) {424return null;425}426return arr;427}428429const negatedPredicate = (a: number) => !predicate(a);430431{432const queue1 = new arrays.ArrayQueue(array);433assert.deepStrictEqual(queue1.takeWhile(predicate), normalize(array.filter(predicate)));434assert.deepStrictEqual(queue1.length, array.length - array.filter(predicate).length);435assert.deepStrictEqual(queue1.takeWhile(() => true), normalize(array.filter(negatedPredicate)));436}437{438const queue3 = new arrays.ArrayQueue(array);439assert.deepStrictEqual(queue3.takeFromEndWhile(negatedPredicate), normalize(array.filter(negatedPredicate)));440assert.deepStrictEqual(queue3.length, array.length - array.filter(negatedPredicate).length);441assert.deepStrictEqual(queue3.takeFromEndWhile(() => true), normalize(array.filter(predicate)));442}443}444445const array = [1, 1, 1, 2, 5, 5, 7, 8, 8];446447test('TakeWhile 1', () => testMonotonous(array, value => value <= 1));448test('TakeWhile 2', () => testMonotonous(array, value => value < 5));449test('TakeWhile 3', () => testMonotonous(array, value => value <= 5));450test('TakeWhile 4', () => testMonotonous(array, value => true));451test('TakeWhile 5', () => testMonotonous(array, value => false));452453const array2 = [1, 1, 1, 2, 5, 5, 7, 8, 8, 9, 9, 9, 9, 10, 10];454455test('TakeWhile 6', () => testMonotonous(array2, value => value < 10));456test('TakeWhile 7', () => testMonotonous(array2, value => value < 7));457test('TakeWhile 8', () => testMonotonous(array2, value => value < 5));458459test('TakeWhile Empty', () => testMonotonous([], value => value <= 5));460});461});462});463464465