Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to fix flaky paste tests #182574

Merged
merged 1 commit into from May 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -5,22 +5,29 @@

import * as assert from 'assert';
import * as vscode from 'vscode';
import { assertNoRpc, createRandomFile, usingDisposables } from '../utils';
import { closeAllEditors, createRandomFile, disposeAll } from '../utils';

const textPlain = 'text/plain';

(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('vscode API - Copy Paste', () => {
(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('vscode API - Copy Paste', function () {

teardown(assertNoRpc);
this.retries(3);

test('Copy should be able to overwrite text/plain', usingDisposables(async (disposables) => {
const testDisposables: vscode.Disposable[] = [];

teardown(async function () {
disposeAll(testDisposables);
await closeAllEditors();
});

test('Copy should be able to overwrite text/plain', async () => {
const file = await createRandomFile('$abcde@');
const doc = await vscode.workspace.openTextDocument(file);

const editor = await vscode.window.showTextDocument(doc);
editor.selections = [new vscode.Selection(0, 1, 0, 6)];

disposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
testDisposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
async prepareDocumentPaste(_document: vscode.TextDocument, _ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise<void> {
const existing = dataTransfer.get(textPlain);
if (existing) {
Expand All @@ -32,17 +39,17 @@ const textPlain = 'text/plain';
}, { copyMimeTypes: [textPlain] }));

await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
const newDocContent = getNextDocumentText(disposables, doc);
const newDocContent = getNextDocumentText(testDisposables, doc);
await vscode.commands.executeCommand('editor.action.clipboardPasteAction');
assert.strictEqual(await newDocContent, '$edcba@');
}));
});

test('Copy with empty selection should copy entire line', usingDisposables(async (disposables) => {
test('Copy with empty selection should copy entire line', async () => {
const file = await createRandomFile('abc\ndef');
const doc = await vscode.workspace.openTextDocument(file);
await vscode.window.showTextDocument(doc);

disposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
testDisposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
async prepareDocumentPaste(_document: vscode.TextDocument, _ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise<void> {
const existing = dataTransfer.get(textPlain);
if (existing) {
Expand All @@ -57,12 +64,12 @@ const textPlain = 'text/plain';
}, { copyMimeTypes: [textPlain] }));

await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
const newDocContent = getNextDocumentText(disposables, doc);
const newDocContent = getNextDocumentText(testDisposables, doc);
await vscode.commands.executeCommand('editor.action.clipboardPasteAction');
assert.strictEqual(await newDocContent, `cba\nabc\ndef`);
}));
});

test('Copy with multiple selections should get all selections', usingDisposables(async (disposables) => {
test('Copy with multiple selections should get all selections', async () => {
const file = await createRandomFile('111\n222\n333');
const doc = await vscode.workspace.openTextDocument(file);
const editor = await vscode.window.showTextDocument(doc);
Expand All @@ -72,7 +79,7 @@ const textPlain = 'text/plain';
new vscode.Selection(2, 0, 2, 3),
];

disposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
testDisposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
async prepareDocumentPaste(document: vscode.TextDocument, ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise<void> {
const existing = dataTransfer.get(textPlain);
if (existing) {
Expand All @@ -84,13 +91,13 @@ const textPlain = 'text/plain';

await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
editor.selections = [new vscode.Selection(0, 0, 0, 0)];
const newDocContent = getNextDocumentText(disposables, doc);
const newDocContent = getNextDocumentText(testDisposables, doc);
await vscode.commands.executeCommand('editor.action.clipboardPasteAction');

assert.strictEqual(await newDocContent, `(2)111 333111\n222\n333`);
}));
});

test('Earlier invoked copy providers should win when writing values', usingDisposables(async (disposables) => {
test('Earlier invoked copy providers should win when writing values', async () => {
const file = await createRandomFile('abc\ndef');
const doc = await vscode.workspace.openTextDocument(file);

Expand All @@ -104,7 +111,7 @@ const textPlain = 'text/plain';
let providerAResolve: () => void;
const providerAFinished = new Promise<void>(resolve => providerAResolve = resolve);

disposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
testDisposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
async prepareDocumentPaste(_document: vscode.TextDocument, _ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise<void> {
callOrder.push(a_id);
dataTransfer.set(textPlain, new vscode.DataTransferItem('a'));
Expand All @@ -113,7 +120,7 @@ const textPlain = 'text/plain';
}, { copyMimeTypes: [textPlain] }));

// Later registered providers will be called first
disposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
testDisposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
async prepareDocumentPaste(_document: vscode.TextDocument, _ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise<void> {
callOrder.push(b_id);

Expand All @@ -127,15 +134,15 @@ const textPlain = 'text/plain';
}, { copyMimeTypes: [textPlain] }));

await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
const newDocContent = getNextDocumentText(disposables, doc);
const newDocContent = getNextDocumentText(testDisposables, doc);
await vscode.commands.executeCommand('editor.action.clipboardPasteAction');
assert.strictEqual(await newDocContent, 'b\ndef');

// Confirm provider call order is what we expected
assert.deepStrictEqual(callOrder, [b_id, a_id]);
}));
});

test('Copy providers should not be able to effect the data transfer of another', usingDisposables(async (disposables) => {
test('Copy providers should not be able to effect the data transfer of another', async () => {
const file = await createRandomFile('abc\ndef');
const doc = await vscode.workspace.openTextDocument(file);

Expand All @@ -146,14 +153,14 @@ const textPlain = 'text/plain';
let providerAResolve: () => void;
const providerAFinished = new Promise<void>(resolve => providerAResolve = resolve);

disposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
testDisposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
async prepareDocumentPaste(_document: vscode.TextDocument, _ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise<void> {
dataTransfer.set(textPlain, new vscode.DataTransferItem('xyz'));
providerAResolve();
}
}, { copyMimeTypes: [textPlain] }));

disposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
testDisposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
async prepareDocumentPaste(_document: vscode.TextDocument, _ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise<void> {

// Wait for the first provider to finish
Expand All @@ -167,36 +174,36 @@ const textPlain = 'text/plain';
}, { copyMimeTypes: [textPlain] }));

await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
const newDocContent = getNextDocumentText(disposables, doc);
const newDocContent = getNextDocumentText(testDisposables, doc);
await vscode.commands.executeCommand('editor.action.clipboardPasteAction');
assert.strictEqual(await newDocContent, 'cba\ndef');
}));
});


test('One failing provider should not effect other', usingDisposables(async (disposables) => {
test('One failing provider should not effect other', async () => {
const file = await createRandomFile('abc\ndef');
const doc = await vscode.workspace.openTextDocument(file);

const editor = await vscode.window.showTextDocument(doc);
editor.selections = [new vscode.Selection(0, 0, 0, 3)];

disposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
testDisposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
async prepareDocumentPaste(_document: vscode.TextDocument, _ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise<void> {
dataTransfer.set(textPlain, new vscode.DataTransferItem('xyz'));
}
}, { copyMimeTypes: [textPlain] }));

disposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
testDisposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
async prepareDocumentPaste(_document: vscode.TextDocument, _ranges: readonly vscode.Range[], _dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise<void> {
throw new Error('Expected testing error from bad provider');
}
}, { copyMimeTypes: [textPlain] }));

await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
const newDocContent = getNextDocumentText(disposables, doc);
const newDocContent = getNextDocumentText(testDisposables, doc);
await vscode.commands.executeCommand('editor.action.clipboardPasteAction');
assert.strictEqual(await newDocContent, 'xyz\ndef');
}));
});
});

function reverseString(str: string) {
Expand Down
11 changes: 0 additions & 11 deletions extensions/vscode-api-tests/src/utils.ts
Expand Up @@ -62,17 +62,6 @@ export function disposeAll(disposables: vscode.Disposable[]) {
vscode.Disposable.from(...disposables).dispose();
}

export function usingDisposables<R>(fn: (this: Mocha.Context, store: vscode.Disposable[]) => Promise<R>) {
return async function (this: Mocha.Context): Promise<R> {
const disposables: vscode.Disposable[] = [];
try {
return await fn.call(this, disposables);
} finally {
disposeAll(disposables);
}
};
}

export function delay(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Expand Down