mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-13 01:54:52 +08:00
Make sure that unit test files use the same base name as the file that they are testing. Also consolidate tests appropriately when they are in the wrong file. Fixed: b:325892225 Bug: b:323795674 Change-Id: I1197a44eb45544c8f6fccf330b7afe6b8e20bd21 Doc: http://go/chrome-devtools:move-unit-tests-design Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5307615 Reviewed-by: Simon Zünd <szuend@chromium.org> Commit-Queue: Benedikt Meurer <bmeurer@chromium.org> Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
271 lines
9.5 KiB
TypeScript
271 lines
9.5 KiB
TypeScript
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
export const removeElement = <T>(array: T[], element: T, firstOnly?: boolean): boolean => {
|
|
let index = array.indexOf(element);
|
|
if (index === -1) {
|
|
return false;
|
|
}
|
|
if (firstOnly) {
|
|
array.splice(index, 1);
|
|
return true;
|
|
}
|
|
for (let i = index + 1, n = array.length; i < n; ++i) {
|
|
if (array[i] !== element) {
|
|
array[index++] = array[i];
|
|
}
|
|
}
|
|
array.length = index;
|
|
return true;
|
|
};
|
|
|
|
type NumberComparator = (a: number, b: number) => number;
|
|
|
|
function swap(array: number[], i1: number, i2: number): void {
|
|
const temp = array[i1];
|
|
array[i1] = array[i2];
|
|
array[i2] = temp;
|
|
}
|
|
|
|
function partition(
|
|
array: number[], comparator: NumberComparator, left: number, right: number, pivotIndex: number): number {
|
|
const pivotValue = array[pivotIndex];
|
|
swap(array, right, pivotIndex);
|
|
let storeIndex = left;
|
|
for (let i = left; i < right; ++i) {
|
|
if (comparator(array[i], pivotValue) < 0) {
|
|
swap(array, storeIndex, i);
|
|
++storeIndex;
|
|
}
|
|
}
|
|
swap(array, right, storeIndex);
|
|
return storeIndex;
|
|
}
|
|
|
|
function quickSortRange(
|
|
array: number[], comparator: NumberComparator, left: number, right: number, sortWindowLeft: number,
|
|
sortWindowRight: number): void {
|
|
if (right <= left) {
|
|
return;
|
|
}
|
|
const pivotIndex = Math.floor(Math.random() * (right - left)) + left;
|
|
const pivotNewIndex = partition(array, comparator, left, right, pivotIndex);
|
|
if (sortWindowLeft < pivotNewIndex) {
|
|
quickSortRange(array, comparator, left, pivotNewIndex - 1, sortWindowLeft, sortWindowRight);
|
|
}
|
|
if (pivotNewIndex < sortWindowRight) {
|
|
quickSortRange(array, comparator, pivotNewIndex + 1, right, sortWindowLeft, sortWindowRight);
|
|
}
|
|
}
|
|
|
|
export function sortRange(
|
|
array: number[], comparator: NumberComparator, leftBound: number, rightBound: number, sortWindowLeft: number,
|
|
sortWindowRight: number): number[] {
|
|
if (leftBound === 0 && rightBound === (array.length - 1) && sortWindowLeft === 0 && sortWindowRight >= rightBound) {
|
|
array.sort(comparator);
|
|
} else {
|
|
quickSortRange(array, comparator, leftBound, rightBound, sortWindowLeft, sortWindowRight);
|
|
}
|
|
return array;
|
|
}
|
|
export const binaryIndexOf = <T, S>(array: T[], value: S, comparator: (a: S, b: T) => number): number => {
|
|
const index = lowerBound(array, value, comparator);
|
|
return index < array.length && comparator(value, array[index]) === 0 ? index : -1;
|
|
};
|
|
|
|
function mergeOrIntersect<T>(
|
|
array1: T[], array2: T[], comparator: (a: T, b: T) => number, mergeNotIntersect: boolean): T[] {
|
|
const result = [];
|
|
let i = 0;
|
|
let j = 0;
|
|
while (i < array1.length && j < array2.length) {
|
|
const compareValue = comparator(array1[i], array2[j]);
|
|
if (mergeNotIntersect || !compareValue) {
|
|
result.push(compareValue <= 0 ? array1[i] : array2[j]);
|
|
}
|
|
if (compareValue <= 0) {
|
|
i++;
|
|
}
|
|
if (compareValue >= 0) {
|
|
j++;
|
|
}
|
|
}
|
|
if (mergeNotIntersect) {
|
|
while (i < array1.length) {
|
|
result.push(array1[i++]);
|
|
}
|
|
while (j < array2.length) {
|
|
result.push(array2[j++]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export const intersectOrdered = <T>(array1: T[], array2: T[], comparator: (a: T, b: T) => number): T[] => {
|
|
return mergeOrIntersect(array1, array2, comparator, false);
|
|
};
|
|
|
|
export const mergeOrdered = <T>(array1: T[], array2: T[], comparator: (a: T, b: T) => number): T[] => {
|
|
return mergeOrIntersect(array1, array2, comparator, true);
|
|
};
|
|
|
|
export const DEFAULT_COMPARATOR = (a: string|number, b: string|number): -1|0|1 => {
|
|
return a < b ? -1 : (a > b ? 1 : 0);
|
|
};
|
|
|
|
/**
|
|
* Returns the index of the element closest to the needle that is equal to or
|
|
* greater than it. Assumes that the provided array is sorted.
|
|
*
|
|
* If no element is found, the right bound is returned.
|
|
*
|
|
* Uses the provided comparator function to determine if two items are equal or
|
|
* if one is greater than the other. If you are working with strings or
|
|
* numbers, you can use ArrayUtilities.DEFAULT_COMPARATOR. Otherwise, you
|
|
* should define one that takes the needle element and an element from the
|
|
* array and returns a positive or negative number to indicate which is greater
|
|
* than the other.
|
|
*
|
|
* When specified, |left| (inclusive) and |right| (exclusive) indices
|
|
* define the search window.
|
|
*/
|
|
export function lowerBound<T>(
|
|
array: Uint32Array|Int32Array, needle: T, comparator: (needle: T, b: number) => number, left?: number,
|
|
right?: number): number;
|
|
export function lowerBound<S, T>(
|
|
array: S[], needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number;
|
|
export function lowerBound<S, T>(
|
|
array: readonly S[], needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number;
|
|
export function lowerBound<S, T, A extends S[]>(
|
|
array: A, needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number {
|
|
let l = left || 0;
|
|
let r = right !== undefined ? right : array.length;
|
|
while (l < r) {
|
|
const m = (l + r) >> 1;
|
|
if (comparator(needle, array[m]) > 0) {
|
|
l = m + 1;
|
|
} else {
|
|
r = m;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the element closest to the needle that is greater than
|
|
* it. Assumes that the provided array is sorted.
|
|
*
|
|
* If no element is found, the right bound is returned.
|
|
*
|
|
* Uses the provided comparator function to determine if two items are equal or
|
|
* if one is greater than the other. If you are working with strings or
|
|
* numbers, you can use ArrayUtilities.DEFAULT_COMPARATOR. Otherwise, you
|
|
* should define one that takes the needle element and an element from the
|
|
* array and returns a positive or negative number to indicate which is greater
|
|
* than the other.
|
|
*
|
|
* When specified, |left| (inclusive) and |right| (exclusive) indices
|
|
* define the search window.
|
|
*/
|
|
export function upperBound<T>(
|
|
array: Uint32Array, needle: T, comparator: (needle: T, b: number) => number, left?: number, right?: number): number;
|
|
export function upperBound<S, T>(
|
|
array: S[], needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number;
|
|
export function upperBound<S, T, A extends S[]>(
|
|
array: A, needle: T, comparator: (needle: T, b: S) => number, left?: number, right?: number): number {
|
|
let l = left || 0;
|
|
let r = right !== undefined ? right : array.length;
|
|
while (l < r) {
|
|
const m = (l + r) >> 1;
|
|
if (comparator(needle, array[m]) >= 0) {
|
|
l = m + 1;
|
|
} else {
|
|
r = m;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
const enum NearestSearchStart {
|
|
BEGINNING = 'BEGINNING',
|
|
END = 'END',
|
|
}
|
|
/**
|
|
* Obtains the first or last item in the array that satisfies the predicate function.
|
|
* So, for example, if the array were arr = [2, 4, 6, 8, 10], and you are looking for
|
|
* the last item arr[i] such that arr[i] < 5 you would be returned 1, because
|
|
* array[1] is 4, the last item in the array that satisfies the
|
|
* predicate function.
|
|
*
|
|
* If instead you were looking for the first item in the same array that satisfies
|
|
* arr[i] > 5 you would be returned 2 because array[2] = 6.
|
|
*
|
|
* Please note: this presupposes that the array is already ordered.
|
|
*/
|
|
function nearestIndex<T>(
|
|
arr: readonly T[], predicate: (arrayItem: T) => boolean, searchStart: NearestSearchStart): number|null {
|
|
const searchFromEnd = searchStart === NearestSearchStart.END;
|
|
if (arr.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
let left = 0;
|
|
let right = arr.length - 1;
|
|
let pivot = 0;
|
|
let matchesPredicate = false;
|
|
let moveToTheRight = false;
|
|
let middle = 0;
|
|
do {
|
|
middle = left + (right - left) / 2;
|
|
pivot = searchFromEnd ? Math.ceil(middle) : Math.floor(middle);
|
|
matchesPredicate = predicate(arr[pivot]);
|
|
moveToTheRight = matchesPredicate === searchFromEnd;
|
|
if (moveToTheRight) {
|
|
left = Math.min(right, pivot + (left === pivot ? 1 : 0));
|
|
} else {
|
|
right = Math.max(left, pivot + (right === pivot ? -1 : 0));
|
|
}
|
|
} while (right !== left);
|
|
|
|
// Special-case: the indexed item doesn't pass the predicate. This
|
|
// occurs when none of the items in the array are a match for the
|
|
// predicate.
|
|
if (!predicate(arr[left])) {
|
|
return null;
|
|
}
|
|
return left;
|
|
}
|
|
|
|
/**
|
|
* Obtains the first item in the array that satisfies the predicate function.
|
|
* So, for example, if the array was arr = [2, 4, 6, 8, 10], and you are looking for
|
|
* the first item arr[i] such that arr[i] > 5 you would be returned 2, because
|
|
* array[2] is 6, the first item in the array that satisfies the
|
|
* predicate function.
|
|
*
|
|
* Please note: this presupposes that the array is already ordered.
|
|
*/
|
|
export function nearestIndexFromBeginning<T>(arr: T[], predicate: (arrayItem: T) => boolean): number|null {
|
|
return nearestIndex(arr, predicate, NearestSearchStart.BEGINNING);
|
|
}
|
|
|
|
/**
|
|
* Obtains the last item in the array that satisfies the predicate function.
|
|
* So, for example, if the array was arr = [2, 4, 6, 8, 10], and you are looking for
|
|
* the last item arr[i] such that arr[i] < 5 you would be returned 1, because
|
|
* arr[1] is 4, the last item in the array that satisfies the
|
|
* predicate function.
|
|
*
|
|
* Please note: this presupposes that the array is already ordered.
|
|
*/
|
|
|
|
export function nearestIndexFromEnd<T>(arr: readonly T[], predicate: (arrayItem: T) => boolean): number|null {
|
|
return nearestIndex(arr, predicate, NearestSearchStart.END);
|
|
}
|
|
|
|
// Type guard for ensuring that `arr` does not contain null or undefined
|
|
export function arrayDoesNotContainNullOrUndefined<T>(arr: (T|null|undefined)[]): arr is T[] {
|
|
return !arr.includes(null) && !arr.includes(undefined);
|
|
}
|