Use case-insensitive path comparison on Windows

This commit is contained in:
Koen Vlaswinkel
2022-12-23 14:01:30 +01:00
committed by Koen Vlaswinkel
parent 477b32662f
commit 6bf19eb52f
5 changed files with 176 additions and 11 deletions

View File

@@ -21,6 +21,7 @@ import { DisposableObject } from "./pure/disposable-object";
import { Logger, extLogger } from "./common";
import { getErrorMessage } from "./pure/helpers-pure";
import { QueryRunner } from "./queryRunner";
import { pathsEqual } from "./pure/files";
/**
* databases.ts
@@ -523,7 +524,11 @@ export class DatabaseItemImpl implements DatabaseItem {
// database for /one/two/three/test.ql is at /one/two/three/three.testproj
const testdir = dirname(testPath);
const testdirbase = basename(testdir);
return databasePath == join(testdir, `${testdirbase}.testproj`);
return pathsEqual(
databasePath,
join(testdir, `${testdirbase}.testproj`),
process.platform,
);
}
} catch {
// No information available for test path - assume database is unaffected.

View File

@@ -1,5 +1,5 @@
import { pathExists, stat, readdir } from "fs-extra";
import { join } from "path";
import { join, resolve } from "path";
/**
* Recursively finds all .ql files in this set of Uris.
@@ -50,3 +50,20 @@ export async function getDirectoryNamesInsidePath(
return dirNames;
}
export function pathsEqual(
path1: string,
path2: string,
platform: NodeJS.Platform,
): boolean {
// On Windows, "C:/", "C:\", and "c:/" are all equivalent. We need
// to normalize the paths to ensure they all get resolved to the
// same format. On Windows, we also need to do the comparison
// case-insensitively.
path1 = resolve(path1);
path2 = resolve(path2);
if (platform === "win32") {
return path1.toLowerCase() === path2.toLowerCase();
}
return path1 === path2;
}

View File

@@ -0,0 +1,53 @@
import { expect } from "@jest/globals";
import type { MatcherFunction } from "expect";
import { pathsEqual } from "../../src/pure/files";
// eslint-disable-next-line func-style -- We need to have access to this and specify the type of the function
const toEqualPath: MatcherFunction<[expectedPath: unknown]> = function (
actual,
expectedPath,
) {
if (typeof actual !== "string" || typeof expectedPath !== "string") {
throw new Error("These must be of type string!");
}
const pass = pathsEqual(actual, expectedPath, process.platform);
if (pass) {
return {
message: () =>
// eslint-disable-next-line @typescript-eslint/no-invalid-this
`expected ${this.utils.printReceived(
actual,
// eslint-disable-next-line @typescript-eslint/no-invalid-this
)} to equal path ${this.utils.printExpected(expectedPath)}`,
pass: true,
};
} else {
return {
message: () =>
// eslint-disable-next-line @typescript-eslint/no-invalid-this
`expected ${this.utils.printReceived(
actual,
// eslint-disable-next-line @typescript-eslint/no-invalid-this
)} to equal path ${this.utils.printExpected(expectedPath)}`,
pass: false,
};
}
};
expect.extend({
toEqualPath,
});
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace -- We need to extend this global declaration
namespace jest {
interface AsymmetricMatchers {
toEqualPath(expectedPath: string): void;
}
interface Matchers<R> {
toEqualPath(expectedPath: string): R;
}
}
}

View File

@@ -3,6 +3,7 @@ import { join } from "path";
import {
gatherQlFiles,
getDirectoryNamesInsidePath,
pathsEqual,
} from "../../../src/pure/files";
describe("files", () => {
@@ -100,3 +101,90 @@ describe("files", () => {
});
});
});
describe("pathsEqual", () => {
const testCases: Array<{
path1: string;
path2: string;
platform: NodeJS.Platform;
expected: boolean;
}> = [
{
path1:
"/home/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
path2:
"/home/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
platform: "linux",
expected: true,
},
{
path1:
"/HOME/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
path2:
"/home/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
platform: "linux",
expected: false,
},
{
path1:
"/home/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
path2:
"\\home\\github\\projects\\vscode-codeql-starter\\codeql-custom-queries-javascript\\example.ql",
platform: "linux",
expected: false,
},
{
path1:
"C:/Users/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
path2:
"C:/Users/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
platform: "win32",
expected: true,
},
{
path1:
"C:/Users/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
path2:
"c:/Users/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
platform: "win32",
expected: true,
},
{
path1:
"C:/Users/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
path2:
"D:/Users/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
platform: "win32",
expected: false,
},
{
path1:
"C:/Users/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
path2:
"C:\\Users\\github\\projects\\vscode-codeql-starter\\codeql-custom-queries-javascript\\example.ql",
platform: "win32",
expected: true,
},
{
path1:
"C:/Users/github/projects/vscode-codeql-starter/codeql-custom-queries-javascript/example.ql",
path2:
"D:\\Users\\github\\projects\\vscode-codeql-starter\\codeql-custom-queries-javascript\\example.ql",
platform: "win32",
expected: false,
},
];
test.each(testCases)(
"$path1 and $path2 are equal on $platform = $expected",
({ path1, path2, platform, expected }) => {
if (platform !== process.platform) {
// We're using the platform-specific path.resolve, so we can't really run
// these tests on all platforms.
return;
}
expect(pathsEqual(path1, path2, platform)).toEqual(expected);
},
);
});

View File

@@ -6,6 +6,8 @@ import { QLTestDiscovery } from "../../../src/qltest-discovery";
import { DirectoryResult } from "tmp-promise";
import * as tmp from "tmp-promise";
import "../../matchers/toEqualPath";
describe("qltest-discovery", () => {
describe("discoverTests", () => {
let directory: DirectoryResult;
@@ -50,30 +52,30 @@ describe("qltest-discovery", () => {
it("should run discovery", async () => {
const result = await (qlTestDiscover as any).discover();
expect(result.watchPath).toBe(baseDir);
expect(result.testDirectory.path).toBe(baseDir);
expect(result.watchPath).toEqualPath(baseDir);
expect(result.testDirectory.path).toEqualPath(baseDir);
expect(result.testDirectory.name).toBe("My tests");
let children = result.testDirectory.children;
expect(children.length).toBe(1);
expect(children[0].path).toBe(cDir);
expect(children[0].path).toEqualPath(cDir);
expect(children[0].name).toBe("c");
children = children[0].children;
expect(children.length).toBe(3);
expect(children[0].path).toBe(dFile);
expect(children[0].path).toEqualPath(dFile);
expect(children[0].name).toBe("d.ql");
expect(children[1].path).toBe(eFile);
expect(children[1].path).toEqualPath(eFile);
expect(children[1].name).toBe("e.ql");
// A merged foler
expect(children[2].path).toBe(hDir);
expect(children[2].path).toEqualPath(hDir);
expect(children[2].name).toBe("f / g / h");
children = children[2].children;
expect(children[0].path).toBe(iFile);
expect(children[0].path).toEqualPath(iFile);
expect(children[0].name).toBe("i.ql");
});
@@ -81,8 +83,8 @@ describe("qltest-discovery", () => {
await fs.remove(baseDir);
const result = await (qlTestDiscover as any).discover();
expect(result.watchPath).toBe(baseDir);
expect(result.testDirectory.path).toBe(baseDir);
expect(result.watchPath).toEqualPath(baseDir);
expect(result.testDirectory.path).toEqualPath(baseDir);
expect(result.testDirectory.name).toBe("My tests");
expect(result.testDirectory.children.length).toBe(0);