import 'mocha';
import assert from 'assert';
import { workspace, commands, window, Uri, WorkspaceEdit, Range, TextDocument, extensions, TabInputTextDiff } from 'vscode';
import * as cp from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { GitExtension, API, Repository, Status } from '../api/git';
import { eventToPromise } from '../util';
suite('git smoke test', function () {
const cwd = workspace.workspaceFolders![0].uri.fsPath;
function file(relativePath: string) {
return path.join(cwd, relativePath);
}
function uri(relativePath: string) {
return Uri.file(file(relativePath));
}
async function open(relativePath: string) {
const doc = await workspace.openTextDocument(uri(relativePath));
await window.showTextDocument(doc);
return doc;
}
async function type(doc: TextDocument, text: string) {
const edit = new WorkspaceEdit();
const end = doc.lineAt(doc.lineCount - 1).range.end;
edit.replace(doc.uri, new Range(end, end), text);
await workspace.applyEdit(edit);
}
let git: API;
let repository: Repository;
suiteSetup(async function () {
fs.writeFileSync(file('app.js'), 'hello', 'utf8');
fs.writeFileSync(file('index.pug'), 'hello', 'utf8');
cp.execSync('git init -b main', { cwd });
cp.execSync('git config user.name testuser', { cwd });
cp.execSync('git config user.email [email protected]', { cwd });
cp.execSync('git config commit.gpgsign false', { cwd });
cp.execSync('git add .', { cwd });
cp.execSync('git commit -m "initial commit"', { cwd });
const ext = extensions.getExtension<GitExtension>('vscode.git');
await ext?.activate();
git = ext!.exports.getAPI(1);
if (git.repositories.length === 0) {
const onDidOpenRepository = eventToPromise(git.onDidOpenRepository);
await commands.executeCommand('git.openRepository', cwd);
await onDidOpenRepository;
}
assert.strictEqual(git.repositories.length, 1);
assert.strictEqual(git.repositories[0].rootUri.fsPath, cwd);
repository = git.repositories[0];
});
test('reflects working tree changes', async function () {
await commands.executeCommand('workbench.view.scm');
const appjs = await open('app.js');
await type(appjs, ' world');
await appjs.save();
await repository.status();
assert.strictEqual(repository.state.workingTreeChanges.length, 1);
assert.strictEqual(repository.state.workingTreeChanges[0].uri.path, appjs.uri.path);
assert.strictEqual(repository.state.workingTreeChanges[0].status, Status.MODIFIED);
fs.writeFileSync(file('newfile.txt'), '');
const newfile = await open('newfile.txt');
await type(newfile, 'hey there');
await newfile.save();
await repository.status();
assert.strictEqual(repository.state.workingTreeChanges.length, 2);
assert.strictEqual(repository.state.workingTreeChanges[0].uri.path, appjs.uri.path);
assert.strictEqual(repository.state.workingTreeChanges[0].status, Status.MODIFIED);
assert.strictEqual(repository.state.workingTreeChanges[1].uri.path, newfile.uri.path);
assert.strictEqual(repository.state.workingTreeChanges[1].status, Status.UNTRACKED);
});
test('opens diff editor', async function () {
const appjs = uri('app.js');
await commands.executeCommand('git.openChange', appjs);
assert(window.activeTextEditor);
assert.strictEqual(window.activeTextEditor!.document.uri.path, appjs.path);
assert(window.tabGroups.activeTabGroup.activeTab);
assert(window.tabGroups.activeTabGroup.activeTab!.input instanceof TabInputTextDiff);
});
test('stages correctly', async function () {
const appjs = uri('app.js');
const newfile = uri('newfile.txt');
await repository.add([appjs.fsPath]);
assert.strictEqual(repository.state.indexChanges.length, 1);
assert.strictEqual(repository.state.indexChanges[0].uri.path, appjs.path);
assert.strictEqual(repository.state.indexChanges[0].status, Status.INDEX_MODIFIED);
assert.strictEqual(repository.state.workingTreeChanges.length, 1);
assert.strictEqual(repository.state.workingTreeChanges[0].uri.path, newfile.path);
assert.strictEqual(repository.state.workingTreeChanges[0].status, Status.UNTRACKED);
await repository.revert([appjs.fsPath]);
assert.strictEqual(repository.state.indexChanges.length, 0);
assert.strictEqual(repository.state.workingTreeChanges.length, 2);
assert.strictEqual(repository.state.workingTreeChanges[0].uri.path, appjs.path);
assert.strictEqual(repository.state.workingTreeChanges[0].status, Status.MODIFIED);
assert.strictEqual(repository.state.workingTreeChanges[1].uri.path, newfile.path);
assert.strictEqual(repository.state.workingTreeChanges[1].status, Status.UNTRACKED);
});
test('stages, commits changes and verifies outgoing change', async function () {
const appjs = uri('app.js');
const newfile = uri('newfile.txt');
await repository.add([appjs.fsPath]);
await repository.commit('second commit');
assert.strictEqual(repository.state.workingTreeChanges.length, 1);
assert.strictEqual(repository.state.workingTreeChanges[0].uri.path, newfile.path);
assert.strictEqual(repository.state.workingTreeChanges[0].status, Status.UNTRACKED);
assert.strictEqual(repository.state.indexChanges.length, 0);
await repository.commit('third commit', { all: true });
assert.strictEqual(repository.state.workingTreeChanges.length, 0);
assert.strictEqual(repository.state.indexChanges.length, 0);
});
test('rename/delete conflict', async function () {
await commands.executeCommand('workbench.view.scm');
const appjs = file('app.js');
const renamejs = file('rename.js');
await repository.createBranch('test', true);
fs.unlinkSync(appjs);
await repository.commit('commit on test', { all: true });
await repository.checkout('main');
fs.renameSync(appjs, renamejs);
await repository.commit('commit on main', { all: true });
try {
await repository.merge('test');
} catch (e) { }
assert.strictEqual(repository.state.mergeChanges.length, 1);
assert.strictEqual(repository.state.mergeChanges[0].status, Status.DELETED_BY_THEM);
assert.strictEqual(repository.state.workingTreeChanges.length, 0);
assert.strictEqual(repository.state.indexChanges.length, 0);
});
});