From 3552054260bbccde53e1a1160d20a75fd1903572 Mon Sep 17 00:00:00 2001 From: recca0120 Date: Tue, 17 Dec 2024 07:02:31 +0800 Subject: [PATCH 1/2] await --- src/extension.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 279c537a..2aff3e77 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -134,9 +134,8 @@ async function getWorkspaceTestPatterns() { async function findInitialFiles(pattern: GlobPattern, exclude: GlobPattern) { testCollection.reset(); - await workspace.findFiles(pattern, exclude).then((files) => { - return Promise.all(files.map((file) => testCollection.add(file))); - }); + const files = await workspace.findFiles(pattern, exclude); + await Promise.all(files.map((file) => testCollection.add(file))); } async function startWatchingWorkspace(fileChangedEmitter: EventEmitter) { From 69d33a5fb9a0950f7065abb8be71b67770ce752d Mon Sep 17 00:00:00 2001 From: recca0120 Date: Tue, 17 Dec 2024 09:06:36 +0800 Subject: [PATCH 2/2] fix performance --- __mocks__/vscode.ts | 14 ++++--- src/PHPUnit/PHPUnitXML.test.ts | 70 +++++++++++++++++++++++++--------- src/PHPUnit/PHPUnitXML.ts | 40 +++++++++++++++---- src/PHPUnit/utils.ts | 2 +- src/extension.ts | 18 ++++++--- 5 files changed, 104 insertions(+), 40 deletions(-) diff --git a/__mocks__/vscode.ts b/__mocks__/vscode.ts index dc6743c3..e06584eb 100644 --- a/__mocks__/vscode.ts +++ b/__mocks__/vscode.ts @@ -266,12 +266,14 @@ const languages = { const RelativePattern = jest .fn() - .mockImplementation((workspaceFolder: WorkspaceFolder, pattern: string) => { - return { - uri: workspaceFolder.uri, - base: workspaceFolder.uri.fsPath, - pattern, - }; + .mockImplementation((workspaceFolder: WorkspaceFolder | URI | string, pattern: string) => { + if (typeof workspaceFolder === 'string') { + workspaceFolder = URI.file(workspaceFolder); + } + + const uri = 'uri' in workspaceFolder ? workspaceFolder.uri : workspaceFolder; + + return { uri, base: uri.fsPath, pattern }; }); const window = { diff --git a/src/PHPUnit/PHPUnitXML.test.ts b/src/PHPUnit/PHPUnitXML.test.ts index 7032406b..6f674c2a 100644 --- a/src/PHPUnit/PHPUnitXML.test.ts +++ b/src/PHPUnit/PHPUnitXML.test.ts @@ -1,5 +1,7 @@ +import { join } from 'node:path'; +import { URI } from 'vscode-uri'; import { generateXML, phpUnitProject } from './__tests__/utils'; -import { Pattern, PHPUnitXML } from './PHPUnitXML'; +import { PHPUnitXML } from './PHPUnitXML'; describe('PHPUnit XML Test', () => { const root = phpUnitProject(''); @@ -55,9 +57,14 @@ describe('PHPUnit XML Test', () => { { tag: 'directory', name: 'Unit', value: 'tests/Unit2' }, ]); - expect(parsed.getGlobPatterns(root)).toEqual({ - 'excludes': new Pattern('.', ['**/.git/**', '**/node_modules/**']), - 'includes': new Pattern('.', ['tests/Unit/**/*.php', 'tests/Unit2/**/*.php']), + const { includes, excludes } = parsed.getPatterns(root); + expect(includes.toGlobPattern()).toEqual({ + uri: URI.file(join(phpUnitXML.root(), 'tests')), + pattern: '{Unit/**/*.php,Unit2/**/*.php}', + }); + expect(excludes.toGlobPattern()).toEqual({ + uri: URI.file(phpUnitXML.root()), + pattern: '{**/.git/**,**/node_modules/**}', }); }); @@ -80,9 +87,14 @@ describe('PHPUnit XML Test', () => { { tag: 'directory', name: 'Feature', value: 'tests/Feature' }, ]); - expect(parsed.getGlobPatterns(root)).toEqual({ - 'excludes': new Pattern('.', ['**/.git/**', '**/node_modules/**']), - 'includes': new Pattern('.', ['tests/Unit/**/*.php', 'tests/Feature/**/*.php']), + const { includes, excludes } = parsed.getPatterns(root); + expect(includes.toGlobPattern()).toEqual({ + uri: URI.file(join(phpUnitXML.root(), 'tests')), + pattern: '{Unit/**/*.php,Feature/**/*.php}', + }); + expect(excludes.toGlobPattern()).toEqual({ + uri: URI.file(phpUnitXML.root()), + pattern: '{**/.git/**,**/node_modules/**}', }); }); @@ -109,9 +121,14 @@ describe('PHPUnit XML Test', () => { { tag: 'directory', name: 'Feature', value: 'tests/Feature2' }, ]); - expect(parsed.getGlobPatterns(root)).toEqual({ - 'excludes': new Pattern('.', ['**/.git/**', '**/node_modules/**']), - 'includes': new Pattern('.', ['tests/Unit/**/*.php', 'tests/Unit2/**/*.php', 'tests/Feature/**/*.php', 'tests/Feature2/**/*.php']), + const { includes, excludes } = parsed.getPatterns(root); + expect(includes.toGlobPattern()).toEqual({ + uri: URI.file(join(phpUnitXML.root(), 'tests')), + pattern: '{Unit/**/*.php,Unit2/**/*.php,Feature/**/*.php,Feature2/**/*.php}', + }); + expect(excludes.toGlobPattern()).toEqual({ + uri: URI.file(phpUnitXML.root()), + pattern: '{**/.git/**,**/node_modules/**}', }); }); @@ -136,9 +153,14 @@ describe('PHPUnit XML Test', () => { { tag: 'file', name: 'Unit', value: './vendor/someone/tests/MyClassTest2.php' }, ]); - expect(parsed.getGlobPatterns(root)).toEqual({ - 'excludes': new Pattern('.', ['**/.git/**', '**/node_modules/**']), - 'includes': new Pattern('.', ['tests/Unit/**/*.php', 'tests/Unit2/**/*.php', 'vendor/someone/tests/MyClassTest.php', 'vendor/someone/tests/MyClassTest2.php']), + const { includes, excludes } = parsed.getPatterns(root); + expect(includes.toGlobPattern()).toEqual({ + uri: URI.file(phpUnitXML.root()), + pattern: '{tests/Unit/**/*.php,tests/Unit2/**/*.php,vendor/someone/tests/MyClassTest.php,vendor/someone/tests/MyClassTest2.php}', + }); + expect(excludes.toGlobPattern()).toEqual({ + uri: URI.file(phpUnitXML.root()), + pattern: '{**/.git/**,**/node_modules/**}', }); }); @@ -159,9 +181,14 @@ describe('PHPUnit XML Test', () => { { tag: 'exclude', name: 'Unit', value: './tests/Integration/OldTests' }, ]); - expect(parsed.getGlobPatterns(root)).toEqual({ - 'excludes': new Pattern('.', ['**/.git/**', '**/node_modules/**', 'tests/Integration/OldTests/**/*']), - 'includes': new Pattern('.', ['tests/Unit/**/*.php']), + const { includes, excludes } = parsed.getPatterns(root); + expect(includes.toGlobPattern()).toEqual({ + uri: URI.file(join(phpUnitXML.root(), 'tests')), + pattern: '{Unit/**/*.php}', + }); + expect(excludes.toGlobPattern()).toEqual({ + uri: URI.file(phpUnitXML.root()), + pattern: '{**/.git/**,**/node_modules/**,tests/Integration/OldTests/**/*}', }); }); @@ -180,9 +207,14 @@ describe('PHPUnit XML Test', () => { { tag: 'directory', name: 'Unit', prefix: undefined, suffix: '.phpt', value: 'tests/Unit' }, ]); - expect(parsed.getGlobPatterns(root)).toEqual({ - 'excludes': new Pattern('.', ['**/.git/**', '**/node_modules/**']), - 'includes': new Pattern('.', ['tests/Unit/**/*.phpt']), + const { includes, excludes } = parsed.getPatterns(root); + expect(includes.toGlobPattern()).toEqual({ + uri: URI.file(join(phpUnitXML.root(), 'tests')), + pattern: '{Unit/**/*.phpt}', + }); + expect(excludes.toGlobPattern()).toEqual({ + uri: URI.file(phpUnitXML.root()), + pattern: '{**/.git/**,**/node_modules/**}', }); }); diff --git a/src/PHPUnit/PHPUnitXML.ts b/src/PHPUnit/PHPUnitXML.ts index 99dfffaf..e666b58a 100644 --- a/src/PHPUnit/PHPUnitXML.ts +++ b/src/PHPUnit/PHPUnitXML.ts @@ -1,6 +1,7 @@ import { XMLParser } from 'fast-xml-parser'; import { readFile } from 'node:fs/promises'; -import { dirname, normalize, relative } from 'node:path'; +import { dirname, join, normalize, relative } from 'node:path'; +import { URI } from 'vscode-uri'; type Source = { tag: string; @@ -51,8 +52,8 @@ class Element { export class Pattern { private readonly relativePath: string; - constructor(relativePath: string, private readonly patterns: string[] = []) { - this.relativePath = Pattern.normalizePath(relativePath); + constructor(private root: string, private testPath: string, private items: string[] = []) { + this.relativePath = Pattern.normalizePath(relative(this.root, this.testPath)); } private static normalizePath(...paths: string[]) { @@ -65,11 +66,34 @@ export class Pattern { args.push('**/*' + (item.suffix ?? extension)); } - this.patterns.push(Pattern.normalizePath(...args)); + this.items.push(Pattern.normalizePath(...args)); + } + + toGlobPattern() { + const dirs = Array.from(new Set(this.items.map((value) => { + if (/^\*/.test(value)) { + return undefined; + } + + const pos = value.indexOf('/'); + + return value.substring(0, pos); + }))); + + if (!(dirs.length === 1 && dirs.filter(value => !!value).length === 1)) { + return { uri: URI.file(this.root), pattern: `{${this.items}}` }; + } + + const dir = dirs.filter(value => !!value)[0]; + const items = this.items.map((value) => value.replace(new RegExp('^' + dir + '[\\/]?'), '')); + const root = URI.file(join(this.root, dir!)); + const pattern = `{${items}}`; + + return { uri: root, pattern }; } toString() { - return `{${this.patterns}}`; + return `{${this.items}}`; } } @@ -125,9 +149,9 @@ export class PHPUnitXML { ]; } - getGlobPatterns(root: string) { - const includes = new Pattern(relative(root, this.root())); - const excludes = new Pattern(relative(root, this.root()), ['**/.git/**', '**/node_modules/**']); + getPatterns(root: string) { + const includes = new Pattern(root, this.root()); + const excludes = new Pattern(root, this.root(), ['**/.git/**', '**/node_modules/**']); this.getTestSuites().forEach((item) => { (item.tag !== 'exclude') ? includes.push(item, '.php') : excludes.push(item); diff --git a/src/PHPUnit/utils.ts b/src/PHPUnit/utils.ts index daae506e..594743da 100644 --- a/src/PHPUnit/utils.ts +++ b/src/PHPUnit/utils.ts @@ -182,4 +182,4 @@ export const snakeCase = (str: string) => str.replace(/([a-z])([A-Z])/g, '$1_$2' export const camelCase = (str: string) => str.toLowerCase().replace(/([-_ \s]+[a-z])/g, (group) => group.toUpperCase().replace(/[-_ \s]/g, '')); export const titleCase = (str: string) => capitalize(str.replace(/([A-Z]+|[_\-\s]+([A-Z]+|[a-z]))/g, (_: string, matched: string) => { return ' ' + matched.trim().replace(/[_\-]/, '').toUpperCase(); -}).trim()); \ No newline at end of file +}).trim()); diff --git a/src/extension.ts b/src/extension.ts index 2aff3e77..dd78b051 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,7 +6,7 @@ import { PHPUnitFileCoverage } from './CloverParser'; import { CommandHandler } from './CommandHandler'; import { Configuration } from './Configuration'; import { Handler } from './Handler'; -import { PHPUnitXML } from './PHPUnit'; +import { Pattern, PHPUnitXML } from './PHPUnit'; import { TestCollection } from './TestCollection'; const phpUnitXML = new PHPUnitXML(); @@ -122,13 +122,19 @@ async function getWorkspaceTestPatterns() { configurationFile ? await phpUnitXML.loadFile(Uri.file(configurationFile).fsPath) : phpUnitXML.setRoot(workspaceFolder.uri.fsPath); - const { includes, excludes } = phpUnitXML.getGlobPatterns(workspaceFolder.uri.fsPath); + const { includes, excludes } = phpUnitXML.getPatterns(workspaceFolder.uri.fsPath); - return ({ + const generateRelativePattern = (includeOrExclude: Pattern) => { + const { uri, pattern } = includeOrExclude.toGlobPattern(); + + return new RelativePattern(uri, pattern); + }; + + return { workspaceFolder, - pattern: new RelativePattern(workspaceFolder, includes.toString()), - exclude: new RelativePattern(workspaceFolder, excludes.toString()), - }); + pattern: generateRelativePattern(includes), + exclude: generateRelativePattern(excludes), + }; })); }