Merge pull request #137201 from microsoft/tyriar/137155

Improve extension pty terminal tests
This commit is contained in:
Daniel Imms 2021-11-15 09:24:00 -08:00 committed by GitHub
commit 303bd5d617
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 123 additions and 167 deletions

View file

@ -425,23 +425,24 @@ import { assertNoRpc } from '../utils';
});
suite('Extension pty terminals', () => {
test('should fire onDidOpenTerminal and onDidCloseTerminal', (done) => {
disposables.push(window.onDidOpenTerminal(term => {
try {
equal(term.name, 'c');
} catch (e) {
done(e);
return;
}
disposables.push(window.onDidCloseTerminal(() => done()));
term.dispose();
}));
test('should fire onDidOpenTerminal and onDidCloseTerminal', async () => {
const pty: Pseudoterminal = {
onDidWrite: new EventEmitter<string>().event,
open: () => { },
close: () => { }
};
window.createTerminal({ name: 'c', pty });
const terminal = await new Promise<Terminal>(r => {
disposables.push(window.onDidOpenTerminal(t => {
if (t.name === 'c') {
r(t);
}
}));
window.createTerminal({ name: 'c', pty });
});
await new Promise<void>(r => {
disposables.push(window.onDidCloseTerminal(() => r()));
terminal.dispose();
});
});
// The below tests depend on global UI state and each other
@ -491,31 +492,7 @@ import { assertNoRpc } from '../utils';
// const terminal = window.createTerminal({ name: 'foo', pty });
// });
test('should respect dimension overrides', (done) => {
disposables.push(window.onDidOpenTerminal(term => {
try {
equal(terminal, term);
} catch (e) {
done(e);
return;
}
term.show();
disposables.push(window.onDidChangeTerminalDimensions(e => {
// The default pty dimensions have a chance to appear here since override
// dimensions happens after the terminal is created. If so just ignore and
// wait for the right dimensions
if (e.dimensions.columns === 10 || e.dimensions.rows === 5) {
try {
equal(e.terminal, terminal);
} catch (e) {
done(e);
return;
}
disposables.push(window.onDidCloseTerminal(() => done()));
terminal.dispose();
}
}));
}));
test('should respect dimension overrides', async () => {
const writeEmitter = new EventEmitter<string>();
const overrideDimensionsEmitter = new EventEmitter<TerminalDimensions>();
const pty: Pseudoterminal = {
@ -524,29 +501,30 @@ import { assertNoRpc } from '../utils';
open: () => overrideDimensionsEmitter.fire({ columns: 10, rows: 5 }),
close: () => { }
};
const terminal = window.createTerminal({ name: 'foo', pty });
const terminal = await new Promise<Terminal>(r => {
disposables.push(window.onDidOpenTerminal(t => {
if (t === created) {
r(t);
}
}));
const created = window.createTerminal({ name: 'foo', pty });
});
await new Promise<void>(r => {
disposables.push(window.onDidChangeTerminalDimensions(e => {
strictEqual(e.terminal, terminal);
// The default pty dimensions have a chance to appear here since override
// dimensions happens after the terminal is created. If so just ignore and
// wait for the right dimensions
if (e.dimensions.columns === 10 || e.dimensions.rows === 5) {
disposables.push(window.onDidCloseTerminal(() => r()));
terminal.dispose();
}
}));
terminal.show();
});
});
test('should change terminal name', (done) => {
disposables.push(window.onDidOpenTerminal(term => {
try {
equal(terminal, term);
equal(terminal.name, 'foo');
} catch (e) {
done(e);
return;
}
disposables.push(window.onDidCloseTerminal(t => {
try {
equal(terminal, t);
equal(terminal.name, 'bar');
} catch (e) {
done(e);
return;
}
done();
}));
}));
test('should change terminal name', async () => {
const changeNameEmitter = new EventEmitter<string>();
const closeEmitter = new EventEmitter<number | undefined>();
const pty: Pseudoterminal = {
@ -559,29 +537,22 @@ import { assertNoRpc } from '../utils';
},
close: () => { }
};
const terminal = window.createTerminal({ name: 'foo', pty });
await new Promise<void>(r => {
disposables.push(window.onDidOpenTerminal(t1 => {
if (t1 === created) {
disposables.push(window.onDidCloseTerminal(t2 => {
if (t2 === created) {
strictEqual(t1.name, 'bar');
r();
}
}));
}
}));
const created = window.createTerminal({ name: 'foo', pty });
});
});
test('exitStatus.code should be set to the exit code (undefined)', (done) => {
disposables.push(window.onDidOpenTerminal(term => {
try {
equal(terminal, term);
equal(terminal.exitStatus, undefined);
} catch (e) {
done(e);
return;
}
disposables.push(window.onDidCloseTerminal(t => {
try {
equal(terminal, t);
deepEqual(terminal.exitStatus, { code: undefined });
} catch (e) {
done(e);
return;
}
done();
}));
}));
test('exitStatus.code should be set to the exit code (undefined)', async () => {
const writeEmitter = new EventEmitter<string>();
const closeEmitter = new EventEmitter<number | undefined>();
const pty: Pseudoterminal = {
@ -590,29 +561,23 @@ import { assertNoRpc } from '../utils';
open: () => closeEmitter.fire(undefined),
close: () => { }
};
const terminal = window.createTerminal({ name: 'foo', pty });
await new Promise<void>(r => {
disposables.push(window.onDidOpenTerminal(t1 => {
if (t1 === created) {
strictEqual(created.exitStatus, undefined);
disposables.push(window.onDidCloseTerminal(t2 => {
if (t2 === created) {
deepStrictEqual(created.exitStatus, { code: undefined });
r();
}
}));
}
}));
const created = window.createTerminal({ name: 'foo', pty });
});
});
test('exitStatus.code should be set to the exit code (zero)', (done) => {
disposables.push(window.onDidOpenTerminal(term => {
try {
equal(terminal, term);
equal(terminal.exitStatus, undefined);
} catch (e) {
done(e);
return;
}
disposables.push(window.onDidCloseTerminal(t => {
try {
equal(terminal, t);
deepEqual(terminal.exitStatus, { code: 0 });
} catch (e) {
done(e);
return;
}
done();
}));
}));
test('exitStatus.code should be set to the exit code (zero)', async () => {
const writeEmitter = new EventEmitter<string>();
const closeEmitter = new EventEmitter<number | undefined>();
const pty: Pseudoterminal = {
@ -621,29 +586,23 @@ import { assertNoRpc } from '../utils';
open: () => closeEmitter.fire(0),
close: () => { }
};
const terminal = window.createTerminal({ name: 'foo', pty });
await new Promise<void>(r => {
disposables.push(window.onDidOpenTerminal(t1 => {
if (t1 === created) {
strictEqual(created.exitStatus, undefined);
disposables.push(window.onDidCloseTerminal(t2 => {
if (t2 === created) {
deepStrictEqual(created.exitStatus, { code: 0 });
r();
}
}));
}
}));
const created = window.createTerminal({ name: 'foo', pty });
});
});
test('exitStatus.code should be set to the exit code (non-zero)', (done) => {
disposables.push(window.onDidOpenTerminal(term => {
try {
equal(terminal, term);
equal(terminal.exitStatus, undefined);
} catch (e) {
done(e);
return;
}
disposables.push(window.onDidCloseTerminal(t => {
try {
equal(terminal, t);
deepEqual(terminal.exitStatus, { code: 22 });
} catch (e) {
done(e);
return;
}
done();
}));
}));
test('exitStatus.code should be set to the exit code (non-zero)', async () => {
const writeEmitter = new EventEmitter<string>();
const closeEmitter = new EventEmitter<number | undefined>();
const pty: Pseudoterminal = {
@ -657,20 +616,23 @@ import { assertNoRpc } from '../utils';
},
close: () => { }
};
const terminal = window.createTerminal({ name: 'foo', pty });
await new Promise<void>(r => {
disposables.push(window.onDidOpenTerminal(t1 => {
if (t1 === created) {
strictEqual(created.exitStatus, undefined);
disposables.push(window.onDidCloseTerminal(t2 => {
if (t2 === created) {
deepStrictEqual(created.exitStatus, { code: 22 });
r();
}
}));
}
}));
const created = window.createTerminal({ name: 'foo', pty });
});
});
test('creationOptions should be set and readonly for ExtensionTerminalOptions terminals', (done) => {
disposables.push(window.onDidOpenTerminal(term => {
try {
equal(terminal, term);
} catch (e) {
done(e);
return;
}
terminal.dispose();
disposables.push(window.onDidCloseTerminal(() => done()));
}));
test('creationOptions should be set and readonly for ExtensionTerminalOptions terminals', async () => {
const writeEmitter = new EventEmitter<string>();
const pty: Pseudoterminal = {
onDidWrite: writeEmitter.event,
@ -678,16 +640,20 @@ import { assertNoRpc } from '../utils';
close: () => { }
};
const options = { name: 'foo', pty };
const terminal = window.createTerminal(options);
try {
equal(terminal.name, 'foo');
await new Promise<void>(r => {
disposables.push(window.onDidOpenTerminal(term => {
if (term === terminal) {
terminal.dispose();
disposables.push(window.onDidCloseTerminal(() => r()));
}
}));
const terminal = window.createTerminal(options);
strictEqual(terminal.name, 'foo');
const terminalOptions = terminal.creationOptions as ExtensionTerminalOptions;
equal(terminalOptions.name, 'foo');
equal(terminalOptions.pty, pty);
strictEqual(terminalOptions.name, 'foo');
strictEqual(terminalOptions.pty, pty);
throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime');
} catch (e) {
done(e);
}
});
});
});

View file

@ -275,15 +275,11 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
}
input(data: string): void {
if (this._pty.handleInput) {
this._pty.handleInput(data);
}
this._pty.handleInput?.(data);
}
resize(cols: number, rows: number): void {
if (this._pty.setDimensions) {
this._pty.setDimensions({ columns: cols, rows });
}
this._pty.setDimensions?.({ columns: cols, rows });
}
async processBinary(data: string): Promise<void> {
@ -314,28 +310,22 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void {
// Attach the listeners
this._pty.onDidWrite(e => this._onProcessData.fire(e));
if (this._pty.onDidClose) {
this._pty.onDidClose((e: number | void = undefined) => {
this._onProcessExit.fire(e === void 0 ? undefined : e);
});
}
if (this._pty.onDidOverrideDimensions) {
this._pty.onDidOverrideDimensions(e => {
if (e) {
this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: { cols: e.columns, rows: e.rows } });
}
});
}
if (this._pty.onDidChangeName) {
this._pty.onDidChangeName(title => {
this._onDidChangeProperty.fire({ type: ProcessPropertyType.Title, value: title });
});
}
this._pty.onDidClose?.((e: number | void = undefined) => {
this._onProcessExit.fire(e === void 0 ? undefined : e);
});
this._pty.onDidOverrideDimensions?.(e => {
if (e) {
this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: { cols: e.columns, rows: e.rows } });
}
});
this._pty.onDidChangeName?.(title => {
this._onDidChangeProperty.fire({ type: ProcessPropertyType.Title, value: title });
});
this._pty.open(initialDimensions ? initialDimensions : undefined);
if (this._pty.setDimensions && initialDimensions) {
this._pty.setDimensions(initialDimensions);
if (initialDimensions) {
this._pty.setDimensions?.(initialDimensions);
}
this._onProcessReady.fire({ pid: -1, cwd: '', capabilities: this._capabilities });
@ -586,7 +576,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
protected _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): IDisposable {
const disposables = new DisposableStore();
disposables.add(p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd)));
disposables.add(p.onProcessReady(e => this._proxy.$sendProcessReady(id, e.pid, e.cwd)));
disposables.add(p.onDidChangeProperty(property => this._proxy.$sendProcessProperty(id, property)));
// Buffer data events to reduce the amount of messages going to the renderer