Parser Internals¶
This page is the technical reference for MethodAtlas's six built-in discovery plugins. Each section describes the parser technology, what the plugin can and cannot detect, the preconditions it requires, how the fully-qualified class name (FQCN) is computed, and how tags are extracted.
Use this page to answer questions such as:
- "Will my Go subtests be discovered?"
- "What Python syntax is too new for the scanner?"
- "Why does this C# file generate a parse warning?"
- "How is the FQCN derived for a file three directories deep?"
How plugins are selected¶
All plugins receive every file that matches their configured (or default) file
suffix. Plugins that require an external runtime — Node.js for TypeScript,
Python for Python — perform a lazy availability check: the check runs only
when at least one matching file is found. Projects with no TypeScript or Python
test files never execute node --version or python3 --version.
When a required runtime is absent, the plugin logs a WARNING, returns an
empty result, and sets hadErrors() = true. All other plugins continue to
function normally.
Java / Kotlin¶
Plugin ID: java
Module: methodatlas-discovery-jvm
Parser: JavaParser 3.28, configured to Java 21 language level
Runtime requirement: none — parsing is performed entirely in the JVM
Parser technology¶
JavaParser builds a full abstract syntax tree (AST) from the source file. MethodAtlas traverses the AST with a recursive visitor that walks into every nested and inner class. Only method nodes annotated with one of the active test markers are emitted.
What is detected¶
| Element | Detected | Notes |
|---|---|---|
JUnit 5 @Test, @ParameterizedTest, @RepeatedTest, @TestFactory, @TestTemplate |
Yes | Auto-detected from org.junit.jupiter.* imports |
JUnit 4 @Test, @Theory |
Yes | Auto-detected from org.junit.* or junit.framework.* imports |
TestNG @Test |
Yes | Auto-detected from org.testng.* imports |
| Methods in nested / inner classes | Yes | Visitor recurses into all class-level members |
@Tag("value") on the method |
Yes | All values extracted as tags |
@DisplayName("text") on the method |
Yes | Stored in the displayName field |
| Custom annotation names | Yes | Via -test-marker or testMarkers: config |
| Mixed JUnit 4 + JUnit 5 in one file | Yes | Union of both marker sets is used |
Automatic framework detection¶
Framework detection is per-file. Before visiting any method, the plugin inspects the file's import declarations:
| Imports found | Annotation set activated |
|---|---|
org.junit.jupiter.* |
JUnit 5 set |
org.junit.* or junit.framework.* |
JUnit 4+5 union |
org.testng.* |
Test (TestNG) |
| None of the above | JUnit 5 set (fallback) |
If testMarkers is non-empty, automatic detection is skipped entirely and
only the supplied names are used for every file.
Known limits¶
| Limit | Detail |
|---|---|
| Java 21 maximum | JavaParser is configured to JAVA_21. Source files using features introduced after Java 21 (e.g. future preview syntax) will fail to parse with a WARNING log; already-discovered methods in other files are unaffected. |
| No Kotlin AST | Kotlin files are matched by suffix but parsed as plain text; the JavaParser AST is not Kotlin-aware. Kotlin test discovery relies on naming conventions and may miss annotation forms not present in Java. |
| No programmatic test generation | Tests registered via @TestFactory return values are not expanded; only the factory method itself is emitted. |
| Class-level annotations ignored | @Test on a class declaration has no effect; only method declarations are checked. |
| Interface methods | Default methods in interfaces annotated with @Test are detected but rarely occur in practice. |
Preconditions¶
- File must be valid Java or Kotlin source that JavaParser can parse at Java 21 language level.
- File encoding must be readable by the JVM's default charset (UTF-8 recommended).
FQCN computation¶
The FQCN is the fully-qualified class name derived directly from the AST:
- Package name is taken from the
packagedeclaration in the file. - For nested classes: each enclosing class name is appended with
.. - When the file has no package declaration: the simple class name is used.
The file stem (used in the manual AI workflow) is computed from the file
path relative to the scan root, with path separators replaced by . and the
.java extension stripped.
Tag extraction¶
Tags are collected from @Tag("value") annotations on the method declaration.
The annotation simple name must be Tag (case-sensitive); the first positional
string argument is taken as the tag value. Multiple @Tag annotations and
@Tag({"a","b"}) array form are both supported. Class-level @Tag
annotations are not propagated to individual methods.
C# / .NET¶
Plugin ID: dotnet
Module: methodatlas-discovery-dotnet
Parser: ANTLR4 structural grammar (CSharpTest.g4) — custom, focused
Runtime requirement: none — parsing is performed entirely in the JVM
Parser technology¶
CSharpTest.g4 is a hand-authored structural grammar. It parses the
skeleton of a C# file — namespaces, type declarations, method declarations,
and attribute sections — while treating method bodies as opaque balanced-brace
content. This makes the grammar fast and highly tolerant of language features
it does not model, at the cost of not understanding anything inside method
bodies.
ANTLR4's built-in error recovery is active. When a parse error occurs,
MethodAtlas logs a WARNING with the file path, line number, and character
position, then continues parsing the remainder of the file.
What is detected¶
| Element | Detected | Notes |
|---|---|---|
NUnit [Test], [TestCase] |
Yes | Auto-detected from using NUnit.* |
xUnit [Fact], [Theory] |
Yes | Auto-detected from using Xunit.* |
MSTest [TestMethod] |
Yes | Auto-detected from using Microsoft.VisualStudio.TestTools.* |
| Methods in nested types | Yes | Visitor tracks the full namespace + class stack |
[Category("value")] (NUnit) |
Yes | First positional argument taken as tag |
[Trait("Tag","value")] (xUnit) |
Yes | Second positional arg taken; first must be "Tag" or "Category" |
[TestCategory("value")] (MSTest) |
Yes | First positional argument taken as tag |
[Fact(DisplayName = "text")] (xUnit) |
Yes | Named DisplayName argument stored |
| Custom test marker names | Yes | Via -test-marker or testMarkers: config |
| Explicit interface implementations | Yes | IFoo.MethodName — IFoo. prefix stripped from the method name |
| Generic method declarations | Yes | Generic parameters are ignored; method name extracted cleanly |
Automatic framework detection¶
Framework detection is per-file based on using directives at the top of the
file. Using directives that import Xunit.*, NUnit.*, or
Microsoft.VisualStudio.TestTools.* activate the corresponding marker set.
If none of those are present, the framework is UNKNOWN and the union of all
known test markers is used.
When testMarkers is non-empty, automatic detection is skipped; only the
supplied names are used.
Known limits¶
| Limit | Detail |
|---|---|
| Structural grammar only | The grammar does not cover the full C# specification. Exotic constructs — top-level statements, primary constructors in unusual positions, preprocessor directives that restructure the token stream — may cause parse warnings. Error recovery keeps scanning; valid test methods before and after the problem point are still discovered. |
| No raw string literal in attributes | C# 11+ raw string literals ("""...""") in attribute arguments are not handled by the unquote logic. Attribute values containing raw strings will be emitted with raw delimiters intact rather than the actual string value. |
| Attribute arguments at parse time | The parser reads attribute positional arguments from the token stream, not from a fully-resolved expression tree. Complex expressions (e.g. nameof(...), concatenation) are returned as literal token text, not their evaluated values. |
| No compile-time constants | Tags and display names must be string literals; const references are not resolved. |
Preconditions¶
- File extension must be
.cs(or a configured suffix). - File encoding should be UTF-8. The ANTLR4
CharStreams.fromPath()call uses the JVM default charset.
FQCN computation¶
The FQCN is the fully-qualified class name built from the nesting context:
- The visitor maintains a namespace stack and a class stack.
- Every
namespacedeclaration pushes onto the namespace stack; everyclassorstructdeclaration pushes onto the class stack. - The final FQCN is
namespace_stack.join(".") + "." + class_stack.join("."). - When a file has no namespace: only the class stack is used.
The file stem is the file path relative to the scan root with path
separators replaced by . and the .cs extension stripped.
Tag extraction¶
Tags are extracted from method-level attributes:
- NUnit — attribute named
Category: first positional string argument. - xUnit — attribute named
Trait: the second positional string argument, but only when the first positional argument equals"Tag"or"Category"(case-insensitive). - MSTest — attribute named
TestCategory: first positional string argument.
Class-level [Category] / [Trait] / [TestCategory] annotations are not
propagated to individual methods.
Display names (xUnit only): [Fact(DisplayName = "text")] and
[Theory(DisplayName = "text")] — the named argument DisplayName is read.
TypeScript / JavaScript¶
Plugin ID: typescript
Module: methodatlas-discovery-typescript
Parser: Pre-built ts-scanner.bundle.js running in a Node.js worker pool
Runtime requirement: Node.js 18 or later on the PATH
Parser technology¶
MethodAtlas embeds a pre-built, esbuild-bundled Node.js script
(ts-scanner.bundle.js) inside the JAR. At startup the JAR manifest entry
TS-Scanner-Bundle-SHA256 is compared against a freshly computed SHA-256 of
the embedded file; a mismatch aborts startup to detect JAR corruption or
tampering.
The scanner bundle is extracted to a temporary directory and launched as a
long-lived subprocess (worker). Multiple workers are maintained in a pool.
Each worker receives JSON-line requests ({ requestId, filePath, functionNames,
scanRoot }) and returns JSON-line responses with discovered method descriptors.
The bundle uses the TypeScript compiler API for full AST-based parsing, which means all valid TypeScript and JavaScript syntax is handled correctly.
What is detected¶
| Element | Detected | Notes |
|---|---|---|
test("name", ...) calls |
Yes | Function name configurable via functionNames property |
it("name", ...) calls |
Yes | Default; configurable |
describe("name", ...) wrappers |
Yes | Name prepended to method name with > separator |
context(...) and suite(...) wrappers |
Yes | Same as describe |
Method chains: test.each, test.skip, test.only, it.each, etc. |
Yes | Base name extracted from the member expression |
| Arrow functions and regular function expressions | Yes | Both forms detected |
describe.each(...) |
Yes | |
| Async test functions | Yes | async (...) callbacks are transparent |
What is not detected¶
| Element | Not detected | Reason |
|---|---|---|
Tests registered via registerSuite, runner.add, or custom DSLs |
No | Only the configured functionNames are recognised |
| Dynamic test names (template literals, variables) | Partial | The literal text is extracted; evaluated result not available |
| Tags / annotations | No | TypeScript/JavaScript test frameworks do not use annotation-based tags |
| Display name separate from test name | No | The test-call string argument is used as both |
Filesystem sandboxing¶
| Node.js version | Permission flag |
|---|---|
| Below 20 | No sandboxing |
| 20 – 21 | --experimental-permission --allow-fs-read=<scan-root> |
| 22 and above | --permission --allow-fs-read=<scan-root> |
Sandboxing prevents the worker process from reading files outside the directory being scanned.
Known limits¶
| Limit | Detail |
|---|---|
| Node.js 18 minimum | Versions below 18 are rejected at startup. Node.js LTS 18 (Hydrogen) reached end-of-life in April 2025; Node.js 20 (Iron) or later is recommended. |
| Bundle is pre-built | The scanner is an esbuild output baked into the JAR at build time. Custom TypeScript transformers or framework plugins that change the AST structure before compilation are not seen. |
describe.skip, describe.only wrappers |
Tests inside skipped or focused suites are still emitted; MethodAtlas does not model runtime-skip semantics. |
| Template-literal test names | If a test name is a template literal (e.g. `test ${i}`), the raw template text is captured, not the evaluated string. |
Preconditions¶
nodemust be on thePATHand report version ≥ 18 whennode --versionis run.- Files must be valid TypeScript or JavaScript syntax.
- The JAR must not be modified after build (bundle SHA-256 verification).
FQCN and file stem computation¶
The FQCN is the file path relative to the scan root with path separators
replaced by . and the file extension stripped:
All test methods in the same file share the same FQCN. The file stem is identical to the FQCN for TypeScript (there is no class hierarchy below the file level).
Tag extraction¶
TypeScript/JavaScript test frameworks do not use annotation-based tags. The
tags field is always empty.
Circuit breaker¶
If a worker process restarts more than typescript.maxConsecutiveRestarts times
(default 5) within typescript.restartWindowSec seconds (default 60), the
circuit opens, the plugin is disabled for the remainder of the scan, a WARNING
is logged, and hadErrors() returns true.
Go¶
Plugin ID: go
Module: methodatlas-discovery-go
Parser: ANTLR4 structural grammar (GoTest.g4) — custom, focused
Runtime requirement: none — parsing is performed entirely in the JVM
Parser technology¶
GoTest.g4 is a hand-authored structural grammar. It parses top-level
declarations — package declarations, import declarations, function declarations,
and method declarations — while treating function bodies as opaque balanced-brace
content. It is not a full implementation of the Go specification.
ANTLR4 error recovery is active. Parse errors are logged as WARNING with
file path, line, and column; scanning continues for the remainder of the file.
What is detected¶
A function is emitted if and only if its declaration matches all three conditions:
- Name starts with
Testfollowed by an upper-case letter or_(or justTestwith no suffix). - First parameter type is
*testing.T(the pointer is required;testing.Twithout*does not match). - The function is a top-level function (not a method with a receiver).
// Discovered
func TestLoginValid(t *testing.T) { ... }
func Test_helperCase(t *testing.T) { ... }
func Test(t *testing.T) { ... }
// Not discovered
func BenchmarkLogin(b *testing.B) { ... } // starts with Benchmark
func ExampleLogin() { ... } // starts with Example
func FuzzLogin(f *testing.F) { ... } // starts with Fuzz
func TestHelper(t *testing.T, extra int) { ... } // extra parameter — note: still detected; parameter check is on type only
func (s *Suite) TestMethod(t *testing.T) { ... } // method with receiver — excluded
func testHelper(t *testing.T) { ... } // lowercase 't' in 'test' — excluded
Known limits¶
| Limit | Detail |
|---|---|
| Methods with receivers excluded | Only top-level functions are examined. Test methods on a struct (func (s *MySuite) TestXxx(...)) are not recognised. |
| Table-driven tests not expanded | t.Run("case", func(t *testing.T) {...}) sub-tests are not emitted as separate records; only the outer TestXxx function is discovered. |
testing.T pointer required |
The parameter must be declared as *testing.T. Type aliases (type T = testing.T) are not resolved. |
| Package name fallback | When the file sits directly in the scan root with no parent directory, the FQCN falls back to the package name extracted from the package declaration. |
| Structural grammar | Exotic Go syntax constructs (type parameters on methods in older toolchain snapshots, unusual blank identifiers in parameter lists) may produce parse warnings with error recovery. |
Preconditions¶
- File suffix must be
_test.go(or a configured override). - File encoding must be UTF-8 (ANTLR4
CharStreams.fromPathdefault).
FQCN computation¶
The FQCN is derived from the parent directory of the source file, relative to the scan root:
When the file is directly in the scan root (no parent directory), the FQCN
falls back to the package name extracted from the package declaration in
the file.
The file stem is the relative path of the file from the root (including the
filename), with path separators replaced by . and the _test.go suffix
stripped:
Tag extraction¶
Go has no annotation-based tag system. The tags field is always empty.
Error handling¶
- Per-file parse errors: logged at
WARNINGwith file, line, column, and error description;hadErrors()set totrue. - File read errors: logged at
WARNING; file is skipped.
Python¶
Plugin ID: python
Module: methodatlas-discovery-python
Parser: Python ast standard-library module via a worker pool
Runtime requirement: Python 3.8 or later on the PATH
Parser technology¶
MethodAtlas embeds a Python script (py-scanner.py) inside the JAR as a
classpath resource. At startup the JAR manifest entry Py-Scanner-SHA256
is compared against a freshly computed SHA-256 of the embedded file; a
mismatch aborts startup to detect JAR corruption or tampering. The verified
script is then extracted to a temporary file. A pool of long-lived Python
worker processes runs the script; each worker receives JSON-line requests
({ requestId, filePath }) and returns JSON-line responses with discovered
method descriptors.
The script calls ast.parse() on each file. Because the ast module is part
of Python's standard library and uses the same parser as the CPython interpreter,
all valid Python 3.8+ syntax is handled correctly — including decorated
functions, async functions, type annotations, positional-only parameters, and
all other language features up to the version of CPython that is installed.
Python executable search¶
At initialisation the plugin tries python3 --version first. If that is not
found or reports a version below 3.8, it falls back to python --version. If
neither executable exists or meets the version requirement, the plugin is
disabled gracefully.
What is detected¶
| Element | Detected | Notes |
|---|---|---|
Module-level def test_*(...) |
Yes | Sync and async def both matched |
Module-level async def test_*(...) |
Yes | |
Methods def test_*(...) inside Test* / *Test / *Tests classes |
Yes | Class name checked with startswith("Test"), endswith("Test"), endswith("Tests") |
| Async methods inside test classes | Yes | |
@pytest.mark.<name> decorators |
Yes | Decorator name extracted as tag |
| Multiple decorators stacked | Yes | Each matching decorator contributes one tag |
| Exact begin/end line numbers | Yes | ast.Node.lineno and ast.Node.end_lineno |
| LOC (lines of code) | Yes | end_lineno - lineno + 1 |
File selection dual-mode¶
The plugin applies two independent rules:
| Rule | Active when | Can be disabled |
|---|---|---|
File name starts with test_ and ends with .py |
Always | No — always active regardless of configured suffixes |
| File name ends with a configured suffix | When fileSuffixesFor("python") is non-empty; defaults to _test.py |
Yes — replaced by any configured suffix |
Example: With -file-suffix python:_spec.py set, a file named test_auth.py
is still scanned (prefix rule), but a file named auth_test.py is not
(suffix rule was replaced by _spec.py).
Known limits¶
| Limit | Detail |
|---|---|
| Python 3.8 minimum | ast.Node.end_lineno was added in Python 3.8 and is required for line-range computation. Earlier Python versions are rejected at startup. |
| No nested-function discovery | Test functions defined inside other functions (closures) are not emitted; only module-level functions and direct methods of a class are recognised. |
| No parametrized test expansion | @pytest.mark.parametrize decorated functions are emitted once as a single record; the individual parameter combinations are not expanded. |
| Class detection by name only | A class is considered a test class solely by its name following the Test* / *Test / *Tests convention. Inheritance from unittest.TestCase does not change behaviour. |
Only @pytest.mark.<name> tags |
Decorators that do not match the pattern @pytest.mark.<name> are silently ignored. Custom markers from plugins that use a different API shape are not extracted. |
| File must be valid Python | ast.parse() raises SyntaxError for invalid syntax; the worker reports an error, MethodAtlas logs a WARNING, and the file is skipped. |
Preconditions¶
python3orpythonmust be on thePATHand report version ≥ 3.8.- Files must be valid UTF-8 Python source.
- Files must be syntactically valid Python (verified by
ast.parse()). - The JAR must not be modified after build (script SHA-256 verification).
FQCN computation¶
The FQCN is the module path — the file path relative to the scan root with
path separators replaced by . and the .py extension stripped — optionally
suffixed with the class name:
scan root: /project/tests
file: /project/tests/auth/test_auth.py
class: TestAuthService
method: test_login_valid
Module path: auth.test_auth
FQCN: auth.test_auth.TestAuthService
For module-level functions (no enclosing class), the FQCN equals the module path.
The file stem is identical to the module path.
Tag extraction¶
Only @pytest.mark.<name> decorators are recognised. The decorator must
follow exactly the pattern attribute.attribute(object) — i.e. a two-level
attribute access on the name pytest, then mark, then the tag name.
Example: @pytest.mark.security → tag security.
@pytest.mark.parametrize(...) is extracted as tag parametrize (the mark
name), not expanded into individual parameter tuples.
Circuit breaker¶
If a worker process restarts more than python.maxConsecutiveRestarts times
(default 5) within python.restartWindowSec seconds (default 60), the circuit
opens, the plugin is disabled for the remainder of the scan, a WARNING is
logged, and hadErrors() returns true.
PowerShell / Pester¶
Plugin ID: powershell
Module: methodatlas-discovery-powershell
Parser: ANTLR4 structural grammar (PowerShellTest.g4) — custom, focused
Runtime requirement: none — parsing is performed entirely in the JVM
Parser technology¶
PowerShellTest.g4 is a hand-authored structural grammar. It recognises
Pester DSL keywords (Describe, Context, It) and their string arguments
and -Tag parameters, while treating all other PowerShell content as opaque
tokens. The grammar uses ANTLR4's caseInsensitive = true option, so all
keyword matches are case-insensitive.
ANTLR4 error recovery is active. Parse errors are logged as WARNING with
file path, line, and column; scanning continues for the remainder of the file.
What is detected¶
| Element | Detected | Notes |
|---|---|---|
It "description" { ... } blocks |
Yes | Case-insensitive: it, It, IT all match |
Single-quoted names It 'description' |
Yes | |
Nested It blocks inside script blocks |
Yes | Recursive descent visits all nesting depths |
-Tag "value" on the It line |
Yes | Plain form |
-Tag "a", "b" comma-separated |
Yes | Multiple values collected |
-Tag @("a", "b") array form |
Yes | ANTLR4 grammar handles @( ... ) |
Describe "..." and Context "..." blocks |
Structural | Used to determine parse structure; not emitted as separate records |
What is not detected¶
| Element | Not detected | Reason |
|---|---|---|
Tags on enclosing Describe / Context blocks |
No | Only -Tag on the It line itself is read. Pester resolves tag inheritance at runtime; MethodAtlas does not replicate that logic. |
It -Name "..." (named-parameter form) |
No | The grammar matches positional string argument only |
BeforeAll, AfterAll, BeforeEach, AfterEach |
No | Setup/teardown hooks are not test cases |
| Dynamically generated test names (variables, expressions) | No | Only string literal names are extracted |
Known limits¶
| Limit | Detail |
|---|---|
| Structural grammar | The grammar does not model full PowerShell syntax. Unusual constructs (e.g. It called via a variable alias, splat syntax on the -Tag parameter) may cause parse warnings with ANTLR4 error recovery engaging. |
| No tag inheritance | Tags declared on parent Describe or Context blocks are not propagated to child It blocks in the MethodAtlas output. If your CI pipeline or test report depends on inherited tags, apply -Tag explicitly at the It level. |
| Line range ends at closing brace | endLine is the line of the } that closes the It script block. If the closing brace is on the same line as It "...", endLine = beginLine and loc = 1. |
Preconditions¶
- File suffix must match
.Tests.ps1or.Test.ps1(or a configured override). - File encoding must be UTF-8 (ANTLR4
CharStreams.fromPathdefault).
FQCN computation¶
The FQCN is the directory path of the source file relative to the scan
root, joined with ., followed by the filename stem (suffix stripped):
scan root: /project
file: /project/modules/auth/Auth.Tests.ps1
Stem: Auth (strip .Tests.ps1)
FQCN: modules.auth.Auth
Suffix stripping order: .Tests.ps1 → .Test.ps1 → .ps1.
When the file is directly in the scan root: the FQCN is the filename stem alone.
The file stem is the relative path from root (including the filename) with
separators replaced by . and the suffix stripped:
Tag extraction¶
Tags are extracted from the -Tag parameter on the It line. Both forms are
supported:
It "name" -Tag "security" # single tag
It "name" -Tag "security", "regression" # comma-separated
It "name" -Tag @("security", "regression") { } # array literal
Only the It line itself is inspected. Tags on enclosing Describe or
Context blocks are not propagated.
SAP ABAP¶
Plugin ID: abap
Module: methodatlas-discovery-abap
Parser: Two ANTLR4 structural grammars — ABAPTest.g4 (ABAP Unit) and ECATTScript.g4 (ecATT)
Runtime requirement: none — parsing is performed entirely in the JVM
Parser technology¶
Two separate grammars cover the two SAP test conventions:
ABAP Unit (.abap files): The ABAPTest.g4 grammar is a case-insensitive structural
grammar that recognises CLASS … DEFINITION … FOR TESTING … ENDCLASS blocks and
CLASS … IMPLEMENTATION … ENDCLASS blocks. The visitor records method declarations
marked FOR TESTING and correlates them with their implementations to obtain precise
begin and end line numbers.
ecATT (.ecl files): The ECATTScript.g4 grammar recognises exported ecATT script
files produced by SAP transaction SECATT. Each FUNCTION … DONE block is one test
case; begin and end lines span the full block.
What is detected¶
| Element | Detected | Notes |
|---|---|---|
CLASS … DEFINITION FOR TESTING methods with FOR TESTING |
Yes | Only methods that carry FOR TESTING in their declaration |
METHODS: name FOR TESTING (chained form) |
Yes | Both single and colon-chained forms |
setup / helper methods without FOR TESTING |
No | Excluded by design |
ecATT FUNCTION blocks |
Yes | Each FUNCTION in an .ecl export is one test |
Known limits¶
| Limit | Detail |
|---|---|
| Fixed-form only | The grammar does not model all ABAP OO constructs (macros, form routines, function modules). Structural class content outside METHOD/ENDMETHOD is consumed as opaque tokens. |
| ecATT file format | Requires exported .ecl files from transaction SECATT. Online scripts stored only inside the SAP system cannot be discovered without export. |
| No tag extraction | ABAP Unit does not use annotation-based tags; the tags field is always empty. |
FQCN computation¶
For ABAP Unit: the FQCN is the class name in upper-case (e.g. ZCL_AUTH_TEST).
For ecATT: the FQCN equals the function name (e.g. Z_AUTH_LOGIN_TEST).
The file stem is the file path relative to the scan root with separators replaced
by . and the extension stripped.
COBOL¶
Plugin ID: cobol
Module: methodatlas-discovery-cobol
Parser: ANTLR4 structural grammar (COBOLTest.g4) — case-insensitive, handles both conventions
Runtime requirement: none — parsing is performed entirely in the JVM
Parser technology¶
COBOLTest.g4 is a case-insensitive structural grammar that recognises two COBOL
test conventions in the same pass:
Micro Focus MFUnit: paragraphs whose names start with MFU-TC- are test cases.
Each paragraph spans from the name line to the line before the next paragraph or
end of file.
COBOL-Check: TestCase 'name' directives (typically in .cut files alongside
COBOL source, or embedded in the source as specially marked statements) are emitted
as test cases. The enclosing TestSuite label is recorded for context.
What is detected¶
| Element | Detected | Notes |
|---|---|---|
MFU-TC-* paragraphs in PROCEDURE DIVISION |
Yes | Case-insensitive match on the MFU-TC- prefix |
TestCase 'name' directives (COBOL-Check) |
Yes | Both single-quoted and double-quoted names |
TestSuite 'name' blocks |
Context only | Suite label is not emitted as a separate record |
Regular COBOL paragraphs without MFU-TC- prefix |
No | Only the MFUnit-prefixed convention is recognised |
Known limits¶
| Limit | Detail |
|---|---|
| Structural grammar | The grammar does not model full COBOL syntax. Fixed-form column restrictions (sequence area, indicator area) are not enforced; the grammar works correctly on free-form COBOL and on fixed-form files where the column restrictions do not affect the keywords parsed. |
| PROGRAM-ID extraction | The grammar does not extract PROGRAM-ID; the FQCN is derived from the file path. |
| No tag extraction | COBOL test frameworks do not use annotation-based tags; the tags field is always empty. |
FQCN computation¶
The FQCN is the file path relative to the scan root with separators replaced by .
and the file extension stripped (e.g. cobol.auth.auth_test).
The file stem is identical to the FQCN.
Summary comparison¶
| Java | C# | TypeScript | Go | Python | PowerShell | SAP ABAP | COBOL | |
|---|---|---|---|---|---|---|---|---|
| Parser | JavaParser AST | ANTLR4 structural | Node.js bundle (TS compiler API) | ANTLR4 structural | Python ast |
ANTLR4 structural | ANTLR4 structural | ANTLR4 structural |
| Runtime needed | None | None | Node.js 18+ | None | Python 3.8+ | None | None | None |
| Full syntax coverage | Java 21 | Structural | Full TS/JS | Structural | Full CPython 3.8+ | Structural | Structural | Structural |
| Framework detection | Auto (imports) | Auto (using directives) | N/A | N/A | N/A (name-based) | N/A (DSL keyword) | FOR TESTING attribute |
MFU-TC- prefix / TestCase keyword |
| Tags | @Tag("v") |
@Category/@Trait/@TestCategory |
None | None | @pytest.mark.X |
-Tag "v" |
None | None |
| Display name | @DisplayName("t") |
[Fact(DisplayName="t")] (xUnit only) |
Test name = display name | None | None | Test description | None | TestCase label |
| Nested classes | Yes | Yes | N/A | N/A | Direct methods only | N/A | N/A | N/A |
| Async tests | N/A | N/A | Yes | N/A | Yes | N/A | N/A | N/A |
| Sub-test / parametrize expansion | No | No | Partial | No | No | No | N/A | N/A |
| Error recovery | Parse failure = skip file | ANTLR4 continues | Worker timeout/crash → replaced | ANTLR4 continues | Worker error → skip file | ANTLR4 continues | ANTLR4 continues | ANTLR4 continues |
| FQCN basis | package + class | namespace + class | file path | parent directory | module path + class | directory + stem | class name / function name | file path |