/*---------------------------------------------------------
 * Copyright 2020 The Go Authors. All rights reserved.
 * Licensed under the MIT License. See LICENSE in the project root for license information.
 *--------------------------------------------------------*/

'use strict';

import assert from 'assert';
import fs = require('fs-extra');
import path = require('path');
import sinon = require('sinon');
import vscode = require('vscode');
import { updateGoVarsFromConfig } from '../../src/goInstallTools';
import { GoRunTestCodeLensProvider } from '../../src/goRunTestCodelens';
import { subTestAtCursor } from '../../src/goTest';
import { getCurrentGoPath, getGoVersion } from '../../src/util';
import { MockExtensionContext } from '../mocks/MockContext';

suite('Code lenses for testing and benchmarking', function () {
	this.timeout(20000);

	let gopath: string;
	let repoPath: string;
	let fixturePath: string;
	let fixtureSourcePath: string;

	let document: vscode.TextDocument;

	// eslint-disable-next-line @typescript-eslint/no-explicit-any
	const ctx = new MockExtensionContext() as any;
	const cancellationTokenSource = new vscode.CancellationTokenSource();
	const codeLensProvider = new GoRunTestCodeLensProvider({});

	suiteSetup(async () => {
		await updateGoVarsFromConfig({});

		gopath = getCurrentGoPath();
		if (!gopath) {
			assert.fail('Cannot run tests without a configured GOPATH');
		}
		console.log(`Using GOPATH: ${gopath}`);

		// Set up the test fixtures.
		repoPath = path.join(gopath, 'src', 'test');
		fixturePath = path.join(repoPath, 'testfixture');
		fixtureSourcePath = path.join(__dirname, '..', '..', '..', 'test', 'testdata', 'codelens');

		fs.removeSync(repoPath);
		fs.copySync(fixtureSourcePath, fixturePath, {
			recursive: true
		});
		const uri = vscode.Uri.file(path.join(fixturePath, 'codelens_test.go'));
		document = await vscode.workspace.openTextDocument(uri);
	});

	suiteTeardown(() => {
		fs.removeSync(repoPath);
	});

	teardown(() => {
		sinon.restore();
	});

	test('Subtests - runs a test with cursor on t.Run line', async () => {
		const editor = await vscode.window.showTextDocument(document);
		editor.selection = new vscode.Selection(7, 4, 7, 4);
		const result = await subTestAtCursor(ctx, {})([]);
		assert.equal(result, true);
	});

	test('Subtests - runs a test with cursor within t.Run function', async () => {
		const editor = await vscode.window.showTextDocument(document);
		editor.selection = new vscode.Selection(8, 4, 8, 4);
		const result = await subTestAtCursor(ctx, {})([]);
		assert.equal(result, true);
	});

	test('Subtests - returns false for a failing test', async () => {
		const editor = await vscode.window.showTextDocument(document);
		editor.selection = new vscode.Selection(11, 4, 11, 4);
		const result = await subTestAtCursor(ctx, {})([]);
		assert.equal(result, false);
	});

	test('Subtests - does nothing for a dynamically defined subtest', async () => {
		const editor = await vscode.window.showTextDocument(document);
		editor.selection = new vscode.Selection(17, 4, 17, 4);
		sinon.stub(vscode.window, 'showInputBox').onFirstCall().resolves(undefined);
		const result = await subTestAtCursor(ctx, {})([]);
		assert.equal(result, undefined);
	});

	test('Subtests - runs a test with curson on t.Run line and dynamic test name is passed in input box', async () => {
		const editor = await vscode.window.showTextDocument(document);
		editor.selection = new vscode.Selection(17, 4, 17, 4);
		sinon.stub(vscode.window, 'showInputBox').onFirstCall().resolves('dynamic test name');
		const result = await subTestAtCursor(ctx, {})([]);
		assert.equal(result, false);
	});

	test('Subtests - does nothing when cursor outside of a test function', async () => {
		const editor = await vscode.window.showTextDocument(document);
		editor.selection = new vscode.Selection(5, 0, 5, 0);
		const result = await subTestAtCursor(ctx, {})([]);
		assert.equal(result, undefined);
	});

	test('Subtests - does nothing when no test function covers the cursor and a function name is passed in', async () => {
		const editor = await vscode.window.showTextDocument(document);
		editor.selection = new vscode.Selection(5, 0, 5, 0);
		const result = await subTestAtCursor(ctx, {})({ functionName: 'TestMyFunction' });
		assert.equal(result, undefined);
	});

	test('Test codelenses', async () => {
		const codeLenses = await codeLensProvider.provideCodeLenses(document, cancellationTokenSource.token);
		assert.equal(codeLenses.length, 4);
		const wantCommands = ['go.test.package', 'go.test.file', 'go.test.cursor', 'go.debug.cursor'];
		for (let i = 0; i < codeLenses.length; i++) {
			assert.equal(codeLenses[i].command?.command, wantCommands[i]);
		}
	});

	test('Benchmark codelenses', async () => {
		const uri = vscode.Uri.file(path.join(fixturePath, 'codelens_benchmark_test.go'));
		const benchmarkDocument = await vscode.workspace.openTextDocument(uri);
		const codeLenses = await codeLensProvider.provideCodeLenses(benchmarkDocument, cancellationTokenSource.token);
		assert.equal(codeLenses.length, 6);
		const wantCommands = [
			'go.test.package',
			'go.test.file',
			'go.benchmark.package',
			'go.benchmark.file',
			'go.benchmark.cursor',
			'go.debug.cursor'
		];
		for (let i = 0; i < codeLenses.length; i++) {
			assert.equal(codeLenses[i].command?.command, wantCommands[i]);
		}
	});

	test('Test codelenses include only valid test function names', async () => {
		const uri = vscode.Uri.file(path.join(fixturePath, 'codelens2_test.go'));
		const benchmarkDocument = await vscode.workspace.openTextDocument(uri);
		const codeLenses = await codeLensProvider.provideCodeLenses(benchmarkDocument, cancellationTokenSource.token);
		assert.equal(codeLenses.length, 20, JSON.stringify(codeLenses, null, 2));
		const found = [] as string[];
		for (let i = 0; i < codeLenses.length; i++) {
			const lens = codeLenses[i];
			if (lens.command?.command === 'go.test.cursor') {
				found.push(lens.command.arguments?.[0].functionName);
			}
		}
		found.sort();
		// Results should match `go test -list`.
		assert.deepStrictEqual(found, [
			'Example',
			'ExampleFunction',
			'Test',
			'Test1Function',
			'TestFunction',
			'TestMain',
			'Test_foobar',
			'TestΣυνάρτηση',
			'Test함수'
		]);
	});

	test('Test codelenses include valid fuzz function names', async function () {
		if ((await getGoVersion()).lt('1.18')) {
			this.skip();
		}
		const uri = vscode.Uri.file(path.join(fixturePath, 'codelens_go118_test.go'));
		const testDocument = await vscode.workspace.openTextDocument(uri);
		const codeLenses = await codeLensProvider.provideCodeLenses(testDocument, cancellationTokenSource.token);
		assert.equal(codeLenses.length, 8, JSON.stringify(codeLenses, null, 2));
		const found = [] as string[];
		for (let i = 0; i < codeLenses.length; i++) {
			const lens = codeLenses[i];
			if (lens.command?.command === 'go.test.cursor') {
				found.push(lens.command.arguments?.[0].functionName);
			}
		}
		found.sort();
		// Results should match `go test -list`.
		assert.deepStrictEqual(found, ['Fuzz', 'FuzzFunc', 'TestGo118']);
	});

	test('Test codelenses skip TestMain', async () => {
		const uri = vscode.Uri.file(path.join(fixturePath, 'testmain/testmain_test.go'));
		const testDocument = await vscode.workspace.openTextDocument(uri);
		const codeLenses = await codeLensProvider.provideCodeLenses(testDocument, cancellationTokenSource.token);
		assert.equal(codeLenses.length, 4, JSON.stringify(codeLenses, null, 2));
		const found = [] as string[];
		for (let i = 0; i < codeLenses.length; i++) {
			const lens = codeLenses[i];
			if (lens.command?.command === 'go.test.cursor') {
				found.push(lens.command.arguments?.[0].functionName);
			}
		}
		found.sort();
		// Results should match `go test -list`.
		assert.deepStrictEqual(found, ['TestNotMain']);
	});
});
