# (DD02) Business Logic — TestDetector.detect() [30 LOC]

| Field | Value |
|-------|-------|
| Fully Qualified Name | `com.optage.parser.TestDetector` |
| Layer | Utility |
| Module | `parser` (Package: `com.optage.parser`) |

## 1. Role

### TestDetector.detect()

This method performs test-file detection for source assets by evaluating multiple signals in priority order: method/class annotations, file path conventions, class naming conventions, and legacy JUnit inheritance. Its business role is to determine whether a given source artifact should be classified as a test case and to capture the evidence that justified that classification.

The method implements a lightweight routing/dispatch pattern for test recognition. It does not persist data or invoke external systems; instead, it aggregates detection signals into a `signals` list and produces a `TestInfo` object that can be consumed by higher-level parsing, reporting, or indexing logic. The control flow is intentionally layered so that stronger signals such as annotations and path conventions can mark the artifact as a test even when the class name is ambiguous.

The method handles four detection branches: annotated tests, path-based test locations, test-like class names, and superclass-based JUnit legacy tests. Each branch contributes an explanatory signal string, allowing downstream consumers to understand why a class was classified as a test. In practice, this makes the method a shared classification utility for the parser module rather than an application feature endpoint.

## 2. Processing Pattern (Detailed Business Logic)

```mermaid
flowchart TD
START(["detect(className, filePath, code)"])
A["Initialize signals list and isTest = false"]
B{"hasTestAnnotation(code)?"}
C["Add annotation:@Test signal and set isTest = true"]
D{"isTestPath(filePath)?"}
E["Add path signal and set isTest = true"]
F{"isTestClassName(className)?"}
G["Add classname signal and set isTest = true only if still false"]
H{"extendsTestCase(code)?"}
I["Add superclass:TestCase signal and set isTest = true"]
J["Return new TestInfo(className, isTest, signals)"]
START --> A
A --> B
B -- "Yes" --> C
B -- "No" --> D
C --> D
D -- "Yes" --> E
D -- "No" --> F
E --> F
F -- "Yes" --> G
F -- "No" --> H
G --> H
H -- "Yes" --> I
H -- "No" --> J
I --> J
```

## 3. Parameter Analysis

| No | Parameter Name | Type | Business Description |
|----|---------------|------|---------------------|
| 1 | `className` | `String` | The parsed Java type name being evaluated for test classification. It may represent a conventional test class name such as `*Test`, `*Tests`, or `Test*`. It affects the class-name branch and can contribute a `classname:` signal even when no annotation or test path is present. |
| 2 | `filePath` | `String` | The source file location for the artifact under analysis. It is used to detect repository path conventions such as `/test/`, `/tests/`, or `__tests__`. A matching path is treated as strong evidence that the file belongs to a test scope. |
| 3 | `code` | `String` | The raw source code text for the class. It is scanned for test annotations and for legacy inheritance markers such as `extends TestCase` or `extends TestSuite`. This input drives the annotation branch and superclass branch. |

**Instance fields / external state read by this method:** `TEST_ANNOTATION_PATTERN` is used through `hasTestAnnotation(code)`; no other instance state, database state, or external services are read.

## 4. CRUD Operations / Called Services

### Pre-computed evidence from code analysis graph:

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| - | `TestDetector.extendsTestCase` | TestDetector | - | Calls `extendsTestCase` in `TestDetector` |
| - | `TestDetector.hasTestAnnotation` | TestDetector | - | Calls `hasTestAnnotation` in `TestDetector` |
| - | `TestDetector.isTestClassName` | TestDetector | - | Calls `isTestClassName` in `TestDetector` |
| - | `TestDetector.isTestPath` | TestDetector | - | Calls `isTestPath` in `TestDetector` |

Analyze all method calls within this method and classify each as a CRUD operation.

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| R | `hasTestAnnotation` | TestDetector | - | Reads the source text and checks whether it contains a supported test annotation pattern. |
| R | `isTestPath` | TestDetector | - | Reads the source path string and checks whether it matches test-directory conventions. |
| R | `isTestClassName` | TestDetector | - | Reads the class name and checks whether it matches a test-oriented naming convention. |
| R | `extendsTestCase` | TestDetector | - | Reads the source text and checks whether it declares a legacy JUnit test superclass. |

## 5. Dependency Trace

### Pre-computed evidence from code analysis graph:

No screen/batch entry points found within 8 hops. Direct callers found: 13 methods.
Terminal operations from this method: `extendsTestCase` [-], `isTestClassName` [-], `isTestPath` [-], `hasTestAnnotation` [-]

Trace who calls this method and what this method ultimately calls.

| # | Caller (Screen/Batch) | Call Chain (Full Path to this Method) | Terminal (SC / CRUD / Entity) |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | CBS/Test | `IntegrationTest.testDetectByAnnotation` -> `TestDetector.detect` | `hasTestAnnotation [R] source text` |
| 2 | CBS/Test | `IntegrationTest.testDetectByClassName` -> `TestDetector.detect` | `isTestClassName [R] class name` |
| 3 | CBS/Test | `TestDetectorTest.testDetectAnnotationPositive` -> `TestDetector.detect` | `hasTestAnnotation [R] source text` |
| 4 | CBS/Test | `TestDetectorTest.testDetectPathPositive` -> `TestDetector.detect` | `isTestPath [R] path text` |
| 5 | CBS/Test | `TestDetectorTest.testDetectClassNamePositive` -> `TestDetector.detect` | `isTestClassName [R] class name` |
| 6 | CBS/Test | `TestDetectorTest.testDetectSuperclassPositive` -> `TestDetector.detect` | `extendsTestCase [R] source text` |
| 7 | CBS/Test | `TestDetectorTest.testDetectAnnotationOverrides` -> `TestDetector.detect` | `hasTestAnnotation [R] source text` |
| 8 | CBS/Test | `TestDetectorTest.testDetectNonTestNegative` -> `TestDetector.detect` | `hasTestAnnotation [R] source text` |
| 9 | CBS/Test | `TestDetectorTest.testDetectWindowsPathPositive` -> `TestDetector.detect` | `isTestPath [R] path text` |
| 10 | CBS/Test | `TestDetectorTest.testDetectUnderscorePathPositive` -> `TestDetector.detect` | `isTestPath [R] path text` |
| 11 | CBS/Test | `TestDetectorTest.testDetectSingleWordTestClass` -> `TestDetector.detect` | `isTestClassName [R] class name` |
| 12 | CBS/Test | `TestDetectorTest.testDetectTestPrefixClass` -> `TestDetector.detect` | `isTestClassName [R] class name` |
| 13 | CBS/Test | `TestDetectorTest.testDetectMixedSignals` -> `TestDetector.detect` | `extendsTestCase [R] source text` |

## 6. Per-Branch Detail Blocks

**Block 1** — [SET] (method entry and initial state setup) (L12-L14)

> Initializes the detection evidence list and defaults the classification to non-test until one of the detection rules matches.

| # | Type | Code |
|---|------|------|
| 1 | SET | `List<String> signals = new ArrayList<>();` |
| 2 | SET | `boolean isTest = false;` |

**Block 2** — [IF] `hasTestAnnotation(code)` (L17)

> Detects whether the source text contains a supported test annotation such as `@Test` or lifecycle annotations. This is the strongest signal because it directly reflects framework usage.

| # | Type | Code |
|---|------|------|
| 1 | CALL | `hasTestAnnotation(code)` |

**Block 2.1** — [THEN] annotation found (L18-L19)

| # | Type | Code |
|---|------|------|
| 1 | SET | `signals.add("annotation:@Test");` |
| 2 | SET | `isTest = true;` |

**Block 3** — [IF] `isTestPath(filePath)` (L22)

> Detects whether the file path places the source in a test-oriented directory structure.

| # | Type | Code |
|---|------|------|
| 1 | CALL | `isTestPath(filePath)` |

**Block 3.1** — [THEN] test path found (L23-L24)

| # | Type | Code |
|---|------|------|
| 1 | SET | `signals.add("path:" + filePath);` |
| 2 | SET | `isTest = true;` |

**Block 4** — [IF] `isTestClassName(className)` (L27)

> Detects whether the class name follows a test naming convention such as suffix `Test`, suffix `Tests`, or prefix `Test`.

| # | Type | Code |
|---|------|------|
| 1 | CALL | `isTestClassName(className)` |

**Block 4.1** — [THEN] test class name found (L28-L29)

| # | Type | Code |
|---|------|------|
| 1 | SET | `signals.add("classname:" + className);` |
| 2 | IF | `if (!isTest) isTest = true;` |
| 3 | SET | `isTest = true;` |

**Block 5** — [IF] `extendsTestCase(code)` (L32)

> Detects legacy JUnit inheritance patterns in the source text.

| # | Type | Code |
|---|------|------|
| 1 | CALL | `extendsTestCase(code)` |

**Block 5.1** — [THEN] legacy test superclass found (L33-L34)

| # | Type | Code |
|---|------|------|
| 1 | SET | `signals.add("superclass:TestCase");` |
| 2 | SET | `isTest = true;` |

**Block 6** — [RETURN] build `TestInfo` result (L36)

> Returns the final classification result together with the collected evidence signals.

| # | Type | Code |
|---|------|------|
| 1 | RETURN | `return new TestInfo(className, isTest, signals);` |

## 7. Glossary

| Term | Type | Business Meaning |
|------|------|------------------|
| `className` | Field | The Java class identifier being analyzed for test classification. |
| `filePath` | Field | The repository path or filesystem path of the source artifact. |
| `code` | Field | Full source text used to inspect annotations and inheritance. |
| `signals` | Field | Collected evidence strings explaining why the artifact was classified as a test. |
| `isTest` | Field | Final boolean classification flag indicating whether the artifact is a test. |
| `TEST_ANNOTATION_PATTERN` | Constant | Regular expression used to recognize supported test lifecycle annotations. |
| `@Test` | Annotation | Standard unit-test annotation that marks a test method or test-related declaration. |
| `@Before` | Annotation | Lifecycle annotation executed before each test. |
| `@After` | Annotation | Lifecycle annotation executed after each test. |
| `@BeforeEach` | Annotation | JUnit 5 lifecycle annotation executed before each test. |
| `@AfterEach` | Annotation | JUnit 5 lifecycle annotation executed after each test. |
| `@BeforeClass` | Annotation | Lifecycle annotation executed once before all tests in a class. |
| `@AfterClass` | Annotation | Lifecycle annotation executed once after all tests in a class. |
| `TestCase` | Legacy test base class | Classic JUnit base class used by older tests. |
| `TestSuite` | Legacy test base class | Classic JUnit aggregation base used by older test suites. |
| `/test/` | Path convention | Standard source tree location for test code. |
| `/tests/` | Path convention | Alternative directory convention for test code. |
| `/__tests__/` | Path convention | Common JavaScript test directory convention. |
| `__tests__` | Path convention | Directory name used to indicate automated tests. |
| `TestInfo` | Data object | Output object containing the class name, classification result, and evidence list. |
| Test detector | Business term | Parser utility that classifies whether a source file is a test artifact. |
| Annotation-based detection | Business term | Test classification driven by framework annotations in the source code. |
| Path-based detection | Business term | Test classification driven by file location conventions. |
| Class-name-based detection | Business term | Test classification driven by naming conventions in the type name. |
| Superclass-based detection | Business term | Test classification driven by inheritance from legacy JUnit test bases. |
