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

Covert some of the config testing to baselines for easy validation #51063

Merged
merged 4 commits into from Oct 5, 2022
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.
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
22 changes: 11 additions & 11 deletions src/server/project.ts
Expand Up @@ -1605,6 +1605,7 @@ namespace ts.server {
}

protected enableGlobalPlugins(options: CompilerOptions, pluginConfigOverrides: Map<any> | undefined): void {
if (!this.projectService.globalPlugins.length) return;
const host = this.projectService.host;

if (!host.require && !host.importPlugin) {
Expand All @@ -1619,20 +1620,18 @@ namespace ts.server {
combinePaths(this.projectService.getExecutingFilePath(), "../../.."),
];

if (this.projectService.globalPlugins) {
// Enable global plugins with synthetic configuration entries
for (const globalPluginName of this.projectService.globalPlugins) {
// Skip empty names from odd commandline parses
if (!globalPluginName) continue;
// Enable global plugins with synthetic configuration entries
for (const globalPluginName of this.projectService.globalPlugins) {
// Skip empty names from odd commandline parses
if (!globalPluginName) continue;

// Skip already-locally-loaded plugins
if (options.plugins && options.plugins.some(p => p.name === globalPluginName)) continue;
// Skip already-locally-loaded plugins
if (options.plugins && options.plugins.some(p => p.name === globalPluginName)) continue;

// Provide global: true so plugins can detect why they can't find their config
this.projectService.logger.info(`Loading global plugin ${globalPluginName}`);
// Provide global: true so plugins can detect why they can't find their config
this.projectService.logger.info(`Loading global plugin ${globalPluginName}`);

this.enablePlugin({ name: globalPluginName, global: true } as PluginImport, searchPaths, pluginConfigOverrides);
}
this.enablePlugin({ name: globalPluginName, global: true } as PluginImport, searchPaths, pluginConfigOverrides);
}
}

Expand Down Expand Up @@ -2521,6 +2520,7 @@ namespace ts.server {

/*@internal*/
enablePluginsWithOptions(options: CompilerOptions, pluginConfigOverrides: ESMap<string, any> | undefined): void {
if (!options.plugins?.length && !this.projectService.globalPlugins.length) return;
const host = this.projectService.host;
if (!host.require && !host.importPlugin) {
this.projectService.logger.info("Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded");
Expand Down
1,107 changes: 147 additions & 960 deletions src/testRunner/unittests/config/commandLineParsing.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/testRunner/unittests/config/initializeTSConfig.ts
Expand Up @@ -4,7 +4,7 @@ namespace ts {
describe(name, () => {
const commandLine = parseCommandLine(commandLinesArgs);
const initResult = generateTSConfig(commandLine.options, commandLine.fileNames, "\n");
const outputFileName = `tsConfig/${name.replace(/[^a-z0-9\-. ]/ig, "")}/tsconfig.json`;
const outputFileName = `config/initTSConfig/${name.replace(/[^a-z0-9\-. ]/ig, "")}/tsconfig.json`;

it(`Correct output for ${outputFileName}`, () => {
Harness.Baseline.runBaseline(outputFileName, initResult, { PrintDiff: true });
Expand Down
2 changes: 1 addition & 1 deletion src/testRunner/unittests/config/showConfig.ts
Expand Up @@ -2,7 +2,7 @@ namespace ts {
describe("unittests:: config:: showConfig", () => {
function showTSConfigCorrectly(name: string, commandLinesArgs: string[], configJson?: object) {
describe(name, () => {
const outputFileName = `showConfig/${name.replace(/[^a-z0-9\-./ ]/ig, "")}/tsconfig.json`;
const outputFileName = `config/showConfig/${name.replace(/[^a-z0-9\-./ ]/ig, "")}/tsconfig.json`;

it(`Correct output for ${outputFileName}`, () => {
const cwd = `/${name}`;
Expand Down
274 changes: 108 additions & 166 deletions src/testRunner/unittests/config/tsconfigParsingWatchOptions.ts
Expand Up @@ -42,190 +42,132 @@ namespace ts {

interface VerifyWatchOptions {
json: object;
expectedOptions: WatchOptions | undefined;
additionalFiles?: vfs.FileSet;
existingWatchOptions?: WatchOptions | undefined;
expectedErrors?: (sourceFile?: SourceFile) => Diagnostic[];
}

function verifyWatchOptions(scenario: () => VerifyWatchOptions[]) {
it("with json api", () => {
for (const { json, expectedOptions, additionalFiles, existingWatchOptions, expectedErrors } of scenario()) {
const parsed = getParsedCommandJson(json, additionalFiles, existingWatchOptions);
assert.deepEqual(parsed.watchOptions, expectedOptions, `With ${JSON.stringify(json)}`);
if (length(parsed.errors)) {
assert.deepEqual(parsed.errors, expectedErrors?.());
function verifyWatchOptions(subScenario: string, scenario: () => VerifyWatchOptions[]) {
describe(subScenario, () => {
it("with json api", () => {
const baseline: string[] = [];
for (const { json, additionalFiles, existingWatchOptions } of scenario()) {
addToBaseLine(baseline, json, getParsedCommandJson(json, additionalFiles, existingWatchOptions));
}
else {
assert.equal(0, length(expectedErrors?.()), `Expected no errors`);
}
}
});
runBaseline(`${subScenario} with json api`, baseline);
});

it("with json source file api", () => {
for (const { json, expectedOptions, additionalFiles, existingWatchOptions, expectedErrors } of scenario()) {
const parsed = getParsedCommandJsonNode(json, additionalFiles, existingWatchOptions);
assert.deepEqual(parsed.watchOptions, expectedOptions);
if (length(parsed.errors)) {
assert.deepEqual(parsed.errors, expectedErrors?.(parsed.options.configFile));
}
else {
assert.equal(0, length(expectedErrors?.(parsed.options.configFile)), `Expected no errors`);
it("with json source file api", () => {
const baseline: string[] = [];
for (const { json, additionalFiles, existingWatchOptions, } of scenario()) {
addToBaseLine(baseline, json, getParsedCommandJsonNode(json, additionalFiles, existingWatchOptions));
}
}
runBaseline(`${subScenario} with jsonSourceFile api`, baseline);
});
});
function addToBaseLine(baseline: string[], json: object, parsed: ParsedCommandLine) {
baseline.push(`Input:: ${JSON.stringify(json, /*replacer*/ undefined, " ")}`);
baseline.push(`Result: WatchOptions::`);
baseline.push(JSON.stringify(parsed.watchOptions, /*replacer*/ undefined, " "));
baseline.push(`Result: Errors::`);
baseline.push(formatDiagnosticsWithColorAndContext(parsed.errors, {
getCurrentDirectory: () => "/",
getCanonicalFileName: identity,
getNewLine: () => "\n"
}));
}
function runBaseline(subScenario: string, baseline: readonly string[]) {
Harness.Baseline.runBaseline(`config/tsconfigParsingWatchOptions/${subScenario}.js`, baseline.join("\n"));
}
}

describe("no watchOptions specified option", () => {
verifyWatchOptions(() => [{
json: {},
expectedOptions: undefined
}]);
});
verifyWatchOptions("no watchOptions specified option", () => [{
json: {},
}]);

describe("empty watchOptions specified option", () => {
verifyWatchOptions(() => [{
json: { watchOptions: {} },
expectedOptions: undefined
}]);
});
verifyWatchOptions("empty watchOptions specified option", () => [{
json: { watchOptions: {} },
}]);

describe("extending config file", () => {
describe("when extending config file without watchOptions", () => {
verifyWatchOptions(() => [
{
json: {
extends: "./base.json",
watchOptions: { watchFile: "UseFsEvents" }
},
expectedOptions: { watchFile: WatchFileKind.UseFsEvents },
additionalFiles: { "/base.json": "{}" }
},
{
json: { extends: "./base.json", },
expectedOptions: undefined,
additionalFiles: { "/base.json": "{}" }
}
]);
});
verifyWatchOptions("when extending config file without watchOptions", () => [
{
json: {
extends: "./base.json",
watchOptions: { watchFile: "UseFsEvents" }
},
additionalFiles: { "/base.json": "{}" }
},
{
json: { extends: "./base.json", },
additionalFiles: { "/base.json": "{}" }
}
]);

describe("when extending config file with watchOptions", () => {
verifyWatchOptions(() => [
{
json: {
extends: "./base.json",
watchOptions: {
watchFile: "UseFsEvents",
}
},
expectedOptions: {
watchFile: WatchFileKind.UseFsEvents,
watchDirectory: WatchDirectoryKind.FixedPollingInterval
},
additionalFiles: {
"/base.json": JSON.stringify({
watchOptions: {
watchFile: "UseFsEventsOnParentDirectory",
watchDirectory: "FixedPollingInterval"
}
})
}
},
{
json: {
extends: "./base.json",
},
expectedOptions: {
watchFile: WatchFileKind.UseFsEventsOnParentDirectory,
watchDirectory: WatchDirectoryKind.FixedPollingInterval
},
additionalFiles: {
"/base.json": JSON.stringify({
watchOptions: {
watchFile: "UseFsEventsOnParentDirectory",
watchDirectory: "FixedPollingInterval"
}
})
}
verifyWatchOptions("when extending config file with watchOptions", () => [
{
json: {
extends: "./base.json",
watchOptions: {
watchFile: "UseFsEvents",
}
]);
});
});

describe("different options", () => {
verifyWatchOptions(() => [
{
json: { watchOptions: { watchFile: "UseFsEvents" } },
expectedOptions: { watchFile: WatchFileKind.UseFsEvents }
},
{
json: { watchOptions: { watchDirectory: "UseFsEvents" } },
expectedOptions: { watchDirectory: WatchDirectoryKind.UseFsEvents }
},
{
json: { watchOptions: { fallbackPolling: "DynamicPriority" } },
expectedOptions: { fallbackPolling: PollingWatchKind.DynamicPriority }
},
{
json: { watchOptions: { synchronousWatchDirectory: true } },
expectedOptions: { synchronousWatchDirectory: true }
},
{
json: { watchOptions: { excludeDirectories: ["**/temp"] } },
expectedOptions: { excludeDirectories: ["/**/temp"] }
},
{
json: { watchOptions: { excludeFiles: ["**/temp/*.ts"] } },
expectedOptions: { excludeFiles: ["/**/temp/*.ts"] }
},
{
json: { watchOptions: { excludeDirectories: ["**/../*"] } },
expectedOptions: { excludeDirectories: [] },
expectedErrors: sourceFile => [
{
messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`,
category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category,
code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code,
file: sourceFile,
start: sourceFile && sourceFile.text.indexOf(`"**/../*"`),
length: sourceFile && `"**/../*"`.length,
reportsDeprecated: undefined,
reportsUnnecessary: undefined
additionalFiles: {
"/base.json": JSON.stringify({
watchOptions: {
watchFile: "UseFsEventsOnParentDirectory",
watchDirectory: "FixedPollingInterval"
}
]
})
}
},
{
json: {
extends: "./base.json",
},
{
json: { watchOptions: { excludeFiles: ["**/../*"] } },
expectedOptions: { excludeFiles: [] },
expectedErrors: sourceFile => [
{
messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`,
category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category,
code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code,
file: sourceFile,
start: sourceFile && sourceFile.text.indexOf(`"**/../*"`),
length: sourceFile && `"**/../*"`.length,
reportsDeprecated: undefined,
reportsUnnecessary: undefined
additionalFiles: {
"/base.json": JSON.stringify({
watchOptions: {
watchFile: "UseFsEventsOnParentDirectory",
watchDirectory: "FixedPollingInterval"
}
]
},
]);
});
})
}
}
]);

describe("watch options extending passed in watch options", () => {
verifyWatchOptions(() => [
{
json: { watchOptions: { watchFile: "UseFsEvents" } },
expectedOptions: { watchFile: WatchFileKind.UseFsEvents, watchDirectory: WatchDirectoryKind.FixedPollingInterval },
existingWatchOptions: { watchDirectory: WatchDirectoryKind.FixedPollingInterval }
},
{
json: {},
expectedOptions: { watchDirectory: WatchDirectoryKind.FixedPollingInterval },
existingWatchOptions: { watchDirectory: WatchDirectoryKind.FixedPollingInterval }
},
]);
});
verifyWatchOptions("different options", () => [
{
json: { watchOptions: { watchFile: "UseFsEvents" } },
},
{
json: { watchOptions: { watchDirectory: "UseFsEvents" } },
},
{
json: { watchOptions: { fallbackPolling: "DynamicPriority" } },
},
{
json: { watchOptions: { synchronousWatchDirectory: true } },
},
{
json: { watchOptions: { excludeDirectories: ["**/temp"] } },
},
{
json: { watchOptions: { excludeFiles: ["**/temp/*.ts"] } },
},
{
json: { watchOptions: { excludeDirectories: ["**/../*"] } },
},
{
json: { watchOptions: { excludeFiles: ["**/../*"] } },
},
]);

verifyWatchOptions("watch options extending passed in watch options", () => [
{
json: { watchOptions: { watchFile: "UseFsEvents" } },
},
{
json: {},
},
]);
});
}
2 changes: 1 addition & 1 deletion src/testRunner/unittests/tsserver/configuredProjects.ts
Expand Up @@ -577,7 +577,7 @@ namespace ts.projectSystem {
content: "let zz = 1;"
};
host.writeFile(file5.path, file5.content);
projectService.baselineHost("File5 written");
projectService.testhost.baselineHost("File5 written");
projectService.openClientFile(file5.path);

baselineTsserverLogs("configuredProjects", "Open ref of configured project when open file gets added to the project as part of configured file update", projectService);
Expand Down