in src/goTest/resolve.ts [429:520]
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 && symbol.kind !== SymbolKind.Method) {
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 ?? '<none>',
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{})
// - suite.Run(t, myVarName), in which case the type will be determined by checking the line where myVarName is defined.
const matchRunSuite = text.match(runTestSuiteRegex);
if (matchRunSuite) {
const g = matchRunSuite.groups;
// When the variable is defined separately from the suite.Run call, get the type from the line where the variable is defined.
let variableDef;
if (g?.varName) {
const typeRegex = new RegExp(`${g.varName} ?:= new\\((?<type3>\\w+)\\)$`, 'mu');
variableDef = text.match(typeRegex);
}
const suite = this.getTestSuite(g?.type1 || g?.type2 || variableDef?.groups?.type3 || '');
suite.func = item;
for (const method of suite.methods) {
if (!method.parent || GoTest.parseId(method.parent.id).kind !== 'file') {
continue;
}
method.parent.children.delete(method.id);
item.children.add(method);
}
}
}