/* eslint-disable prettier/prettier */
/* eslint-disable @typescript-eslint/no-unused-vars */
/*---------------------------------------------------------
 * Copyright (C) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See LICENSE in the project root for license information.
 *--------------------------------------------------------*/

import assert from 'assert';
import * as vscode from 'vscode';
import { GoVersion, guessPackageNameFromFile, removeDuplicateDiagnostics, substituteEnv } from '../../src/util';
import path = require('path');

suite('utils Tests', () => {
	test('substituteEnv: default', () => {
		// prepare test
		const env = Object.assign({}, process.env);
		process.env['test1'] = 'abcd';
		process.env['test2'] = 'defg';

		const actual = substituteEnv(' ${env:test1} \r\n ${env:test2}\r\n${env:test1}');
		const expected = ' abcd \r\n defg\r\nabcd';

		assert.equal(actual, expected);

		// test completed
		process.env = env;
	});

	test('build GoVersion', () => {
		// [input, wantFormat, wantFormatIncludePrerelease, wantIsValid]
		const testCases: [string | undefined, string, string, boolean][] = [
			[
				'go version devel +a295d59d Fri Jun 26 19:00:25 2020 +0000 darwin/amd64',
				'devel +a295d59d',
				'devel +a295d59d',
				true
			],
			[
				'go version devel go1.17-756fd56bbf Thu Apr 29 01:15:34 2021 +0000 darwin/amd64',
				'devel go1.17-756fd56bbf',
				'devel go1.17-756fd56bbf',
				true
			],
			['go version go1.14 darwin/amd64', '1.14.0', '1.14', true],
			['go version go1.14.1 linux/amd64', '1.14.1', '1.14.1', true],
			['go version go1.15rc1 darwin/amd64', '1.15.0', '1.15rc1', true],
			['go version go1.15.1rc2 windows/amd64', '1.15.1', '1.15.1rc2', true],
			['go version go1.15.3-beta.1 darwin/amd64', '1.15.3', '1.15.3-beta.1', true],
			['go version go1.15.3-beta.1.2.3 foobar/amd64', '1.15.3', '1.15.3-beta.1.2.3', true],
			['go version go10.0.1 js/amd64', 'unknown', 'unknown', false],
			[undefined, 'unknown', 'unknown', false],
			['something wrong', 'unknown', 'unknown', false]
		];
		for (const [input, wantFormat, wantFormatIncludePrerelease, wantIsValid] of testCases) {
			const go = new GoVersion('/path/to/go', input);

			assert.equal(go.isValid(), wantIsValid, `GoVersion(${input}) = ${JSON.stringify(go)}`);
			assert.equal(go.format(), wantFormat, `GoVersion(${input}) = ${JSON.stringify(go)}`);
			assert.equal(go.format(true), wantFormatIncludePrerelease, `GoVersion(${input}) = ${JSON.stringify(go)}`);
		}
	});
});

suite('GuessPackageNameFromFile Tests', () => {
	test('package name from main file', (done) => {
		const expectedPackageName = 'main';
		const filename = 'main.go';

		guessPackageNameFromFile(filename)
			.then((result) => {
				assert.equal(result, expectedPackageName);
			})
			.then(() => done(), done);
	});

	test('package name from dirpath', (done) => {
		const expectedPackageName = 'package';
		const fileDir = 'path/package/file.go';

		guessPackageNameFromFile(fileDir)
			.then(([result]) => {
				assert.equal(result, expectedPackageName);
			})
			.then(() => done(), done);
	});

	test('package name from test file', (done) => {
		const expectedPackageName = 'file';
		const expectedPackageTestName = 'file_test';
		const fileDir = 'file_test.go';

		guessPackageNameFromFile(fileDir)
			.then(([packageNameResult, packageTestNameResult]) => {
				assert.equal(packageNameResult, expectedPackageName);
				assert.equal(packageTestNameResult, expectedPackageTestName);
			})
			.then(() => done(), done);
	});
});

suite('Duplicate Diagnostics Tests', () => {
	test('remove duplicate diagnostics', async () => {
		const fixturePath = path.join(__dirname, '..', '..', '..', 'test', 'testdata');
		const uri1 = vscode.Uri.file(path.join(fixturePath, 'linterTest', 'linter_1.go'));
		const uri2 = vscode.Uri.file(path.join(fixturePath, 'linterTest', 'linter_2.go'));

		const diagnosticCollection = vscode.languages.createDiagnosticCollection('linttest');

		// Populate the diagnostic collection
		const diag1 = [
			new vscode.Diagnostic(
				new vscode.Range(1, 2, 1, 3),
				'first line diagnostic',
				vscode.DiagnosticSeverity.Warning
			),
			new vscode.Diagnostic(
				new vscode.Range(2, 0, 2, 3),
				'second line diagnostic',
				vscode.DiagnosticSeverity.Warning
			),
			new vscode.Diagnostic(new vscode.Range(2, 3, 2, 5), 'second line error', vscode.DiagnosticSeverity.Error),
			new vscode.Diagnostic(
				new vscode.Range(4, 0, 4, 3),
				'fourth line diagnostic',
				vscode.DiagnosticSeverity.Warning
			)
		];
		const diag2 = [
			new vscode.Diagnostic(
				new vscode.Range(1, 2, 1, 3),
				'first line diagnostic',
				vscode.DiagnosticSeverity.Warning
			),
			new vscode.Diagnostic(
				new vscode.Range(2, 0, 2, 3),
				'second line diagnostic',
				vscode.DiagnosticSeverity.Warning
			),
			new vscode.Diagnostic(new vscode.Range(2, 3, 2, 5), 'second line error', vscode.DiagnosticSeverity.Error),
			new vscode.Diagnostic(
				new vscode.Range(4, 0, 4, 3),
				'fourth line diagnostic',
				vscode.DiagnosticSeverity.Warning
			)
		];
		diagnosticCollection.set(uri1, diag1);
		diagnosticCollection.set(uri2, diag2);

		// After removing diagnostics from uri1, there should only be one diagnostic remaining, and
		// the diagnostics for uri2 should not be changed.
		const want1 = [diag1[3]];
		const want2: vscode.Diagnostic[] = [];
		diag2.forEach((diag) => {
			want2.push(diag);
		});

		const newDiagnostics: vscode.Diagnostic[] = [
			new vscode.Diagnostic(
				new vscode.Range(1, 2, 1, 3),
				'first line diagnostic',
				vscode.DiagnosticSeverity.Warning
			),
			new vscode.Diagnostic(new vscode.Range(2, 3, 2, 5), 'second line error', vscode.DiagnosticSeverity.Error)
		];

		removeDuplicateDiagnostics(diagnosticCollection, uri1, newDiagnostics);

		assert.strictEqual(diagnosticCollection.get(uri1).length, want1.length);
		for (let i = 0; i < want1.length; i++) {
			assert.strictEqual(diagnosticCollection.get(uri1)[i], want1[i]);
		}

		assert.strictEqual(diagnosticCollection.get(uri2).length, want2.length);
		for (let i = 0; i < want2.length; i++) {
			assert.strictEqual(diagnosticCollection.get(uri2)[i], want2[i]);
		}
	});
});
