Skip to content

Commit

Permalink
Merge pull request #247 from recca0120/fix/find-files-performance
Browse files Browse the repository at this point in the history
Fix/find files performance
  • Loading branch information
recca0120 authored Dec 17, 2024
2 parents 2626df3 + 69d33a5 commit ce860ed
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 43 deletions.
14 changes: 8 additions & 6 deletions __mocks__/vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
70 changes: 51 additions & 19 deletions src/PHPUnit/PHPUnitXML.test.ts
Original file line number Diff line number Diff line change
@@ -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('');
Expand Down Expand Up @@ -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/**}',
});
});

Expand All @@ -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/**}',
});
});

Expand All @@ -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/**}',
});
});

Expand All @@ -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/**}',
});
});

Expand All @@ -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/**/*}',
});
});

Expand All @@ -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/**}',
});
});

Expand Down
40 changes: 32 additions & 8 deletions src/PHPUnit/PHPUnitXML.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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[]) {
Expand All @@ -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}}`;
}
}

Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/PHPUnit/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}).trim());
23 changes: 14 additions & 9 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -122,21 +122,26 @@ 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),
};
}));
}

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<Uri>) {
Expand Down

0 comments on commit ce860ed

Please sign in to comment.