test/gopls: print gopls traces when test fails This is done by stubbing vscode.window.createOutputChannel with a fake output channel that dumps buffered output when the test fails. Change-Id: I5fb1dff2e27ecb203f276ee1b82b1b6f7237ece4 Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/233518 Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com> TryBot-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/test/gopls/extension.test.ts b/test/gopls/extension.test.ts index 7f5104c..2816e2e 100644 --- a/test/gopls/extension.test.ts +++ b/test/gopls/extension.test.ts
@@ -6,9 +6,34 @@ import cp = require('child_process'); import * as fs from 'fs-extra'; import * as path from 'path'; +import sinon = require('sinon'); import * as vscode from 'vscode'; import { extensionId } from '../../src/const'; +// FakeOutputChannel is a fake output channel used to buffer +// the output of the tested language client in an in-memory +// string array until cleared. +class FakeOutputChannel implements vscode.OutputChannel { + public name = 'FakeOutputChannel'; + public show = sinon.fake(); // no-empty + public hide = sinon.fake(); // no-empty + public dispose = sinon.fake(); // no-empty + + private buf = [] as string[]; + + public append = (v: string) => this.enqueue(v); + public appendLine = (v: string) => this.enqueue(v); + public clear = () => { this.buf = []; }; + public toString = () => { + return this.buf.join('\n'); + } + + private enqueue = (v: string) => { + if (this.buf.length > 1024) { this.buf.shift(); } + this.buf.push(v.trim()); + } +} + // Env is a collection of test related variables // that define the test environment such as vscode workspace. class Env { @@ -28,6 +53,8 @@ public extension: vscode.Extension<any>; + private fakeOutputChannel: FakeOutputChannel; + constructor(projectDir: string) { if (!projectDir) { assert.fail('project directory cannot be determined'); @@ -35,6 +62,7 @@ this.workspaceDir = path.resolve(projectDir, 'test/gopls/testfixtures/src/workspace'); this.fixturesRoot = path.resolve(projectDir, 'test/fixtures'); this.extension = vscode.extensions.getExtension(extensionId); + this.fakeOutputChannel = new FakeOutputChannel(); // Ensure the vscode extension host is configured as expected. const workspaceFolder = path.resolve(vscode.workspace.workspaceFolders[0].uri.fsPath); @@ -43,7 +71,18 @@ } } + public flushTrace(print: boolean) { + if (print) { + console.log(this.fakeOutputChannel.toString()); + this.fakeOutputChannel.clear(); + } + } + public async setup() { + // stub the language server's output channel to intercept the trace. + sinon.stub(vscode.window, 'createOutputChannel') + .callThrough().withArgs('gopls (server)').returns(this.fakeOutputChannel); + await this.reset(); await this.extension.activate(); await sleep(2000); // allow the language server to start. @@ -52,6 +91,10 @@ // but couldn't make it working yet. } + public teardown() { + sinon.restore(); + } + public async reset(fixtureDirName?: string) { // name of the fixtures subdirectory to use. try { // clean everything except the .gitignore file @@ -97,6 +140,13 @@ }); suiteTeardown(async () => { await env.reset(); }); + this.afterEach(function () { + // Note: this shouldn't use () => {...}. Arrow functions do not have 'this'. + // I don't know why but this.currentTest.state does not have the expected value when + // used with teardown. + env.flushTrace(this.currentTest.state === 'failed'); + }); + test('HoverProvider', async () => { await env.reset('gogetdocTestData'); const { uri, doc } = await env.openDoc('test.go');