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

This is a test commit #1

Closed
wants to merge 7 commits into from
Closed
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
12 changes: 9 additions & 3 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ on:

jobs:
build-and-run:
runs-on: ubuntu-latest
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: 'Check out the code'
uses: actions/checkout@v3
Expand All @@ -14,8 +17,11 @@ jobs:
node-version: 'lts/*' # Node LTS should always be fine.
- name: 'Install node module dependencies'
run: yarn
- name: 'Run Unit Tests'
- name: 'Run Unit Tests (Linux)'
run: xvfb-run -a yarn test
if: runner.os == 'Linux'
- name: 'Run Unit Tests (non-Linux)'
run: yarn test
if: runner.os != 'Linux'
- name: 'Lint'
run: yarn lint

20 changes: 16 additions & 4 deletions src/lib/apex-lsp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,26 @@ export type GenericSymbol = vscode.DocumentSymbol | vscode.SymbolInformation;
* Class that handles interactions with the Apex Language Server.
*/
export class ApexLsp {

/**
* Get an array of {@link GenericSymbol}s indicating the classes, methods, etc defined
* in the provided file.
* @param documentUri
* @param documentUri
* @returns An array of symbols if the server is available, otherwise undefined
*/
public static async getSymbols(documentUri: vscode.Uri): Promise<GenericSymbol[]> {
return vscode.commands.executeCommand('vscode.executeDocumentSymbolProvider', documentUri);












return vscode.commands.executeCommand('vscode.executeDocumentSymbolProvider', documentUri);
}
}
}
10 changes: 5 additions & 5 deletions src/lib/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import * as vscode from 'vscode';
* Class that handles the creation, display, and removal of {@link vscode.Diagnostic}s.
*/
export class DiagnosticManager {

/**
*
*
* @param {string[]} targets The names of ALL files targeted by a particular scan.
* @param {RuleResult[]} results The results of the scan.
* @param {vscode.DiagnosticCollection} diagnosticCollection The diagnostic collection to which new diagnostics should be added.
Expand Down Expand Up @@ -81,7 +81,7 @@ export class DiagnosticManager {
);
diagnostic.source = messages.diagnostics.source.generator(engine);
diagnostic.code = violation.url ? {
target: vscode.Uri.parse(violation.url),
target: vscode.Uri.file(violation.url),
value: violation.ruleName
} : violation.ruleName;
return diagnostic;
Expand All @@ -90,9 +90,9 @@ export class DiagnosticManager {
/**
* Type-guard for {@link PathlessRuleViolation}s.
* @param violation A violation that may or may not be a {@link PathlessRuleViolation}.
* @returns
* @returns
*/
private isPathlessViolation(violation: RuleViolation): violation is PathlessRuleViolation {
return 'line' in violation;
}
}
}
25 changes: 17 additions & 8 deletions src/lib/targeting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@ export async function getTargets(selections: vscode.Uri[]): Promise<string[]> {
// This should never happen, but we should handle it gracefully regardless.
throw new Error(messages.targeting.error.nonexistentSelectedFileGenerator(selection.fsPath));
} else if (await isDir(selection.fsPath)) {
const globOut: string[] = await globby(`${selection.fsPath}/**/*`);
globOut.forEach(o => targets.add(o));
// Globby wants forward-slashes, but Windows uses back-slashes, so we need to convert the
// latter into the former.
const globbablePath = selection.fsPath.replace(/\\/g, '/');
const globOut: string[] = await globby(`${globbablePath}/**/*`);
// Globby's results are Unix-formatted. Do a Uri.file roundtrip to return the path
// to its expected form.
globOut.forEach(o => targets.add(vscode.Uri.file(o).fsPath));
} else {
targets.add(selection.fsPath);
}
Expand Down Expand Up @@ -67,6 +72,10 @@ export async function getSelectedMethod(): Promise<string> {
const textDocument: vscode.TextDocument = activeEditor.document;
const cursorPosition: vscode.Position = activeEditor.selection.active;

// The filename-portion of the target string needs to be Unix-formatted,
// otherwise it will parse as a glob and kill the process.
const fileName: string = textDocument.fileName.replace(/\\/g, '/');

// If the Apex Language Server is available, we can use it to derive much more robust
// targeting information than we can independently.
const symbols: GenericSymbol[] = await ApexLsp.getSymbols(textDocument.uri);
Expand All @@ -79,22 +88,22 @@ export async function getSelectedMethod(): Promise<string> {
// The symbol's name property is the method signature, so we want to lop off everything
// after the first open-paren.
const methodSignature: string = nearestMethodSymbol.name;
return `${textDocument.fileName}#${methodSignature.substring(0, methodSignature.indexOf('('))}`;
return `${fileName}#${methodSignature.substring(0, methodSignature.indexOf('('))}`;
} else {
// Without the Apex Language Server, we'll take the quick-and-dirty route
// of just identifying the exact word the user selected, and assuming that's the name of a method.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
vscode.window.showWarningMessage(messages.targeting.warnings.apexLspUnavailable);
const wordRange: vscode.Range = textDocument.getWordRangeAtPosition(cursorPosition);
return `${textDocument.fileName}#${textDocument.getText(wordRange)}`;
return `${fileName}#${textDocument.getText(wordRange)}`;
}
}

/**
* Identifies the method definition symbol that most closely precedes the cursor's current position.
* @param symbols Symbols returned via the Apex Language Server
* @param cursorPosition The current location of the cursor
* @returns
* @returns
*/
function getNearestMethodSymbol(symbols: GenericSymbol[], cursorPosition: vscode.Position): GenericSymbol {
let nearestMethodSymbol: GenericSymbol = null;
Expand All @@ -116,7 +125,7 @@ function getNearestMethodSymbol(symbols: GenericSymbol[], cursorPosition: vscode
if (symbolStartPosition.line > cursorPosition.line) {
continue;
}

// Compare this method to the current nearest, and keep the later one.
if (!nearestMethodPosition || nearestMethodPosition.isBefore(symbolStartPosition)) {
nearestMethodSymbol = symbol;
Expand All @@ -130,7 +139,7 @@ function getNearestMethodSymbol(symbols: GenericSymbol[], cursorPosition: vscode
* Get the project containing the specified file.
*/
export function getProjectDir(targetFile: string): string {
const uri = vscode.Uri.parse(targetFile);
const uri = vscode.Uri.file(targetFile);
return vscode.workspace.getWorkspaceFolder(uri).uri.fsPath;
}

Expand All @@ -139,4 +148,4 @@ export function getProjectDir(targetFile: string): string {
*/
function isDocumentSymbol(o: GenericSymbol): o is vscode.DocumentSymbol {
return 'range' in o;
}
}
28 changes: 14 additions & 14 deletions src/test/suite/diagnostics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {DfaRuleViolation, PathlessRuleViolation, RuleResult} from '../../types';

suite('diagnostics.ts', () => {
suite('#displayDiagnostics()', () => {
// Note: This path is relative to the project's root directory.
const codeFixturesPath: string = path.resolve('.', 'code-fixtures');
// Note: __dirname is used here because it's consistent across file systems.
const codeFixturesPath: string = path.resolve(__dirname, '..', '..', '..', 'code-fixtures');
const pathToFirstFile: string = path.join(codeFixturesPath, 'folder-a', 'MyClassA1.cls');
const firstFileResults: RuleResult = {
engine: "pmd",
Expand Down Expand Up @@ -60,14 +60,14 @@ suite('diagnostics.ts', () => {

// ===== ASSERTIONS =====
// Validate that the file now has one violation.
expect(diagnosticCollection.get(vscode.Uri.parse(pathToFirstFile))).to.have.lengthOf(1, 'Wrong number of diagnostics');
expect(diagnosticCollection.get(vscode.Uri.file(pathToFirstFile))).to.have.lengthOf(1, 'Wrong number of diagnostics');
});

test('Refreshes stale violations on second-time target', () => {
// ===== SETUP =====
// Create a diagnostic collection and seed it with a diagnostic in file 2.
const diagnosticCollection = vscode.languages.createDiagnosticCollection('sfca');
const secondFileUri = vscode.Uri.parse(pathToSecondFile);
const secondFileUri = vscode.Uri.file(pathToSecondFile);
diagnosticCollection.set(secondFileUri, [
new vscode.Diagnostic(
new vscode.Range(new vscode.Position(1, 2), new vscode.Position(2, 3)),
Expand All @@ -91,7 +91,7 @@ suite('diagnostics.ts', () => {
// ===== SETUP =====
// Create a diagnostic collection and seed it with a diagnostic in file 2.
const diagnosticCollection = vscode.languages.createDiagnosticCollection('sfca');
const secondFileUri = vscode.Uri.parse(pathToSecondFile);
const secondFileUri = vscode.Uri.file(pathToSecondFile);
diagnosticCollection.set(secondFileUri, [
new vscode.Diagnostic(
new vscode.Range(new vscode.Position(1, 2), new vscode.Position(2, 3)),
Expand All @@ -115,7 +115,7 @@ suite('diagnostics.ts', () => {
// ===== SETUP =====
// Create a diagnostic collection and seed it with a diagnostic in file 2.
const diagnosticCollection = vscode.languages.createDiagnosticCollection('sfca');
const secondFileUri = vscode.Uri.parse(pathToSecondFile);
const secondFileUri = vscode.Uri.file(pathToSecondFile);
diagnosticCollection.set(secondFileUri, [
new vscode.Diagnostic(
new vscode.Range(new vscode.Position(1, 2), new vscode.Position(2, 3)),
Expand Down Expand Up @@ -145,14 +145,14 @@ suite('diagnostics.ts', () => {
line: 15,
column: 7
};

// TODO: Perhaps wait on this test until the messages/source/code specifics are sorted out.
test('Generates correct rule data', () => {
// ===== SETUP =====
// ===== TEST =====
// ===== ASSERTIONS =====
});

test('Generates positioning from violation WITH endLine and endColumn', () => {
// ===== SETUP =====
// Create our diagnostic manager and a copy of the violation.
Expand All @@ -161,11 +161,11 @@ suite('diagnostics.ts', () => {
// Give the violation some end positioning.
spoofedViolation.endLine = 30;
spoofedViolation.endColumn = 23;

// ===== TEST =====
// Create a diagnostic using our fake violation.
const diagnostic: vscode.Diagnostic = (diagnosticManager as any).createDiagnostic("pmd", spoofedViolation);

// ===== ASSERTIONS =====
// Verify that the starting and ending position both use the explicit values.
// Bear in mind that start line, end line, and start column are all zero-indexed,
Expand All @@ -177,17 +177,17 @@ suite('diagnostics.ts', () => {
expect(endingPosition.line).to.equal(spoofedViolation.endLine - 1, 'Wrong end line');
expect(endingPosition.character).to.equal(spoofedViolation.endColumn, 'Wrong end column');
});

test('Generates positioning from violation WITHOUT endLine or endColumn', () => {
// ===== SETUP =====
// Create our diagnostic manager and a copy of the violation.
const spoofedViolation: PathlessRuleViolation = JSON.parse(JSON.stringify(baseSpoofedViolation)) as PathlessRuleViolation;
const diagnosticManager: DiagnosticManager = new DiagnosticManager();

// ===== TEST =====
// Create a diagnostic using our fake violation.
const diagnostic: vscode.Diagnostic = (diagnosticManager as any).createDiagnostic("pmd", spoofedViolation);

// ===== ASSERTIONS =====
// Verify that the starting position uses the explicit value, and the end
// position uses the end of the start line.
Expand Down Expand Up @@ -239,4 +239,4 @@ suite('diagnostics.ts', () => {
});
});
});
});
});
12 changes: 6 additions & 6 deletions src/test/suite/fixer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {messages} from '../../lib/messages';
import {_NoOpFixGenerator, _PmdFixGenerator} from '../../lib/fixer';

suite('fixer.ts', () => {
// NOTE: This path is relative to the project's root directory.
const codeFixturesPath: string = path.resolve('.', 'code-fixtures', 'fixer-tests');
// Note: __dirname is used here because it's consistent across file systems.
const codeFixturesPath: string = path.resolve(__dirname, '..', '..', '..', 'code-fixtures', 'fixer-tests');

suite('_NoOpFixGenerator', () => {
suite('#generateFixes()', () => {
Expand All @@ -33,7 +33,7 @@ suite('fixer.ts', () => {
suite('#generateFixes()', () => {
suite('XML doc', () => {
// Get the URI for the XML doc.
const xmlDocUri: vscode.Uri = vscode.Uri.parse(path.join(codeFixturesPath, 'MyDoc1.xml'));
const xmlDocUri: vscode.Uri = vscode.Uri.file(path.join(codeFixturesPath, 'MyDoc1.xml'));

// At this time, we don't support injecting suppression for XML.
test('No fixes are offered', async () => {
Expand Down Expand Up @@ -62,7 +62,7 @@ suite('fixer.ts', () => {

suite('Apex doc', () => {
let originalFileContents: string;
const fileUri = vscode.Uri.parse(path.join(codeFixturesPath, 'MyClass1.cls'));
const fileUri = vscode.Uri.file(path.join(codeFixturesPath, 'MyClass1.cls'));

let doc: vscode.TextDocument;
// Load the document and store its starting contents.
Expand Down Expand Up @@ -118,7 +118,7 @@ suite('fixer.ts', () => {

// Attempt to generate fixes for the file.
const fixes: vscode.CodeAction[] = fixGenerator.generateFixes();

// We expect to get one fix, to inject the suppression at the s tart of the comment that ends the line.
expect(fixes).to.have.lengthOf(1, 'Wrong action count');
const fix = fixes[0].edit.get(fileUri)[0];
Expand All @@ -130,4 +130,4 @@ suite('fixer.ts', () => {
});
});
});
});
});
Loading