Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use in-memory source code for diagnostic printing #217

Merged
merged 5 commits into from
Oct 15, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
140 changes: 140 additions & 0 deletions src/ProgramBuilder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { Program } from './Program';
import { ProgramBuilder } from './ProgramBuilder';
import { standardizePath as s, util } from './util';
import { Logger, LogLevel } from './Logger';
import * as diagnosticUtils from './diagnosticUtils';
import { Range, BscFile, BsDiagnostic } from '.';
import { DiagnosticSeverity } from './astUtils';
import { BrsFile } from './files/BrsFile';

let tmpPath = s`${process.cwd()}/.tmp`;
let rootDir = s`${tmpPath}/rootDir`;
Expand Down Expand Up @@ -172,4 +176,140 @@ describe('ProgramBuilder', () => {
expect(beforeProgramValidate.callCount).to.equal(1);
expect(afterProgramValidate.callCount).to.equal(1);
});


describe('printDiagnostics', () => {

beforeEach(() => {
fsExtra.ensureDirSync(tmpPath);
fsExtra.emptyDirSync(tmpPath);
});

afterEach(() => {
sinon.restore();
});

it('prints no diagnostics when showDiagnosticsInConsole is false', () => {
builder = new ProgramBuilder();
builder.options = {
showDiagnosticsInConsole: false
};

let stub = sinon.stub(builder, 'getDiagnostics').returns([]);
expect(stub.called).to.be.false;
builder['printDiagnostics']();
});


it('prints nothing when there are no diagnostics', () => {

builder = new ProgramBuilder();
builder.options = {
showDiagnosticsInConsole: true
};
sinon.stub(builder, 'getDiagnostics').returns([]);
let printStub = sinon.stub(diagnosticUtils, 'printDiagnostic');

builder['printDiagnostics']();

expect(printStub.called).to.be.false;
});

it('prints diagnostic, when file is present in project', () => {

builder = new ProgramBuilder();
builder.options = {
showDiagnosticsInConsole: true
};
builder.program = new Program({});

let diagnostics = createBsDiagnostic('p1', ['m1']);
let f1 = diagnostics[0].file as BrsFile;
f1.fileContents = `l1
l2
l3`;
sinon.stub(builder, 'getDiagnostics').returns(diagnostics);

sinon.stub(builder.program, 'getFileByPathAbsolute').returns(f1);

let printStub = sinon.stub(diagnosticUtils, 'printDiagnostic');

builder['printDiagnostics']();

expect(printStub.called).to.be.true;
});
});

it('prints diagnostic, when file has no lines', () => {

builder = new ProgramBuilder();
builder.options = {
showDiagnosticsInConsole: true
};
builder.program = new Program({});

let diagnostics = createBsDiagnostic('p1', ['m1']);
let f1 = diagnostics[0].file as BrsFile;
f1.fileContents = null;
sinon.stub(builder, 'getDiagnostics').returns(diagnostics);

sinon.stub(builder.program, 'getFileByPathAbsolute').returns(f1);

let printStub = sinon.stub(diagnosticUtils, 'printDiagnostic');

builder['printDiagnostics']();

expect(printStub.called).to.be.true;
});

it('prints diagnostic, when no file present', () => {

builder = new ProgramBuilder();
builder.options = {
showDiagnosticsInConsole: true
};
builder.program = new Program({});

let diagnostics = createBsDiagnostic('p1', ['m1']);
sinon.stub(builder, 'getDiagnostics').returns(diagnostics);

sinon.stub(builder.program, 'getFileByPathAbsolute').returns(null);

let printStub = sinon.stub(diagnosticUtils, 'printDiagnostic');

builder['printDiagnostics']();

expect(printStub.called).to.be.true;
});
});

function createBsDiagnostic(filePath: string, messages: string[]): BsDiagnostic[] {
let file = new BrsFile(filePath, filePath, null);
let diagnostics = [];
for (let message in messages) {
let d = createDiagnostic(file, 1, message);
d.file = file;
diagnostics.push(d);
}
return diagnostics;
}
function createDiagnostic(
bscFile: BscFile,
code: number,
message: string,
startLine: number = 0,
startCol: number = 99999,
endLine: number = 0,
endCol: number = 99999,
severity: DiagnosticSeverity = DiagnosticSeverity.Error
) {
const diagnostic = {
code: code,
message: message,
range: Range.create(startLine, startCol, endLine, endCol),
file: bscFile,
severity: severity
};
return diagnostic;
}

30 changes: 18 additions & 12 deletions src/ProgramBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import { standardizePath as s, util, loadPlugins } from './util';
import { Watcher } from './Watcher';
import { DiagnosticSeverity } from 'vscode-languageserver';
import { Logger, LogLevel } from './Logger';
import { getPrintDiagnosticOptions, printDiagnostic } from './diagnosticUtils';
import PluginInterface from './PluginInterface';

import * as diagnosticUtils from './diagnosticUtils';
/**
* A runner class that handles
*/
Expand Down Expand Up @@ -221,7 +220,7 @@ export class ProgramBuilder {
}

//get printing options
const options = getPrintDiagnosticOptions(this.options);
const options = diagnosticUtils.getPrintDiagnosticOptions(this.options);
const { cwd, emitFullPaths } = options;

let pathsAbsolute = Object.keys(diagnosticsByFile).sort();
Expand All @@ -239,16 +238,23 @@ export class ProgramBuilder {
if (!emitFullPaths) {
filePath = path.relative(cwd, filePath);
}

let linesByFile = {};
//load the file text
let fileText = await util.getFileContents(pathAbsolute);
let lines = util.getLines(fileText);

for (let diagnostic of sortedDiagnostics) {
//default the severity to error if undefined
let severity = typeof diagnostic.severity === 'number' ? diagnostic.severity : DiagnosticSeverity.Error;
//format output
printDiagnostic(options, severity, filePath, lines, diagnostic);
try {
Copy link
Member

Choose a reason for hiding this comment

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

We should not be wrapping and then throwing away any runtime exceptions that happen here...that would cause even more confusion for plugin authors and developers because there wouldn't even be runtime error messages or stack traces if something went wrong.

let file = this.program.getFileByPathAbsolute(pathAbsolute);
let lines = linesByFile[pathAbsolute];
if (!lines) {
lines = file && file.fileContents ? file.fileContents.split(/\r?\n/g) : [];
linesByFile[pathAbsolute] = lines
}

for (let diagnostic of sortedDiagnostics) {
//default the severity to error if undefined
let severity = typeof diagnostic.severity === 'number' ? diagnostic.severity : DiagnosticSeverity.Error;
//format output
diagnosticUtils.printDiagnostic(options, severity, filePath, lines, diagnostic);
}
} catch (e) {
}
}
}
Expand Down