Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/2 Fixes/6738.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Debugging an untitled file causes an error 'Untitled-1 cannot be opened'.
46 changes: 23 additions & 23 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 32 additions & 3 deletions src/client/datascience/interactive-window/interactiveWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,38 @@ export class InteractiveWindow extends WebViewHost<IInteractiveWindowMapping> im
return this.submitCode(code, file, line, undefined, editor, false);
}

public debugCode(code: string, file: string, line: number, editor?: TextEditor): Promise<boolean> {
// Call the internal method.
return this.submitCode(code, file, line, undefined, editor, true);
public async debugCode(code: string, file: string, line: number, editor?: TextEditor): Promise<boolean> {
let saved = true;
// Make sure the file is saved before debugging
const doc = this.documentManager.textDocuments.find(d => d.fileName === file);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually use IFileSystem.arePathsSame for these types of comparisons. Probably not an issue, but I think that it's a bit safer.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I want case sensitive on Windows even.

if (doc && doc.isUntitled) {
// Before we start, get the list of documents
const beforeSave = [...this.documentManager.textDocuments];

saved = await doc.save();

// If that worked, we have to open the new document. It should be
// the new entry in the list
if (saved) {
const diff = this.documentManager.textDocuments.filter(f => beforeSave.indexOf(f) === -1);
if (diff && diff.length > 0) {
file = diff[0].fileName;

// Open the new document
await this.documentManager.openTextDocument(file);

// Change the editor to the new file
editor = this.documentManager.visibleTextEditors.find(e => e.document.fileName === file);
}
}
}

// Call the internal method if we were able to save
if (saved) {
return this.submitCode(code, file, line, undefined, editor, true);
}

return false;
}

// tslint:disable-next-line: no-any no-empty cyclomatic-complexity max-func-body-length
Expand Down
39 changes: 39 additions & 0 deletions src/test/datascience/debugger.functional.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { MockDebuggerService } from './mockDebugService';
import { MockDocumentManager } from './mockDocumentManager';

//import { asyncDump } from '../common/asyncDump';
import { MockDocument } from './mockDocument';
// tslint:disable-next-line:max-func-body-length no-any
suite('DataScience Debugger tests', () => {
const disposables: Disposable[] = [];
Expand Down Expand Up @@ -240,4 +241,42 @@ suite('DataScience Debugger tests', () => {
await debugCell('#%%\nprint("bar")', undefined, undefined, true);
}
});

test('Debug temporary file', async () => {
ioc.getSettings().datascience.stopOnFirstLineWhileDebugging = true;
const code = '#%%\nprint("bar")';

// Create a dummy document with just this code
const docManager = ioc.get<IDocumentManager>(IDocumentManager) as MockDocumentManager;
const fileName = 'Untitled-1';
docManager.addDocument(code, fileName);
const mockDoc = docManager.textDocuments[0] as MockDocument;
mockDoc.forceUntitled();

// Start the jupyter server
const history = await getOrCreateInteractiveWindow();
const expectedBreakLine = 2; // 2 because of the 'breakpoint()' that gets added

// Debug this code. We should either hit the breakpoint or stop on entry
const resultPromise = getCellResults(ioc.wrapper!, 5, async () => {
const breakPromise = createDeferred<void>();
disposables.push(mockDebuggerService!.onBreakpointHit(() => breakPromise.resolve()));
const done = history.debugCode(code, fileName, 0, docManager.activeTextEditor);
await waitForPromise(Promise.race([done, breakPromise.promise]), 60000);
assert.ok(breakPromise.resolved, 'Breakpoint event did not fire');
assert.ok(!lastErrorMessage, `Error occurred ${lastErrorMessage}`);
const stackTrace = await mockDebuggerService!.getStackTrace();
assert.ok(stackTrace, 'Stack trace not computable');
assert.ok(stackTrace!.body.stackFrames.length >= 1, 'Not enough frames');
assert.equal(stackTrace!.body.stackFrames[0].line, expectedBreakLine, 'Stopped on wrong line number');
assert.equal(stackTrace!.body.stackFrames[0].source!.path, path.join(EXTENSION_ROOT_DIR, 'baz.py'), 'Stopped on wrong file name. Name should have been saved');
// Verify break location
await mockDebuggerService!.continue();
});

const cellResults = await resultPromise;
assert.ok(cellResults, 'No cell results after finishing debugging');
await history.dispose();
});

});
17 changes: 13 additions & 4 deletions src/test/datascience/mockDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,20 @@ export class MockDocument implements TextDocument {
private _version: number = 0;
private _lines: MockLine[] = [];
private _contents: string = '';
private _isUntitled = false;
private _isDirty = false;
private _onSave: (doc: TextDocument) => Promise<boolean>;

constructor(contents: string, fileName: string) {
constructor(contents: string, fileName: string, onSave: (doc: TextDocument) => Promise<boolean>) {
this._uri = Uri.file(fileName);
this._contents = contents;
this._lines = this.createLines();
this._onSave = onSave;
}

public forceUntitled(): void {
this._isUntitled = true;
this._isDirty = true;
}

public get uri(): Uri {
Expand All @@ -70,7 +79,7 @@ export class MockDocument implements TextDocument {
}

public get isUntitled(): boolean {
return true;
return this._isUntitled;
}
public get languageId(): string {
return 'python';
Expand All @@ -79,13 +88,13 @@ export class MockDocument implements TextDocument {
return this._version;
}
public get isDirty(): boolean {
return true;
return this._isDirty;
}
public get isClosed(): boolean {
return false;
}
public save(): Thenable<boolean> {
return Promise.resolve(true);
return this._onSave(this);
}
public get eol(): EndOfLine {
return EndOfLine.LF;
Expand Down
11 changes: 10 additions & 1 deletion src/test/datascience/mockDocumentManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import * as path from 'path';
import {
DecorationRenderOptions,
Event,
Expand All @@ -20,8 +21,10 @@ import {
} from 'vscode';

import { IDocumentManager } from '../../client/common/application/types';
import { EXTENSION_ROOT_DIR } from '../../client/constants';
import { MockDocument } from './mockDocument';
import { MockEditor } from './mockTextEditor';

// tslint:disable:no-any no-http-string no-multiline-string max-func-body-length

export class MockDocumentManager implements IDocumentManager {
Expand Down Expand Up @@ -81,7 +84,7 @@ export class MockDocumentManager implements IDocumentManager {
}

public addDocument(code: string, file: string) {
const mockDoc = new MockDocument(code, file);
const mockDoc = new MockDocument(code, file, this.saveDocument);
this.textDocuments.push(mockDoc);
}

Expand Down Expand Up @@ -118,4 +121,10 @@ export class MockDocumentManager implements IDocumentManager {
}
throw new Error('No documents in MockDocumentManager');
}

private saveDocument = (doc: TextDocument): Promise<boolean> => {
// Create a new document with the contents of the doc passed in
this.addDocument(doc.getText(), path.join(EXTENSION_ROOT_DIR, 'baz.py'));
return Promise.resolve(true);
}
}