Path: blob/main/extensions/copilot/src/platform/inlineEdits/test/node/random.ts
13405 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*--------------------------------------------------------------------------------------------*/45import { numberComparator } from '../../../../util/vs/base/common/arrays';6import { BugIndicatingError } from '../../../../util/vs/base/common/errors';7import { StringEdit, StringReplacement } from '../../../../util/vs/editor/common/core/edits/stringEdit';8import { TextEdit, TextReplacement } from '../../../../util/vs/editor/common/core/edits/textEdit';9import { Position } from '../../../../util/vs/editor/common/core/position';10import { Range } from '../../../../util/vs/editor/common/core/range';11import { OffsetRange } from '../../../../util/vs/editor/common/core/ranges/offsetRange';12import { AbstractText } from '../../../../util/vs/editor/common/core/text/abstractText';13import { PositionOffsetTransformer } from '../../../../util/vs/editor/common/core/text/positionToOffset';1415export abstract class Random {16public static readonly alphabetSmallLowercase = 'abcdefgh';17public static readonly alphabetSmallUppercase = 'ABCDEFGH';18public static readonly alphabetLowercase = 'abcdefghijklmnopqrstuvwxyz';19public static readonly alphabetUppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';20public static readonly basicAlphabet: string = ' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';21public static readonly basicAlphabetMultiline: string = ' \n\n\nabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';2223public static create(seed: number): Random {24return new MersenneTwister(seed);25}2627public stringGenerator(alphabet: string): IGenerator<string> {28return {29next: () => {30const characterIndex = this.nextIntRange(0, alphabet.length);31return alphabet.charAt(characterIndex);32}33};34}3536public abstract nextIntRange(start: number, endExclusive: number): number;3738public nextString(length: number, alphabet = this.stringGenerator(Random.basicAlphabet)): string {39let randomText: string = '';40for (let i = 0; i < length; i++) {41randomText += alphabet.next();42}43return randomText;44}4546public nextMultiLineString(lineCount: number, lineLengthRange: OffsetRange, alphabet = this.stringGenerator(Random.basicAlphabet)): string {47const lines: string[] = [];48for (let i = 0; i < lineCount; i++) {49const lineLength = this.nextIntRange(lineLengthRange.start, lineLengthRange.endExclusive);50lines.push(this.nextString(lineLength, alphabet));51}52return lines.join('\n');53}5455public nextConsecutiveOffsets(range: OffsetRange, count: number): number[] {56const offsets = OffsetRange.ofLength(count).map(() => this.nextIntRange(range.start, range.endExclusive));57offsets.sort(numberComparator);58return offsets;59}6061public nextConsecutivePositions(source: AbstractText, count: number): Position[] {62const t = new PositionOffsetTransformer(source.getValue());63const offsets = this.nextConsecutiveOffsets(new OffsetRange(0, t.text.length), count);64return offsets.map(offset => t.getPosition(offset));65}6667public nextRange(source: AbstractText): Range {68const [start, end] = this.nextConsecutivePositions(source, 2);69return Range.fromPositions(start, end);70}7172public nextTextEdit(target: AbstractText, singleTextEditCount: number): TextEdit {73const singleTextEdits: TextReplacement[] = [];7475const positions = this.nextConsecutivePositions(target, singleTextEditCount * 2);7677for (let i = 0; i < singleTextEditCount; i++) {78const start = positions[i * 2];79const end = positions[i * 2 + 1];80const newText = this.nextString(end.column - start.column, this.stringGenerator(Random.basicAlphabetMultiline));81singleTextEdits.push(new TextReplacement(Range.fromPositions(start, end), newText));82}8384return new TextEdit(singleTextEdits).normalize();85}8687public nextOffsetEdit(target: string, singleTextEditCount: number, newTextAlphabet = Random.basicAlphabetMultiline): StringEdit {88const singleTextEdits: StringReplacement[] = [];8990const positions = this.nextConsecutiveOffsets(new OffsetRange(0, target.length), singleTextEditCount * 2);9192for (let i = 0; i < singleTextEditCount; i++) {93const start = positions[i * 2];94const end = positions[i * 2 + 1];95const range = new OffsetRange(start, end);9697const newTextLen = this.nextIntRange(range.isEmpty ? 1 : 0, 10);98const newText = this.nextString(newTextLen, this.stringGenerator(newTextAlphabet));99singleTextEdits.push(new StringReplacement(range, newText));100}101102return new StringEdit(singleTextEdits).normalize();103}104105public nextSingleOffsetEdit(target: string, newTextAlphabet = Random.basicAlphabetMultiline): StringReplacement {106const edit = this.nextOffsetEdit(target, 1, newTextAlphabet);107return edit.replacements[0];108}109}110111export function sequenceGenerator<T>(sequence: T[]): IGenerator<T> {112let index = 0;113return {114next: () => {115if (index >= sequence.length) {116throw new BugIndicatingError('End of sequence');117}118const element = sequence[index];119index++;120return element;121}122};123}124125export interface IGenerator<T> {126next(): T;127}128129class MersenneTwister extends Random {130private readonly mt = new Array(624);131private index = 0;132133constructor(seed: number) {134super();135136this.mt[0] = seed >>> 0;137for (let i = 1; i < 624; i++) {138const s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30);139this.mt[i] = (((((s & 0xffff0000) >>> 16) * 0x6c078965) << 16) + (s & 0x0000ffff) * 0x6c078965 + i) >>> 0;140}141}142143private _nextInt() {144if (this.index === 0) {145this.generateNumbers();146}147148let y = this.mt[this.index];149y = y ^ (y >>> 11);150y = y ^ ((y << 7) & 0x9d2c5680);151y = y ^ ((y << 15) & 0xefc60000);152y = y ^ (y >>> 18);153154this.index = (this.index + 1) % 624;155156return y >>> 0;157}158159public nextIntRange(start: number, endExclusive: number) {160const range = endExclusive - start;161return Math.floor(this._nextInt() / (0x100000000 / range)) + start;162}163164private generateNumbers() {165for (let i = 0; i < 624; i++) {166const y = (this.mt[i] & 0x80000000) + (this.mt[(i + 1) % 624] & 0x7fffffff);167this.mt[i] = this.mt[(i + 397) % 624] ^ (y >>> 1);168if ((y % 2) !== 0) {169this.mt[i] = this.mt[i] ^ 0x9908b0df;170}171}172}173}174175176