From 38bed611c52994520ffa3e607d735446c0729fd3 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 6 May 2021 07:58:42 -0500 Subject: [PATCH] test: add tests for getWorkspaceFolders --- test/auto-languageclient.test.ts | 43 +++++----- typings/spawk/index.d.ts | 130 +++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 20 deletions(-) create mode 100644 typings/spawk/index.d.ts diff --git a/test/auto-languageclient.test.ts b/test/auto-languageclient.test.ts index 70954606..3ef4cb0f 100644 --- a/test/auto-languageclient.test.ts +++ b/test/auto-languageclient.test.ts @@ -1,6 +1,8 @@ import AutoLanguageClient from "../lib/auto-languageclient" -import { projectPathToWorkspaceFolder } from "../lib/server-manager" +import { projectPathToWorkspaceFolder, normalizePath } from "../lib/server-manager" import { expect } from "chai" +import { FakeAutoLanguageClient } from "./helpers" +import { dirname } from "path" function mockEditor(uri: string, scopeName: string): any { return { @@ -11,23 +13,9 @@ function mockEditor(uri: string, scopeName: string): any { } } -/* eslint-disable class-methods-use-this */ - describe("AutoLanguageClient", () => { describe("ServerManager", () => { - class CustomAutoLanguageClient extends AutoLanguageClient { - public getLanguageName() { - return "JavaScript" - } - public getServerName() { - return "JavaScriptTest" - } - public getGrammarScopes() { - return ["source.javascript"] - } - } - - const client = new CustomAutoLanguageClient() + const client = new FakeAutoLanguageClient() client.activate() @@ -46,16 +34,29 @@ describe("AutoLanguageClient", () => { expect(workspaceFolders).to.be.null }) it("gives the open workspace folders", async () => { - atom.project.addPath(__dirname) - serverManager.startServer(__dirname) - const workspaceFolders = await serverManager.getWorkspaceFolders() - expect(workspaceFolders).to.equal([projectPathToWorkspaceFolder(__dirname)]) + const projectPath = __dirname + const projectPath2 = dirname(__dirname) + + const workspaceFolder = projectPathToWorkspaceFolder(normalizePath(projectPath)) + const workspaceFolder2 = projectPathToWorkspaceFolder(normalizePath(projectPath2)) + + // gives the open workspace folder + atom.project.addPath(projectPath) + await serverManager.startServer(projectPath) + expect(await serverManager.getWorkspaceFolders()).to.deep.equals([workspaceFolder]) + + // doesn't give the workspace folder if it the server is not started for that project + atom.project.addPath(projectPath2) + expect(await serverManager.getWorkspaceFolders()).to.deep.equals([workspaceFolder]) + await serverManager.startServer(projectPath) + expect(await serverManager.getWorkspaceFolders()).to.deep.equals([workspaceFolder, workspaceFolder2]) }) }) }) }) describe("shouldSyncForEditor", () => { + /* eslint-disable class-methods-use-this */ class CustomAutoLanguageClient extends AutoLanguageClient { public getLanguageName() { return "Java" @@ -64,6 +65,8 @@ describe("AutoLanguageClient", () => { return ["Java", "Python"] } } + /* eslint-enable class-methods-use-this */ + const client = new CustomAutoLanguageClient() it("selects documents in project and in supported language", () => { diff --git a/typings/spawk/index.d.ts b/typings/spawk/index.d.ts new file mode 100644 index 00000000..a23368b3 --- /dev/null +++ b/typings/spawk/index.d.ts @@ -0,0 +1,130 @@ +declare module "spawk" { + import { spawn as realSpawn, ChildProcess } from "child_process" + + type CommandType = Parameters[0] + type ArgsType = Parameters[1] + type OptionsType = Parameters[2] + + /** + * Intercept and mock a call to child_process.spawn. Returns a Interceptor object, see below for more info. Parameters + * are defined as follows: + * + * @param command Command to intercept and mock. Can either be a string, a RegExp, or a function. The interceptor will + * mock a given call if the string matches exactly, or the RegExp matches, or the function returns true. The + * function will be passed three parameters: the command, args, and options passed to `child_process.spawn`. The + * function will be called under the context of the Interceptor, so you will have access to the methods and + * attributes described below. + * @param arguments Optional arguments that must accompany the given command in order to be mocked. Can either be an + * array or a function. The interceptor will mock a given call if the array matches exactly, or if the function + * returns true. The function will be passed one parameter: the args passed to `child_process.spawn`. The function + * will be called under the context of the Interceptor, so you will have access to the methods and attributes + * described below. + * @param options Optional options that must accompany the given command in order to be mocked. Can either be an + * object or a function. The interceptor will mock a given call if all of the attributes in these options match, or + * if the function returns true. If an object, only the attributes you give are matched, others do not affect + * whether or not it matches. If a function, it will be passed one parameter: the options passed to + * `child_process.spawn`. The function will be called under the context of the Interceptor, so you will have access + * to the methods and attributes described below. When generating stdin/stdin/stdout streams for the interceptor, if + * the call to spawn specifies inherit for their modes they will be mapped to process.stdin etc. + * + * By default, any calls to spawn that do not match an existing mock will pass through to the original spawn. See + * `preventUnmatched` for more info on how to change this. Each intercepted call will only be used once, so if you + * want to intercept multiple calls to the same command you need to call spawk.spawn for each call you want to be + * intercepted. They will be used in the order that they were created. + */ + export function spawn( + command: + | CommandType + | RegExp + | ((commandToCheck: CommandType, argsToCheck?: ArgsType, optionsToCheck?: OptionsType) => boolean), + args?: ArgsType | ((argsToCheck?: ArgsType) => boolean), + options?: OptionsType | ((optionsToCheck?: OptionsType) => boolean) + ): Interceptor + + /** + * Allow calls to `child_process.spawn` that do not match any interceptor to pass through to node's implementation. + * This is the default state. + */ + export function allowUnmatched(): void + + /** + * Allow calls to `child_process.spawn` that do not match any interceptor from passing through to node's + * implementation. An unmatched call will cause an exception to be thrown. + */ + export function preventUnmatched(): void + + /** + * Ensure that all configured interceptors have been called. If they have this will return true. If they have not this + * will throw an exception. + */ + export function done(): boolean + + /** Remove any currently configured interceptors. */ + export function clean(): void + + /** + * Unloads spawk from intercepting `child_process.spawn` calls completely. This also removes any currently configured + * interceptors. + */ + export function unload(): void + + /** + * Loads spawk for intercepting `child_process.spawn` calls. This is called by default, you should only need to call + * this if you have previously called spawk.unload() for some reason. + */ + export function load(): void + + class Interceptor { + /** Boolean that denotes whether or not this interceptor has been called yet */ + called: boolean + + /** Helpful string representation of the interceptor. */ + description: string + + /** + * When the interceptor has been called, this will be an object that contains the command, args, and options that + * were actually called. + */ + calledWith: { command: CommandType; args: ArgsType; options: OptionsType } + + /** + * Tells the interceptor what status code to exit with. Defaults to 0. This can be either a number or a function + * that returns a number. The function can also be async or return a Promise. The function will be called with + * `this` set to the interceptor. + * + * @default `0` + */ + exit(code?: number | (() => number | Promise)): Interceptor + + /** + * Tells the interceptor what signal to exit with. Defaults to null (exit with no signal). This can be either a + * string or a function that returns a string. The function can also be async or return a Promise. The function will + * be called with `this` set to the interceptor. + * + * @default `null` + */ + signal(signal?: null | string | (() => string | Promise)): Interceptor + + /** + * Tells the interceptor what to write to stdout before exit. This can be either a string, buffer, or a function + * that returns a string or buffer. The function can also be async or return a Promise. The function will be called + * with `this` set to the interceptor. + */ + stdout(data: string | Buffer | (() => string | Buffer | Promise | Promise)): Interceptor + + /** + * Tells the interceptor what to write to stderr before exit. This can be either a string, buffer, or a function + * that returns a string or buffer. The function can also be async or return a Promise. The function will be called + * with `this` set to the interceptor. + */ + strerr(data: string | Buffer | (() => string | Buffer | Promise | Promise)): Interceptor + + private child: ChildProcess + + private match: typeof spawn + + private run: typeof spawn + + private toString(): string + } +}