diff --git a/src/PHPUnit/PHPUnitXML.ts b/src/PHPUnit/PHPUnitXML.ts index 37c4590c..d3b5fa22 100644 --- a/src/PHPUnit/PHPUnitXML.ts +++ b/src/PHPUnit/PHPUnitXML.ts @@ -91,9 +91,9 @@ export class PHPUnitXML { private readonly cached: Map = new Map(); load(text: string | Buffer | Uint8Array, file: string) { + this.element = new Element(parser.parse(text.toString())); this._file = file; this.setRoot(dirname(file)); - this.element = new Element(parser.parse(text.toString())); return this; } diff --git a/src/PHPUnit/ProblemMatcher/TestResultSummaryParser.ts b/src/PHPUnit/ProblemMatcher/TestResultSummaryParser.ts index 5a598548..0d378899 100644 --- a/src/PHPUnit/ProblemMatcher/TestResultSummaryParser.ts +++ b/src/PHPUnit/ProblemMatcher/TestResultSummaryParser.ts @@ -38,10 +38,10 @@ export class TestResultSummaryParser implements IParser { return [...text.matchAll(pattern)].reduce( (result: any, match) => { - const groups = match.groups!; - const [name, count] = groups.name - ? [groups.name, groups.count] - : [groups.name2, groups.count2]; + const matched = match.groups!; + const [name, count] = matched.name + ? [matched.name, matched.count] + : [matched.name2, matched.count2]; result[this.normalize(name)] = parseInt(count, 10); return result; diff --git a/src/PHPUnit/ProblemMatcher/TestVersionParser.ts b/src/PHPUnit/ProblemMatcher/TestVersionParser.ts index 8deda163..f40e9291 100644 --- a/src/PHPUnit/ProblemMatcher/TestVersionParser.ts +++ b/src/PHPUnit/ProblemMatcher/TestVersionParser.ts @@ -12,12 +12,12 @@ export class TestVersionParser implements IParser { } parse(text: string) { - const groups = text.match(this.pattern)!.groups!; + const matched = text.match(this.pattern)!.groups!; return { event: TeamcityEvent.testVersion, - phpunit: groups.phpunit, - paratest: groups.paratest, + phpunit: matched.phpunit, + paratest: matched.paratest, text, }; } diff --git a/src/PHPUnit/ProblemMatcher/ValueParser.ts b/src/PHPUnit/ProblemMatcher/ValueParser.ts index e6015db4..896aef8a 100644 --- a/src/PHPUnit/ProblemMatcher/ValueParser.ts +++ b/src/PHPUnit/ProblemMatcher/ValueParser.ts @@ -15,11 +15,11 @@ export abstract class ValueParser implements IParser { } parse(text: string) { - const groups = text.match(this.pattern)!.groups!; + const matched = text.match(this.pattern)!.groups!; return { event: this.event, - [this.name.toLowerCase()]: groups[this.name], + [this.name.toLowerCase()]: matched[this.name], text, } as T; } diff --git a/src/PHPUnit/TestCollection/TestCollection.test.ts b/src/PHPUnit/TestCollection/TestCollection.test.ts index 59d6ea35..bba5fc12 100644 --- a/src/PHPUnit/TestCollection/TestCollection.test.ts +++ b/src/PHPUnit/TestCollection/TestCollection.test.ts @@ -14,10 +14,10 @@ describe('TestCollection', () => { return testCollection; }; - const shouldBe = async (collection: TestCollection, group: any) => { + const shouldBe = async (collection: TestCollection, testsuites: any) => { const phpUnitXML = new PHPUnitXML(); phpUnitXML.setRoot(phpUnitProject('')); - for (const [name, files] of Object.entries(group)) { + for (const [testsuite, files] of Object.entries(testsuites)) { const expected: TestDefinition[] = []; for (const uri of (files as URI[])) { const testParser = new TestParser(phpUnitXML); @@ -25,10 +25,10 @@ describe('TestCollection', () => { testParser.on(TestType.class, (testDefinition) => expected.push(testDefinition)); testParser.on(TestType.namespace, (testDefinition) => expected.push(testDefinition)); - await testParser.parseFile(uri.fsPath); + await testParser.parseFile(uri.fsPath, testsuite); } const actual: TestDefinition[] = []; - collection.items().get(name)?.items().forEach((item) => actual.push(...item)); + collection.items().get(testsuite)?.items().forEach((item) => actual.push(...item)); expect(actual).toEqual(expected); } }; diff --git a/src/PHPUnit/TestCollection/TestCollection.ts b/src/PHPUnit/TestCollection/TestCollection.ts index cb3bf137..6b3fb943 100644 --- a/src/PHPUnit/TestCollection/TestCollection.ts +++ b/src/PHPUnit/TestCollection/TestCollection.ts @@ -5,7 +5,7 @@ import { PHPUnitXML, TestDefinition, TestParser, TestSuite } from '../index'; import { TestDefinitionBuilder } from './TestDefinitionBuilder'; export interface File { - group: string; + testsuite: string; uri: URI; tests: T[]; } @@ -99,17 +99,17 @@ export class TestCollection { } async change(uri: URI) { - const group = this.getGroup(uri); - if (!group) { + const testsuite = this.parseTestsuite(uri); + if (!testsuite) { return this; } const files = this.items(); - const testDefinitions = await this.parseTests(uri); + const testDefinitions = await this.parseTests(uri, testsuite); if (testDefinitions.length === 0) { this.delete(uri); } - files.get(group)!.set(uri, testDefinitions); + files.get(testsuite)!.set(uri, testDefinitions); return this; } @@ -147,9 +147,9 @@ export class TestCollection { return undefined; } - protected async parseTests(uri: URI) { + protected async parseTests(uri: URI, testsuite: string) { const { testParser, testDefinitionBuilder } = this.createTestParser(); - await testParser.parseFile(uri.fsPath); + await testParser.parseFile(uri.fsPath, testsuite); return testDefinitionBuilder.get(); } @@ -162,34 +162,36 @@ export class TestCollection { } protected deleteFile(file: File) { - return this.items().get(file.group)?.delete(file.uri); + return this.items().get(file.testsuite)?.delete(file.uri); } private* gatherFiles() { - for (const [group, files] of this.items()) { + for (const [testsuite, files] of this.items()) { for (const [uri, tests] of files) { - yield { group, uri, tests }; + yield { testsuite, uri, tests }; } } } - private getGroup(uri: URI) { + private parseTestsuite(uri: URI) { const testSuites = this.phpUnitXML.getTestSuites(); - const group = testSuites.find(item => { + const testsuite = testSuites.find(item => { return ['directory', 'file'].includes(item.tag) && this.match(item, uri); }); - if (!group) { + + if (!testsuite) { return; } const exclude = testSuites.find((item) => { - return item.name === group.name && item.tag === 'exclude' && this.match(item, uri); + return item.name === testsuite.name && item.tag === 'exclude' && this.match(item, uri); }); + if (exclude) { return; } - return group.name; + return testsuite.name; } private match(testSuite: TestSuite, uri: URI) { diff --git a/src/PHPUnit/TestParser/PHPUnitParser.test.ts b/src/PHPUnit/TestParser/PHPUnitParser.test.ts index ce3a8238..d15c3c8a 100644 --- a/src/PHPUnit/TestParser/PHPUnitParser.test.ts +++ b/src/PHPUnit/TestParser/PHPUnitParser.test.ts @@ -46,12 +46,12 @@ describe('PHPUnitParser Test', () => { beforeAll(async () => content = (await readFile(file)).toString()); it('parse namespace', () => { - expect(givenTest(file, content, 'Recca0120\\VSCode\\Tests')).toEqual(expect.objectContaining({ + expect(givenTest(file, content, 'Tests')).toEqual(expect.objectContaining({ type: TestType.namespace, // file, - id: 'namespace:Tests (Recca0120\\VSCode\\Tests)', - classFQN: 'Recca0120\\VSCode\\Tests', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'namespace:Tests', + classFQN: 'Tests', + namespace: 'Tests', depth: 0, })); }); @@ -60,9 +60,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'AssertionsTest')).toEqual(expect.objectContaining({ type: TestType.class, file, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)', - classFQN: 'Recca0120\\VSCode\\Tests\\AssertionsTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Assertions (Tests\\Assertions)', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', className: 'AssertionsTest', start: { line: 8, character: 0 }, end: { line: 83, character: 1 }, @@ -74,9 +74,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'test_passed')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Passed', - classFQN: 'Recca0120\\VSCode\\Tests\\AssertionsTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Assertions (Tests\\Assertions)::Passed', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', className: 'AssertionsTest', methodName: 'test_passed', start: { line: 12, character: 4 }, @@ -89,9 +89,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'test_failed')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Failed', - classFQN: 'Recca0120\\VSCode\\Tests\\AssertionsTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Assertions (Tests\\Assertions)::Failed', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', className: 'AssertionsTest', methodName: 'test_failed', annotations: { depends: ['test_passed'] }, @@ -105,9 +105,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'test_is_not_same')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Is not same', - classFQN: 'Recca0120\\VSCode\\Tests\\AssertionsTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Assertions (Tests\\Assertions)::Is not same', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', className: 'AssertionsTest', methodName: 'test_is_not_same', start: { line: 25, character: 4 }, @@ -120,9 +120,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'test_risky')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Risky', - classFQN: 'Recca0120\\VSCode\\Tests\\AssertionsTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Assertions (Tests\\Assertions)::Risky', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', className: 'AssertionsTest', methodName: 'test_risky', start: { line: 30, character: 4 }, @@ -135,9 +135,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'annotation_test')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Annotation test', - classFQN: 'Recca0120\\VSCode\\Tests\\AssertionsTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Assertions (Tests\\Assertions)::Annotation test', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', className: 'AssertionsTest', methodName: 'annotation_test', start: { line: 38, character: 4 }, @@ -150,9 +150,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'test_skipped')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Skipped', - classFQN: 'Recca0120\\VSCode\\Tests\\AssertionsTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Assertions (Tests\\Assertions)::Skipped', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', className: 'AssertionsTest', methodName: 'test_skipped', start: { line: 43, character: 4 }, @@ -165,9 +165,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'test_incomplete')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Incomplete', - classFQN: 'Recca0120\\VSCode\\Tests\\AssertionsTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Assertions (Tests\\Assertions)::Incomplete', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', className: 'AssertionsTest', methodName: 'test_incomplete', start: { line: 48, character: 4 }, @@ -180,9 +180,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'addition_provider')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', - classFQN: 'Recca0120\\VSCode\\Tests\\AssertionsTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Assertions (Tests\\Assertions)::Addition provider', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', className: 'AssertionsTest', methodName: 'addition_provider', annotations: { dataProvider: ['additionProvider'], depends: ['test_passed'] }, @@ -196,9 +196,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'balanceIsInitiallyZero')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Balance is initially zero', - classFQN: 'Recca0120\\VSCode\\Tests\\AssertionsTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Assertions (Tests\\Assertions)::Balance is initially zero', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', className: 'AssertionsTest', methodName: 'balanceIsInitiallyZero', annotations: { testdox: ['has an initial balance of zero'] }, @@ -232,9 +232,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'test_static_public_fail')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Static Method (Recca0120\\VSCode\\Tests\\StaticMethod)::Static public fail', - classFQN: 'Recca0120\\VSCode\\Tests\\StaticMethodTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Static Method (Tests\\StaticMethod)::Static public fail', + classFQN: 'Tests\\StaticMethodTest', + namespace: 'Tests', className: 'StaticMethodTest', methodName: 'test_static_public_fail', start: { line: 9, character: 4 }, @@ -257,9 +257,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'property')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Has Property (Recca0120\\VSCode\\Tests\\SubFolder\\HasProperty)::Property', - classFQN: 'Recca0120\\VSCode\\Tests\\SubFolder\\HasPropertyTest', - namespace: 'Recca0120\\VSCode\\Tests\\SubFolder', + id: 'Has Property (Tests\\SubFolder\\HasProperty)::Property', + classFQN: 'Tests\\SubFolder\\HasPropertyTest', + namespace: 'Tests\\SubFolder', className: 'HasPropertyTest', methodName: 'property', start: { line: 17, character: 4 }, @@ -278,9 +278,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'firstLeadingComments')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Leading Comments (Recca0120\\VSCode\\Tests\\SubFolder\\LeadingComments)::First leading comments', - classFQN: 'Recca0120\\VSCode\\Tests\\SubFolder\\LeadingCommentsTest', - namespace: 'Recca0120\\VSCode\\Tests\\SubFolder', + id: 'Leading Comments (Tests\\SubFolder\\LeadingComments)::First leading comments', + classFQN: 'Tests\\SubFolder\\LeadingCommentsTest', + namespace: 'Tests\\SubFolder', className: 'LeadingCommentsTest', methodName: 'firstLeadingComments', start: { line: 10, character: 4 }, @@ -299,9 +299,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'use_trait')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Use Trait (Recca0120\\VSCode\\Tests\\SubFolder\\UseTrait)::Use trait', - classFQN: 'Recca0120\\VSCode\\Tests\\SubFolder\\UseTraitTest', - namespace: 'Recca0120\\VSCode\\Tests\\SubFolder', + id: 'Use Trait (Tests\\SubFolder\\UseTrait)::Use trait', + classFQN: 'Tests\\SubFolder\\UseTraitTest', + namespace: 'Tests\\SubFolder', className: 'UseTraitTest', methodName: 'use_trait', start: { line: 12, character: 4 }, @@ -320,9 +320,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'hi')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Attribute (Recca0120\\VSCode\\Tests\\Attribute)::Hi', - classFQN: 'Recca0120\\VSCode\\Tests\\AttributeTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Attribute (Tests\\Attribute)::Hi', + classFQN: 'Tests\\AttributeTest', + namespace: 'Tests', className: 'AttributeTest', methodName: 'hi', start: { line: 14, character: 4 }, @@ -335,9 +335,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'testAdd')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Attribute (Recca0120\\VSCode\\Tests\\Attribute)::Add', - classFQN: 'Recca0120\\VSCode\\Tests\\AttributeTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Attribute (Tests\\Attribute)::Add', + classFQN: 'Tests\\AttributeTest', + namespace: 'Tests', className: 'AttributeTest', methodName: 'testAdd', annotations: { dataProvider: ['additionProvider'] }, @@ -351,9 +351,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'testPush')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Attribute (Recca0120\\VSCode\\Tests\\Attribute)::Push', - classFQN: 'Recca0120\\VSCode\\Tests\\AttributeTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Attribute (Tests\\Attribute)::Push', + classFQN: 'Tests\\AttributeTest', + namespace: 'Tests', className: 'AttributeTest', methodName: 'testPush', annotations: { depends: ['testEmpty'] }, @@ -367,9 +367,9 @@ describe('PHPUnitParser Test', () => { expect(givenTest(file, content, 'balanceIsInitiallyZero')).toEqual(expect.objectContaining({ type: TestType.method, file, - id: 'Attribute (Recca0120\\VSCode\\Tests\\Attribute)::Balance is initially zero', - classFQN: 'Recca0120\\VSCode\\Tests\\AttributeTest', - namespace: 'Recca0120\\VSCode\\Tests', + id: 'Attribute (Tests\\Attribute)::Balance is initially zero', + classFQN: 'Tests\\AttributeTest', + namespace: 'Tests', className: 'AttributeTest', methodName: 'balanceIsInitiallyZero', annotations: { testdox: ['has an initial balance of zero'] }, diff --git a/src/PHPUnit/TestParser/TestParser.ts b/src/PHPUnit/TestParser/TestParser.ts index c1ac70a1..779d8c6d 100644 --- a/src/PHPUnit/TestParser/TestParser.ts +++ b/src/PHPUnit/TestParser/TestParser.ts @@ -22,11 +22,11 @@ export class TestParser { this.eventEmitter.on(`${eventName}`, callback); } - async parseFile(file: string) { - return this.parse(textDecoder.decode(await readFile(file)), file); + async parseFile(file: string, testsuite?: string) { + return this.parse(textDecoder.decode(await readFile(file)), file, testsuite); } - parse(text: Buffer | string, file: string) { + parse(text: Buffer | string, file: string, testsuite?: string) { text = text.toString(); // Todo https://github.com/glayzzle/php-parser/issues/170 @@ -49,7 +49,7 @@ export class TestParser { } }); - return this.parseAst(ast, file); + return this.parseAst(ast, file, testsuite); } catch (e) { console.error(e); @@ -57,11 +57,12 @@ export class TestParser { } } - private parseAst(declaration: Declaration | Node, file: string): TestDefinition[] | undefined { + private parseAst(declaration: Declaration | Node, file: string, testsuite?: string): TestDefinition[] | undefined { const definition = new PHPDefinition(declaration, { phpUnitXML: this.phpUnitXML, file }); for (const parser of this.parsers) { const tests = parser.parse(definition); + tests?.forEach((testDefinition) => testDefinition.testsuite = testsuite); if (tests) { return this.emit(tests); } diff --git a/src/PHPUnit/TestRunner.test.ts b/src/PHPUnit/TestRunner.test.ts index 2065a602..f33e9bf4 100644 --- a/src/PHPUnit/TestRunner.test.ts +++ b/src/PHPUnit/TestRunner.test.ts @@ -195,12 +195,12 @@ const shouldRunAllTest = async (expected: string[], builder: CommandBuilder, pro event: TeamcityEvent.testStarted, name: 'test_passed', file: appPath('tests/AssertionsTest.php'), - id: 'Recca0120\\VSCode\\Tests\\AssertionsTest', + id: 'Tests\\AssertionsTest', }, { event: TeamcityEvent.testFinished, name: 'test_passed', flowId: expect.any(Number), - id: 'Recca0120\\VSCode\\Tests\\AssertionsTest::test_passed', + id: 'Tests\\AssertionsTest::test_passed', file: projectPath('tests/AssertionsTest.php'), }); }; @@ -211,11 +211,11 @@ const shouldRunTestSuite = async (expected: string[], builder: CommandBuilder, p await shouldRunTest(expected, builder, projectPath, appPath, { event: TeamcityEvent.testSuiteStarted, file: appPath('tests/AssertionsTest.php'), - id: 'Recca0120\\VSCode\\Tests\\AssertionsTest', + id: 'Tests\\AssertionsTest', }, { event: TeamcityEvent.testSuiteFinished, flowId: expect.any(Number), - id: 'Recca0120\\VSCode\\Tests\\AssertionsTest', + id: 'Tests\\AssertionsTest', file: projectPath('tests/AssertionsTest.php'), }); }; @@ -228,11 +228,11 @@ const shouldRunTestPassed = async (expected: string[], command: CommandBuilder, event: TeamcityEvent.testStarted, name: 'test_passed', file: appPath('tests/AssertionsTest.php'), - id: 'Recca0120\\VSCode\\Tests\\AssertionsTest', + id: 'Tests\\AssertionsTest', }, { event: TeamcityEvent.testFinished, flowId: expect.any(Number), - id: 'Recca0120\\VSCode\\Tests\\AssertionsTest::test_passed', + id: 'Tests\\AssertionsTest::test_passed', file: projectPath('tests/AssertionsTest.php'), }); }; @@ -245,12 +245,12 @@ const shouldRunTestFailed = async (expected: string[], command: CommandBuilder, event: TeamcityEvent.testFailed, name: 'test_failed', file: appPath('tests/AssertionsTest.php'), - id: 'Recca0120\\VSCode\\Tests\\AssertionsTest', + id: 'Tests\\AssertionsTest', phpVfsComposer, }, { event: TeamcityEvent.testFailed, flowId: expect.any(Number), - id: 'Recca0120\\VSCode\\Tests\\AssertionsTest::test_failed', + id: 'Tests\\AssertionsTest::test_failed', file: projectPath('tests/AssertionsTest.php'), message: 'Failed asserting that false is true.', details: [{ file: projectPath('tests/AssertionsTest.php'), line: 22 }], diff --git a/src/PHPUnit/__tests__/fixtures/pest-stub/composer.json b/src/PHPUnit/__tests__/fixtures/pest-stub/composer.json index f491ef85..14e18a16 100644 --- a/src/PHPUnit/__tests__/fixtures/pest-stub/composer.json +++ b/src/PHPUnit/__tests__/fixtures/pest-stub/composer.json @@ -8,12 +8,12 @@ "license": "MIT", "autoload": { "psr-4": { - "Recca0120\\VSCode\\": "src/" + "App\\": "src/" } }, "autoload-dev": { "psr-4": { - "Recca0120\\VSCode\\Tests\\": "tests/" + "Tests\\": "tests/" } }, "authors": [ diff --git a/src/PHPUnit/__tests__/fixtures/pest-stub/src/Calculator.php b/src/PHPUnit/__tests__/fixtures/pest-stub/src/Calculator.php index 1b0cd400..af7091df 100644 --- a/src/PHPUnit/__tests__/fixtures/pest-stub/src/Calculator.php +++ b/src/PHPUnit/__tests__/fixtures/pest-stub/src/Calculator.php @@ -1,6 +1,6 @@ { return results; }; - const shouldBe = async (_collection: TestCollection, group: any) => { + const shouldBe = async (_collection: TestCollection, testsuites: any) => { const phpUnitXML = new PHPUnitXML(); phpUnitXML.setRoot(phpUnitProject('')); const testParser = new TestParser(phpUnitXML); const expected = new Files; - for (const [name, files] of Object.entries(group)) { + for (const [name, files] of Object.entries(testsuites)) { const tests = new TestDefinitions(); for (const uri of (files as URI[])) { tests.set(uri, await testParser.parseFile(uri.fsPath) ?? []); @@ -88,22 +88,16 @@ describe('Extension TestCollection', () => { expect(toTree(ctrl.items)).toEqual([ expect.objectContaining( { - id: 'namespace:VSCode (Recca0120\\VSCode)', - label: '$(symbol-namespace) Recca0120\\VSCode', + id: 'namespace:Tests', + label: '$(symbol-namespace) Tests', children: [ expect.objectContaining({ - id: 'namespace:Tests (Recca0120\\VSCode\\Tests)', - label: '$(symbol-namespace) Tests', - children: [ - expect.objectContaining({ - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)', - label: '$(symbol-class) AssertionsTest', - }), - expect.objectContaining({ - id: 'Attribute (Recca0120\\VSCode\\Tests\\Attribute)', - label: '$(symbol-class) AttributeTest', - }), - ], + id: 'Assertions (Tests\\Assertions)', + label: '$(symbol-class) AssertionsTest', + }), + expect.objectContaining({ + id: 'Attribute (Tests\\Attribute)', + label: '$(symbol-class) AttributeTest', }), ], }, @@ -111,7 +105,7 @@ describe('Extension TestCollection', () => { ]); }); - it('with groups', async () => { + it('with testsuites', async () => { const collection = givenTestCollection(` @@ -126,38 +120,34 @@ describe('Extension TestCollection', () => { await collection.add(URI.file(phpUnitProject('tests/Unit/ExampleTest.php'))); await collection.add(URI.file(phpUnitProject('tests/Feature/ExampleTest.php'))); - expect(toTree(ctrl.items)).toEqual([expect.objectContaining({ - id: 'namespace:VSCode (Recca0120\\VSCode)', - label: '$(symbol-namespace) Recca0120\\VSCode', - children: [ - expect.objectContaining({ - id: 'namespace:Tests (Recca0120\\VSCode\\Tests)', - label: '$(symbol-namespace) Tests', - children: [ - expect.objectContaining({ - id: 'namespace:Unit (Recca0120\\VSCode\\Tests\\Unit)', - label: '$(symbol-namespace) Unit', - children: [ - expect.objectContaining({ - id: 'Example (Recca0120\\VSCode\\Tests\\Unit\\Example)', - label: '$(symbol-class) ExampleTest', - }), - ], - }), - expect.objectContaining({ - id: 'namespace:Feature (Recca0120\\VSCode\\Tests\\Feature)', - label: '$(symbol-namespace) Feature', - children: [ - expect.objectContaining({ - id: 'Example (Recca0120\\VSCode\\Tests\\Feature\\Example)', - label: '$(symbol-class) ExampleTest', - }), - ], - }), - ], - }), - ], - })]); + expect(toTree(ctrl.items)).toEqual([ + { + id: 'namespace:Tests', + label: '$(symbol-namespace) Tests', + children: [ + expect.objectContaining({ + id: 'namespace:Unit (Tests\\Unit)', + label: '$(symbol-namespace) Unit', + children: [ + expect.objectContaining({ + id: 'Example (Tests\\Unit\\Example)', + label: '$(symbol-class) ExampleTest', + }), + ], + }), + expect.objectContaining({ + id: 'namespace:Feature (Tests\\Feature)', + label: '$(symbol-namespace) Feature', + children: [ + expect.objectContaining({ + id: 'Example (Tests\\Feature\\Example)', + label: '$(symbol-class) ExampleTest', + }), + ], + }), + ], + }, + ]); }); it('add test', async () => { diff --git a/src/TestCollection/TestCollection.ts b/src/TestCollection/TestCollection.ts index 1beb59a2..dc8de4ec 100644 --- a/src/TestCollection/TestCollection.ts +++ b/src/TestCollection/TestCollection.ts @@ -72,10 +72,10 @@ export class TestCollection extends BaseTestCollection { return super.reset(); } - protected async parseTests(uri: URI) { + protected async parseTests(uri: URI, testsuite: string) { const { testParser, testDefinitionBuilder } = this.createTestParser(); - const testHierarchyBuilder = new TestHierarchyBuilder(testParser, this.ctrl); - await testParser.parseFile(uri.fsPath); + const testHierarchyBuilder = new TestHierarchyBuilder(this.ctrl, testParser); + await testParser.parseFile(uri.fsPath, testsuite); this.removeTestItems(uri); const testData = this.getTestCases(uri); diff --git a/src/TestCollection/TestHierarchyBuilder.test.ts b/src/TestCollection/TestHierarchyBuilder.test.ts index bf21a72c..e849f375 100644 --- a/src/TestCollection/TestHierarchyBuilder.test.ts +++ b/src/TestCollection/TestHierarchyBuilder.test.ts @@ -4,8 +4,24 @@ import { PHPUnitXML, TestParser } from '../PHPUnit'; import { pestProject, phpUnitProject } from '../PHPUnit/__tests__/utils'; import { TestHierarchyBuilder } from './TestHierarchyBuilder'; -function givenPhp(namespace: string, className: string, methods: string[]) { - return ` { + return ` + + ${text.trim()} +`; +}; + +const givenPhp = (namespace: string, className: string, methods: string[]) => ` ` } `).join('')} }`; -} describe('TestHierarchyBuilder', () => { let ctrl: TestController; - let testParser: TestParser; - let builder: TestHierarchyBuilder; + let configurationFile: string; const toTree = (items: any) => { const results = [] as any[]; items.forEach((item: any) => { - results.push({ - id: item.id, - label: item.label, - children: toTree(item.children), - }); + results.push({ id: item.id, label: item.label, children: toTree(item.children) }); }); return results; }; - const givenCodes = (files: { file: string, code: string }[]) => { - files.forEach(({ file, code }) => { - testParser.parse(code, file); - }); + const givenCodes = (codes: CODE[]) => { + const testsuites = Object.entries(codes + .map(({ testsuite }) => testsuite) + .reduce((items, item) => { + if (!(item.name in items)) { + items[item.name] = []; + } + items[item.name].push(item.path); + + return items; + }, {} as { [index: string]: string[] })) + .map(([name, paths]) => { + const directories = paths.map(path => `${path}`).join(''); + return `${directories}`; + }); + + const phpUnitXml = (new PHPUnitXML()).load(generateXML( + `${testsuites.join('')}`, + ), configurationFile); + + const testParser = new TestParser(phpUnitXml); + const builder = new TestHierarchyBuilder(ctrl, testParser); + codes.map(({ testsuite, file, code }) => { + testParser.parse(code, file, testsuite.name); + }); builder.get(); }; + beforeEach(() => { + ctrl = tests.createTestController('phpUnitTestController', 'PHPUnit'); + }); + describe('PHPUnit', () => { - beforeEach(() => { - ctrl = tests.createTestController('phpUnitTestController', 'PHPUnit'); - const phpUnitXML = new PHPUnitXML().setRoot(phpUnitProject('')); - testParser = new TestParser(phpUnitXML); - builder = new TestHierarchyBuilder(testParser, ctrl); - }); + beforeEach(() => configurationFile = phpUnitProject('phpunit.xml')); it('no namespace', () => { givenCodes([{ + testsuite: { name: 'default', path: 'tests' }, file: phpUnitProject('tests/AssertionsTest.php'), - code: givenPhp( - '', - 'AssertionsTest', - ['test_passed', 'test_failed'], - ), + code: givenPhp('', 'AssertionsTest', ['test_passed', 'test_failed']), }]); expect(toTree(ctrl.items)).toEqual([ @@ -78,40 +105,30 @@ describe('TestHierarchyBuilder', () => { children: [], }, ], - } - , + }, ]); }); it('nested namespace', () => { givenCodes([{ + testsuite: { name: 'default', path: 'tests' }, file: phpUnitProject('tests/AssertionsTest.php'), - code: givenPhp( - 'namespace Recca0120\\VSCode\\Tests', - 'AssertionsTest', - ['test_passed'], - ), + code: givenPhp('namespace Tests', 'AssertionsTest', ['test_passed']), }]); expect(toTree(ctrl.items)).toEqual([ { - id: 'namespace:VSCode (Recca0120\\VSCode)', - label: '$(symbol-namespace) Recca0120\\VSCode', + id: 'namespace:Tests', + label: '$(symbol-namespace) Tests', children: [ { - id: 'namespace:Tests (Recca0120\\VSCode\\Tests)', - label: '$(symbol-namespace) Tests', + id: 'Assertions (Tests\\Assertions)', + label: '$(symbol-class) AssertionsTest', children: [ { - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)', - label: '$(symbol-class) AssertionsTest', - children: [ - { - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Passed', - label: '$(symbol-method) test_passed', - children: [], - }, - ], + id: 'Assertions (Tests\\Assertions)::Passed', + label: '$(symbol-method) test_passed', + children: [], }, ], }, @@ -122,51 +139,39 @@ describe('TestHierarchyBuilder', () => { it('sibling namespace', () => { givenCodes([{ + testsuite: { name: 'default', path: 'tests' }, file: phpUnitProject('tests/AssertionsTest.php'), - code: givenPhp( - 'namespace Recca0120\\VSCode\\Tests', - 'AssertionsTest', - ['test_passed'], - ), + code: givenPhp('namespace Tests', 'AssertionsTest', ['test_passed']), }, { + testsuite: { name: 'default', path: 'tests' }, file: phpUnitProject('tests/Assertions2Test.php'), - code: givenPhp( - 'namespace Recca0120\\VSCode\\Tests', - 'Assertions2Test', - ['test_passed'], - ), + code: givenPhp('namespace Tests', 'Assertions2Test', ['test_passed']), }]); expect(toTree(ctrl.items)).toEqual([ { - id: 'namespace:VSCode (Recca0120\\VSCode)', - label: '$(symbol-namespace) Recca0120\\VSCode', + id: 'namespace:Tests', + label: '$(symbol-namespace) Tests', children: [ { - id: 'namespace:Tests (Recca0120\\VSCode\\Tests)', - label: '$(symbol-namespace) Tests', + id: 'Assertions (Tests\\Assertions)', + label: '$(symbol-class) AssertionsTest', children: [ { - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)', - label: '$(symbol-class) AssertionsTest', - children: [ - { - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Passed', - label: '$(symbol-method) test_passed', - children: [], - }, - ], + id: 'Assertions (Tests\\Assertions)::Passed', + label: '$(symbol-method) test_passed', + children: [], }, + ], + }, + { + id: 'Assertions2 (Tests\\Assertions2)', + label: `$(symbol-class) Assertions2Test`, + children: [ { - id: 'Assertions2 (Recca0120\\VSCode\\Tests\\Assertions2)', - label: `$(symbol-class) Assertions2Test`, - children: [ - { - id: 'Assertions2 (Recca0120\\VSCode\\Tests\\Assertions2)::Passed', - label: '$(symbol-method) test_passed', - children: [], - }, - ], + id: 'Assertions2 (Tests\\Assertions2)::Passed', + label: '$(symbol-method) test_passed', + children: [], }, ], }, @@ -174,15 +179,24 @@ describe('TestHierarchyBuilder', () => { }, ]); }); + + xit('two testsuites', () => { + givenCodes([{ + testsuite: { name: 'Unit', path: 'tests/Unit' }, + file: phpUnitProject('tests/Feature/ExampleTest.php'), + code: givenPhp('namespace Tests\\Unit', 'ExampleTest', ['test_passed']), + }, { + testsuite: { name: 'Feature', path: 'tests/Feature' }, + file: phpUnitProject('tests/Feature/ExampleTest.php'), + code: givenPhp('namespace Tests\\Feature', 'ExampleTest', ['test_passed']), + }]); + + // console.log(toTree(ctrl.items)); + }); }); describe('PEST', () => { - beforeEach(() => { - ctrl = tests.createTestController('phpUnitTestController', 'PHPUnit'); - const phpUnitXML = new PHPUnitXML().setRoot(pestProject('')); - testParser = new TestParser(phpUnitXML); - builder = new TestHierarchyBuilder(testParser, ctrl); - }); + beforeEach(() => configurationFile = pestProject('phpunit.xml')); it('nested describe', () => { const code = `(); - constructor(private testParser: TestParser, private ctrl: TestController) { + constructor(private ctrl: TestController, private testParser: TestParser) { this.onInit(); } @@ -45,37 +45,36 @@ export class TestHierarchyBuilder { } private addNamespaceTestItems(testDefinition: TestDefinition) { - const converter = TransformerFactory.factory(testDefinition.classFQN!); + const transformer = TransformerFactory.factory(testDefinition.classFQN!); - let parentTestCollection = this.ctrl.items; + let children = this.ctrl.items; let testItem: TestItem | undefined; - let namespaceParts = testDefinition.label?.split('\\') ?? []; - const vendorNamespace = namespaceParts.splice(0, 2).join('\\'); - namespaceParts = [vendorNamespace, ...namespaceParts].filter(value => !!value); - this.length = namespaceParts.length; + let parts = testDefinition.label?.split('\\') ?? []; + parts = parts.filter(value => !!value); + this.length = parts.length; - namespaceParts.forEach((namespacePart, index, namespaceParts) => { + parts.forEach((part, index, parts) => { const type = TestType.namespace; - const classFQN = namespaceParts.slice(0, index + 1).join('\\'); - const id = converter.uniqueId({ type, classFQN }); - const label = converter.generateLabel({ type, classFQN: namespacePart }); - const testDefinition = { type, id, namespace: classFQN, label, depth: index + 1 } as TestDefinition; + const classFQN = parts.slice(0, index + 1).join('\\'); + const id = transformer.uniqueId({ type, classFQN }); - testItem = parentTestCollection.get(testDefinition.id); + testItem = children.get(id); if (!testItem) { - testItem = this.ctrl.createTestItem(testDefinition.id, this.createLabel(testDefinition)); + const label = transformer.generateLabel({ type, classFQN: part }); + const testDefinition = { type, id, namespace: classFQN, label, depth: index + 1 } as TestDefinition; + testItem = this.ctrl.createTestItem(id, this.parseLabelWithIcon(testDefinition)); testItem.canResolveChildren = true; - testItem.sortText = testDefinition.id; - parentTestCollection.add(testItem); + testItem.sortText = id; + children.add(testItem); this.testData.set(testItem, new TestCase(testDefinition)); } const parent = this.ancestors[this.ancestors.length - 1]; parent.children.push(testItem); - this.ancestors.push({ item: testItem, type: testDefinition.type, children: [] }); + this.ancestors.push({ item: testItem, type, children: [] }); - parentTestCollection = testItem.children; + children = testItem.children; }); } @@ -92,7 +91,7 @@ export class TestHierarchyBuilder { } private createTestItem(testDefinition: TestDefinition, sortText: string) { - const testItem = this.ctrl.createTestItem(testDefinition.id, this.createLabel(testDefinition), Uri.file(testDefinition.file!)); + const testItem = this.ctrl.createTestItem(testDefinition.id, this.parseLabelWithIcon(testDefinition), Uri.file(testDefinition.file!)); testItem.canResolveChildren = testDefinition.type === TestType.class; testItem.sortText = sortText; testItem.range = this.createRange(testDefinition); @@ -129,7 +128,7 @@ export class TestHierarchyBuilder { }) as TestItem; } - private createLabel(testDefinition: TestDefinition) { + private parseLabelWithIcon(testDefinition: TestDefinition) { const icon = this.icons[testDefinition.type]; return icon ? `${icon} ${testDefinition.label}` : testDefinition.label; diff --git a/src/extension.test.ts b/src/extension.test.ts index b04fa4b6..c52480dd 100644 --- a/src/extension.test.ts +++ b/src/extension.test.ts @@ -152,7 +152,7 @@ describe('Extension Test', () => { await activate(context); const ctrl = getTestController(); const uri = Uri.file(join(root, 'tests/AssertionsTest.php')); - const itemId = `Assertions (Recca0120\\VSCode\\Tests\\Assertions)`; + const itemId = `Assertions (Tests\\Assertions)`; const parent = findTest(ctrl.items, itemId)!; const child = parent.children.get(`${itemId}::Passed`); @@ -214,14 +214,14 @@ describe('Extension Test', () => { await activate(context); const ctrl = getTestController(); const runProfile = getRunProfile(ctrl); - const id = `namespace:Tests (Recca0120\\VSCode\\Tests)`; + const id = `namespace:Tests`; const request = { include: [findTest(ctrl.items, id)], exclude: [], profile: runProfile }; await runProfile.runHandler(request, new CancellationTokenSource().token); expect(spawn).toHaveBeenCalledWith(phpBinary, [ 'vendor/bin/phpunit', - '--filter=^(Recca0120\\\\VSCode\\\\Tests.*)(( with (data set )?.*)?)?$', + '--filter=^(Tests.*)(( with (data set )?.*)?)?$', '--colors=never', '--teamcity', ], expect.objectContaining({ cwd })); @@ -237,7 +237,7 @@ describe('Extension Test', () => { await activate(context); const ctrl = getTestController(); const runProfile = getRunProfile(ctrl); - const id = `Assertions (Recca0120\\VSCode\\Tests\\Assertions)`; + const id = `Assertions (Tests\\Assertions)`; const request = { include: [findTest(ctrl.items, id)], exclude: [], profile: runProfile }; await runProfile.runHandler(request, new CancellationTokenSource().token); @@ -258,7 +258,7 @@ describe('Extension Test', () => { const runProfile = getRunProfile(ctrl); const method = 'test_throw_exception'; - const id = `Calculator (Recca0120\\VSCode\\Tests\\Calculator)::Throw exception`; + const id = `Calculator (Tests\\Calculator)::Throw exception`; const request = { include: [findTest(ctrl.items, id)], exclude: [], profile: runProfile }; @@ -300,7 +300,7 @@ describe('Extension Test', () => { await ctrl.resolveHandler(); - expect(countItems(ctrl.items)).toEqual(47); + expect(countItems(ctrl.items)).toEqual(46); }); it('should resolve tests without phpunit.xml', async () => { @@ -313,7 +313,7 @@ describe('Extension Test', () => { await ctrl.resolveHandler(); - expect(countItems(ctrl.items)).toEqual(47); + expect(countItems(ctrl.items)).toEqual(46); }); it('should resolve tests with phpunit.xml.dist', async () => { @@ -327,7 +327,7 @@ describe('Extension Test', () => { await ctrl.resolveHandler(); - expect(countItems(ctrl.items)).toEqual(14); + expect(countItems(ctrl.items)).toEqual(13); }); it('run phpunit.run-file', async () => {