Make canUseWatchEvents test framework more generic so we can add more tests easily (#58962)

This commit is contained in:
Sheetal Nandi
2024-06-25 10:19:01 -07:00
committed by GitHub
parent b3840541a9
commit f2f91ccc64
6 changed files with 1433 additions and 1075 deletions

View File

@@ -1,3 +1,4 @@
import path from "path";
import { incrementalVerifier } from "../../../harness/incrementalUtils.js";
import { patchServiceForStateBaseline } from "../../../harness/projectServiceStateLogger.js";
import {
@@ -67,6 +68,130 @@ export function patchHostTimeouts(
}
}
function patchSessionToHandleWatchEvents(session: TestSession) {
const event = session.event;
const idToClose = new Map<number, () => void>();
session.event = (data, eventName) => {
event.call(session, data, eventName);
switch (eventName) {
case ts.server.CreateFileWatcherEvent:
watchFile(data as ts.server.protocol.CreateFileWatcherEventBody);
break;
case ts.server.CreateDirectoryWatcherEvent:
watchDirectory(data as ts.server.protocol.CreateDirectoryWatcherEventBody);
break;
case ts.server.CloseFileWatcherEvent:
closeWatcher(data as ts.server.protocol.CloseFileWatcherEventBody);
break;
default:
break;
}
};
function watchFile(event: ts.server.protocol.CreateFileWatcherEventBody) {
createWatcher(
"watchFile",
event,
recordChange =>
session.host.watchUtils.pollingWatch(
session.host.toNormalizedAbsolutePath(event.path),
{
cb: (fileName, eventKind) =>
recordChange(
event.id,
session.host.windowsStyleRoot ?
path.win32.resolve(fileName) :
path.posix.resolve(fileName),
eventKind === ts.FileWatcherEventKind.Created ?
"created" :
eventKind === ts.FileWatcherEventKind.Deleted ? "deleted" : "updated",
/*ignoreUpdate*/ false,
),
pollingInterval: undefined!,
event,
},
),
);
}
function watchDirectory(event: ts.server.protocol.CreateDirectoryWatcherEventBody) {
createWatcher(
"watchDirectory",
event,
recordChange =>
session.host.watchUtils.fsWatch(
session.host.toNormalizedAbsolutePath(event.path),
event.recursive,
{
cb: (eventName, relativeFileName) => {
if (!relativeFileName) return;
const fileName = session.host.windowsStyleRoot ?
path.win32.join(event.path, relativeFileName) :
path.posix.join(event.path, relativeFileName);
if (eventName === "change") {
recordChange(
event.id,
fileName,
"updated",
!!event.ignoreUpdate,
);
}
else {
recordChange(
event.id,
fileName,
session.host.fileExists(fileName) || session.host.directoryExists(fileName) ?
"created" :
"deleted",
!!event.ignoreUpdate,
);
}
},
inode: undefined,
event,
},
),
);
}
function createWatcher(
watchType: string,
event: ts.server.protocol.CreateFileWatcherEventBody | ts.server.protocol.CreateDirectoryWatcherEventBody,
create: (
recordChange: (
id: number,
file: string,
eventType: "created" | "deleted" | "updated",
ignoreUpdate: boolean,
) => void,
) => ts.FileWatcher,
) {
session.logger.log(`Custom ${watchType}:: Added:: ${JSON.stringify(event)}`);
ts.Debug.assert(!idToClose.has(event.id));
const result = create((id, file, eventType, ignoreUpdate) => {
const ignored = eventType === "updated" && ignoreUpdate;
session.logger.log(`Custom ${watchType}:: Triggered${ignoreUpdate ? " Ignored" : ""}:: ${JSON.stringify(event)}:: ${file} ${eventType}`);
if (!ignored) {
let watchChange = session.watchChanges.get(id);
if (!watchChange) session.watchChanges.set(id, watchChange = { id });
(watchChange[eventType] ??= []).push(file);
}
});
idToClose.set(event.id, () => {
session.logger.log(`Custom ${watchType}:: Close:: ${JSON.stringify(event)}`);
result.close();
});
}
function closeWatcher(data: ts.server.protocol.CloseFileWatcherEventBody) {
const close = idToClose.get(data.id);
if (close) {
idToClose.delete(data.id);
close();
}
}
}
export interface TestSessionOptions extends ts.server.SessionOptions, TestTypingsInstallerOptions {
host: TestServerHost;
logger: LoggerWithInMemoryLogs;
@@ -90,6 +215,7 @@ export class TestSession extends ts.server.Session {
public override logger!: LoggerWithInMemoryLogs;
public override readonly typingsInstaller!: TestTypingsInstallerAdapter;
public serverCancellationToken: TestServerCancellationToken;
public watchChanges = new Map<number, ts.server.protocol.WatchChangeRequestArgs>();
constructor(optsOrHost: TestSessionConstructorOptions) {
const opts = getTestSessionPartialOptionsAndHost(optsOrHost);
@@ -125,6 +251,7 @@ export class TestSession extends ts.server.Session {
if (opts.regionDiagLineCountThreshold !== undefined) {
this.regionDiagLineCountThreshold = opts.regionDiagLineCountThreshold;
}
if (opts.canUseWatchEvents) patchSessionToHandleWatchEvents(this);
}
getProjectService() {
@@ -159,6 +286,15 @@ export class TestSession extends ts.server.Session {
request.type = "request";
return this.executeCommand(request);
}
public invokeWatchChanges() {
const changes = ts.singleOrMany(ts.arrayFrom(this.watchChanges.values()));
this.watchChanges.clear();
this.executeCommandSeq<ts.server.protocol.WatchChangeRequest>({
command: ts.server.protocol.CommandTypes.WatchChange,
arguments: changes,
});
}
}
export function createSessionWithCustomEventHandler(

View File

@@ -3,6 +3,10 @@ import {
Watches,
WatchUtils,
} from "../../../harness/watchUtils.js";
import {
CreateDirectoryWatcherEventBody,
CreateFileWatcherEventBody,
} from "../../../server/protocol.js";
import {
append,
arrayFrom,
@@ -276,11 +280,13 @@ type TimeOutCallback = (...args: any[]) => void;
export interface TestFileWatcher {
cb: FileWatcherCallback;
pollingInterval: PollingInterval;
event?: CreateFileWatcherEventBody;
}
export interface TestFsWatcher {
cb: FsWatchCallback;
inode: number | undefined;
event?: CreateDirectoryWatcherEventBody;
}
export interface WatchInvokeOptions {

View File

@@ -1,403 +1,80 @@
import {
createLoggerWithInMemoryLogs,
LoggerWithInMemoryLogs,
} from "../../../../harness/tsserverLogger.js";
import {
createWatchUtils,
Watches,
WatchUtils,
} from "../../../../harness/watchUtils.js";
import * as ts from "../../../_namespaces/ts.js";
import {
baselineTsserverLogs,
closeFilesForSession,
createSessionWithCustomEventHandler,
openFilesForSession,
TestSession,
} from "../../helpers/tsserver.js";
import {
createServerHost,
libFile,
TestServerHost,
} from "../../helpers/virtualFileSystemWithWatch.js";
describe("unittests:: tsserver:: events:: watchEvents", () => {
interface TestServerHostWithCustomWatch extends TestServerHost {
factoryData: {
watchUtils: WatchUtils<ts.server.protocol.CreateFileWatcherEventBody, ts.server.protocol.CreateDirectoryWatcherEventBody>;
watchFile(data: ts.server.protocol.CreateFileWatcherEventBody): void;
watchDirectory(data: ts.server.protocol.CreateDirectoryWatcherEventBody): void;
closeWatcher(data: ts.server.protocol.CloseFileWatcherEventBody): void;
};
}
function createTestServerHostWithCustomWatch(
logger: LoggerWithInMemoryLogs,
function verifyCanUseWatchEvents(
canUseEvents: boolean,
projectPath: string,
directorySeparator: string,
windowsStyleRoot?: string,
) {
const idToClose = new Map<number, () => void>();
const host = logger.host as TestServerHostWithCustomWatch;
const originalSerializeWatches = host.serializeWatches;
host.serializeWatches = serializeWatches;
host.factoryData = {
watchUtils: createWatchUtils<ts.server.protocol.CreateFileWatcherEventBody, ts.server.protocol.CreateDirectoryWatcherEventBody>(
"Custom WatchedFiles",
"Custom WatchedDirectories",
host.getCanonicalFileName,
host,
),
watchFile,
watchDirectory,
closeWatcher,
};
return host;
it(canUseEvents ? windowsStyleRoot ? "canUseWatchEvents on windows" : "canUseWatchEvents" : "canUseWatchEvents without canUseEvents", () => {
const host = createServerHost({
[`${projectPath}${directorySeparator}tsconfig.json`]: "{}",
[`${projectPath}${directorySeparator}a.ts`]: `export class a { prop = "hello"; foo() { return this.prop; } }`,
[`${projectPath}${directorySeparator}b.ts`]: `export class b { prop = "hello"; foo() { return this.prop; } }`,
[`${projectPath}${directorySeparator}m.ts`]: `import { x } from "something"`,
[`${projectPath}${directorySeparator}node_modules${directorySeparator}something${directorySeparator}index.d.ts`]: `export const x = 10;`,
[libFile.path]: libFile.content,
}, { windowsStyleRoot });
const session = new TestSession({ host, canUseWatchEvents: true, canUseEvents });
if (!canUseEvents) session.logger.msg = (s, type) => session.logger.info(`${type}:: ${s}`);
openFilesForSession([`${projectPath}${directorySeparator}a.ts`], session);
function watchFile(data: ts.server.protocol.CreateFileWatcherEventBody) {
logger.log(`Custom watchFile: ${data.id}: ${data.path}`);
ts.Debug.assert(!idToClose.has(data.id));
const result = host.factoryData.watchUtils.pollingWatch(data.path, data);
idToClose.set(data.id, () => {
logger.log(`Custom watchFile:: Close:: ${data.id}: ${data.path}`);
result.close();
});
}
// Directory watcher
host.writeFile(`${projectPath}${directorySeparator}c.ts`, `export class a { prop = "hello"; foo() { return this.prop; } }`);
host.runQueuedTimeoutCallbacks();
session.invokeWatchChanges();
host.runQueuedTimeoutCallbacks();
function watchDirectory(data: ts.server.protocol.CreateDirectoryWatcherEventBody) {
logger.log(`Custom watchDirectory: ${data.id}: ${data.path} ${data.recursive} ${data.ignoreUpdate}`);
ts.Debug.assert(!idToClose.has(data.id));
const result = host.factoryData.watchUtils.fsWatch(data.path, data.recursive, data);
idToClose.set(data.id, () => {
logger.log(`Custom watchDirectory:: Close:: ${data.id}: ${data.path} ${data.recursive} ${data.ignoreUpdate}`);
result.close();
});
}
// File Watcher
host.writeFile(`${projectPath}${directorySeparator}b.ts`, `export class a { prop = "hello"; foo() { return this.prop; } }`);
host.runQueuedTimeoutCallbacks();
session.invokeWatchChanges();
host.runQueuedTimeoutCallbacks();
function closeWatcher(data: ts.server.protocol.CloseFileWatcherEventBody) {
const close = idToClose.get(data.id);
if (close) {
idToClose.delete(data.id);
close();
}
}
// Close watcher
openFilesForSession([`${projectPath}${directorySeparator}b.ts`], session);
function serializeWatches(baseline: string[] = []) {
if (host.factoryData.watchUtils.getHasWatchChanges()) host.watchUtils.setHasWatchChanges();
const hasWatchChanges = host.watchUtils.getHasWatchChanges();
originalSerializeWatches.call(host, baseline);
if (hasWatchChanges) {
host.factoryData.watchUtils.setHasWatchChanges();
host.factoryData.watchUtils.serializeWatches(baseline);
}
return baseline;
}
}
// Re watch
closeFilesForSession([`${projectPath}${directorySeparator}b.ts`], session);
function updateFileOnHost(session: TestSession, file: string, log: string, content?: string) {
// Change b.ts
session.logger.log(`${log}: ${file}`);
if (content && session.host.fileExists(file)) session.host.appendFile(file, content);
else session.host.writeFile(file, content ?? session.host.readFile("/user/username/projects/myproject/a.ts")!);
session.host.runQueuedTimeoutCallbacks();
}
// Update c.ts
host.appendFile(`${projectPath}${directorySeparator}c.ts`, `export const y = 20;`);
host.runQueuedTimeoutCallbacks();
session.invokeWatchChanges();
host.runQueuedTimeoutCallbacks();
function collectWatchChanges<T extends ts.server.protocol.CreateFileWatcherEventBody | ts.server.protocol.CreateDirectoryWatcherEventBody>(
session: TestSession,
watches: Watches<T>,
path: string,
eventPath: string,
eventType: "created" | "deleted" | "updated",
ignoreUpdate?: (data: T) => boolean,
) {
session.logger.log(`Custom watch:: ${path} ${eventPath} ${eventType}`);
let result: ts.server.protocol.WatchChangeRequestArgs[] | undefined;
watches.forEach(
path,
data => {
if (ignoreUpdate?.(data)) return;
switch (eventType) {
case "created":
(result ??= []).push({ id: data.id, created: [eventPath] });
break;
case "deleted":
(result ??= []).push({ id: data.id, deleted: [eventPath] });
break;
case "updated":
(result ??= []).push({ id: data.id, updated: [eventPath] });
break;
default:
ts.Debug.assertNever(eventType);
}
},
);
return result;
}
// Add and change multiple files - combine and send multiple requests together
session.host.writeFile(`${projectPath}${directorySeparator}d.ts`, `export class a { prop = "hello"; foo() { return this.prop; } }`);
session.host.runQueuedTimeoutCallbacks();
session.host.appendFile(`${projectPath}${directorySeparator}c.ts`, `export const z = 30;`);
session.host.runQueuedTimeoutCallbacks();
session.host.writeFile(`${projectPath}${directorySeparator}e.ts`, `export class a { prop = "hello"; foo() { return this.prop; } }`);
session.host.runQueuedTimeoutCallbacks();
session.invokeWatchChanges();
host.runQueuedTimeoutCallbacks();
function collectDirectoryWatcherChanges(
session: TestSession,
dir: string,
eventPath: string,
eventType: "created" | "deleted" | "updated",
) {
return collectWatchChanges(
session,
(session.logger.host as TestServerHostWithCustomWatch).factoryData.watchUtils.fsWatchesRecursive,
dir,
eventPath,
eventType,
data => !!data.ignoreUpdate && eventType === "updated",
);
}
// Update with npm install
host.appendFile(`${projectPath}${directorySeparator}node_modules${directorySeparator}something${directorySeparator}index.d.ts`, `export const y = 20;`);
host.runQueuedTimeoutCallbacks();
session.invokeWatchChanges();
host.runQueuedTimeoutCallbacks();
host.runQueuedTimeoutCallbacks();
function collectFileWatcherChanges(
session: TestSession,
file: string,
eventType: "created" | "deleted" | "updated",
eventPath?: string,
) {
return collectWatchChanges(
session,
(session.logger.host as TestServerHostWithCustomWatch).factoryData.watchUtils.pollingWatches,
file,
eventPath ?? file,
eventType,
);
}
function invokeWatchChange(
session: TestSession,
...args: (ts.server.protocol.WatchChangeRequestArgs[] | undefined)[]
) {
let result: Map<number, ts.server.protocol.WatchChangeRequestArgs> | undefined;
args.forEach(arg =>
arg?.forEach(value => {
result ??= new Map();
const valueInResult = result.get(value.id);
if (!valueInResult) result.set(value.id, value);
else {
valueInResult.created = ts.combine(valueInResult.created, value.created);
valueInResult.deleted = ts.combine(valueInResult.deleted, value.deleted);
valueInResult.updated = ts.combine(valueInResult.updated, value.updated);
}
})
);
if (result) {
session.executeCommandSeq<ts.server.protocol.WatchChangeRequest>({
command: ts.server.protocol.CommandTypes.WatchChange,
arguments: ts.singleOrMany(ts.arrayFrom(result.values())),
});
}
}
function addFile(session: TestSession, path: string, content?: string, eventPath?: string) {
updateFileOnHost(session, path, "Add file", content);
invokeWatchChange(
session,
collectDirectoryWatcherChanges(session, ts.getDirectoryPath(path), eventPath ?? path, "created"),
);
session.host.runQueuedTimeoutCallbacks();
}
function changeFile(session: TestSession, path: string, content?: string, eventPath?: string) {
updateFileOnHost(session, path, "Change File", content);
invokeWatchChange(
session,
collectFileWatcherChanges(session, path, "updated", eventPath),
collectDirectoryWatcherChanges(session, ts.getDirectoryPath(path), eventPath ?? path, "updated"),
);
session.host.runQueuedTimeoutCallbacks();
}
function npmInstall(session: TestSession) {
session.logger.log("update with npm install");
session.host.appendFile("/user/username/projects/myproject/node_modules/something/index.d.ts", `export const y = 20;`);
session.host.runQueuedTimeoutCallbacks();
invokeWatchChange(
session,
collectDirectoryWatcherChanges(
session,
"/user/username/projects/myproject/node_modules",
"/user/username/projects/myproject/node_modules/something/index.d.ts",
"updated",
),
);
session.host.runQueuedTimeoutCallbacks();
}
function setup() {
const inputHost = createServerHost({
"/user/username/projects/myproject/tsconfig.json": "{}",
"/user/username/projects/myproject/a.ts": `export class a { prop = "hello"; foo() { return this.prop; } }`,
"/user/username/projects/myproject/b.ts": `export class b { prop = "hello"; foo() { return this.prop; } }`,
"/user/username/projects/myproject/m.ts": `import { x } from "something"`,
"/user/username/projects/myproject/node_modules/something/index.d.ts": `export const x = 10;`,
[libFile.path]: libFile.content,
baselineTsserverLogs("events/watchEvents", canUseEvents ? windowsStyleRoot ? "canUseWatchEvents on windows" : "canUseWatchEvents" : "canUseWatchEvents without canUseEvents", session);
});
const logger = createLoggerWithInMemoryLogs(inputHost);
const host = createTestServerHostWithCustomWatch(logger);
return { host, logger };
}
it("canUseWatchEvents", () => {
const { host, logger } = setup();
const session = createSessionWithCustomEventHandler({ host, canUseWatchEvents: true, logger }, handleWatchEvents);
openFilesForSession(["/user/username/projects/myproject/a.ts"], session);
// Directory watcher
addFile(session, "/user/username/projects/myproject/c.ts");
// File Watcher
changeFile(session, "/user/username/projects/myproject/b.ts");
// Close watcher
openFilesForSession(["/user/username/projects/myproject/b.ts"], session);
// Re watch
closeFilesForSession(["/user/username/projects/myproject/b.ts"], session);
// Update c.ts
changeFile(session, "/user/username/projects/myproject/c.ts", `export const y = 20;`);
// Update with npm install
npmInstall(session);
host.runQueuedTimeoutCallbacks();
// Add and change multiple files - combine and send multiple requests together
updateFileOnHost(session, "/user/username/projects/myproject/d.ts", "Add file");
updateFileOnHost(session, "/user/username/projects/myproject/c.ts", "Change File", `export const z = 30;`);
updateFileOnHost(session, "/user/username/projects/myproject/e.ts", "Add File");
invokeWatchChange(
session,
collectDirectoryWatcherChanges(session, "/user/username/projects/myproject", "/user/username/projects/myproject/d.ts", "created"),
collectFileWatcherChanges(session, "/user/username/projects/myproject/c.ts", "updated"),
collectDirectoryWatcherChanges(session, "/user/username/projects/myproject", "/user/username/projects/myproject/c.ts", "updated"),
collectDirectoryWatcherChanges(session, "/user/username/projects/myproject", "/user/username/projects/myproject/e.ts", "created"),
);
session.host.runQueuedTimeoutCallbacks();
baselineTsserverLogs("events/watchEvents", `canUseWatchEvents`, session);
function handleWatchEvents(event: ts.server.ProjectServiceEvent) {
switch (event.eventName) {
case ts.server.CreateFileWatcherEvent:
host.factoryData.watchFile(event.data);
break;
case ts.server.CreateDirectoryWatcherEvent:
host.factoryData.watchDirectory(event.data);
break;
case ts.server.CloseFileWatcherEvent:
host.factoryData.closeWatcher(event.data);
break;
default:
break;
}
}
});
it("canUseWatchEvents without canUseEvents", () => {
const { host, logger } = setup();
const session = new TestSession({ host, canUseEvents: false, canUseWatchEvents: true, logger });
openFilesForSession(["/user/username/projects/myproject/a.ts"], session);
// Directory watcher
addFile(session, "/user/username/projects/myproject/c.ts");
// File Watcher
changeFile(session, "/user/username/projects/myproject/b.ts");
// Close watcher
openFilesForSession(["/user/username/projects/myproject/b.ts"], session);
// Re watch
closeFilesForSession(["/user/username/projects/myproject/b.ts"], session);
// Shouldnt have watch change request
logger.msg = (s, type) => logger.info(`${type}:: ${s}`);
session.executeCommandSeq<ts.server.protocol.WatchChangeRequest>({
command: ts.server.protocol.CommandTypes.WatchChange,
arguments: { id: 1, updated: ["/user/username/projects/myproject/b.ts"] },
});
// Update c.ts
changeFile(session, "/user/username/projects/myproject/c.ts", `export const y = 20;`);
// Update with npm install
npmInstall(session);
baselineTsserverLogs("events/watchEvents", `canUseWatchEvents without canUseEvents`, session);
});
it("canUseWatchEvents on windows", () => {
const inputHost = createServerHost({
"c:\\projects\\myproject\\tsconfig.json": "{}",
"c:\\projects\\myproject\\a.ts": `export class a { prop = "hello"; foo() { return this.prop; } }`,
"c:\\projects\\myproject\\b.ts": `export class b { prop = "hello"; foo() { return this.prop; } }`,
"c:\\projects\\myproject\\m.ts": `import { x } from "something"`,
"c:\\projects\\myproject\\node_modules\\something\\index.d.ts": `export const x = 10;`,
[libFile.path]: libFile.content,
}, { windowsStyleRoot: "c:\\" });
const logger = createLoggerWithInMemoryLogs(inputHost);
const host = createTestServerHostWithCustomWatch(logger);
const session = createSessionWithCustomEventHandler({ host, canUseWatchEvents: true, logger }, handleWatchEvents);
openFilesForSession(["c:\\projects\\myproject\\a.ts"], session);
// Directory watcher
addFile(session, "c:/projects/myproject/c.ts", `export xyx = 10;`, "c:\\projects\\myproject\\c.ts");
// File Watcher
changeFile(session, "c:/projects/myproject/b.ts", "export const ss = 20;", "c:\\projects\\myproject\\b.ts");
// Close watcher
openFilesForSession(["c:\\projects\\myproject\\b.ts"], session);
// Re watch
closeFilesForSession(["c:\\projects\\myproject\\b.ts"], session);
// Update c.ts
changeFile(session, "c:/projects/myproject/c.ts", "export const ss = 20;", "c:\\projects\\myproject\\b.ts");
// Update with npm install
session.logger.log("update with npm install");
session.host.appendFile("c:\\projects\\myproject\\node_modules\\something\\index.d.ts", `export const y = 20;`);
session.host.runQueuedTimeoutCallbacks();
invokeWatchChange(
session,
collectDirectoryWatcherChanges(
session,
"c:/projects/myproject/node_modules",
"c:\\projects\\myproject\\node_modules\\something\\index.d.ts",
"updated",
),
);
session.host.runQueuedTimeoutCallbacks();
host.runQueuedTimeoutCallbacks();
// Add and change multiple files - combine and send multiple requests together
updateFileOnHost(session, "c:/projects/myproject/d.ts", "Add file", "export const yy = 10;");
updateFileOnHost(session, "c:/projects/myproject/c.ts", "Change File", `export const z = 30;`);
updateFileOnHost(session, "c:/projects/myproject/e.ts", "Add File", "export const zz = 40;");
invokeWatchChange(
session,
collectDirectoryWatcherChanges(session, "c:/projects/myproject", "c:\\projects\\myproject\\d.ts", "created"),
collectFileWatcherChanges(session, "c:/projects/myproject/c.ts", "updated", "c:\\projects\\myproject\\c.ts"),
collectDirectoryWatcherChanges(session, "c:/projects/myproject", "c:\\projects\\myproject\\c.ts", "updated"),
collectDirectoryWatcherChanges(session, "c:/projects/myproject", "c:\\projects\\myproject\\e.ts", "created"),
);
session.host.runQueuedTimeoutCallbacks();
baselineTsserverLogs("events/watchEvents", `canUseWatchEvents on windows`, session);
function handleWatchEvents(event: ts.server.ProjectServiceEvent) {
switch (event.eventName) {
case ts.server.CreateFileWatcherEvent:
host.factoryData.watchFile(event.data);
break;
case ts.server.CreateDirectoryWatcherEvent:
host.factoryData.watchDirectory(event.data);
break;
case ts.server.CloseFileWatcherEvent:
host.factoryData.closeWatcher(event.data);
break;
default:
break;
}
}
});
verifyCanUseWatchEvents(/*canUseEvents*/ true, "/user/username/projects/myproject", "/");
verifyCanUseWatchEvents(/*canUseEvents*/ false, "/user/username/projects/myproject", "/");
verifyCanUseWatchEvents(/*canUseEvents*/ true, "c:\\projects\\myproject", "\\", "c:\\");
});