Skip to content

Commit 804ab05

Browse files
authored
Merge pull request #299 from recca0120/fix/pest-path
fix pest link
2 parents 4e5d971 + 94d518a commit 804ab05

11 files changed

Lines changed: 112 additions & 37 deletions

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"displayName": "PHPUnit Test Explorer",
55
"icon": "img/icon.png",
66
"publisher": "recca0120",
7-
"version": "3.6.0",
7+
"version": "3.6.1",
88
"private": true,
99
"license": "MIT",
1010
"repository": {

src/Handler.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@ import {
77
} from 'vscode';
88
import { CloverParser } from './CloverParser';
99
import { Configuration } from './Configuration';
10-
import { CollisionPrinter, OutputChannelObserver, TestResultObserver } from './Observers';
10+
import { OutputChannelObserver, Printer, TestResultObserver } from './Observers';
1111
import { MessageObserver } from './Observers/MessageObserver';
1212
import { CommandBuilder, TestRunner, TestRunnerEvent, TestType } from './PHPUnit';
1313
import { TestCase, TestCollection } from './TestCollection';
1414

1515
export class Handler {
1616
private previousRequest: TestRunRequest | undefined;
17-
private printer = new CollisionPrinter();
1817

19-
constructor(private ctrl: TestController, private configuration: Configuration, private testCollection: TestCollection, private outputChannel: OutputChannel) { }
18+
constructor(
19+
private ctrl: TestController,
20+
private configuration: Configuration,
21+
private testCollection: TestCollection, private outputChannel: OutputChannel,
22+
private printer: Printer,
23+
) { }
2024

2125
getPreviousRequest() {
2226
return this.previousRequest;
@@ -55,7 +59,7 @@ export class Handler {
5559

5660
const runner = new TestRunner();
5761
runner.observe(new TestResultObserver(queue, testRun));
58-
runner.observe(new OutputChannelObserver(this.outputChannel, this.configuration, request, this.printer));
62+
runner.observe(new OutputChannelObserver(this.outputChannel, this.configuration, this.printer, request));
5963
runner.observe(new MessageObserver(this.configuration));
6064

6165
let tmpd: string | undefined;

src/Observers/OutputChannelObserver.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ describe('OutputChannelObserver', () => {
2525
const observer = new OutputChannelObserver(
2626
outputChannel,
2727
configuration,
28-
{ continuous: false } as TestRunRequest,
2928
new PrettyPrinter(),
29+
{ continuous: false } as TestRunRequest,
3030
);
3131
testRunner.observe(observer);
3232
});

src/Observers/OutputChannelObserver.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
TestProcesses, TestResult, TestResultSummary, TestRunnerObserver, TestRuntime, TestStarted, TestSuiteFinished,
55
TestSuiteStarted, TestVersion,
66
} from '../PHPUnit';
7-
import { PrettyPrinter, Printer } from './Printers';
7+
import { Printer } from './Printers';
88

99
enum ShowOutputState {
1010
always = 'always',
@@ -15,12 +15,7 @@ enum ShowOutputState {
1515
export class OutputChannelObserver implements TestRunnerObserver {
1616
private lastCommand = '';
1717

18-
constructor(
19-
private outputChannel: OutputChannel,
20-
private configuration: IConfiguration,
21-
private request: TestRunRequest,
22-
private printer: Printer = new PrettyPrinter(),
23-
) {}
18+
constructor(private outputChannel: OutputChannel, private configuration: IConfiguration, private printer: Printer, private request: TestRunRequest) {}
2419

2520
run(command: CommandBuilder): void {
2621
this.clearOutputOnRun();

src/Observers/Printers/CollisionPrinter.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { EOL, TeamcityEvent } from '../../PHPUnit';
1+
import { EOL, PHPUnitXML, TeamcityEvent } from '../../PHPUnit';
22
import { phpUnitProject } from '../../PHPUnit/__tests__/utils';
33
import { CollisionPrinter } from './CollisionPrinter';
44
import { Printer } from './Printer';
55

66
describe('CollisionPrinter', () => {
7-
const printer = new CollisionPrinter();
7+
const phpUnitXML = new PHPUnitXML().setRoot(phpUnitProject(''));
8+
const printer = new CollisionPrinter(phpUnitXML);
89

910
beforeEach(() => printer.start());
1011
afterEach(() => printer.close());

src/Observers/Printers/CollisionPrinter.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Printer } from './Printer';
55
export class CollisionPrinter extends Printer {
66
private errors: TestFailed[] = [];
77

8+
89
start() {
910
super.start();
1011
this.errors = [];
@@ -72,16 +73,17 @@ export class CollisionPrinter extends Printer {
7273
}
7374

7475
private getFileContent(result: TestFailed) {
75-
const detail = result.details.find(({ file }) => {
76-
return file === result.file;
77-
})!;
76+
let detail = result.details.find(({ file }) => file === result.file)!;
77+
if (result.details.length > 0) {
78+
detail = result.details[0];
79+
}
7880

7981
if (!detail) {
8082
return undefined;
8183
}
8284

8385
try {
84-
const data = readFileSync(detail.file, 'utf8');
86+
const data = readFileSync(this.absolutePath(detail.file), 'utf8');
8587
const position = detail.line - 5;
8688
const lines = data.split(/\r\n|\n/).splice(position, 10).map((line, index) => {
8789
const currentPosition = position + index + 1;

src/Observers/Printers/PrettyPrinter.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { EOL, TeamcityEvent } from '../../PHPUnit';
1+
import { EOL, PHPUnitXML, TeamcityEvent } from '../../PHPUnit';
22
import { phpUnitProject } from '../../PHPUnit/__tests__/utils';
33
import { PrettyPrinter } from './PrettyPrinter';
44
import { Printer } from './Printer';
55

66
describe('PrettyPrinter', () => {
7-
const printer = new PrettyPrinter();
7+
const phpUnitXML = new PHPUnitXML().setRoot(phpUnitProject(''));
8+
const printer = new PrettyPrinter(phpUnitXML);
89

910
beforeEach(() => printer.start());
1011
afterEach(() => printer.close());

src/Observers/Printers/Printer.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { isAbsolute, join } from 'node:path';
12
import {
2-
EOL, TeamcityEvent, TestConfiguration, TestDuration, TestFailed, TestFinished, TestProcesses, TestResult,
3-
TestResultSummary, TestRuntime, TestStarted, TestSuiteFinished, TestSuiteStarted, TestVersion,
3+
EOL, PHPUnitXML, TeamcityEvent, TestConfiguration, TestDuration, TestFailed, TestFinished, TestProcesses,
4+
TestResult, TestResultSummary, TestRuntime, TestStarted, TestSuiteFinished, TestSuiteStarted, TestVersion,
45
} from '../../PHPUnit';
56

67
class OutputBuffer {
@@ -47,6 +48,8 @@ export abstract class Printer {
4748
[TeamcityEvent.testIgnored, ['➖', 'IGNORED']],
4849
]);
4950

51+
constructor(private phpUnitXML: PHPUnitXML) {}
52+
5053
static fileFormat(file: string, line: number) {
5154
return `${file}:${line}`;
5255
}
@@ -139,6 +142,12 @@ export abstract class Printer {
139142
this.outputBuffer.append(line);
140143
}
141144

145+
protected absolutePath(filePath: string): string {
146+
const root = this.phpUnitXML.root();
147+
148+
return isAbsolute(filePath) && root ? filePath : join(root, filePath);
149+
}
150+
142151
private setCurrent(current?: string) {
143152
this.outputBuffer.setCurrent(current);
144153
}

src/PHPUnitLinkProvider.test.ts

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { relative } from 'path';
1+
import { relative } from 'node:path';
22
import { DocumentLink, Position, Range } from 'vscode';
3+
import { PHPUnitXML } from './PHPUnit';
34
import { phpUnitProject } from './PHPUnit/__tests__/utils';
45
import { PHPUnitLinkProvider } from './PHPUnitLinkProvider';
56

@@ -30,9 +31,16 @@ class TextDocument {
3031

3132
describe('PHPUnitLinkProvider', () => {
3233
const root = phpUnitProject('');
33-
const normalizePath = (file: string) => relative(root, file).replace(/\\/g, '/');
34+
const phpUnitXML = new PHPUnitXML().setRoot(root);
35+
const normalizePath = (file: string) => {
36+
return relative(root, file).replace(/\\/g, '/');
37+
};
3438

35-
const text = `❌ FAILED Calculator (Tests\Calculator) > Sum item method not call
39+
let provider: PHPUnitLinkProvider;
40+
beforeEach(() => provider = new PHPUnitLinkProvider(phpUnitXML));
41+
42+
it('get PHPUnit links', () => {
43+
const document = new TextDocument(`❌ FAILED Calculator (Tests\Calculator) > Sum item method not call
3644
Mockery\Exception\InvalidCountException: Method test(<Any Arguments>) from Mockery_0_App_Item_App_Item should be called
3745
exactly 1 times but called 0 times.
3846
@@ -44,13 +52,7 @@ Mockery\Exception\InvalidCountException: Method test(<Any Arguments>) from Mocke
4452
6. ${phpUnitProject('vendor/mockery/mockery/library/Mockery.php')}:176
4553
7. ${phpUnitProject('vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegration.php')}:49
4654
8. ${phpUnitProject('vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegration.php')}:61
47-
9. ${phpUnitProject('vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegrationAssertPostConditions.php')}:19`;
48-
49-
let provider: PHPUnitLinkProvider;
50-
beforeEach(() => provider = new PHPUnitLinkProvider());
51-
52-
it('get links', () => {
53-
const document = new TextDocument(text);
55+
9. ${phpUnitProject('vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegrationAssertPostConditions.php')}:19`);
5456

5557
const links = (provider.provideDocumentLinks(document as any, {} as any) as DocumentLink[])
5658
.map((link) => [normalizePath(link.target!.fsPath), link.target!.fragment]);
@@ -67,4 +69,53 @@ Mockery\Exception\InvalidCountException: Method test(<Any Arguments>) from Mocke
6769
['vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegrationAssertPostConditions.php', 'L19'],
6870
]);
6971
});
72+
73+
it('get PEST links', () => {
74+
const document = new TextDocument(`❌ FAILED tests/Unit/ArchTest.php > preset → strict
75+
Expecting 'src/Calculator.php' to be final.
76+
77+
at src/Calculator.php:7
78+
3 ▕ namespace App;
79+
4 ▕
80+
5 ▕ use Exception;
81+
6 ▕
82+
➜ 7 ▕ class Calculator
83+
8 ▕ {
84+
9 ▕ public function sum($a, $b)
85+
10 ▕ {
86+
11 ▕ return $a + $b;
87+
12 ▕ }
88+
89+
1. src/Calculator.php:7
90+
2. vendor/pestphp/pest-plugin-arch/src/Expectations/Targeted.php:43
91+
3. vendor/pestphp/pest-plugin-arch/src/Blueprint.php:137
92+
4. vendor/pestphp/pest-plugin-arch/src/Expectations/Targeted.php:40
93+
5. vendor/pestphp/pest-plugin-arch/src/SingleArchExpectation.php:156
94+
6. vendor/pestphp/pest-plugin-arch/src/SingleArchExpectation.php:140
95+
7. src/Calculator.php:1
96+
8. vendor/pestphp/pest-plugin-arch/src/Expectations/Targeted.php:43
97+
9. vendor/pestphp/pest-plugin-arch/src/Blueprint.php:137
98+
10. vendor/pestphp/pest-plugin-arch/src/Expectations/Targeted.php:40
99+
11. vendor/pestphp/pest-plugin-arch/src/SingleArchExpectation.php:156
100+
12. vendor/pestphp/pest-plugin-arch/src/SingleArchExpectation.php:140`);
101+
102+
const links = (provider.provideDocumentLinks(document as any, {} as any) as DocumentLink[])
103+
.map((link) => [normalizePath(link.target!.fsPath), link.target!.fragment]);
104+
105+
expect(links).toEqual([
106+
['src/Calculator.php', 'L7'],
107+
['src/Calculator.php', 'L7'],
108+
['vendor/pestphp/pest-plugin-arch/src/Expectations/Targeted.php', 'L43'],
109+
['vendor/pestphp/pest-plugin-arch/src/Blueprint.php', 'L137'],
110+
['vendor/pestphp/pest-plugin-arch/src/Expectations/Targeted.php', 'L40'],
111+
['vendor/pestphp/pest-plugin-arch/src/SingleArchExpectation.php', 'L156'],
112+
['vendor/pestphp/pest-plugin-arch/src/SingleArchExpectation.php', 'L140'],
113+
['src/Calculator.php', 'L1'],
114+
['vendor/pestphp/pest-plugin-arch/src/Expectations/Targeted.php', 'L43'],
115+
['vendor/pestphp/pest-plugin-arch/src/Blueprint.php', 'L137'],
116+
['vendor/pestphp/pest-plugin-arch/src/Expectations/Targeted.php', 'L40'],
117+
['vendor/pestphp/pest-plugin-arch/src/SingleArchExpectation.php', 'L156'],
118+
['vendor/pestphp/pest-plugin-arch/src/SingleArchExpectation.php', 'L140'],
119+
]);
120+
});
70121
});

src/PHPUnitLinkProvider.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
import { isAbsolute, join } from 'node:path';
12
import {
23
CancellationToken, DocumentLink, DocumentLinkProvider, Position, ProviderResult, Range, TextDocument,
34
} from 'vscode';
45
import { URI } from 'vscode-uri';
6+
import { PHPUnitXML } from './PHPUnit';
57

68
export class PHPUnitLinkProvider implements DocumentLinkProvider {
79
private regex = /((?:[A-Z]:)?(?:\.{0,2}[\\/])?[^\s:]+\.php):(\d+)(?::(\d+))?/gi;
810

11+
constructor(private phpUnitXML: PHPUnitXML) {}
12+
913
provideDocumentLinks(document: TextDocument, _token: CancellationToken): ProviderResult<DocumentLink[]> {
1014
const links: DocumentLink[] = [];
1115

@@ -14,10 +18,10 @@ export class PHPUnitLinkProvider implements DocumentLinkProvider {
1418
let match: RegExpExecArray | null;
1519

1620
while ((match = this.regex.exec(line.text)) !== null) {
17-
const [fullMatch, filePath, lineStr, colStr] = match;
21+
const [fullMatch, filePath, lineStr] = match;
1822
const lineNumber = parseInt(lineStr, 10);
1923

20-
const targetUri = URI.file(filePath).with({ fragment: `L${lineNumber}` });
24+
const targetUri = URI.file(this.absolutePath(filePath)).with({ fragment: `L${lineNumber}` });
2125
const start = new Position(lineIndex, match.index);
2226
const end = new Position(lineIndex, match.index + fullMatch.length);
2327
const range = new Range(start, end);
@@ -28,4 +32,10 @@ export class PHPUnitLinkProvider implements DocumentLinkProvider {
2832

2933
return links;
3034
}
35+
36+
private absolutePath(filePath: string): string {
37+
const root = this.phpUnitXML.root();
38+
39+
return isAbsolute(filePath) && root ? filePath : join(root, filePath);
40+
}
3141
}

0 commit comments

Comments
 (0)