diff --git a/src/extension/debugger/configuration/launch.json/launchJsonReader.ts b/src/extension/debugger/configuration/launch.json/launchJsonReader.ts index e2cad8b2..ac906613 100644 --- a/src/extension/debugger/configuration/launch.json/launchJsonReader.ts +++ b/src/extension/debugger/configuration/launch.json/launchJsonReader.ts @@ -12,19 +12,18 @@ export async function getConfigurationsForWorkspace(workspace: WorkspaceFolder): traceLog('Getting configurations for workspace'); const filename = path.join(workspace.uri.fsPath, '.vscode', 'launch.json'); if (!(await fs.pathExists(filename))) { - // Check launch config in the workspace file - const codeWorkspaceConfig = getConfiguration('launch', workspace); - if (!codeWorkspaceConfig.configurations || !Array.isArray(codeWorkspaceConfig.configurations)) { - return []; - } - traceLog('Using configuration in workspace'); - return codeWorkspaceConfig.configurations; + return getConfigurationsFromSettings(workspace); } - const text = await fs.readFile(filename, 'utf-8'); const parsed = parse(text, [], { allowTrailingComma: true, disallowComments: false }); - if (!parsed.configurations || !Array.isArray(parsed.configurations)) { - throw Error('Missing field in launch.json: configurations'); + // no launch.json or no configurations found in launch.json, look in settings.json + if (!parsed || !parsed.configurations) { + traceLog('No configurations found in launch.json, looking in settings.json.'); + return getConfigurationsFromSettings(workspace); + } + // configurations found in launch.json, verify them then return + if (!Array.isArray(parsed.configurations) || parsed.configurations.length === 0) { + throw Error('Invalid configurations in launch.json'); } if (!parsed.version) { throw Error('Missing field in launch.json: version'); @@ -42,3 +41,18 @@ export async function getConfigurationsByUri(uri?: Uri): Promise { + let sandbox: sinon.SinonSandbox; + + setup(() => { + sandbox = sinon.createSandbox(); + }); + + teardown(() => { + sandbox.restore(); + }); + + suite('getConfigurationsForWorkspace', () => { + test('Should return configurations from launch.json if it exists', async () => { + const workspace = typemoq.Mock.ofType(); + workspace.setup((w) => w.uri).returns(() => Uri.file('/path/to/workspace')); + + const launchJsonContent = `{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Program", + "type": "python", + "request": "launch", + "program": "${workspace.object.uri}/app.py" + } + ] + }`; + + sandbox.stub(fs, 'pathExists').resolves(true); + sandbox.stub(fs, 'readFile').resolves(launchJsonContent); + + const configurations = await getConfigurationsForWorkspace(workspace.object); + assert.strictEqual(configurations.length, 1); + assert.strictEqual(configurations[0].name, 'Launch Program'); + }); + + test('Should return configurations from settings.json if launch.json does not exist', async () => { + const workspace = typemoq.Mock.ofType(); + workspace.setup((w) => w.uri).returns(() => Uri.file('/path/to/workspace')); + + const mockConfig = typemoq.Mock.ofType(); + mockConfig + .setup((c) => c.configurations) + .returns(() => [ + { + name: 'Launch Program 2', + type: 'python', + request: 'launch', + program: '${workspaceFolder}/app.py', + }, + ]); + + sandbox.stub(fs, 'pathExists').resolves(false); + sandbox.stub(vscodeapi, 'getConfiguration').returns(mockConfig.object); + + const configurations = await getConfigurationsForWorkspace(workspace.object); + assert.strictEqual(configurations.length, 1); + assert.strictEqual(configurations[0].name, 'Launch Program 2'); + }); + }); + + suite('getConfigurationsFromSettings', () => { + test('Should return configurations from settings.json', () => { + const workspace = typemoq.Mock.ofType(); + workspace.setup((w) => w.uri).returns(() => Uri.file('/path/to/workspace')); + + const mockConfig = typemoq.Mock.ofType(); + mockConfig + .setup((c) => c.configurations) + .returns(() => [ + { + name: 'Launch Program 3', + type: 'python', + request: 'launch', + program: '${workspaceFolder}/app.py', + }, + ]); + + sandbox.stub(vscodeapi, 'getConfiguration').returns(mockConfig.object); + + const configurations = getConfigurationsFromSettings(workspace.object); + assert.strictEqual(configurations.length, 1); + assert.strictEqual(configurations[0].name, 'Launch Program 3'); + }); + + test('Should error if no configurations in settings.json', () => { + const workspace = typemoq.Mock.ofType(); + workspace.setup((w) => w.uri).returns(() => Uri.file('/path/to/workspace')); + + const mockConfig = typemoq.Mock.ofType(); + mockConfig.setup((c) => c.get('configurations')).returns(() => []); + mockConfig.setup((c) => c.configurations).returns(() => []); + + sandbox.stub(vscodeapi, 'getConfiguration').returns(mockConfig.object); + + assert.throws( + () => getConfigurationsFromSettings(workspace.object), + Error, + 'No configurations found in launch.json or settings.json', + ); + }); + }); +});