in src/goTest/resolve.ts [400:477]
private async processSymbol(
doc: TextDocument,
file: TestItem,
seen: Set<string>,
importsTestify: boolean,
symbol: DocumentSymbol
) {
// Skip TestMain(*testing.M) - allow TestMain(*testing.T)
if (symbol.name === 'TestMain' && /\*testing.M\)/.test(symbol.detail)) {
return;
}
// Recursively process symbols that are nested
if (symbol.kind !== SymbolKind.Function) {
for (const sym of symbol.children) await this.processSymbol(doc, file, seen, importsTestify, sym);
return;
}
const match = symbol.name.match(testFuncRegex) || (importsTestify && symbol.name.match(testMethodRegex));
if (!match) {
return;
}
seen.add(symbol.name);
const kind = match.groups.kind.toLowerCase() as GoTestKind;
const suite = match.groups.type ? this.getTestSuite(match.groups.type) : undefined;
const existing =
this.getItem(file, doc.uri, kind, symbol.name) ||
(suite?.func && this.getItem(suite?.func, doc.uri, kind, symbol.name));
if (existing) {
if (!existing.range.isEqual(symbol.range)) {
existing.range = symbol.range;
this.relocateChildren(existing);
}
return existing;
}
const item = this.getOrCreateItem(suite?.func || file, match.groups.name, doc.uri, kind, symbol.name);
item.range = symbol.range;
if (suite) {
this.isTestMethod.add(item);
if (!suite.func) suite.methods.add(item);
return;
}
if (!importsTestify) {
return;
}
// Runs any suite
const text = doc.getText(symbol.range);
if (text.includes('suite.Run(')) {
this.isTestSuiteFunc.add(item);
}
// Runs a specific suite
// - suite.Run(t, new(MySuite))
// - suite.Run(t, MySuite{})
// - suite.Run(t, &MySuite{})
const matchRunSuite = text.match(runTestSuiteRegex);
if (matchRunSuite) {
const g = matchRunSuite.groups;
const suite = this.getTestSuite(g.type1 || g.type2);
suite.func = item;
for (const method of suite.methods) {
if (GoTest.parseId(method.parent.id).kind !== 'file') {
continue;
}
method.parent.children.delete(method.id);
item.children.add(method);
}
}
}