diff --git a/src/svnRepository.ts b/src/svnRepository.ts index b5279ba0..27d98a4e 100644 --- a/src/svnRepository.ts +++ b/src/svnRepository.ts @@ -18,6 +18,10 @@ export class Repository { return await parseStatusXml(result.stdout); } + resetInfo() { + this._info = undefined; + } + async getInfo(): Promise { if (this._info) { return this._info; @@ -28,7 +32,7 @@ export class Repository { //Cache for 30 seconds setTimeout(() => { - this._info = undefined; + this.resetInfo(); }, 30000); return this._info; @@ -210,6 +214,8 @@ export class Repository { throw new Error(switchBranch.stderr); } + this.resetInfo(); + return true; } @@ -227,6 +233,8 @@ export class Repository { throw new Error(switchBranch.stderr); } + this.resetInfo(); + return true; } diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 0830cbbc..9e6b1d46 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -17,30 +17,40 @@ import { SvnFinder } from "../svnFinder"; // Defines a Mocha test suite to group tests of similar kind together suite("Extension Tests", () => { - //Before Each - setup(async () => { - }); + setup(async () => {}); teardown(() => { testUtil.destroyAllTempPaths(); }); - test("Find Repository", async () => { - const svnFinder = new SvnFinder(); - const info = await svnFinder.findSvn(); + test("should be present", () => { + assert.ok(vscode.extensions.getExtension("johnstoncode.svn-scm")); }); - test("Try Open Repository", async () => { - const repoUrl = await testUtil.createRepoServer(); - await testUtil.createStandardLayout(repoUrl); - const checkoutDir = await testUtil.createRepoCheckout(repoUrl + "/trunk"); - - const svnFinder = new SvnFinder(); - const info = await svnFinder.findSvn(); - const svn = new Svn({ svnPath: info.path, version: info.version }); - const model = new Model(svn); - await model.tryOpenRepository(checkoutDir); - model.dispose(); + // The extension is already activated by vscode before running mocha test framework. + // No need to test activate any more. So commenting this case. + // tslint:disable-next-line: only-arrow-functions + test("should be able to activate the extension", function(done) { + this.timeout(60 * 1000); + const extension = vscode.extensions.getExtension("johnstoncode.svn-scm"); + + if (!extension) { + done("Extension not found"); + return; + } + + if (!extension.isActive) { + extension.activate().then( + api => { + done(); + }, + () => { + done("Failed to activate extension"); + } + ); + } else { + done(); + } }); }); diff --git a/src/test/repository.test.ts b/src/test/repository.test.ts new file mode 100644 index 00000000..f34ac49e --- /dev/null +++ b/src/test/repository.test.ts @@ -0,0 +1,144 @@ +// +// Note: This example test is leveraging the Mocha test framework. +// Please refer to their documentation on https://mochajs.org/ for help. +// + +// The module 'assert' provides assertion methods from node +import * as assert from "assert"; + +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +import * as fs from "fs"; +import * as path from "path"; +import * as vscode from "vscode"; +import * as testUtil from "./testUtil"; +import { Uri } from "vscode"; +import { Svn } from "../svn"; +import { Model } from "../model"; +import { SvnFinder, ISvn } from "../svnFinder"; +import { Repository } from "../repository"; + +// Defines a Mocha test suite to group tests of similar kind together +suite("Repository Tests", () => { + let repoUri: Uri; + let checkoutDir: Uri; + let svnFinder: SvnFinder; + let info: ISvn; + let svn: Svn; + let model: Model; + + suiteSetup(async () => { + repoUri = await testUtil.createRepoServer(); + await testUtil.createStandardLayout(testUtil.getSvnUrl(repoUri)); + checkoutDir = await testUtil.createRepoCheckout( + testUtil.getSvnUrl(repoUri) + "/trunk" + ); + + svnFinder = new SvnFinder(); + info = await svnFinder.findSvn(); + svn = new Svn({ svnPath: info.path, version: info.version }); + model = new Model(svn); + await model.tryOpenRepository(checkoutDir.fsPath); + }); + + suiteTeardown(() => { + testUtil.destroyAllTempPaths(); + }); + + test("Find Repository", async () => { + assert.ok(info); + assert.ok(info.path); + assert.ok(info.version); + }); + + test("Try Open Repository", async function() { + assert.equal(model.repositories.length, 1); + }); + + test("Try Open Repository Again", async () => { + await model.tryOpenRepository(checkoutDir.fsPath); + assert.equal(model.repositories.length, 1); + }); + + test("Try get repository from Uri", () => { + const repository = model.getRepository(checkoutDir); + assert.ok(repository); + }); + + test("Try get repository from string", () => { + const repository = model.getRepository(checkoutDir.fsPath); + assert.ok(repository); + }); + + test("Try get repository from repository", () => { + const repository = model.getRepository(checkoutDir.fsPath); + const repository2 = model.getRepository(repository); + assert.ok(repository2); + assert.equal(repository, repository2); + }); + + test("Try get current branch name", async () => { + const repository: Repository | undefined = model.getRepository( + checkoutDir.fsPath + ); + if (!repository) return; + + const name = await repository.getCurrentBranch(); + assert.equal(name, "trunk"); + }); + + test("Try commit file", async function() { + this.timeout(60000); + const repository: Repository | undefined = model.getRepository( + checkoutDir.fsPath + ); + if (!repository) return; + + assert.equal(repository.changes.resourceStates.length, 0); + + const file = path.join(checkoutDir.fsPath, "new.txt"); + + await repository.update(); + fs.writeFileSync(file, "test"); + + await repository.addFile(file); + + await repository.update(); + await testUtil.delay(1500); //Wait the debounce time + assert.equal(repository.changes.resourceStates.length, 1); + + const message = await repository.repository.commitFiles("First Commit", [ + file + ]); + assert.ok(/Committed revision (.*)\./i.test(message)); + + await repository.update(); + await testUtil.delay(1500); //Wait the debounce time + assert.equal(repository.changes.resourceStates.length, 0); + + const remoteContent = await repository.show(file, "HEAD"); + assert.equal(remoteContent, "test"); + }); + + test("Try switch branch", async function() { + this.timeout(60000); + const newCheckoutDir = await testUtil.createRepoCheckout( + testUtil.getSvnUrl(repoUri) + "/trunk" + ); + + await model.tryOpenRepository(newCheckoutDir.fsPath); + + const newRepository: Repository | undefined = model.getRepository( + newCheckoutDir.fsPath + ); + if (!newRepository) return; + assert.ok(newRepository); + + const isSwitched = await newRepository.branch("test"); + assert.ok(isSwitched); + + const currentBranch = await newRepository.getCurrentBranch(); + + assert.equal(currentBranch, "test"); + }); +}); diff --git a/src/test/testUtil.ts b/src/test/testUtil.ts index 30078a57..7394dd1c 100644 --- a/src/test/testUtil.ts +++ b/src/test/testUtil.ts @@ -8,6 +8,16 @@ import { SpawnOptions, ChildProcess } from "child_process"; const tempDir = os.tmpdir(); var tempDirList: string[] = []; +export function getSvnUrl(uri: Uri) { + const url = uri.toString(); + + return url.replace(/%3A/g, ":"); +} + +export function delay(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + export function spawn( command: string, args?: string[], @@ -46,7 +56,7 @@ export function newTempDir(prefix: string) { } export function createRepoServer() { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const fullpath = newTempDir("svn_server_"); const dirname = path.basename(fullpath); @@ -58,8 +68,7 @@ export function createRepoServer() { proc.once("exit", exitCode => { if (exitCode === 0) { - const url = "file:///" + fullpath.replace(/\\/g, "/"); - resolve(url); + resolve(Uri.file(fullpath)); } reject(); }); @@ -105,21 +114,21 @@ export async function createStandardLayout( } export function createRepoCheckout(url: string) { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const fullpath = newTempDir("svn_checkout_"); let proc = spawn("svn", ["checkout", url, fullpath], { cwd: tempDir }); proc.once("exit", exitCode => { if (exitCode === 0) { - resolve(fullpath); + resolve(Uri.file(fullpath)); } reject(); }); }); } -export function destroyPath(fullPath: string) { +export async function destroyPath(fullPath: string) { fullPath = fullPath.replace(/^file\:\/\/\//, ""); if (!fs.existsSync(fullPath)) { @@ -137,10 +146,14 @@ export function destroyPath(fullPath: string) { } //Error in windows with anti-malware - try { - fs.rmdirSync(fullPath); - } catch (error) { - console.error(error); + for (let i = 0; i < 3; i++) { + try { + fs.rmdirSync(fullPath); + break; + } catch (error) { + await delay(3000); + console.error(error); + } } return true; }