|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +IntelliJ IDEA / PhpStorm plugin for **Testo** — a PHP testing framework. |
| 6 | +Provides full IDE integration: test discovery, run configurations, code generation, inspections, and navigation. |
| 7 | + |
| 8 | +- **Plugin ID:** `com.github.xepozz.testo` |
| 9 | +- **Plugin Name:** Testo PHP |
| 10 | +- **Author:** Dmitrii Derepko (@xepozz) |
| 11 | +- **Repository:** https://github.com/j-plugins/testo-plugin |
| 12 | +- **Marketplace:** JetBrains Marketplace |
| 13 | + |
| 14 | +## Tech Stack |
| 15 | + |
| 16 | +| Component | Version / Value | |
| 17 | +|----------------------|---------------------------| |
| 18 | +| Language | Kotlin 2.3.0 | |
| 19 | +| JVM Toolchain | Java 21 | |
| 20 | +| IntelliJ Platform | 2024.3.4 (IU — Ultimate) | |
| 21 | +| Min platform build | 243 (2024.3.x) | |
| 22 | +| Build system | Gradle 9.3.0 | |
| 23 | +| IntelliJ Plugin SDK | `org.jetbrains.intellij.platform` 2.11.0 | |
| 24 | +| Changelog plugin | `org.jetbrains.changelog` 2.5.0 | |
| 25 | +| Code quality | Qodana 2025.3.1 | |
| 26 | +| Coverage | Kover 0.9.4 | |
| 27 | +| Test framework | JUnit 4.13.2, OpenTest4J 1.3.0 | |
| 28 | + |
| 29 | +## Build & Run Commands |
| 30 | + |
| 31 | +```bash |
| 32 | +# Build the plugin |
| 33 | +./gradlew buildPlugin |
| 34 | + |
| 35 | +# Run tests |
| 36 | +./gradlew check |
| 37 | + |
| 38 | +# Run IDE with plugin loaded (for manual testing) |
| 39 | +./gradlew runIde |
| 40 | + |
| 41 | +# Verify plugin compatibility |
| 42 | +./gradlew verifyPlugin |
| 43 | + |
| 44 | +# Run UI tests (requires robot-server) |
| 45 | +./gradlew runIdeForUiTests |
| 46 | +``` |
| 47 | + |
| 48 | +## Project Structure |
| 49 | + |
| 50 | +``` |
| 51 | +src/main/kotlin/com/github/xepozz/testo/ |
| 52 | +├── TestoBundle.kt # i18n message bundle |
| 53 | +├── TestoClasses.kt # FQN constants for Testo PHP classes/attributes |
| 54 | +├── TestoContext.kt # Live template context |
| 55 | +├── TestoIcons.kt # Icon definitions |
| 56 | +├── TestoUtil.kt # Project-level Testo availability check |
| 57 | +├── TestoComposerConfig.kt # Composer package detection |
| 58 | +├── mixin.kt # PSI extension functions (isTestoMethod, isTestoClass, etc.) |
| 59 | +├── PsiUtil.kt # General PSI utilities |
| 60 | +├── ExitStatementsVisitor.kt # PHP exit statement analysis |
| 61 | +├── SpellcheckingDictionaryProvider.kt |
| 62 | +│ |
| 63 | +├── actions/ # Code generation actions |
| 64 | +│ ├── TestoGenerateTestMethodAction.kt |
| 65 | +│ └── TestoGenerateMethodActionBase.kt |
| 66 | +│ |
| 67 | +├── index/ # File-based index for data providers |
| 68 | +│ ├── TestoDataProvidersIndex.kt |
| 69 | +│ └── TestoDataProviderUtils.kt |
| 70 | +│ |
| 71 | +├── references/ # Reference resolution & implicit usage |
| 72 | +│ └── TestFunctionImplicitUsageProvider.kt |
| 73 | +│ |
| 74 | +├── tests/ # Core test framework integration |
| 75 | +│ ├── TestoFrameworkType.kt # PhpTestFrameworkType implementation |
| 76 | +│ ├── TestoTestDescriptor.kt # Test class/method discovery |
| 77 | +│ ├── TestoTestLocator.kt # Stack trace → source navigation |
| 78 | +│ ├── TestoTestRunLineMarkerProvider.kt # Gutter run icons |
| 79 | +│ ├── TestoStackTraceParser.kt # Test output parsing |
| 80 | +│ ├── TestoConsoleProperties.kt # Console configuration |
| 81 | +│ ├── TestoVersionDetector.kt # Testo version detection |
| 82 | +│ │ |
| 83 | +│ ├── actions/ # Test-specific actions |
| 84 | +│ │ ├── TestoNewTestFromClassAction.kt |
| 85 | +│ │ ├── TestoTestActionProvider.kt |
| 86 | +│ │ ├── TestoRerunFailedTestsAction.kt |
| 87 | +│ │ └── TestoRunCommandAction.kt |
| 88 | +│ │ |
| 89 | +│ ├── inspections/ |
| 90 | +│ │ └── TestoInspectionSuppressor.kt |
| 91 | +│ │ |
| 92 | +│ ├── overrides/ # UI customization |
| 93 | +│ │ |
| 94 | +│ ├── run/ # Run configuration subsystem |
| 95 | +│ │ ├── TestoRunConfigurationType.kt |
| 96 | +│ │ ├── TestoRunConfiguration.kt |
| 97 | +│ │ ├── TestoRunConfigurationFactory.kt |
| 98 | +│ │ ├── TestoRunConfigurationProducer.kt # Context-based config creation |
| 99 | +│ │ ├── TestoRunConfigurationHandler.kt |
| 100 | +│ │ ├── TestoRunConfigurationSettings.kt |
| 101 | +│ │ ├── TestoRunTestConfigurationEditor.kt |
| 102 | +│ │ ├── TestoTestRunnerSettingsValidator.kt |
| 103 | +│ │ ├── TestoTestMethodFinder.kt |
| 104 | +│ │ ├── TestoRunnerSettings.kt |
| 105 | +│ │ └── TestoDebugRunner.kt |
| 106 | +│ │ |
| 107 | +│ └── runAnything/ |
| 108 | +│ └── TestoRunAnythingProvider.kt |
| 109 | +│ |
| 110 | +└── ui/ # UI components |
| 111 | + ├── TestoIconProvider.kt |
| 112 | + ├── TestoStackTraceConsoleFolding.kt |
| 113 | + └── PhpRunInheritorsListCellRenderer.kt |
| 114 | +
|
| 115 | +src/main/resources/ |
| 116 | +├── META-INF/plugin.xml # Plugin descriptor (extensions, actions) |
| 117 | +├── fileTemplates/ # New file templates (Testo Test.php.ft) |
| 118 | +├── icons/ # SVG icons (light + dark variants) |
| 119 | +├── liveTemplates/Testo.xml # Live templates: `test`, `data` |
| 120 | +├── messages/TestoBundle.properties # i18n strings |
| 121 | +└── testo.dic # Spellchecker dictionary |
| 122 | +
|
| 123 | +src/test/ # Unit tests (JUnit 4 + BasePlatformTestCase) |
| 124 | +``` |
| 125 | + |
| 126 | +## Architecture |
| 127 | + |
| 128 | +### Plugin Extension Points |
| 129 | + |
| 130 | +The plugin registers extensions in `plugin.xml` under two namespaces: |
| 131 | + |
| 132 | +- **`com.intellij`** — standard IntelliJ extensions: `fileType`, `runLineMarkerContributor`, `configurationType`, `runConfigurationProducer`, `programRunner`, `implicitUsageProvider`, `iconProvider`, `fileBasedIndex`, `console.folding`, `lang.inspectionSuppressor`, `testActionProvider`, live templates, etc. |
| 133 | +- **`com.jetbrains.php`** — PHP-specific: `testFrameworkType` (TestoFrameworkType), `composerConfigClient` (TestoComposerConfig). |
| 134 | + |
| 135 | +### Required Plugin Dependencies |
| 136 | + |
| 137 | +- `com.intellij.modules.platform` — IntelliJ Platform core |
| 138 | +- `com.jetbrains.php` — PHP language support (makes this plugin work in PhpStorm / IDEA Ultimate with PHP plugin) |
| 139 | + |
| 140 | +### Testo PHP Framework — Supported Classes |
| 141 | + |
| 142 | +The plugin recognizes these PHP namespaces/attributes (defined in `TestoClasses.kt`): |
| 143 | + |
| 144 | +| Category | Old namespace (`\Testo\Sample\*`, `\Testo\Attribute\*`) | New namespace (`\Testo\Application\*`, `\Testo\Data\*`, etc.) | |
| 145 | +|-----------------|----------------------------------------------------------|---------------------------------------------------------------| |
| 146 | +| Test attribute | `\Testo\Attribute\Test` | `\Testo\Application\Attribute\Test` | |
| 147 | +| Inline test | `\Testo\Sample\TestInline` | `\Testo\Inline\TestInline` | |
| 148 | +| Data provider | `\Testo\Sample\DataProvider` | `\Testo\Data\DataProvider` | |
| 149 | +| Data set | `\Testo\Sample\DataSet` | `\Testo\Data\DataSet` | |
| 150 | +| Data union | — | `\Testo\Data\DataUnion` | |
| 151 | +| Data cross | — | `\Testo\Data\DataCross` | |
| 152 | +| Data zip | — | `\Testo\Data\DataZip` | |
| 153 | +| Benchmark | — | `\Testo\Bench\BenchWith` | |
| 154 | +| Assertions | — | `\Testo\Assert`, `\Testo\Expect` | |
| 155 | + |
| 156 | +### Test Detection Logic (mixin.kt) |
| 157 | + |
| 158 | +A PHP element is recognized as a Testo test when: |
| 159 | +- **Method:** public + name starts with `test`, OR has `#[Test]` / `#[TestInline]` attribute |
| 160 | +- **Function:** has `#[Test]` / `#[TestInline]` attribute (standalone test functions) |
| 161 | +- **Benchmark:** has `#[BenchWith]` attribute |
| 162 | +- **Class:** name ends with `Test` or `TestBase`, OR contains test/bench methods |
| 163 | +- **File:** filename matches test class pattern, OR contains test classes/functions/benchmarks |
| 164 | + |
| 165 | +### Key Subsystems |
| 166 | + |
| 167 | +1. **Run Configuration** (`tests/run/`) — creates and manages run/debug configurations for Testo tests. `TestoRunConfigurationProducer` is the largest file (~527 lines) handling context-based config creation for methods, classes, files, data providers, and datasets. |
| 168 | + |
| 169 | +2. **Line Markers** (`TestoTestRunLineMarkerProvider`) — adds green play buttons in the gutter next to test methods, classes, and data providers. |
| 170 | + |
| 171 | +3. **Data Provider Index** (`index/TestoDataProvidersIndex`) — file-based index that maps test methods to their data providers for quick lookup across the project. |
| 172 | + |
| 173 | +4. **Code Generation** — "Create Test from Class" action and "Generate Test Method" action integrated into IDE menus. |
| 174 | + |
| 175 | +5. **Stack Trace Navigation** (`TestoTestLocator`) — click-to-navigate from test output to source code. |
| 176 | + |
| 177 | +## Constraints & Important Notes |
| 178 | + |
| 179 | +- **Platform:** IntelliJ IDEA Ultimate or PhpStorm only (requires `com.jetbrains.php` plugin) |
| 180 | +- **Min IDE version:** 2024.3 (build 243+) |
| 181 | +- **Kotlin stdlib is NOT bundled** (`kotlin.stdlib.default.dependency = false`) — uses the one shipped with IntelliJ |
| 182 | +- **Gradle Configuration Cache** and **Build Cache** are enabled |
| 183 | +- **Code and comments language:** English |
| 184 | +- **Plugin description** is extracted from `README.md` between `<!-- Plugin description -->` markers during build |
| 185 | +- **Signing & publishing** require environment variables: `CERTIFICATE_CHAIN`, `PRIVATE_KEY`, `PRIVATE_KEY_PASSWORD`, `PUBLISH_TOKEN` |
| 186 | + |
| 187 | +## CI/CD |
| 188 | + |
| 189 | +- **build.yml** (on push to main / PRs): build → test (with Kover coverage → Codecov) → Qodana inspections → plugin verification → draft release |
| 190 | +- **release.yml** (on GitHub release): publish to JetBrains Marketplace, update changelog |
| 191 | +- **run-ui-tests.yml** (manual): UI tests on Ubuntu, Windows, macOS via robot-server |
| 192 | + |
| 193 | +## Conventions |
| 194 | + |
| 195 | +- All source code is in Kotlin |
| 196 | +- Package root: `com.github.xepozz.testo` |
| 197 | +- i18n strings go in `messages/TestoBundle.properties`, accessed via `TestoBundle` |
| 198 | +- Icons follow IntelliJ conventions: SVG with `_dark` suffix variant |
| 199 | +- New extension points must be registered in `plugin.xml` |
| 200 | +- Version follows SemVer; `pluginVersion` in `gradle.properties` is the single source of truth |
0 commit comments