Skip to content

Commit 1b0ceec

Browse files
add a chai plugin to check for path equality
1 parent 6322877 commit 1b0ceec

File tree

7 files changed

+96
-37
lines changed

7 files changed

+96
-37
lines changed

test/chai-path-plugin.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the VS Code Swift open source project
4+
//
5+
// Copyright (c) 2025 the VS Code Swift project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of VS Code Swift project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
import * as path from "path";
15+
16+
declare global {
17+
// eslint-disable-next-line @typescript-eslint/no-namespace
18+
namespace Chai {
19+
interface Assertion {
20+
/**
21+
* Asserts that the object equals the expected path.
22+
*
23+
* This assertion will convert both paths to the same file separator and then
24+
* compare them to ensure consistent behavior on all platforms.
25+
*
26+
* @param expected The expected path string.
27+
*/
28+
equalPath(expected: string): Assertion;
29+
}
30+
}
31+
}
32+
33+
export function chaiPathPlugin(chai: Chai.ChaiStatic, _utils: Chai.ChaiUtils): void {
34+
chai.Assertion.addMethod("equalPath", function (expected: string) {
35+
const obj = this._obj;
36+
// First make sure the object is a string.
37+
new chai.Assertion(obj).to.be.a.string;
38+
// Then check for path equality.
39+
const expectedNormalized = normalizePath(expected);
40+
const objNormalized = normalizePath(obj);
41+
this.assert(
42+
objNormalized === expectedNormalized,
43+
`expected path "${objNormalized}" to equal "${expectedNormalized}"`,
44+
`expected path "${objNormalized}" to not equal "${expectedNormalized}"`,
45+
expectedNormalized,
46+
objNormalized
47+
);
48+
});
49+
}
50+
51+
function normalizePath(input: string): string {
52+
return normalizeWindowsDriveLetter(path.resolve(input));
53+
}
54+
55+
function normalizeWindowsDriveLetter(input: string): string {
56+
if (process.platform !== "win32") {
57+
return input;
58+
}
59+
const root = path.parse(input).root;
60+
return root.toLocaleUpperCase() + input.slice(root.length);
61+
}

test/common.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import * as sinonChai from "sinon-chai";
2121
import * as sourceMapSupport from "source-map-support";
2222
import * as tsConfigPaths from "tsconfig-paths";
2323

24+
import { chaiPathPlugin } from "./chai-path-plugin";
2425
import { installTagSupport } from "./tags";
2526

2627
// Use source-map-support to get better stack traces.
@@ -48,8 +49,11 @@ tsConfigPaths.register({
4849
paths: tsConfig.compilerOptions.paths,
4950
});
5051

52+
// Install chai plugins
5153
chai.use(sinonChai);
52-
chai.use(chaiAsPromised);
5354
chai.use(chaiSubset);
55+
chai.use(chaiPathPlugin);
56+
// chai-as-promised must always be installed last!
57+
chai.use(chaiAsPromised);
5458

5559
installTagSupport();

test/integration-tests/SwiftSnippet.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ tag("large").suite("SwiftSnippet Test Suite", function () {
7878

7979
expect(succeeded).to.be.true;
8080
const session = await sessionPromise;
81-
expect(vscode.Uri.file(session.configuration.program).fsPath).to.equal(
81+
expect(session.configuration.program).to.equalPath(
8282
realpathSync(
8383
testAssetUri(
8484
"defaultPackage/.build/debug/hello" +
@@ -118,7 +118,7 @@ tag("large").suite("SwiftSnippet Test Suite", function () {
118118
expect(succeeded).to.be.true;
119119

120120
const session = await sessionPromise;
121-
expect(vscode.Uri.file(session.configuration.program).fsPath).to.equal(
121+
expect(session.configuration.program).to.equalPath(
122122
realpathSync(
123123
testAssetUri(
124124
"defaultPackage/.build/debug/hello" +

test/integration-tests/ui/ProjectPanelProvider.test.ts

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -313,9 +313,8 @@ tag("medium").suite("ProjectPanelProvider Test Suite", function () {
313313
const dep = items.find(n => n.name === "swift-markdown") as PackageNode;
314314
expect(dep, `${JSON.stringify(items, null, 2)}`).to.not.be.undefined;
315315
expect(dep?.location).to.equal("https://github.com/swiftlang/swift-markdown.git");
316-
assertPathsEqual(
317-
dep?.path,
318-
path.join(testAssetPath("targets"), ".build/checkouts/swift-markdown")
316+
expect(dep?.path).to.equalPath(
317+
testAssetPath("targets/.build/checkouts/swift-markdown")
319318
);
320319
});
321320

@@ -326,8 +325,8 @@ tag("medium").suite("ProjectPanelProvider Test Suite", function () {
326325
dep,
327326
`Expected to find defaultPackage, but instead items were ${items.map(n => n.name)}`
328327
).to.not.be.undefined;
329-
assertPathsEqual(dep?.location, testAssetPath("defaultPackage"));
330-
assertPathsEqual(dep?.path, testAssetPath("defaultPackage"));
328+
expect(dep?.location).to.equalPath(testAssetPath("defaultPackage"));
329+
expect(dep?.path).to.equalPath(testAssetPath("defaultPackage"));
331330
});
332331

333332
test("Lists local dependency file structure", async () => {
@@ -343,24 +342,22 @@ tag("medium").suite("ProjectPanelProvider Test Suite", function () {
343342
const folder = folders.find(n => n.name === "Sources") as FileNode;
344343
expect(folder).to.not.be.undefined;
345344

346-
assertPathsEqual(folder?.path, path.join(testAssetPath("defaultPackage"), "Sources"));
345+
expect(folder?.path).to.equalPath(testAssetPath("defaultPackage/Sources"));
347346

348347
const childFolders = await treeProvider.getChildren(folder);
349348
const childFolder = childFolders.find(n => n.name === "PackageExe") as FileNode;
350349
expect(childFolder).to.not.be.undefined;
351350

352-
assertPathsEqual(
353-
childFolder?.path,
354-
path.join(testAssetPath("defaultPackage"), "Sources/PackageExe")
351+
expect(childFolder?.path).to.equalPath(
352+
testAssetPath("defaultPackage/Sources/PackageExe")
355353
);
356354

357355
const files = await treeProvider.getChildren(childFolder);
358356
const file = files.find(n => n.name === "main.swift") as FileNode;
359357
expect(file).to.not.be.undefined;
360358

361-
assertPathsEqual(
362-
file?.path,
363-
path.join(testAssetPath("defaultPackage"), "Sources/PackageExe/main.swift")
359+
expect(file?.path).to.equalPath(
360+
testAssetPath("defaultPackage/Sources/PackageExe/main.swift")
364361
);
365362
});
366363

@@ -375,19 +372,19 @@ tag("medium").suite("ProjectPanelProvider Test Suite", function () {
375372
expect(folder).to.not.be.undefined;
376373

377374
const depPath = path.join(testAssetPath("targets"), ".build/checkouts/swift-markdown");
378-
assertPathsEqual(folder?.path, path.join(depPath, "Sources"));
375+
expect(folder?.path).to.equalPath(path.join(depPath, "Sources"));
379376

380377
const childFolders = await treeProvider.getChildren(folder);
381378
const childFolder = childFolders.find(n => n.name === "CAtomic") as FileNode;
382379
expect(childFolder).to.not.be.undefined;
383380

384-
assertPathsEqual(childFolder?.path, path.join(depPath, "Sources/CAtomic"));
381+
expect(childFolder?.path).to.equalPath(path.join(depPath, "Sources/CAtomic"));
385382

386383
const files = await treeProvider.getChildren(childFolder);
387384
const file = files.find(n => n.name === "CAtomic.c") as FileNode;
388385
expect(file).to.not.be.undefined;
389386

390-
assertPathsEqual(file?.path, path.join(depPath, "Sources/CAtomic/CAtomic.c"));
387+
expect(file?.path).to.equalPath(path.join(depPath, "Sources/CAtomic/CAtomic.c"));
391388
});
392389

393390
test("Shows a flat dependency list", async () => {
@@ -501,11 +498,4 @@ tag("medium").suite("ProjectPanelProvider Test Suite", function () {
501498
throw error;
502499
}
503500
}
504-
505-
function assertPathsEqual(path1: string | undefined, path2: string | undefined) {
506-
expect(path1).to.not.be.undefined;
507-
expect(path2).to.not.be.undefined;
508-
// Convert to vscode.Uri to normalize paths, including drive letter capitalization on Windows.
509-
expect(vscode.Uri.file(path1!).fsPath).to.equal(vscode.Uri.file(path2!).fsPath);
510-
}
511501
});

test/unit-tests/tasks/SwiftPluginTaskProvider.test.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414
import * as assert from "assert";
15+
import { expect } from "chai";
1516
import * as os from "os";
16-
import * as path from "path";
1717
import { match } from "sinon";
1818
import * as vscode from "vscode";
1919

@@ -122,7 +122,7 @@ suite("SwiftPluginTaskProvider Unit Test Suite", () => {
122122
new vscode.CancellationTokenSource().token
123123
);
124124
const swiftExecution = resolvedTask.execution as SwiftExecution;
125-
assert.equal(swiftExecution.options.cwd, `${workspaceFolder.uri.fsPath}/myCWD`);
125+
expect(swiftExecution.options.cwd).to.equalPath(`${workspaceFolder.uri.fsPath}/myCWD`);
126126
});
127127

128128
test("includes scope cwd", async () => {
@@ -141,7 +141,7 @@ suite("SwiftPluginTaskProvider Unit Test Suite", () => {
141141
new vscode.CancellationTokenSource().token
142142
);
143143
const swiftExecution = resolvedTask.execution as SwiftExecution;
144-
assert.equal(swiftExecution.options.cwd, workspaceFolder.uri.fsPath);
144+
expect(swiftExecution.options.cwd).to.equalPath(workspaceFolder.uri.fsPath);
145145
});
146146

147147
test("includes resolved cwd", async () => {
@@ -161,10 +161,7 @@ suite("SwiftPluginTaskProvider Unit Test Suite", () => {
161161
new vscode.CancellationTokenSource().token
162162
);
163163
const swiftExecution = resolvedTask.execution as SwiftExecution;
164-
assert.equal(
165-
swiftExecution.options.cwd,
166-
path.normalize(`${workspaceFolder.uri.fsPath}/myCWD`)
167-
);
164+
expect(swiftExecution.options.cwd).to.equalPath(`${workspaceFolder.uri.fsPath}/myCWD`);
168165
});
169166

170167
test("includes fallback cwd", async () => {

test/unit-tests/tasks/SwiftTaskProvider.test.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414
import * as assert from "assert";
15+
import { expect } from "chai";
1516
import * as os from "os";
1617
import { match } from "sinon";
1718
import * as vscode from "vscode";
@@ -379,7 +380,9 @@ suite("SwiftTaskProvider Unit Test Suite", () => {
379380
new vscode.CancellationTokenSource().token
380381
);
381382
const swiftExecution = resolvedTask.execution as SwiftExecution;
382-
assert.equal(swiftExecution.options.cwd, `${workspaceFolder.uri.fsPath}/macos`);
383+
expect(swiftExecution.options.cwd).to.equalPath(
384+
`${workspaceFolder.uri.fsPath}/macos`
385+
);
383386
});
384387

385388
test("includes linux cwd", () => {
@@ -403,7 +406,9 @@ suite("SwiftTaskProvider Unit Test Suite", () => {
403406
new vscode.CancellationTokenSource().token
404407
);
405408
const swiftExecution = resolvedTask.execution as SwiftExecution;
406-
assert.equal(swiftExecution.options.cwd, `${workspaceFolder.uri.fsPath}/linux`);
409+
expect(swiftExecution.options.cwd).to.equalPath(
410+
`${workspaceFolder.uri.fsPath}/linux`
411+
);
407412
});
408413

409414
test("includes windows cwd", () => {
@@ -427,7 +432,9 @@ suite("SwiftTaskProvider Unit Test Suite", () => {
427432
new vscode.CancellationTokenSource().token
428433
);
429434
const swiftExecution = resolvedTask.execution as SwiftExecution;
430-
assert.equal(swiftExecution.options.cwd, `${workspaceFolder.uri.fsPath}/windows`);
435+
expect(swiftExecution.options.cwd).to.equalPath(
436+
`${workspaceFolder.uri.fsPath}/windows`
437+
);
431438
});
432439

433440
test("fallback default cwd", () => {
@@ -451,7 +458,7 @@ suite("SwiftTaskProvider Unit Test Suite", () => {
451458
new vscode.CancellationTokenSource().token
452459
);
453460
const swiftExecution = resolvedTask.execution as SwiftExecution;
454-
assert.equal(swiftExecution.options.cwd, workspaceFolder.uri.fsPath);
461+
expect(swiftExecution.options.cwd).to.equalPath(workspaceFolder.uri.fsPath);
455462
});
456463
});
457464

test/unit-tests/toolchain/BuildFlags.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ suite("BuildFlags Test Suite", () => {
554554
const result = await buildFlags.getBuildBinaryPath("/test/workspace", "debug", log);
555555

556556
// Should fallback to traditional path
557-
expect(result).to.equal(path.normalize("/test/workspace/.build/debug"));
557+
expect(result).to.equalPath("/test/workspace/.build/debug");
558558
expect(log.warn).to.have.been.calledOnce;
559559
});
560560

0 commit comments

Comments
 (0)