Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TypeSpecValidation] bug fix: drive letter inconsistency for windows #27002

Merged
merged 4 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions eng/tools/typespec-validation/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { access } from "fs/promises";
import { exec } from "child_process";
import path from "path";
import defaultPath, { PlatformPath } from "path";

export async function runCmd(cmd: string, cwd: string) {
console.log(`run command:${cmd}`);
Expand All @@ -22,6 +22,10 @@ export async function checkFileExists(file: string) {
.catch(() => false);
}

export function normalizePath(folder: string) {
return path.resolve(folder).split(path.sep).join("/");
export function normalizePath(folder: string, path: PlatformPath = defaultPath) {
return path
.resolve(folder)
.split(path.sep)
.join("/")
.replace(/^([a-z]):/, (_match, driveLetter) => driveLetter.toUpperCase() + ":");
}
68 changes: 68 additions & 0 deletions eng/tools/typespec-validation/test/npm-prefix.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { NpmPrefixRule } from "../src/rules/npm-prefix.js";
import { IGitOperation, TsvTestHost } from "./tsv-test-host.js";
import { strict as assert } from "node:assert";
import path from "path";

describe("npm-prefix", function () {
it("should succeed if node returns inconsistent drive letter capitalization", async function () {
let host = new TsvTestHost(path.win32);
host.runCmd = async (cmd: string, _cwd: string): Promise<[Error | null, string, string]> => {
if (cmd.includes("npm prefix")) {
return [null, `C:${path.sep}Git${path.sep}azure-rest-api-specs`, ""];
} else {
return [null, "", ""];
}
};
host.gitOperation = (_folder: string): IGitOperation => {
return {
status: () => {
return Promise.resolve({
modified: [],
isClean: () => true,
});
},
diff: () => {
return Promise.resolve("");
},
revparse: () => {
return Promise.resolve("c:/Git/azure-rest-api-specs");
},
};
};

const result = await new NpmPrefixRule().execute(host, TsvTestHost.folder);

assert(result.success);
});

it("should fail if npm prefix mismatch", async function () {
let host = new TsvTestHost();
host.runCmd = async (cmd: string, _cwd: string): Promise<[Error | null, string, string]> => {
if (cmd.includes("npm prefix")) {
return [null, "/Git/azure-rest-api-specs/specification/foo", ""];
} else {
return [null, "", ""];
}
};
host.gitOperation = (_folder: string): IGitOperation => {
return {
status: () => {
return Promise.resolve({
modified: [],
isClean: () => true,
});
},
diff: () => {
return Promise.resolve("");
},
revparse: () => {
return Promise.resolve("/Git/azure-rest-api-specs");
},
};
};

const result = await new NpmPrefixRule().execute(host, TsvTestHost.folder);

assert(!result.success);
});
});
11 changes: 10 additions & 1 deletion eng/tools/typespec-validation/test/tsv-test-host.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { IGitOperation, TsvHost } from "../src/tsv-host.js";
import { normalizePath } from "../src/utils.js";
import defaultPath, { PlatformPath } from "path";

export { IGitOperation } from "../src/tsv-host.js";

export class TsvTestHost implements TsvHost {
path: PlatformPath;

constructor(path: PlatformPath = defaultPath) {
this.path = path;
}

static get folder() {
return "specification/foo/Foo";
}
Expand Down Expand Up @@ -36,7 +45,7 @@ export class TsvTestHost implements TsvHost {
}

normalizePath(folder: string): string {
return normalizePath(folder);
return normalizePath(folder, this.path);
}

async readTspConfig(_folder: string): Promise<string> {
Expand Down
27 changes: 16 additions & 11 deletions eng/tools/typespec-validation/test/util.test.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import { TsvTestHost } from "./tsv-test-host.js";
import { normalizePath } from "../src/utils.js";
import { strict as assert } from "node:assert";
import process from "process";
import path from "path";

describe("normalize", function () {
it("should succeed if normalized . and normalized cwd matches", async function () {
let host = new TsvTestHost();
const dotResult = host.normalizePath(".");
const cwdResult = host.normalizePath(process.cwd());
const dotResult = normalizePath(".");
const cwdResult = normalizePath(process.cwd());
assert(dotResult === cwdResult);
});

it("should succeed if /foo/bar/ is normalized", async function () {
let host = new TsvTestHost();
const result = host.normalizePath("/foo/bar/").replace(/^[a-zA-Z]:/g, "");
assert(result === "/foo/bar");
const result = normalizePath("/foo/bar/", path.posix);
assert.equal(result, "/foo/bar");
});

it("should succeed if /foo/bar is normalized", async function () {
let host = new TsvTestHost();
const result = host.normalizePath("/foo/bar").replace(/^[a-zA-Z]:/g, "");
assert(result === "/foo/bar");
it("should normalize windows drive letter", async function () {
const lowerResult = normalizePath("c:\\foo\\bar", path.win32);
const upperResult = normalizePath("C:\\foo\\bar", path.win32);
assert.equal(lowerResult, upperResult);
});

it("should distinguish different windows drive letters", async function () {
const lowerResult = normalizePath("c:\\foo\\bar", path.win32);
const upperResult = normalizePath("d:\\foo\\bar", path.win32);
assert.notEqual(lowerResult, upperResult);
});
});