diff --git a/extensions/git/src/test/git.test.ts b/extensions/git/src/test/git.test.ts index b9c08fb907fa0..51042a9a845aa 100644 --- a/extensions/git/src/test/git.test.ts +++ b/extensions/git/src/test/git.test.ts @@ -6,7 +6,7 @@ import 'mocha'; import { GitStatusParser, parseGitCommits, parseGitmodules, parseLsTree, parseLsFiles, parseGitRemotes, parseCoAuthors } from '../git'; import * as assert from 'assert'; -import { splitInChunks } from '../util'; +import { splitInChunks, isDescendant, pathEquals, relativePath } from '../util'; suite('git', () => { suite('GitStatusParser', () => { @@ -644,6 +644,90 @@ suite('git', () => { }); }); + suite('isDescendant', () => { + test('regular paths (posix)', function () { + if (process.platform !== 'win32') { + assert.strictEqual(isDescendant('/foo', '/foo/bar'), true); + assert.strictEqual(isDescendant('/foo/', '/foo/bar'), true); + assert.strictEqual(isDescendant('/foo', '/bar/baz'), false); + assert.strictEqual(isDescendant('/foo', '/foo'), true); + } + }); + + test('root path "/" (chroot environments)', function () { + if (process.platform !== 'win32') { + assert.strictEqual(isDescendant('/', '/foo'), true); + assert.strictEqual(isDescendant('/', '/foo/bar'), true); + assert.strictEqual(isDescendant('/', '/'), true); + } + }); + + test('regular paths (win32)', function () { + if (process.platform === 'win32') { + assert.strictEqual(isDescendant('C:\\foo', 'C:\\foo\\bar'), true); + assert.strictEqual(isDescendant('C:\\foo\\', 'C:\\foo\\bar'), true); + assert.strictEqual(isDescendant('C:\\foo', 'C:\\bar\\baz'), false); + assert.strictEqual(isDescendant('C:\\foo', 'C:\\foo'), true); + } + }); + + test('drive root "C:\\" (win32)', function () { + if (process.platform === 'win32') { + assert.strictEqual(isDescendant('C:\\', 'C:\\foo'), true); + assert.strictEqual(isDescendant('C:\\', 'C:\\foo\\bar'), true); + assert.strictEqual(isDescendant('C:\\', 'C:\\'), true); + } + }); + }); + + suite('pathEquals', () => { + test('regular paths (posix)', function () { + if (process.platform !== 'win32') { + assert.strictEqual(pathEquals('/foo', '/foo'), true); + assert.strictEqual(pathEquals('/foo/', '/foo'), true); + assert.strictEqual(pathEquals('/foo', '/bar'), false); + } + }); + + test('root path "/"', function () { + if (process.platform !== 'win32') { + assert.strictEqual(pathEquals('/', '/'), true); + assert.strictEqual(pathEquals('/', '/foo'), false); + } + }); + + test('regular paths (win32)', function () { + if (process.platform === 'win32') { + assert.strictEqual(pathEquals('C:\\foo', 'C:\\foo'), true); + assert.strictEqual(pathEquals('C:\\foo\\', 'C:\\foo'), true); + assert.strictEqual(pathEquals('C:\\foo', 'C:\\bar'), false); + } + }); + + test('drive root "C:\\" (win32)', function () { + if (process.platform === 'win32') { + assert.strictEqual(pathEquals('C:\\', 'C:\\'), true); + assert.strictEqual(pathEquals('C:\\', 'C:\\foo'), false); + } + }); + }); + + suite('relativePath', () => { + test('root path "/" as base (chroot environments)', function () { + if (process.platform !== 'win32') { + assert.strictEqual(relativePath('/', '/foo'), 'foo'); + assert.strictEqual(relativePath('/', '/foo/bar'), 'foo/bar'); + } + }); + + test('drive root "C:\\" as base (win32)', function () { + if (process.platform === 'win32') { + assert.strictEqual(relativePath('C:\\', 'C:\\foo'), 'foo'); + assert.strictEqual(relativePath('C:\\', 'C:\\foo\\bar'), 'foo\\bar'); + } + }); + }); + suite('splitInChunks', () => { test('unit tests', function () { assert.deepStrictEqual( diff --git a/extensions/git/src/util.ts b/extensions/git/src/util.ts index dfe3c4e07757d..0b8c2eb4d8d77 100644 --- a/extensions/git/src/util.ts +++ b/extensions/git/src/util.ts @@ -312,9 +312,9 @@ function normalizePath(path: string): string { path = path.toLowerCase(); } - // Trailing separator - if (/[/\\]$/.test(path)) { - // Remove trailing separator + // Trailing separator — only strip when the path is not + // a filesystem root (e.g., "/" on POSIX, "C:\" or UNC roots on Windows). + if (/[/\\]$/.test(path) && path !== dirname(path)) { path = path.substring(0, path.length - 1); }