Skip to content

Commit 5bc4712

Browse files
committed
Add debugger test with project Bundler settings
1 parent 02f86f3 commit 5bc4712

File tree

3 files changed

+180
-8
lines changed

3 files changed

+180
-8
lines changed

vscode/src/debugger.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,24 @@ export class Debugger
102102
debugConfiguration: vscode.DebugConfiguration,
103103
_token?: vscode.CancellationToken,
104104
): vscode.ProviderResult<vscode.DebugConfiguration> {
105-
const workspace = this.workspaceResolver(folder?.uri);
105+
// On certain occasions, the objects passed to this method are serialized. In particular for the URI, we have to
106+
// ensure we're dealing with a `vscode.Uri` object and not a plain object
107+
const uriAttributes =
108+
folder?.uri ?? debugConfiguration.workspaceFolder?.uri;
109+
110+
if (!uriAttributes) {
111+
throw new Error(`Couldn't find a workspace to start debugging`);
112+
}
113+
114+
const uri =
115+
uriAttributes instanceof vscode.Uri
116+
? uriAttributes
117+
: vscode.Uri.from(uriAttributes);
118+
119+
const workspace = this.workspaceResolver(uri);
106120

107121
if (!workspace) {
108-
throw new Error(
109-
`Couldn't find a workspace for URI: ${folder?.uri} or editor: ${vscode.window.activeTextEditor}`,
110-
);
122+
throw new Error(`Couldn't find a workspace for URI: ${uri}`);
111123
}
112124

113125
if (debugConfiguration.env) {
@@ -120,10 +132,8 @@ export class Debugger
120132
debugConfiguration.env = workspace.ruby.env;
121133
}
122134

123-
const workspaceUri = workspace.workspaceFolder.uri;
124-
125135
debugConfiguration.targetFolder = {
126-
path: workspaceUri.fsPath,
136+
path: uri.fsPath,
127137
name: workspace.workspaceFolder.name,
128138
};
129139

@@ -133,7 +143,7 @@ export class Debugger
133143
return debugConfiguration;
134144
}
135145

136-
const customBundleUri = vscode.Uri.joinPath(workspaceUri, ".ruby-lsp");
146+
const customBundleUri = vscode.Uri.joinPath(uri, ".ruby-lsp");
137147

138148
return vscode.workspace.fs.readDirectory(customBundleUri).then(
139149
(value) => {
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/* eslint-disable no-process-env */
2+
import path from "path";
3+
import assert from "assert";
4+
import fs from "fs";
5+
import os from "os";
6+
7+
import sinon from "sinon";
8+
import * as vscode from "vscode";
9+
import { beforeEach, afterEach } from "mocha";
10+
11+
import { RubyLsp } from "../../rubyLsp";
12+
import { RUBY_VERSION } from "../rubyVersion";
13+
import { ManagerIdentifier } from "../../ruby";
14+
15+
import { FAKE_TELEMETRY } from "./fakeTelemetry";
16+
import { createRubySymlinks } from "./helpers";
17+
18+
suite("Ruby LSP", () => {
19+
const context = {
20+
extensionMode: vscode.ExtensionMode.Test,
21+
subscriptions: [],
22+
workspaceState: {
23+
get: (_name: string) => undefined,
24+
update: (_name: string, _value: any) => Promise.resolve(),
25+
},
26+
extensionUri: vscode.Uri.file(
27+
path.dirname(path.dirname(path.dirname(__dirname))),
28+
),
29+
} as unknown as vscode.ExtensionContext;
30+
let workspacePath: string;
31+
let workspaceUri: vscode.Uri;
32+
let workspaceFolder: vscode.WorkspaceFolder;
33+
const originalSaveBeforeStart = vscode.workspace
34+
.getConfiguration("debug")
35+
.get("saveBeforeStart");
36+
let workspacesStub: sinon.SinonStub;
37+
38+
beforeEach(async () => {
39+
await vscode.workspace
40+
.getConfiguration("debug")
41+
.update("saveBeforeStart", "none", true);
42+
workspacePath = fs.mkdtempSync(
43+
path.join(os.tmpdir(), "ruby-lsp-integration-test-"),
44+
);
45+
workspaceUri = vscode.Uri.file(workspacePath);
46+
workspaceFolder = {
47+
uri: workspaceUri,
48+
name: path.basename(workspacePath),
49+
index: 0,
50+
};
51+
52+
workspacesStub = sinon
53+
.stub(vscode.workspace, "workspaceFolders")
54+
.get(() => [workspaceFolder]);
55+
56+
if (process.env.CI) {
57+
createRubySymlinks();
58+
}
59+
});
60+
61+
afterEach(async () => {
62+
workspacesStub.restore();
63+
fs.rmSync(workspacePath, { recursive: true, force: true });
64+
65+
await vscode.workspace
66+
.getConfiguration("debug")
67+
.update("saveBeforeStart", originalSaveBeforeStart, true);
68+
});
69+
70+
function writeFileSetup() {
71+
fs.writeFileSync(path.join(workspacePath, "test.rb"), "1 + 1");
72+
fs.writeFileSync(path.join(workspacePath, ".ruby-version"), RUBY_VERSION);
73+
fs.writeFileSync(
74+
path.join(workspacePath, "Gemfile"),
75+
'source "https://rubygems.org"\n',
76+
);
77+
fs.writeFileSync(
78+
path.join(workspacePath, "Gemfile.lock"),
79+
[
80+
"GEM",
81+
" remote: https://rubygems.org/",
82+
" specs:",
83+
"",
84+
"PLATFORMS",
85+
" arm64-darwin-23",
86+
" ruby",
87+
"",
88+
"DEPENDENCIES",
89+
"",
90+
"BUNDLED WITH",
91+
" 2.5.16",
92+
].join("\n"),
93+
);
94+
fs.mkdirSync(path.join(workspacePath, ".bundle"));
95+
fs.writeFileSync(
96+
path.join(workspacePath, ".bundle", "config"),
97+
`BUNDLE_PATH: ${path.join("vendor", "bundle")}`,
98+
);
99+
}
100+
101+
test("launching debugger in a project with local Bundler settings and composed bundle", async () => {
102+
writeFileSetup();
103+
104+
if (process.env.CI && os.platform() === "win32") {
105+
await vscode.workspace
106+
.getConfiguration("rubyLsp")
107+
.update(
108+
"rubyVersionManager",
109+
{ identifier: ManagerIdentifier.RubyInstaller },
110+
true,
111+
);
112+
} else if (process.env.CI) {
113+
await vscode.workspace
114+
.getConfiguration("rubyLsp")
115+
.update(
116+
"rubyVersionManager",
117+
{ identifier: ManagerIdentifier.Chruby },
118+
true,
119+
);
120+
}
121+
122+
const rubyLsp = new RubyLsp(context, FAKE_TELEMETRY);
123+
124+
try {
125+
await rubyLsp.activate();
126+
} catch (error: any) {
127+
assert.fail(
128+
`Failed to activate Ruby LSP: ${error.message}\n\n${error.stack}`,
129+
);
130+
}
131+
132+
try {
133+
await vscode.debug.startDebugging(workspaceFolder, {
134+
type: "ruby_lsp",
135+
name: "Debug",
136+
request: "launch",
137+
program: `ruby ${path.join(workspacePath, "test.rb")}`,
138+
workspaceFolder,
139+
});
140+
} catch (error: any) {
141+
assert.fail(`Failed to launch debugger: ${error.message}`);
142+
}
143+
144+
await new Promise<void>((resolve) => {
145+
const callback = vscode.debug.onDidTerminateDebugSession((_session) => {
146+
context.subscriptions.forEach((subscription) => {
147+
if (!("logLevel" in subscription)) {
148+
subscription.dispose();
149+
}
150+
});
151+
152+
callback.dispose();
153+
resolve();
154+
});
155+
});
156+
}).timeout(90000);
157+
});

vscode/src/test/suite/testController.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as assert from "assert";
22

33
import * as vscode from "vscode";
44
import { CodeLens } from "vscode-languageclient/node";
5+
import { afterEach } from "mocha";
56

67
import { TestController } from "../../testController";
78
import { Command } from "../../common";
@@ -18,6 +19,10 @@ suite("TestController", () => {
1819
},
1920
} as unknown as vscode.ExtensionContext;
2021

22+
afterEach(() => {
23+
context.subscriptions.forEach((subscription) => subscription.dispose());
24+
});
25+
2126
test("createTestItems doesn't break when there's a missing group", () => {
2227
const controller = new TestController(
2328
context,

0 commit comments

Comments
 (0)