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

[WIP] Create a custom Logger to gather the data from the test run #271

Draft
wants to merge 38 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
3e5bcda
Started implementing a DataCollector
GeorchW Jun 9, 2020
2aa35dc
Implement basic TCP server in the extension
GeorchW Jun 9, 2020
e8cfd4e
Tidying up executor, part 1
GeorchW Jun 9, 2020
429f945
Tidying up executor, part 2
GeorchW Jun 9, 2020
b58f8bd
Add code to set the server port for the subprocess
GeorchW Jun 9, 2020
5f277ad
Add publish dir to .gitignore
GeorchW Jun 9, 2020
edddb24
Add process env back in
GeorchW Jun 9, 2020
ce6b03f
Add data collector arguments to dotnet test
GeorchW Jun 9, 2020
b84e3a1
Send some slightly less nonsense data
GeorchW Jun 9, 2020
8b2fc4f
Send data as JSON
GeorchW Jun 9, 2020
4511b76
Make Executor.exec awaitable
GeorchW Jun 9, 2020
0d665bb
Make use of the received data
GeorchW Jun 9, 2020
a0db0fd
Use Logger instead of DataCollector API
GeorchW Jun 10, 2020
b4db6e3
Minor corrections
GeorchW Jun 10, 2020
560222f
Tidy up a little
GeorchW Jun 10, 2020
37353bc
Don't parse trx
GeorchW Jun 10, 2020
79527ef
Rename ITestResult => ITestResults
GeorchW Jun 10, 2020
3abb168
Fix event surface
GeorchW Jun 10, 2020
2bee683
Remove testResultsFile
GeorchW Jun 10, 2020
7062995
Clean up TestResult class
GeorchW Jun 10, 2020
3e7a541
Make an interface out of TestResult
GeorchW Jun 10, 2020
3a77b44
Use logger for test discovery
GeorchW Jun 10, 2020
d3e96f8
Remove unused usings
GeorchW Jun 11, 2020
50bfeee
Notify watcher of start/end of test run
GeorchW Jun 11, 2020
358bc47
Rework tree code
GeorchW Jun 11, 2020
8df96c9
Clean up subprocess logging
GeorchW Jun 11, 2020
acacf60
Spam less output
GeorchW Jun 11, 2020
c83800b
Apply old test results after discovery
GeorchW Jun 11, 2020
974ae83
Fix watch, remove tests that are not found
GeorchW Jun 11, 2020
8e96ffd
Fix gotoTest
GeorchW Jun 11, 2020
3d3df54
Log child process output by default
GeorchW Jun 11, 2020
044955c
Fix weird XUnit names
GeorchW Jun 11, 2020
d410eeb
Replace then with async/await
GeorchW Jun 11, 2020
5403938
Send messages asynchronously
GeorchW Jun 12, 2020
579e9d0
Rebuild tree when tests are removed
GeorchW Jun 12, 2020
09f7e83
Add proper names
GeorchW Jun 12, 2020
18effd7
Update language version
GeorchW Feb 26, 2022
f6fef75
Update packages
GeorchW Feb 26, 2022
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
Prev Previous commit
Next Next commit
Fix gotoTest
  • Loading branch information
GeorchW committed Jun 11, 2020
commit 8e96ffdcdb6058dfd2edd93d08a5a979f5345d6e
8 changes: 4 additions & 4 deletions src/buildTree.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IParsedName } from "./parseTestName";
import { IParsedName, getSegmentString, getSegmentEnd } from "./parseTestName";

/**
* This is an "abstract" version of a tree node, containing the logical structure
Expand All @@ -19,8 +19,8 @@ export function buildTree(parsedNames: IParsedName[]): ITestTreeNode {
for (let i = 0; i < parsedName.segments.length - 1; i++) {
const segment = parsedName.segments[i];

const part = parsedName.fullName.substr(segment.start, segment.end - segment.start);
const fullName = parsedName.fullName.substr(0, segment.end);
const part = getSegmentString(parsedName.fullName, segment);
const fullName = parsedName.fullName.substring(0, getSegmentEnd(segment));
if (!currentNode.subTrees.has(part)) {
const newTree: ITestTreeNode = {
fullName,
Expand All @@ -36,7 +36,7 @@ export function buildTree(parsedNames: IParsedName[]): ITestTreeNode {
}

const lastSegment = parsedName.segments[parsedName.segments.length - 1];
const testName = parsedName.fullName.substr(lastSegment.start, lastSegment.end - lastSegment.start);
const testName = getSegmentString(parsedName.fullName, lastSegment);
currentNode.tests.push(testName);
}
return root;
Expand Down
67 changes: 30 additions & 37 deletions src/gotoTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,48 @@ import { AppInsightsClient } from "./appInsightsClient";
import { Logger } from "./logger";
import { Utility } from "./utility";
import { TestNode } from "./treeNodes/testNode";
import { parseTestName, IStringView, getSegmentStart } from "./parseTestName";

export class GotoTest {

public go(test: TestNode): void {
public async go(test: TestNode) {

AppInsightsClient.sendEvent("gotoTest");

const symbolInformation = vscode.commands.executeCommand<vscode.SymbolInformation[]>(
"vscode.executeWorkspaceSymbolProvider",
test.fullName,
).then((symbols) => {

let symbol: vscode.SymbolInformation;

try {
symbol = this.findTestLocation(symbols, test);
// Remove all brackets from the test name
const parsed = parseTestName(test.fullName);
const bracketsRemoved = parsed.segments
.map(segment => parsed.fullName.substring(getSegmentStart(segment), segment.name.end))
.join("");

vscode.workspace.openTextDocument(symbol.location.uri).then((doc) => {
vscode.window.showTextDocument(doc).then((editor) => {
const loc = symbol.location.range;
const selection = new vscode.Selection(loc.start.line, loc.start.character, loc.start.line, loc.end.character);
vscode.window.activeTextEditor.selection = selection;
vscode.window.activeTextEditor.revealRange(selection, vscode.TextEditorRevealType.InCenter);
});
});

} catch (r) {
Logger.Log(r.message);
vscode.window.showWarningMessage(r.message);
}

});
const symbols = await vscode.commands.executeCommand<vscode.SymbolInformation[]>(
"vscode.executeWorkspaceSymbolProvider",
bracketsRemoved,
)

let symbol: vscode.SymbolInformation;

try {
symbol = this.findTestLocation(symbols, bracketsRemoved);
const doc = await vscode.workspace.openTextDocument(symbol.location.uri);
const editor = await vscode.window.showTextDocument(doc)
const loc = symbol.location.range;
const selection = new vscode.Selection(loc.start.line, loc.start.character, loc.start.line, loc.end.character);
editor.selection = selection;
editor.revealRange(selection, vscode.TextEditorRevealType.InCenter);
} catch (r) {
Logger.Log(r.message);
vscode.window.showWarningMessage(r.message);
}
}

public findTestLocation(symbols: vscode.SymbolInformation[], testNode: TestNode): vscode.SymbolInformation {
public findTestLocation(symbols: vscode.SymbolInformation[], testName: string): vscode.SymbolInformation {

if (symbols.length === 0) {
throw new Error("Could not find test (no symbols found)");
}

const testFqn = testNode.fullName;

symbols = symbols.filter((s) => this.isSymbolATestCandidate(s) && testFqn.endsWith(this.getTestMethodFqn(s.name)));
symbols = symbols.filter((s) => this.isSymbolATestCandidate(s) && testName.endsWith(this.getTestMethodName(s.name)));

if (symbols.length === 0) {
throw Error("Could not find test (no symbols matching)");
Expand All @@ -58,16 +57,10 @@ export class GotoTest {
return symbols[0];
}

public getTestMethodFqn(testName: string): string {
public getTestMethodName(testName: string): string {
// The symbols are reported on the form Method or Method(string, int) (in case of test cases etc).
// We are only interested in the method name, not its arguments
const firstParanthesis = testName.indexOf("(");

if (firstParanthesis > -1) {
testName = testName.substring(0, firstParanthesis);
}

return testName;
return testName.replace(/\(.*$/, "");
}

private isSymbolATestCandidate(s: vscode.SymbolInformation): boolean {
Expand Down
56 changes: 47 additions & 9 deletions src/parseTestName.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,54 @@
export interface INameSegment {
export interface IStringView {
start: number;
end: number;
}

export interface ISegment {
prefix?: IStringView,
name: IStringView,
brackets?: IStringView,
}

export interface IParsedName {
fullName: string;
segments: INameSegment[];
segments: ISegment[];
}

export function parseTestName(name: string): IParsedName {
let i = 0;
const segments = [];
const segments: ISegment[] = [];
while (i < name.length) {
segments.push(parseSegment());
}
return { fullName: name, segments };

function parseSegment(): INameSegment {
function parseSegment(): ISegment {
const prefix = parsePrefix();
const _name = parseName();
const brackets = parseBrackets();
return { prefix, name: _name, brackets };
}

function parsePrefix(): IStringView | undefined {
if (name[i] === "." || name[i] === "+") {
const result = { start: i, end: i + 1 };
i++;
return result;
}
}
function parseName(): IStringView {
const start = i;
while (i < name.length) {
if (tryParseBrackets()) { continue; }
if (name[i] === "." || name[i] === "+") { break; }
if (name[i] === "(" || name[i] === "+" || name[i] === ".") {
break;
}
i++;
}
const end = i;
i++;
return { start, end };
return { start, end: i };
}
function parseBrackets(): IStringView | undefined {
const start = i;
if (tryParseBrackets()) { return { start, end: i }; }
}

function tryParseBrackets(): boolean {
Expand Down Expand Up @@ -62,3 +85,18 @@ export function parseTestName(name: string): IParsedName {
return true;
}
}

export function getSegmentString(fullName: string, segment: ISegment) {
return fullName.substring(segment.name.start, getSegmentEnd(segment));
}

export function getSegmentStart(segment: ISegment) {
return segment.prefix?.start ?? segment.name.start;
}

export function getSegmentEnd(segment: ISegment) {
return segment.brackets?.end ?? segment.name.end;
}
export function viewToString(fullName: string, view: IStringView) {
return fullName.substring(view.start, view.end);
}
4 changes: 2 additions & 2 deletions test/gotoTest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,15 @@ suite("Get test method name", () => {
test("Test name without namespace", () => {

const gotoTest = new GotoTest();
const result = gotoTest.getTestMethodFqn("Test");
const result = gotoTest.getTestMethodName("Test");

assert.equal(result, "Test");
});

test("XUnit theory name without namespace", () => {

const gotoTest = new GotoTest();
const result = gotoTest.getTestMethodFqn("Test(param: value)");
const result = gotoTest.getTestMethodName("Test(param: value)");

assert.equal(result, "Test");
});
Expand Down
4 changes: 2 additions & 2 deletions test/parseTestName.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as assert from "assert";
import { parseTestName } from "../src/parseTestName";
import { parseTestName, getSegmentString } from "../src/parseTestName";

suite("parseTestName - test names are parsed correctly", () => {
function testParsing(input, expected) {
test(`${input} -> ${expected.map((x) => `"${x}"`).join(" ")}`, () => {
const result = parseTestName(input);
assert.equal(result.fullName, input);
const segmentsAsStrings = result.segments.map(
(segment) => input.substr(segment.start, segment.end - segment.start));
(segment) => getSegmentString(input, segment));
assert.deepEqual(segmentsAsStrings, expected);
});
}
Expand Down