Full Code of pestphp/pest-intellij for AI

master 8c7aca5430a1 cached
461 files
542.8 KB
141.5k tokens
224 symbols
1 requests
Download .txt
Showing preview only (680K chars total). Download the full file or copy to clipboard to get everything.
Repository: pestphp/pest-intellij
Branch: master
Commit: 8c7aca5430a1
Files: 461
Total size: 542.8 KB

Directory structure:
gitextract_h0dnztv0/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature-request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── auto-close.yml
│       ├── build.yml
│       ├── qodana.yml
│       ├── release.yml
│       └── run-ui-tests.yml
├── .gitignore
├── .run/
│   ├── Run IDE with Plugin.run.xml
│   ├── Run Plugin Tests.run.xml
│   ├── Run Plugin Verification.run.xml
│   └── Run Qodana.run.xml
├── BUILD.bazel
├── CHANGELOG.md
├── CLAUDE.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── build.gradle.kts
├── coverage/
│   ├── BUILD.bazel
│   ├── intellij.pest.coverage.iml
│   ├── resources/
│   │   └── intellij.pest.coverage.xml
│   ├── src/
│   │   ├── PestCoverageEnabledConfiguration.kt
│   │   ├── PestCoverageEngine.kt
│   │   ├── PestCoverageProgramRunner.kt
│   │   └── features/
│   │       └── mutate/
│   │           ├── PestMutateProgramRunner.kt
│   │           └── PestMutateTestExecutor.kt
│   └── tests/
│       ├── BUILD.bazel
│       ├── intellij.pest.coverage.tests.iml
│       ├── src/
│       │   └── com/
│       │       └── intellij/
│       │           └── pest/
│       │               └── coverage/
│       │                   ├── PestCoverageProgramRunnerTest.kt
│       │                   └── features/
│       │                       └── mutate/
│       │                           └── PestMutateProgramRunnerTest.kt
│       └── testData/
│           ├── ATest.php
│           ├── features/
│           │   └── mutate/
│           │       ├── ATest.php
│           │       └── php
│           └── php
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── intellij.pest.iml
├── intellij.pest.tests.iml
├── plugin-content.yaml
├── settings.gradle.kts
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/
    │   │       └── pestphp/
    │   │           └── pest/
    │   │               ├── PestIcons.java
    │   │               └── configuration/
    │   │                   ├── PestRunConfigurationSettings.java
    │   │                   └── PhpTestRunConfiguration.java
    │   ├── kotlin/
    │   │   └── com/
    │   │       └── pestphp/
    │   │           └── pest/
    │   │               ├── FileUtil.kt
    │   │               ├── PestBundle.kt
    │   │               ├── PestComposerConfig.kt
    │   │               ├── PestFrameworkType.kt
    │   │               ├── PestFunctionsUtil.kt
    │   │               ├── PestIconProvider.kt
    │   │               ├── PestNamingUtil.kt
    │   │               ├── PestNewTestFromClassAction.kt
    │   │               ├── PestPluginDisposable.kt
    │   │               ├── PestSettings.kt
    │   │               ├── PestTestCreateInfo.kt
    │   │               ├── PestTestDescriptor.kt
    │   │               ├── PestTestFileUtil.kt
    │   │               ├── PestTestRunLineMarkerProvider.kt
    │   │               ├── PestUtil.kt
    │   │               ├── annotator/
    │   │               │   ├── PestAnnotator.kt
    │   │               │   └── PestAnnotatorVisitor.kt
    │   │               ├── completion/
    │   │               │   ├── InternalMembersCompletionProvider.kt
    │   │               │   ├── PestCompletionContributor.kt
    │   │               │   ├── PestCustomExtensionCompletionProvider.kt
    │   │               │   └── ThisFieldsCompletionProvider.kt
    │   │               ├── configuration/
    │   │               │   ├── PestDebugRunner.kt
    │   │               │   ├── PestLocationProvider.kt
    │   │               │   ├── PestRerunFailedTestsAction.kt
    │   │               │   ├── PestRerunProfile.kt
    │   │               │   ├── PestRunConfiguration.kt
    │   │               │   ├── PestRunConfigurationHandler.kt
    │   │               │   ├── PestRunConfigurationProducer.kt
    │   │               │   ├── PestRunConfigurationType.kt
    │   │               │   ├── PestRunnerSettings.kt
    │   │               │   ├── PestTestRunConfigurationEditor.kt
    │   │               │   └── PestVersionDetector.kt
    │   │               ├── features/
    │   │               │   ├── configuration/
    │   │               │   │   ├── ConfigurationInDirectoryReferenceProvider.kt
    │   │               │   │   ├── ConfigurationReferenceContributor.kt
    │   │               │   │   └── PhpFolderReferenceSet.kt
    │   │               │   ├── customExpectations/
    │   │               │   │   ├── CustomExpectationIndex.kt
    │   │               │   │   ├── CustomExpectationNotifier.kt
    │   │               │   │   ├── CustomExpectationParameterInfoHandler.kt
    │   │               │   │   ├── CustomExpectationRemoveGeneratedFileStartupActivity.kt
    │   │               │   │   ├── ListMethodDataExternalizer.kt
    │   │               │   │   ├── MethodDataExternalizer.kt
    │   │               │   │   ├── expectationUtil.kt
    │   │               │   │   ├── externalizers/
    │   │               │   │   │   ├── ListDataExternalizer.kt
    │   │               │   │   │   ├── MethodDataExternalizer.kt
    │   │               │   │   │   ├── ParameterDataExternalizer.kt
    │   │               │   │   │   └── PhpTypeDataExternalizer.kt
    │   │               │   │   ├── generators/
    │   │               │   │   │   ├── ExpectationGenerator.kt
    │   │               │   │   │   ├── Method.kt
    │   │               │   │   │   └── Parameter.kt
    │   │               │   │   └── symbols/
    │   │               │   │       ├── PestCustomExpectationReference.kt
    │   │               │   │       ├── PestCustomExpectationReferenceProvider.kt
    │   │               │   │       ├── PestCustomExpectationRenameUsageSearcher.kt
    │   │               │   │       ├── PestCustomExpectationSymbol.kt
    │   │               │   │       ├── PestCustomExpectationSymbolDeclaration.kt
    │   │               │   │       ├── PestCustomExpectationSymbolDeclarationProvider.kt
    │   │               │   │       └── PestCustomExpectationUsageSearcher.kt
    │   │               │   ├── datasets/
    │   │               │   │   ├── DatasetIndex.kt
    │   │               │   │   ├── DatasetReference.kt
    │   │               │   │   ├── DatasetReferenceContributor.kt
    │   │               │   │   ├── DatasetReferenceProvider.kt
    │   │               │   │   ├── DatasetUtil.kt
    │   │               │   │   ├── InvalidDatasetNameCaseInspection.kt
    │   │               │   │   └── InvalidDatasetReferenceInspection.kt
    │   │               │   ├── parallel/
    │   │               │   │   ├── PestParallelProgramRunner.kt
    │   │               │   │   ├── PestParallelSMTEventsAdapter.kt
    │   │               │   │   └── PestParallelTestExecutor.kt
    │   │               │   └── snapshotTesting/
    │   │               │       ├── SnapshotLineMarkerProvider.kt
    │   │               │       └── SnapshotUtil.kt
    │   │               ├── goto/
    │   │               │   ├── PestDatasetUsagesGotoHandler.kt
    │   │               │   ├── PestGotoTargetPresentationProvider.kt
    │   │               │   ├── PestTestFinder.kt
    │   │               │   └── PestTestGoToSymbolContributor.kt
    │   │               ├── indexers/
    │   │               │   └── PestTestIndex.kt
    │   │               ├── inspections/
    │   │               │   ├── ChangeMultipleExpectCallsToChainableQuickFix.kt
    │   │               │   ├── ChangeTestNameCasingQuickFix.kt
    │   │               │   ├── InvalidTestNameCaseInspection.kt
    │   │               │   ├── MissingScreenshotSnapshotInspection.kt
    │   │               │   ├── MultipleExpectChainableInspection.kt
    │   │               │   ├── PestAssertionCanBeSimplifiedInspection.kt
    │   │               │   ├── PestTestFailedLineInspection.kt
    │   │               │   ├── SuppressExpressionResultUnusedInspection.kt
    │   │               │   └── SuppressUndefinedPropertyInspection.kt
    │   │               ├── notifications/
    │   │               │   └── OutdatedNotification.kt
    │   │               ├── parser/
    │   │               │   ├── PestConfigurationFile.kt
    │   │               │   └── PestConfigurationFileParser.kt
    │   │               ├── runner/
    │   │               │   ├── LocationInfo.kt
    │   │               │   ├── PestConsoleProperties.kt
    │   │               │   ├── PestFailedLineManager.kt
    │   │               │   ├── PestPressToContinueAction.kt
    │   │               │   ├── PestPromptConsoleFolding.kt
    │   │               │   └── PestTestStackTraceParser.kt
    │   │               ├── statistics/
    │   │               │   └── PestUsagesCollector.kt
    │   │               ├── structureView/
    │   │               │   ├── PestStructureViewElement.kt
    │   │               │   └── PestStructureViewExtension.kt
    │   │               ├── surrounders/
    │   │               │   ├── ExpectStatementSurrounder.kt
    │   │               │   └── StatementSurroundDescriptor.kt
    │   │               ├── templates/
    │   │               │   ├── PestConfigNewDatasetFileAction.kt
    │   │               │   ├── PestConfigNewFileAction.kt
    │   │               │   ├── PestDescribePostfixTemplate.kt
    │   │               │   ├── PestItPostfixTemplate.kt
    │   │               │   ├── PestPostfixTemplateProvider.kt
    │   │               │   └── PestRootTemplateContextType.kt
    │   │               └── types/
    │   │                   ├── HigherOrderExtendTypeProvider.kt
    │   │                   ├── InnerTestTypeProvider.kt
    │   │                   ├── ThisExtendTypeProvider.kt
    │   │                   ├── ThisFieldTypeProvider.kt
    │   │                   └── ThisTypeProvider.kt
    │   └── resources/
    │       ├── META-INF/
    │       │   └── plugin.xml
    │       ├── fileTemplates/
    │       │   └── internal/
    │       │       ├── Pest It.php.ft
    │       │       ├── Pest Scoped Dataset.php.ft
    │       │       ├── Pest Shared Dataset.php.ft
    │       │       ├── Pest Test.php.ft
    │       │       └── Pest file from class.php.ft
    │       ├── inspectionDescriptions/
    │       │   ├── InvalidDatasetNameCaseInspection.html
    │       │   ├── InvalidDatasetReferenceInspection.html
    │       │   ├── InvalidTestNameCaseInspection.html
    │       │   ├── MissingScreenshotSnapshotInspection.html
    │       │   ├── MultipleExpectChainableInspection.html
    │       │   ├── PestAssertionCanBeSimplifiedInspection.html
    │       │   └── PestTestFailedLineInspection.html
    │       ├── liveTemplates/
    │       │   └── PestPHP.xml
    │       ├── log4j.properties
    │       ├── messages/
    │       │   └── pestBundle.properties
    │       └── postfixTemplates/
    │           ├── PestDescribePostfixTemplate/
    │           │   ├── after.php.template
    │           │   ├── before.php.template
    │           │   └── description.html
    │           └── PestItPostfixTemplate/
    │               ├── after.php.template
    │               ├── before.php.template
    │               └── description.html
    └── test/
        ├── kotlin/
        │   └── com/
        │       └── pestphp/
        │           └── pest/
        │               ├── PestIconProviderTest.kt
        │               ├── PestLightCodeFixture.kt
        │               ├── PestTestRunLineMarkerProviderTest.kt
        │               ├── annotator/
        │               │   └── PestAnnotatorTest.kt
        │               ├── codeInsight/
        │               │   └── typeInference/
        │               │       └── PestTypeInferenceTest.kt
        │               ├── configuration/
        │               │   ├── PestLocationProviderTest.kt
        │               │   ├── PestRunConfigurationTest.kt
        │               │   ├── PestVersionDetectorTest.kt
        │               │   ├── PestVersionParserTest.kt
        │               │   ├── pest/
        │               │   │   └── PestConfigurationFileTest.kt
        │               │   └── uses/
        │               │       └── PestConfigurationFileTest.kt
        │               ├── customExpectations/
        │               │   ├── ListMethodDataExternalizerTest.kt
        │               │   ├── MethodDataExternalizerTest.kt
        │               │   └── generators/
        │               │       └── ExpectationGeneratorTest.kt
        │               ├── features/
        │               │   ├── configuration/
        │               │   │   ├── PestCompletionTest.kt
        │               │   │   └── UsesCompletionTest.kt
        │               │   ├── datasets/
        │               │   │   ├── DatasetCompletionTest.kt
        │               │   │   ├── DatasetGoToTest.kt
        │               │   │   ├── DatasetIndexTest.kt
        │               │   │   ├── DatasetReferenceTest.kt
        │               │   │   ├── DatasetUsagesTest.kt
        │               │   │   ├── InvalidDatasetNameCaseInspectionTest.kt
        │               │   │   └── InvalidDatasetReferenceInspectionTest.kt
        │               │   ├── parallel/
        │               │   │   ├── PestParallelProgramRunnerTest.kt
        │               │   │   └── PestParallelSMTEventsAdapterTest.kt
        │               │   └── snapshotTesting/
        │               │       ├── SnapshotLineMarkerProviderTest.kt
        │               │       └── SnapshotUtilTest.kt
        │               ├── generateTest/
        │               │   └── PestNewTestFromClassActionTest.kt
        │               ├── goto/
        │               │   └── PestTestFinderTest.kt
        │               ├── higherOrderExpectations/
        │               │   ├── HigherOrderExpectationAssertionCompletionTest.kt
        │               │   └── HigherOrderExpectationCompletionTest.kt
        │               ├── indexers/
        │               │   └── PestTestIndexTest.kt
        │               ├── inspections/
        │               │   ├── InvalidTestNameCaseInspectionTest.kt
        │               │   ├── MissingScreenshotSnapshotInspectionTest.kt
        │               │   ├── MultipleExpectChainableInspectionTest.kt
        │               │   ├── PestAssertionCanBeSimplifiedInspectionTest.kt
        │               │   ├── PestTestFailedLineInspectionTest.kt
        │               │   └── PhpStormInspectionsTest.kt
        │               ├── runner/
        │               │   ├── PestPressToContinueActionTest.kt
        │               │   └── PestTestStackTraceParserTest.kt
        │               ├── surrounders/
        │               │   ├── ExpectStatementSurrounderTest.kt
        │               │   └── SurroundTestCase.kt
        │               ├── templates/
        │               │   └── PestPostfixTemplateProviderTest.kt
        │               ├── types/
        │               │   ├── BaseTypeTestCase.kt
        │               │   ├── ExpectCallCompletionTest.kt
        │               │   ├── FunctionTypeTest.kt
        │               │   ├── ThisFieldCompletionTest.kt
        │               │   ├── ThisFieldTypeTest.kt
        │               │   └── ThisTypeTest.kt
        │               └── utilTests/
        │                   ├── GetPestTestNameTests.kt
        │                   ├── GetPestTestsTest.kt
        │                   ├── IsPestTestFileTest.kt
        │                   ├── IsPestTestFunctionTest.kt
        │                   ├── PestUtilTest.kt
        │                   ├── ToPestFqnTests.kt
        │                   └── ToPestTestRegexTests.kt
        └── resources/
            └── com/
                └── pestphp/
                    └── pest/
                        ├── Dataset.php
                        ├── Pest.php
                        ├── PestTestRunLineMarkerProviderTest/
                        │   ├── AssignmentFunctionCallNamedTest.php
                        │   ├── AssignmentFunctionCallNamedTestWithoutPest.php
                        │   ├── FunctionCallNamedTestAsArgument.php
                        │   ├── FunctionCallNamedTestInsideDescribeBlock.php
                        │   ├── FunctionCallNamedTestInsideTest.php
                        │   ├── FunctionCallNamedTestWithoutPest.php
                        │   ├── MethodCallNamedItAndVariableTest.php
                        │   ├── NamedDataSets.php
                        │   ├── PestItFunctionCallWithDescriptionAndClosure.php
                        │   ├── PestItFunctionCallWithRedefinition.php
                        │   └── contextProject/
                        │       └── tests/
                        │           └── Test.php
                        ├── PestUtil/
                        │   ├── Login.integration.test.php
                        │   ├── Login.test.php
                        │   ├── MethodCallNamedIt.php
                        │   ├── MethodCallNamedItAndVariableTest.php
                        │   ├── MethodCallNamedTest.php
                        │   ├── NestedDescribeFunctionCalls.php
                        │   ├── PestArchFunctionCall.php
                        │   ├── PestDescribeBlock.php
                        │   ├── PestDescribeBlockAndTestFunctionEndOfLine.php
                        │   ├── PestItFunctionCallWithConcatString.php
                        │   ├── PestItFunctionCallWithDescriptionAndClosure.php
                        │   ├── PestItFunctionCallWithDescriptionAndHigherOrder.php
                        │   ├── PestTestFunctionCallWithCircumflex.php
                        │   ├── PestTestFunctionCallWithConcatString.php
                        │   ├── PestTestFunctionCallWithDescriptionAndClosure.php
                        │   ├── PestTestFunctionCallWithDescriptionAndHigherOrder.php
                        │   ├── PestTestFunctionCallWithNamesapce.php
                        │   ├── PestTestFunctionCallWithParenthesis.php
                        │   ├── PestTestWithPlusAndQuestionMark.php
                        │   ├── User.spec.php
                        │   └── dir.name/
                        │       └── Test.php
                        ├── SimpleHigherOrderNotTest.php
                        ├── SimpleHigherOrderTestWithName.php
                        ├── SimpleScript.php
                        ├── TestWithDataset.php
                        ├── annotator/
                        │   ├── DuplicateCustomExpectation.afterDelete.php
                        │   ├── DuplicateCustomExpectation.afterNavigate.php
                        │   ├── DuplicateCustomExpectation.php
                        │   ├── DuplicateTestName.afterDelete.php
                        │   ├── DuplicateTestName.afterNavigate.php
                        │   ├── DuplicateTestName.php
                        │   ├── DuplicateTestNameInDescribeBlock.php
                        │   ├── NoDuplicateCustomExpectation.php
                        │   ├── NoDuplicateTestName.php
                        │   └── stub/
                        │       └── Functions.php
                        ├── codeInsight/
                        │   └── typeInference/
                        │       ├── ThisInInnerClosure.php
                        │       └── ThisInSubproject/
                        │           └── Test.php
                        ├── configuration/
                        │   ├── FileWithPestTest.php
                        │   ├── locationProvider/
                        │   │   ├── DescribeBlock/
                        │   │   │   └── subdir/
                        │   │   │       └── Test.php
                        │   │   ├── DescribeBlockIt/
                        │   │   │   └── subdir/
                        │   │   │       └── Test.php
                        │   │   ├── SubprojectFor1xVersion/
                        │   │   │   └── subdir/
                        │   │   │       └── Test.php
                        │   │   └── SubprojectFor2xVersion/
                        │   │       └── subdir/
                        │   │           └── Test.php
                        │   ├── pest/
                        │   │   ├── tests/
                        │   │   │   ├── DIRFeature/
                        │   │   │   │   └── FeatureTest.php
                        │   │   │   ├── DynamicFeature/
                        │   │   │   │   └── FeatureTest.php
                        │   │   │   ├── Feature/
                        │   │   │   │   └── FeatureTest.php
                        │   │   │   ├── GlobPattern/
                        │   │   │   │   ├── DirectoryTest.php
                        │   │   │   │   ├── FileTest.php
                        │   │   │   │   └── FileWithRelativePathTest.php
                        │   │   │   ├── GroupedFeature/
                        │   │   │   │   └── GroupedFeatureTest.php
                        │   │   │   ├── Pest.php
                        │   │   │   └── Unit/
                        │   │   │       ├── PestExtendUnitTest.php
                        │   │   │       └── UnitTest.php
                        │   │   └── tests2/
                        │   │       └── Unit/
                        │   │           └── UnitTest.php
                        │   ├── php
                        │   └── uses/
                        │       ├── DIRFeature/
                        │       │   └── FeatureTest.php
                        │       ├── DynamicFeature/
                        │       │   └── FeatureTest.php
                        │       ├── Feature/
                        │       │   └── FeatureTest.php
                        │       ├── GlobPattern/
                        │       │   ├── DirectoryTest.php
                        │       │   ├── FileTest.php
                        │       │   └── FileWithRelativePathTest.php
                        │       ├── GroupedFeature/
                        │       │   └── GroupedFeatureTest.php
                        │       ├── Pest.php
                        │       └── Unit/
                        │           ├── UnitTest.php
                        │           └── UsesUnitTest.php
                        ├── customExpectations/
                        │   ├── CustomExpectation.php
                        │   ├── CustomExpectationWithParameter.php
                        │   ├── CustomThisExpectation.php
                        │   ├── CustomUserExpectation.php
                        │   ├── UnfinishedCustomExpectation.php
                        │   ├── generators/
                        │   │   └── ExpectationGenerator/
                        │   │       └── GeneratedWithMethod.php
                        │   └── subFolder/
                        │       └── CustomExpectation.php
                        ├── features/
                        │   ├── configuration/
                        │   │   ├── pest/
                        │   │   │   ├── CompleteFakePestInFolder.php
                        │   │   │   ├── CompleteInFolder.php
                        │   │   │   └── Test.php
                        │   │   └── uses/
                        │   │       ├── CompleteFakeInFolder.php
                        │   │       ├── CompleteInFolder.php
                        │   │       └── Test.php
                        │   ├── datasets/
                        │   │   ├── AutocompleteDatasetTest.php
                        │   │   ├── DatasetInDescribeBlock.php
                        │   │   ├── DatasetInDescribeBlockCompletion.php
                        │   │   ├── DatasetInDescribeBlockReference.php
                        │   │   ├── DatasetInsideDescribeBlockTest.php
                        │   │   ├── DatasetNoArgsTest.php
                        │   │   ├── DatasetOnNonPestTest.php
                        │   │   ├── DatasetOnNonPestTestCompletion.php
                        │   │   ├── DatasetReference.php
                        │   │   ├── DatasetTest.php
                        │   │   ├── Datasets.php
                        │   │   ├── DoubleWithDatasetReference.php
                        │   │   ├── InvalidDatasetInDescribeBlockTest.php
                        │   │   ├── InvalidDatasetNameCase.after.php
                        │   │   ├── InvalidDatasetNameCase.php
                        │   │   ├── InvalidDatasetTest.php
                        │   │   ├── NotDatasetReference.php
                        │   │   ├── SharedDatasetReference.php
                        │   │   └── ValidDatasetNameCase.php
                        │   └── parallel/
                        │       ├── ATest.php
                        │       └── php
                        ├── generateTest/
                        │   ├── testWithNamespace.after.php
                        │   └── testWithNamespace.php
                        ├── goto/
                        │   ├── PestTestFinder/
                        │   │   ├── App/
                        │   │   │   └── User.php
                        │   │   └── test/
                        │   │       └── App/
                        │   │           ├── MockTest.php
                        │   │           ├── UserDescribeTest.php
                        │   │           └── UserTest.php
                        │   └── datasetUsages/
                        │       ├── DatasetDeclaration.php
                        │       └── DatasetUsage.php
                        ├── higherOrderExpectations/
                        │   ├── .phpstorm.meta.php
                        │   ├── ExpectMethodAssertionCompletion.php
                        │   ├── ExpectMethodAssertionCompletionChained.php
                        │   ├── ExpectMethodAssertionCompletionChainedAssertions.php
                        │   ├── ExpectMethodCompletion.php
                        │   ├── ExpectMethodCompletionChained.php
                        │   ├── ExpectMethodCompletionChainedAssertions.php
                        │   ├── ExpectPropertyAssertionCompletion.php
                        │   ├── ExpectPropertyAssertionCompletionChained.php
                        │   ├── ExpectPropertyAssertionCompletionChainedAssertions.php
                        │   ├── ExpectPropertyCompletion.php
                        │   ├── ExpectPropertyCompletionChained.php
                        │   ├── ExpectPropertyCompletionChainedAssertions.php
                        │   └── stubs.php
                        ├── indexers/
                        │   └── PestTestIndexTest/
                        │       ├── FileWithDescribeBlockTest.php
                        │       ├── FileWithPestTest.php
                        │       ├── FileWithPestTodosTest.php
                        │       └── FileWithoutPestTest.php
                        ├── inspections/
                        │   ├── ExpectCallsWithOtherStatementsBetween.php
                        │   ├── InvalidTestNameAndDatasetName.after.php
                        │   ├── InvalidTestNameAndDatasetName.php
                        │   ├── InvalidTestNameCase.after.php
                        │   ├── InvalidTestNameCase.php
                        │   ├── ManyExpectCall.after.php
                        │   ├── ManyExpectCall.php
                        │   ├── MultipleExpectCall.after.php
                        │   ├── MultipleExpectCall.php
                        │   ├── MultipleExpectCallsWithOtherStatementsBetween.after.php
                        │   ├── MultipleExpectCallsWithOtherStatementsBetween.php
                        │   ├── SingleExpectCall.php
                        │   ├── ValidHigherOrderTestNameCase.php
                        │   ├── ValidItTestNameWithoutSpaces.php
                        │   ├── ValidTestNameCase.php
                        │   ├── ValidTestNameWhenWrongCasingOnOneWord.php
                        │   ├── assertionCanBeSimplified/
                        │   │   ├── ToBeWithFalse.after.php
                        │   │   ├── ToBeWithFalse.php
                        │   │   ├── ToBeWithNull.after.php
                        │   │   ├── ToBeWithNull.php
                        │   │   ├── ToBeWithTrue.after.php
                        │   │   ├── ToBeWithTrue.php
                        │   │   ├── ToHaveCountWithZero.after.php
                        │   │   └── ToHaveCountWithZero.php
                        │   ├── pestTestFailedLine/
                        │   │   ├── AnonymousFunction.php
                        │   │   ├── FailedOneLine.php
                        │   │   ├── LambdaFunction.php
                        │   │   ├── MismatchLine.php
                        │   │   ├── MultipleStatementsInOneLine.php
                        │   │   ├── OutRange.php
                        │   │   ├── SingleLeafElementReported.php
                        │   │   ├── TypeBefore.php
                        │   │   ├── TypeInside.php
                        │   │   ├── WithDataSet.php
                        │   │   ├── WithDataSetAndKeys.php
                        │   │   ├── WithDataSetAndSeveralFails.php
                        │   │   └── WithNamedDataSet.php
                        │   ├── phpstorm/
                        │   │   └── MultipleClassesDeclarationsInPestFileTest.php
                        │   └── screenshotProject/
                        │       └── tests/
                        │           ├── .pest/
                        │           │   └── snapshots/
                        │           │       └── Feature/
                        │           │           ├── ScreenshotSnapshot/
                        │           │           │   └── it_browser_testing.snap
                        │           │           ├── ScreenshotSnapshotComplexName/
                        │           │           │   └── it_1__2_3_4_.snap
                        │           │           ├── ScreenshotSnapshotMultiple/
                        │           │           │   ├── it_test.snap
                        │           │           │   └── it_test2.snap
                        │           │           └── nested/
                        │           │               └── ScreenshotSnapshotNested/
                        │           │                   └── nested.snap
                        │           └── Feature/
                        │               ├── MissingScreenshotSnapshot.php
                        │               ├── MissingScreenshotSnapshotComplexName.php
                        │               ├── MissingScreenshotSnapshotMultiple.php
                        │               ├── ScreenshotSnapshot.php
                        │               ├── ScreenshotSnapshotComplexName.php
                        │               ├── ScreenshotSnapshotMultiple.php
                        │               └── nested/
                        │                   ├── MissingScreenshotSnapshotNested.php
                        │                   └── ScreenshotSnapshotNested.php
                        ├── runner/
                        │   └── pestTestStacktraceParser/
                        │       ├── Multiline.php
                        │       ├── OneLine.php
                        │       ├── OneLineRemote.php
                        │       ├── OutRangeLineNumber.php
                        │       └── WrongLineNumber.php
                        ├── snapshotTesting/
                        │   ├── allSnapshotAssertions.php
                        │   ├── nonSnapshotAssertions.php
                        │   ├── snapshotAssertionUseStatement.php
                        │   ├── snapshotTest.php
                        │   └── tests/
                        │       └── __snapshots__/
                        │           └── snapshotTest__it_renders_correctly__1.txt
                        ├── stubs.php
                        ├── templates/
                        │   ├── describe.after.php
                        │   ├── describe.php
                        │   ├── it.after.php
                        │   └── it.php
                        ├── types/
                        │   ├── TestCase.php
                        │   ├── expect/
                        │   │   ├── expectCallCompletion.php
                        │   │   ├── expectCallCompletionChainedNotMethod.php
                        │   │   ├── expectCallCompletionChainedNotProperty.php
                        │   │   ├── expectExtendCallOnNonExpectFunction.php
                        │   │   ├── expectExtendReturnType.php
                        │   │   ├── expectInvalidExtendNoReturnType.php
                        │   │   └── extendCallOnChainedExpectation.php
                        │   ├── function/
                        │   │   └── testTest.php
                        │   ├── this/
                        │   │   ├── beforeEach.php
                        │   │   ├── itShortLambdaTest.php
                        │   │   ├── itTest.php
                        │   │   └── testTest.php
                        │   └── thisField/
                        │       ├── afterEach.php
                        │       ├── afterEachNamespace.php
                        │       ├── beforeEach.php
                        │       ├── beforeEachCompletion.php
                        │       ├── beforeEachNamespace.php
                        │       └── beforeEachNamespaceCompletion.php
                        └── utilTests/
                            ├── ClassNameResolutionInNamespaceTest.php
                            ├── ClassNameResolutionTest.php
                            └── SimpleTest.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
[*]
indent_size = 4

[{*.kt,*.kts}]
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
ij_kotlin_continuation_indent_size = 4

================================================
FILE: .github/FUNDING.yml
================================================
github: olivernybroe

================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

Please report a bug to [YouTrack](https://youtrack.jetbrains.com/newIssue?project=WI)


================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

Create a discussion instead.


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!-- Description of what has been changed or added in this pr and why -->

- [ ] Added or updated tests
- [ ] Updated `CHANGELOG.md`

issues: #...


================================================
FILE: .github/dependabot.yml
================================================
# Dependabot configuration:
# https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
  - package-ecosystem: "gradle"
    directory: "/"
    schedule:
      interval: "daily"


================================================
FILE: .github/workflows/auto-close.yml
================================================
on:
  issues:
    types: [opened, edited]

jobs:
  auto_close_issues:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v1
      - name: Automatically close issues that don't follow the issue template
        uses: lucasbento/auto-close-issues@v1.0.2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          issue-close-message: "@${issue.user.login}: hello! :wave:\n\nThis issue is being automatically closed because it does not follow the issue template." # optional property


================================================
FILE: .github/workflows/build.yml
================================================
# GitHub Actions Workflow created for testing and preparing the plugin release in following steps:
# - validate Gradle Wrapper,
# - run 'test' and 'verifyPlugin' tasks,
# - run Qodana inspections,
# - run 'buildPlugin' task and prepare artifact for the further tests,
# - run 'runPluginVerifier' task,
# - create a draft release.
#
# Workflow is triggered on push and pull_request events.
#
# GitHub Actions reference: https://help.github.com/en/actions
#
## JBIJPPTPL

name: Build
on:
  # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g. for dependabot pull requests)
  push:
    branches: [main]
  # Trigger the workflow on any pull request
  pull_request:

jobs:

  # Run Gradle Wrapper Validation Action to verify the wrapper's checksum
  # Run verifyPlugin, IntelliJ Plugin Verifier, and test Gradle tasks
  # Build plugin and provide the artifact for the next workflow jobs
  build:
    name: Build
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.properties.outputs.version }}
      changelog: ${{ steps.properties.outputs.changelog }}
    steps:

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v2.4.0

      # Validate wrapper
      - name: Gradle Wrapper Validation
        uses: gradle/wrapper-validation-action@v1.0.4

      # Setup Java 11 environment for the next steps
      - name: Setup Java
        uses: actions/setup-java@v2
        with:
          distribution: zulu
          java-version: 11
          cache: gradle

      # Set environment variables
      - name: Export Properties
        id: properties
        shell: bash
        run: |
          PROPERTIES="$(./gradlew properties --console=plain -q)"
          VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')"
          NAME="$(echo "$PROPERTIES" | grep "^pluginName:" | cut -f2- -d ' ')"
          CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)"
          CHANGELOG="${CHANGELOG//'%'/'%25'}"
          CHANGELOG="${CHANGELOG//$'\n'/'%0A'}"
          CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"

          echo "::set-output name=version::$VERSION"
          echo "::set-output name=name::$NAME"
          echo "::set-output name=changelog::$CHANGELOG"
          echo "::set-output name=pluginVerifierHomeDir::~/.pluginVerifier"

          ./gradlew listProductsReleases # prepare list of IDEs for Plugin Verifier

      # Run tests
      - name: Run Tests
        run: ./gradlew test

      # Collect Tests Result of failed tests
      - name: Collect Tests Result
        if: ${{ failure() }}
        uses: actions/upload-artifact@v2
        with:
          name: tests-result
          path: ${{ github.workspace }}/build/reports/tests

#      # Cache Plugin Verifier IDEs
#      - name: Setup Plugin Verifier IDEs Cache
#        uses: actions/cache@v2.1.7
#        with:
#          path: ${{ steps.properties.outputs.pluginVerifierHomeDir }}/ides
#          key: plugin-verifier-${{ hashFiles('build/listProductsReleases.txt') }}
#
#      # Run Verify Plugin task and IntelliJ Plugin Verifier tool
#      - name: Run Plugin Verification tasks
#        run: ./gradlew runPluginVerifier -Pplugin.verifier.home.dir=${{ steps.properties.outputs.pluginVerifierHomeDir }}
#
#      # Collect Plugin Verifier Result
#      - name: Collect Plugin Verifier Result
#        if: ${{ always() }}
#        uses: actions/upload-artifact@v2
#        with:
#          name: pluginVerifier-result
#          path: ${{ github.workspace }}/build/reports/pluginVerifier

      # TODO: temp needed because verifier disabled
      - run: ./gradlew buildPlugin

      # Prepare plugin archive content for creating artifact
      - name: Prepare Plugin Artifact
        id: artifact
        shell: bash
        run: |
          cd ${{ github.workspace }}/build/distributions
          FILENAME=`ls *.zip`
          unzip "$FILENAME" -d content

          echo "::set-output name=filename::${FILENAME:0:-4}"

      # Store already-built plugin as an artifact for downloading
      - name: Upload artifact
        uses: actions/upload-artifact@v2.2.4
        with:
          name: ${{ steps.artifact.outputs.filename }}
          path: ./build/distributions/content/*/*

  # Prepare a draft release for GitHub Releases page for the manual verification
  # If accepted and published, release workflow would be triggered
  releaseDraft:
    name: Release Draft
    if: github.event_name != 'pull_request'
    needs: build
    runs-on: ubuntu-latest
    steps:

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v2.4.0

      # Remove old release drafts by using the curl request for the available releases with draft flag
      - name: Remove Old Release Drafts
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh api repos/{owner}/{repo}/releases \
            --jq '.[] | select(.draft == true) | .id' \
            | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{}

      # Create new release draft - which is not publicly visible and requires manual acceptance
      - name: Create Release Draft
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh release create v${{ needs.build.outputs.version }} \
            --draft \
            --title "v${{ needs.build.outputs.version }}" \
            --notes "$(cat << 'EOM'
          ${{ needs.build.outputs.changelog }}
          EOM
          )"

================================================
FILE: .github/workflows/qodana.yml
================================================
name: Qodana
on:
  workflow_dispatch:
  pull_request:
    branches:
      - main
  push:
    branches:
      - main

jobs:
  qodana:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      # Setup Java 11 environment for the next steps
      - name: Setup Java
        uses: actions/setup-java@v2
        with:
          distribution: zulu
          java-version: 11
          cache: gradle

      # Build
      - name: Run Build
        run: ./gradlew build

      - name: 'Qodana Scan'
        uses: JetBrains/qodana-action@v2023.1.0
        env:
          QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}


================================================
FILE: .github/workflows/release.yml
================================================
# GitHub Actions Workflow created for handling the release process based on the draft release prepared
# with the Build workflow. Running the publishPlugin task requires the PUBLISH_TOKEN secret provided.

name: Release
on:
  release:
    types: [prereleased, released]

jobs:

  # Prepare and publish the plugin to the Marketplace repository
  release:
    name: Publish Plugin
    runs-on: ubuntu-latest
    steps:

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v2.4.0
        with:
          ref: ${{ github.event.release.tag_name }}

      # Setup Java 11 environment for the next steps
      - name: Setup Java
        uses: actions/setup-java@v2
        with:
          distribution: zulu
          java-version: 11
          cache: gradle

      # Set environment variables
      - name: Export Properties
        id: properties
        shell: bash
        run: |
          CHANGELOG="$(cat << 'EOM' | sed -e 's/^[[:space:]]*$//g' -e '/./,$!d'
          ${{ github.event.release.body }}
          EOM
          )"
          
          CHANGELOG="${CHANGELOG//'%'/'%25'}"
          CHANGELOG="${CHANGELOG//$'\n'/'%0A'}"
          CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"

          echo "::set-output name=changelog::$CHANGELOG"

      # Update Unreleased section with the current release note
      - name: Patch Changelog
        if: ${{ steps.properties.outputs.changelog != '' }}
        env:
          CHANGELOG: ${{ steps.properties.outputs.changelog }}
        run: |
          ./gradlew patchChangelog --release-note="$CHANGELOG"

      # Publish the plugin to the Marketplace
      - name: Publish Plugin
        env:
          PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
        run: ./gradlew publishPlugin

      # Upload artifact as a release asset
      - name: Upload Release Asset
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/*

      # Create pull request
      - name: Create Pull Request
        if: ${{ steps.properties.outputs.changelog != '' }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          VERSION="${{ github.event.release.tag_name }}"
          BRANCH="changelog-update-$VERSION"

          git config user.email "action@github.com"
          git config user.name "GitHub Action"

          git checkout -b $BRANCH
          git commit -am "Changelog update - $VERSION"
          git push --set-upstream origin $BRANCH

          gh pr create \
            --title "Changelog update - \`$VERSION\`" \
            --body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \
            --base main \
            --head $BRANCH

================================================
FILE: .github/workflows/run-ui-tests.yml
================================================
# GitHub Actions Workflow for launching UI tests on Linux, Windows, and Mac in the following steps:
# - prepare and launch IDE with your plugin and robot-server plugin, which is needed to interact with UI
# - wait for IDE to start
# - run UI tests with separate Gradle task
#
# Please check https://github.com/JetBrains/intellij-ui-test-robot for information about UI tests with IntelliJ Platform
#
# Workflow is triggered manually.

name: Run UI Tests
on:
  workflow_dispatch

jobs:

  testUI:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            runIde: |
              export DISPLAY=:99.0
              Xvfb -ac :99 -screen 0 1920x1080x16 &
              gradle runIdeForUiTests &
          - os: windows-latest
            runIde: start gradlew.bat runIdeForUiTests
          - os: macos-latest
            runIde: ./gradlew runIdeForUiTests &

    steps:

      # Check out current repository
      - name: Fetch Sources
        uses: actions/checkout@v2.4.0

      # Setup Java 11 environment for the next steps
      - name: Setup Java
        uses: actions/setup-java@v2
        with:
          distribution: zulu
          java-version: 11
          cache: gradle

      # Run IDEA prepared for UI testing
      - name: Run IDE
        run: ${{ matrix.runIde }}

      # Wait for IDEA to be started
      - name: Health Check
        uses: jtalk/url-health-check-action@v2
        with:
          url: http://127.0.0.1:8082
          max-attempts: 15
          retry-delay: 30s

      # Run tests
      - name: Tests
        run: ./gradlew test

================================================
FILE: .gitignore
================================================
.gradle
build
.idea
.intellijPlatform

================================================
FILE: .run/Run IDE with Plugin.run.xml
================================================
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="Run PhpStorm with Plugin" type="GradleRunConfiguration" factoryName="Gradle">
    <log_file alias="idea.log" path="$PROJECT_DIR$/build/idea-sandbox/system/log/idea.log" />
    <ExternalSystemSettings>
      <option name="executionName" />
      <option name="externalProjectPath" value="$PROJECT_DIR$" />
      <option name="externalSystemIdString" value="GRADLE" />
      <option name="scriptParameters" value="" />
      <option name="taskDescriptions">
        <list />
      </option>
      <option name="taskNames">
        <list>
          <option value="runIde" />
        </list>
      </option>
      <option name="vmOptions" value="" />
    </ExternalSystemSettings>
    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
    <DebugAllEnabled>false</DebugAllEnabled>
    <method v="2" />
  </configuration>
</component>

================================================
FILE: .run/Run Plugin Tests.run.xml
================================================
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="Run Tests" type="GradleRunConfiguration" factoryName="Gradle">
    <log_file alias="idea.log" path="$PROJECT_DIR$/build/idea-sandbox/system/log/idea.log" />
    <ExternalSystemSettings>
      <option name="executionName" />
      <option name="externalProjectPath" value="$PROJECT_DIR$" />
      <option name="externalSystemIdString" value="GRADLE" />
      <option name="scriptParameters" value="" />
      <option name="taskDescriptions">
        <list />
      </option>
      <option name="taskNames">
        <list>
          <option value="test" />
        </list>
      </option>
      <option name="vmOptions" value="" />
    </ExternalSystemSettings>
    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
    <DebugAllEnabled>false</DebugAllEnabled>
    <method v="2" />
  </configuration>
</component>

================================================
FILE: .run/Run Plugin Verification.run.xml
================================================
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="Run Verifications" type="GradleRunConfiguration" factoryName="Gradle">
    <log_file alias="idea.log" path="$PROJECT_DIR$/build/idea-sandbox/system/log/idea.log" />
    <ExternalSystemSettings>
      <option name="executionName" />
      <option name="externalProjectPath" value="$PROJECT_DIR$" />
      <option name="externalSystemIdString" value="GRADLE" />
      <option name="scriptParameters" value="" />
      <option name="taskDescriptions">
        <list />
      </option>
      <option name="taskNames">
        <list>
          <option value="runPluginVerifier" />
        </list>
      </option>
      <option name="vmOptions" value="" />
    </ExternalSystemSettings>
    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
    <DebugAllEnabled>false</DebugAllEnabled>
    <method v="2">
      <option name="Gradle.BeforeRunTask" enabled="true" tasks="clean" externalProjectPath="$PROJECT_DIR$" vmOptions="" scriptParameters="" />
    </method>
  </configuration>
</component>

================================================
FILE: .run/Run Qodana.run.xml
================================================
<component name="ProjectRunConfigurationManager">
    <configuration default="false" name="Run Qodana" type="GradleRunConfiguration" factoryName="Gradle">
        <ExternalSystemSettings>
            <option name="env">
                <map>
                    <entry key="QODANA_SHOW_REPORT" value="true" />
                </map>
            </option>
            <option name="executionName" />
            <option name="externalProjectPath" value="$PROJECT_DIR$" />
            <option name="externalSystemIdString" value="GRADLE" />
            <option name="scriptParameters" value="cleanInspections runInspections" />
            <option name="taskDescriptions">
                <list />
            </option>
            <option name="taskNames">
                <list />
            </option>
            <option name="vmOptions" />
        </ExternalSystemSettings>
        <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
        <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
        <DebugAllEnabled>false</DebugAllEnabled>
        <method v="2" />
    </configuration>
</component>

================================================
FILE: BUILD.bazel
================================================
### auto-generated section `build intellij.pest` start
load("@rules_jvm//:jvm.bzl", "jvm_library")

jvm_library(
  name = "pest",
  module_name = "intellij.pest",
  visibility = ["//visibility:public"],
  srcs = glob(["src/main/java/**/*.kt", "src/main/java/**/*.java", "src/main/java/**/*.form", "src/main/kotlin/**/*.kt", "src/main/kotlin/**/*.java", "src/main/kotlin/**/*.form"], allow_empty = True),
  resources = glob(["src/main/resources/**/*"]),
  resource_strip_prefix = "src/main/resources",
  deps = [
    "@community//platform/core-api:core",
    "@community//platform/execution",
    "@community//platform/execution-impl",
    "@community//platform/ide-core-impl",
    "@community//platform/platform-impl:ide-impl",
    "//phpstorm/php-openapi:php",
    "@community//platform/analysis-api:analysis",
    "@community//platform/lang-core",
    "@community//platform/projectModel-api:projectModel",
    "@community//platform/remote-core",
    "@community//platform/structure-view-impl:structureView-impl",
    "@community//platform/util",
    "@community//platform/indexing-api:indexing",
    "//phpstorm/php:php-impl",
    "@community//platform/analysis-impl",
    "@community//platform/editor-ui-api:editor-ui",
    "@community//platform/smRunner",
    "@community//platform/platform-util-io:ide-util-io",
    "@community//platform/ide-core",
    "@community//platform/lang-api:lang",
    "@community//platform/lang-impl",
    "@community//xml/xml-psi-impl:psi-impl",
    "@community//libraries/fastutil",
    "@community//xml/dom-impl",
    "@community//platform/core-ui",
    "@community//platform/core-impl",
    "@community//platform/util/text-matching",
    "@community//platform/util:util-ui",
    "@community//platform/statistics",
    "@community//platform/testRunner",
  ]
)

jvm_library(
  name = "pest_test_lib",
  testonly = True,
  module_name = "intellij.pest",
  visibility = ["//visibility:public"],
  srcs = glob([], allow_empty = True),
  runtime_deps = [
    ":pest",
    "@community//platform/core-api:core_test_lib",
    "@community//platform/execution:execution_test_lib",
    "@community//platform/execution-impl:execution-impl_test_lib",
    "@community//platform/ide-core-impl:ide-core-impl_test_lib",
    "@community//platform/platform-impl:ide-impl_test_lib",
    "//phpstorm/php-openapi:php_test_lib",
    "@community//platform/analysis-api:analysis_test_lib",
    "@community//jps/model-api:model",
    "@community//jps/model-api:model_test_lib",
    "@community//platform/lang-core:lang-core_test_lib",
    "@community//platform/projectModel-api:projectModel_test_lib",
    "@community//platform/remote-core:remote-core_test_lib",
    "@community//platform/structure-view-impl:structureView-impl_test_lib",
    "@community//platform/testFramework",
    "@community//platform/testFramework:testFramework_test_lib",
    "@community//platform/util:util_test_lib",
    "@community//platform/indexing-api:indexing_test_lib",
    "//phpstorm/php:php-impl_test_lib",
    "@community//platform/analysis-impl:analysis-impl_test_lib",
    "@community//platform/editor-ui-api:editor-ui_test_lib",
    "@community//platform/smRunner:smRunner_test_lib",
    "@community//platform/platform-util-io:ide-util-io_test_lib",
    "@community//platform/ide-core:ide-core_test_lib",
    "@community//platform/lang-api:lang_test_lib",
    "@community//platform/lang-impl:lang-impl_test_lib",
    "@community//xml/xml-psi-impl:psi-impl_test_lib",
    "@community//libraries/fastutil:fastutil_test_lib",
    "@community//xml/dom-impl:dom-impl_test_lib",
    "@community//platform/core-ui:core-ui_test_lib",
    "@community//platform/core-impl:core-impl_test_lib",
    "@community//platform/util/text-matching:text-matching_test_lib",
    "@community//platform/util:util-ui_test_lib",
    "@lib//:io-mockk",
    "@lib//:io-mockk-jvm",
    "@community//platform/statistics:statistics_test_lib",
    "@community//platform/testRunner:testRunner_test_lib",
  ]
)
### auto-generated section `build intellij.pest` end

### auto-generated section `iml intellij.pest` start
exports_files([
  "intellij.pest.iml",
], visibility = ["//visibility:public"])
### auto-generated section `iml intellij.pest` end

### auto-generated section `build intellij.pest.tests` start
jvm_library(
  name = "pest-tests",
  module_name = "intellij.pest.tests",
  visibility = ["//visibility:public"],
  srcs = glob([], allow_empty = True)
)

jvm_library(
  name = "pest-tests_test_lib",
  testonly = True,
  visibility = ["//visibility:public"],
  srcs = glob(["src/test/kotlin/**/*.kt", "src/test/kotlin/**/*.java", "src/test/kotlin/**/*.form"], allow_empty = True),
  resources = glob(["src/test/resources/**/*"]),
  resource_strip_prefix = "src/test/resources",
  associates = [
    "//phpstorm/pest",
    "//phpstorm/pest:pest_test_lib",
  ],
  deps = [
    "@community//platform/core-api:core",
    "@community//platform/core-api:core_test_lib",
    "@community//platform/execution",
    "@community//platform/execution:execution_test_lib",
    "@community//platform/execution-impl",
    "@community//platform/execution-impl:execution-impl_test_lib",
    "@community//platform/ide-core-impl",
    "@community//platform/platform-impl:ide-impl",
    "//phpstorm/php-openapi:php",
    "//phpstorm/php-openapi:php_test_lib",
    "@community//platform/analysis-api:analysis",
    "@community//platform/analysis-api:analysis_test_lib",
    "@community//jps/model-api:model",
    "@community//jps/model-api:model_test_lib",
    "@community//platform/lang-core",
    "@community//platform/lang-core:lang-core_test_lib",
    "@community//platform/projectModel-api:projectModel",
    "@community//platform/projectModel-api:projectModel_test_lib",
    "@community//platform/remote-core",
    "@community//platform/remote-core:remote-core_test_lib",
    "@community//platform/structure-view-impl:structureView-impl",
    "@community//platform/structure-view-impl:structureView-impl_test_lib",
    "@community//platform/testFramework",
    "@community//platform/testFramework:testFramework_test_lib",
    "@community//platform/util",
    "@community//platform/util:util_test_lib",
    "@community//platform/indexing-api:indexing",
    "@community//platform/indexing-api:indexing_test_lib",
    "//phpstorm/php:php-impl",
    "//phpstorm/php:php-impl_test_lib",
    "@community//platform/analysis-impl",
    "@community//platform/analysis-impl:analysis-impl_test_lib",
    "@community//platform/editor-ui-api:editor-ui",
    "@community//platform/editor-ui-api:editor-ui_test_lib",
    "@community//platform/smRunner",
    "@community//platform/smRunner:smRunner_test_lib",
    "@community//platform/platform-util-io:ide-util-io",
    "@community//platform/ide-core",
    "@community//platform/lang-api:lang",
    "@community//platform/lang-api:lang_test_lib",
    "@community//platform/lang-impl",
    "@community//platform/lang-impl:lang-impl_test_lib",
    "@community//xml/xml-psi-impl:psi-impl",
    "@community//xml/xml-psi-impl:psi-impl_test_lib",
    "@community//libraries/fastutil",
    "@community//libraries/fastutil:fastutil_test_lib",
    "@community//plugins/coverage-common:coverage",
    "@community//plugins/coverage-common:coverage_test_lib",
    "@community//xml/dom-impl",
    "@community//xml/dom-impl:dom-impl_test_lib",
    "@community//platform/core-ui",
    "@community//platform/core-ui:core-ui_test_lib",
    "@community//platform/core-impl",
    "@community//platform/core-impl:core-impl_test_lib",
    "@community//platform/util/text-matching",
    "@community//platform/util/text-matching:text-matching_test_lib",
    "@community//platform/util:util-ui",
    "@community//platform/util:util-ui_test_lib",
    "@lib//:io-mockk",
    "@lib//:io-mockk-jvm",
    "@community//platform/statistics",
    "@community//platform/statistics:statistics_test_lib",
    "@community//platform/testRunner",
    "@community//platform/testRunner:testRunner_test_lib",
  ],
  runtime_deps = [
    ":pest-tests",
    "@community//platform/ide-core-impl:ide-core-impl_test_lib",
    "@community//platform/platform-impl:ide-impl_test_lib",
    "@community//platform/platform-util-io:ide-util-io_test_lib",
    "@community//platform/ide-core:ide-core_test_lib",
  ]
)
### auto-generated section `build intellij.pest.tests` end

### auto-generated section `iml intellij.pest.tests` start
exports_files([
  "intellij.pest.tests.iml",
], visibility = ["//visibility:public"])
### auto-generated section `iml intellij.pest.tests` end

### auto-generated section `test intellij.pest.tests` start
load("@community//build:tests-options.bzl", "jps_test")

jps_test(
  name = "pest-tests_test",
  runtime_deps = [":pest-tests_test_lib"]
)
### auto-generated section `test intellij.pest.tests` end

================================================
FILE: CHANGELOG.md
================================================
<!-- Keep a Changelog guide -> https://keepachangelog.com -->

# PEST IntelliJ Changelog

## Unreleased

### Added

- Added proper resolve for custom expectations
- Added proper rename for custom expectations
- Added migration startup activity to delete redundant generated `Expectation.php` file

### Fixed

- Fixed infinite "Closing project..." dialog issue on project close

### Changed

- Reworked custom expectations engine using Symbol API 
- Removed `Expectation.php` generation

## 1.11.0 - 2023-09-12

### Added

- Added support for running tests in describe block ([#498](https://github.com/pestphp/pest-intellij/pull/498))

### Fixed

- Fixed property declared dynamically showing warning in pest test cases
- Fixed goto and rerun tests not working on new pest versions

## 1.10.1 - 2023-05-31

### Changed

- Changed pest file creation to two actions (tests and dataset)

### Added

- Save test flavour preferences when creating a new test

## 1.10.0 - 2023-05-31

### Added

- Added pest file creation support

### Fixed

- Remove test sources filter lookup, as it breaks others plugins

## 1.9.3 - 2023-05-31

### Fixed

- Fixed file icon missing if all tests has property calls
- Fixed gutter icon not updating state correctly
- Fixed test names with `[` and `]` not being matched correctly
- Fixed test name casing inspection not working correctly with `it` tests

## 1.9.2 - 2023-03-01

### Fixed

- Fixed "Preferred Coverage Engine" not being saved

## 1.9.1 - 2023-02-28

### Fixed

- Fixed ComposerLibraryManager being nullable now.
- Fixed running tests with filenames containing `_`.

### Changed

- Changed logic for base path to be from composer.json file.

## 1.9.0 - 2023-01-15

### Added

- Added support for running specific tests on Pest 2.0
- Added support for running todo's as tests

### Fixed

- Fixed running tests with `?` in the name

## 1.8.3

### Added

- Added support for test names with string concat statements
- Added stacktrace folding for Pest 2.0 output

### Changed

- Removed the "test started at" text on the test console output

### Fixed

- Fixed regex to match tests that have both named and unnamed datasets

## 1.8.1

### Fixed

- Fixed originalFile in iconProvider sometimes being null
- Fixed DuplicateCustomExpectation testing crashing on unfinished inspections

## 1.8.0

### Added

- Added support for using goto location when using remote interpreters

### Fixed

- Fixed nested `readAction` calls in Icon Provider

### Changed

- Changed Icon Provider to use indexes for better performance

## 1.7.0

### Added

- Added `uses->in` folder reference
- Added registry entry for disabling expectation file generation

### Changed

- Changed goto and completion contributor to reference provider
- Changed icons to use build-in dark mode switching

### Fixed

- Fixed dataset reference error when no dataset provided yet.

## 1.6.2

### Fixed

- Fixed duplicate type provider key with nette plugin

## 1.6.1

### Added

- Added inspection for checking if dataset exists

### Fixed

- Fixed dataset autocompletion triggering on all strings
- Fixed dataset goto triggering on all strings

## 1.6.0

### Added

- Added converting multiple `expect` to `and` calls instead
- Added dataset completion
- Added dataset goto

### Fixed

- Fixed automatic case changing on multicased string

## 1.5.0

### Added

- Added automatic case changing to pest test names

## 1.4.2

### Fixed

- Changed runReadAction to runReadActionInSmartMode in startup activity

## 1.4.1

### Changed

- Reduced custom expectation index size by over 95%

### Fixed

- Check if file exist in index (can happen if file is deleted outside IDE)
- Handle path separators per OS

## 1.4.0

### Added

- Added support for dynamic paths in `uses->in` statements
- Added inspection for duplicate custom expectation name
- Add surrounder for `expect`

### Changed

- Define root path from phpunit.xml instead of composer path

### Fixed

- Remove `-` from the pest generated regex
- Escape `/` in regex method name

## 1.3.0

### Fixed

- Changed services to light services for auto disposable
- Fixed null pointer error when no virtual file

### Changed

- Change reporting on GitHub to contain full stacktracepa

### Added

- Added higher order expectation type provider
- Added support for xdebug3 and xdebug2 coverage option

## 1.2.2

### Fixed

- Hide snapshot icon for import statements
- Fix ArrayIndex error from ExpectationFileService
- Fixed wrong file expectation matching in ExpectationFileService

### Added

- Add support for  in  calls
- Added support for running key value datasets

### Changed

- Changed root path for regex to be based of vendor dir location instead of working directory

### Removed

- Remove service message newline requirement as method is deprecated

## 1.2.1

### Fixed

- Moved file generation into smart invocation

## 1.2.0

### Added

- Added gutter icon for snapshots
- Added goto snapshot file

### Fixed

- Rewrote the custom expectation system to use a more robust system
- Updated custom expectation indexer to v2

### Changed

- Removed decorator in favor of implementing interface

## 1.1.0

### Fixed

- Invoke the FileListener PSI part later (should fix indexing issues)
- Fixed stub issues on PestIconProvider by wrapping `runReadAction`
- Fixed `$this->field` not working when namespace exist
- Fixed Concurrent modification errors on expectation file service
- Fixed file generation triggering on projects without pest

### Added

- Added new context type for the root of a pest file
- Added post fix template for `it` tests
- Added live template for `it` test
- Added live template for `test` test
- Added light icon for `pest.php` file

## 1.0.5

### Changed

- Bumped min IntelliJ version to 2021.1

## 1.0.4

### Added

- Added Suppress inspection for `$this->field`

## 1.0.3

### Fixed

- Fixed php type resolving during event dispatching on file listener
- Fixed PSI and index mismatch on file listener

## 1.0.2

### Fixed

- Fixed indexes being out of date in file listener

## 1.0.1

### Fixed

- Removed usage of globalType (needed for 2020.3 support)

## 1.0.0

### Added

- Added structure support for tests
- Added autocompletion for custom expectations
- Added pest icon for the Pest.php config file
- Added symbol contributor for pest tests

### Fixed

- Fixed a read only permission bug when used with Code with me
- Fixed wrong namespace in custom expectations file generation

## 0.4.3

### Added

- Added IntelliJ version to bug report
- Added new Dataset icons (Thanks @caneco!)
- Added test state icons
- Added run all test in file icon

### Fixed

- Fix support for 2021.1
- Fix running tests with circumflex (^)

### Changed

- Bumped min IntelliJ version to 2020.3

## 0.4.2

### Added

- Added path mapping support ([#77](https://github.com/pestphp/pest-intellij/pull/77))

### Changed

- Bumped min plugin version to 2020.2
- Bumped Java version to 11

### Removed

- Disabled version checking (did not work with path mapping) ([#77](https://github.com/pestphp/pest-intellij/pull/77))

### Fixed

- Escape parenthesis in regex for single test ([#80](https://github.com/pestphp/pest-intellij/pull/80))
- Suppressed expression result unused inspection when on Pest test function element. ([#84](https://github.com/pestphp/pest-intellij/pull/84))

## 0.4.1

### Added

- Added support for auto-generated `it` test names. ([#72](https://github.com/pestphp/pest-intellij/pull/72))

### Changed

- Made the regex tightly bound and reused the same regex in rerun action. ([#72](https://github.com/pestphp/pest-intellij/pull/72))

## 0.4.0

### Added

- Added support for showing pest version ([#52](https://github.com/pestphp/pest-intellij/pull/52))
- Type provider for Pest test functions ([#48](https://github.com/pestphp/pest-intellij/pull/48))
- Added support for navigation between tests and test subject ([#53](https://github.com/pestphp/pest-intellij/pull/53))
- Added error reporting to GitHub issues ([#55](https://github.com/pestphp/pest-intellij/pull/55))
- Added inspection for duplicate test names in same file. ([#56](https://github.com/pestphp/pest-intellij/pull/56))
- Added completions for static and protected $this methods. ([#66](https://github.com/pestphp/pest-intellij/pull/66))
- Added completions $this fields declared in beforeEach functions. ([#66](https://github.com/pestphp/pest-intellij/pull/66))
- Added pcov coverage engine support ([#64](https://github.com/pestphp/pest-intellij/pull/64))

### Fixed

- Fixed duplicate test name error when no test name is given yet. ([#61](https://github.com/pestphp/pest-intellij/pull/61))
- Fixed finding tests with namespace at the top. ([#65](https://github.com/pestphp/pest-intellij/pull/65))
- Fixed allow location to be null in location provider. ([#68](https://github.com/pestphp/pest-intellij/pull/68))
- Fixed rerunning tests with namespaces ([#69](https://github.com/pestphp/pest-intellij/pull/69))

## 0.3.3

### Fixed

- Fixed running with dataset ([#47](https://github.com/pestphp/pest-intellij/pull/47))

## 0.3.2

### Added

- Added dark/light mode icons ([#45](https://github.com/pestphp/pest-intellij/pull/45))

## 0.3.1

### Changed

- Change the name of the plugin

## 0.3.0

### Added

- Basic autocompletion for `$this` for PhpUnit TestCase base class ([#11](https://github.com/pestphp/pest-intellij/pull/11))
- Line markers now works, for the whole file and the single test. ([#17](https://github.com/pestphp/pest-intellij/pull/17), [#24](https://github.com/pestphp/pest-intellij/pull/24))
- Add running support with debugger ([#19](https://github.com/pestphp/pest-intellij/pull/19))
- `$this->field` type support for fields declared in `beforeEach` and `beforeAll` functions ([#22](https://github.com/pestphp/pest-intellij/pull/22))
- Run tests scoped based on the cursor ([#24](https://github.com/pestphp/pest-intellij/pull/24), [#26](https://github.com/pestphp/pest-intellij/pull/26))
- Added support for rerun tests when using new pest version ([#39](https://github.com/pestphp/pest-intellij/pull/39))
- Added coverage support with clover output ([#39](https://github.com/pestphp/pest-intellij/pull/39))

### Changed

- Migrated all Java classes to Kotlin

### Fixed

- Plugin require restart as PhpTestFrameworkType does not support dynamic plugins
- Line markers reported false positives with method calls([#31](https://github.com/pestphp/pest-intellij/pull/31))

## 0.1.1

### Added

- Initial scaffold created from [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template)


================================================
FILE: CLAUDE.md
================================================
# Pest Plugin

## Mock Usage Guidelines

Prefer MockK to other mocking approaches.

When using MockK, prefer explicit stubbing over inline lambda syntax:

```kotlin
val config = mockk<RunConfiguration>()
every { config.project } returns project
every { config.name } returns "Test"
```

================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Pest IntelliJ

Thank you for wanting to contribute!

## What should I know before getting started?
The project is coded in Kotlin using the IntelliJ platform.  
The IntelliJ platform has a great wiki for documentation which is recommended to get familiar for understanding
many of the things happening in this project.  
[plugins.jetbrains.com/docs/intellij](https://plugins.jetbrains.com/docs/intellij/welcome.html)

## How to run project locally?




================================================
FILE: LICENSE.md
================================================
MIT License

Copyright (c) Oliver Nybroe olivernybroe@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<p align="center">
    <img src="/art/banner.png" width="914" title="PEST IntelliJ Banner">
    <p align="center">
        <a href="https://github.com/pestphp/pest/actions"><img alt="GitHub Workflow Status (master)" src="https://github.com/pestphp/pest-intellij/workflows/Build/badge.svg"></a>
        <a href="https://plugins.jetbrains.com/plugin/14636-pest"><img alt="Total Downloads" src="https://img.shields.io/jetbrains/plugin/d/14636"></a>
        <a href="https://plugins.jetbrains.com/plugin/14636-pest"><img alt="Latest Version" src="https://img.shields.io/jetbrains/plugin/v/14636"></a>
	    <a href="https://plugins.jetbrains.com/plugin/14636-pest"><img alt="Latest EAP Version" src="https://img.shields.io/badge/dynamic/xml?label=EAP version&query=%2Fplugin-repository%2Fcategory%2Fidea-plugin%5B1%5D%2Fversion&url=https%3A%2F%2Fplugins.jetbrains.com%2Fplugins%2Flist%3Fchannel%3Deap%26pluginId%3D14636"></a>
	    <a href="https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub"><img alt="official JetBrains project" src="https://jb.gg/badges/official.svg"></a>
    </p>
</p>

# Pest IntelliJ

<!-- Plugin description -->
This plugin adds support for using Pest PHP inside PHPStorm

## Installation

- Using IDE built-in plugin system:

  <kbd>Preferences</kbd> > <kbd>Plugins</kbd> > <kbd>Marketplace</kbd> > <kbd>Search for "Pest"</kbd> >
  <kbd>Install Plugin</kbd>

- Manually:

  Download the [latest release](https://github.com/pestphp/pest-intellij/releases/latest) and install it manually using
  <kbd>Preferences</kbd> > <kbd>Plugins</kbd> > <kbd>⚙️</kbd> > <kbd>Install plugin from disk...</kbd>

- Using Early Access Program (EAP) builds:

  <kbd>Preferences</kbd> > <kbd>Plugins</kbd> > <kbd>⚙️</kbd> > <kbd>Manage plugin repositories</kbd>

  Add a new entry for [`https://plugins.jetbrains.com/plugins/eap/14636`](https://plugins.jetbrains.com/plugins/eap/14636)

  Then search for the plugin and install it as usual.

## Configuration

To configure pest to run properly, you need to setup the the proper local test framework

- Navigate to

  <kbd>Preferences</kbd> > <kbd>Languages & Frameworks</kbd> > <kbd>PHP</kbd> > <kbd>Test Frameworks</kbd>

  And add the following two configuration fields:

  Set "Path to Pest Executable" to
	<code>/path/to/your/project/vendor/bin/pest</code>

  Set the "Test Runner" to
	<code>/path/to/your/project/phpunit.xml</code>


## Resources
For a great video course on how to write tests with Pest, check out [Testing Laravel](https://testing-laravel.com/) or [Pest From Scratch](https://laracasts.com/series/pest-from-scratch).

## Issue?
Please report it to [YouTrack](https://youtrack.jetbrains.com/newIssue?project=WI)

## Credits
Originally developed by [Oliver Nybroe](https://github.com/olivernybroe)

<!-- Plugin description end -->

---
Plugin based on the [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template).


================================================
FILE: build.gradle.kts
================================================
import org.jetbrains.intellij.platform.gradle.ProductMode
import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.markdownToHTML
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

fun properties(key: String) = project.findProperty(key).toString()

plugins {
    // Java support
    id("java")
    // Kotlin support
    id("org.jetbrains.kotlin.jvm") version "2.3.0"
    // Gradle IntelliJ Plugin
    id("org.jetbrains.intellij.platform") version "2.7.0"
    // Gradle Changelog Plugin
    id("org.jetbrains.changelog") version "2.2.0"
}

group = properties("pluginGroup")
version = properties("pluginVersion")

// Configure project's dependencies
repositories {
    mavenCentral()
    intellijPlatform {
        defaultRepositories()
    }
}

dependencies {
    implementation(kotlin("stdlib"))
    testImplementation("io.mockk:mockk:1.14.3") {
        exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm")
    }
    testImplementation("junit:junit:4.13.2")
    intellijPlatform {
        val type = providers.gradleProperty("platformType")
        val version = providers.gradleProperty("platformVersion")

        create(type, version) {
            useInstaller = false
            productMode = ProductMode.MONOLITH
        }
        testFramework(TestFrameworkType.Platform)
        bundledPlugins(properties("platformBundledPlugins").toPlugins())
        bundledModules(properties("platformBundledModules").toPlugins())
    }
}

// Configure Gradle Changelog Plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin
changelog {
    version.set(properties("pluginVersion"))
    groups.set(emptyList())
}

kotlin {
    jvmToolchain {
        languageVersion.set(JavaLanguageVersion.of(providers.gradleProperty("javaVersion").get()))
    }
    compilerOptions {
        jvmTarget.set(JvmTarget.fromTarget(providers.gradleProperty("javaVersion").get()))
    }
}

tasks {
    withType<JavaCompile>().configureEach {
        val javaVersion = properties("javaVersion")
        sourceCompatibility = javaVersion
        targetCompatibility = javaVersion
    }

    wrapper {
        gradleVersion = properties("gradleVersion")
    }

    patchPluginXml {
        version = properties("pluginVersion")
        sinceBuild.set(properties("pluginSinceBuild"))
        untilBuild.set(properties("pluginUntilBuild"))

        // Extract the <!-- Plugin description --> section from README.md and provide for the plugin's manifest
        pluginDescription.set(
            projectDir.resolve("README.md").readText().lines().run {
                val start = "<!-- Plugin description -->"
                val end = "<!-- Plugin description end -->"

                if (!containsAll(listOf(start, end))) {
                    throw GradleException("Plugin description section not found in README.md:\n$start ... $end")
                }
                subList(indexOf(start) + 1, indexOf(end))
            }.joinToString("\n").run { markdownToHTML(this) }
        )

        // Get the latest available change notes from the changelog file
        changeNotes.set(provider {
            changelog.renderItem(changelog.run {
                getOrNull(properties("pluginVersion")) ?: getLatest()
            }, Changelog.OutputType.HTML)
        })
    }

    signPlugin {
        certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
        privateKey.set(System.getenv("PRIVATE_KEY"))
        password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
    }

    publishPlugin {
        dependsOn("patchChangelog")
        token.set(System.getenv("PUBLISH_TOKEN"))
        // pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3
        // Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more:
        // https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel
        // channels = listOf(properties("pluginVersion").split('-').getOrElse(1) { "default" }.split('.').first())
    }
}

private fun String.toPlugins(): List<String> = split(',')
    .map(String::trim)
    .filter(String::isNotEmpty)

================================================
FILE: coverage/BUILD.bazel
================================================
### auto-generated section `build intellij.pest.coverage` start
load("@rules_jvm//:jvm.bzl", "jvm_library")

jvm_library(
  name = "coverage",
  module_name = "intellij.pest.coverage",
  visibility = ["//visibility:public"],
  srcs = glob(["src/**/*.kt", "src/**/*.java", "src/**/*.form"], allow_empty = True),
  resources = glob(["resources/**/*"]),
  resource_strip_prefix = "resources",
  deps = [
    "@lib//:kotlin-stdlib",
    "//phpstorm/pest",
    "//phpstorm/php:php-impl",
    "@community//plugins/coverage-common:coverage",
    "@community//platform/execution",
    "@community//platform/smRunner",
    "@community//platform/core-api:core",
    "@community//platform/util",
    "@community//platform/util:util-ui",
    "@community//platform/ide-core",
    "@community//platform/statistics",
    "@community//platform/testRunner",
    "//phpstorm/coverage",
  ]
)

jvm_library(
  name = "coverage_test_lib",
  testonly = True,
  module_name = "intellij.pest.coverage",
  visibility = ["//visibility:public"],
  srcs = glob([], allow_empty = True),
  runtime_deps = [
    ":coverage",
    "//phpstorm/pest:pest_test_lib",
    "//phpstorm/php:php-impl_test_lib",
    "@community//plugins/coverage-common:coverage_test_lib",
    "@community//platform/execution:execution_test_lib",
    "@community//platform/smRunner:smRunner_test_lib",
    "@community//platform/core-api:core_test_lib",
    "@community//platform/util:util_test_lib",
    "@community//platform/util:util-ui_test_lib",
    "@community//platform/ide-core:ide-core_test_lib",
    "@community//platform/statistics:statistics_test_lib",
    "@community//platform/lang-api:lang",
    "@community//platform/lang-api:lang_test_lib",
    "@community//platform/projectModel-impl",
    "@community//platform/projectModel-impl:projectModel-impl_test_lib",
    "@community//platform/projectModel-api:projectModel",
    "@community//platform/projectModel-api:projectModel_test_lib",
    "@community//platform/platform-util-io:ide-util-io",
    "@community//platform/platform-util-io:ide-util-io_test_lib",
    "@community//platform/testRunner:testRunner_test_lib",
    "//phpstorm/coverage:coverage_test_lib",
  ]
)
### auto-generated section `build intellij.pest.coverage` end

### auto-generated section `iml intellij.pest.coverage` start
exports_files([
  "intellij.pest.coverage.iml",
], visibility = ["//visibility:public"])
### auto-generated section `iml intellij.pest.coverage` end

================================================
FILE: coverage/intellij.pest.coverage.iml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="com.intellij.pest.coverage" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="library" name="kotlin-stdlib" level="project" />
    <orderEntry type="module" module-name="intellij.pest" />
    <orderEntry type="module" module-name="intellij.php.impl" />
    <orderEntry type="module" module-name="intellij.platform.coverage" />
    <orderEntry type="module" module-name="intellij.platform.execution" />
    <orderEntry type="module" module-name="intellij.platform.smRunner" />
    <orderEntry type="module" module-name="intellij.platform.core" />
    <orderEntry type="module" module-name="intellij.platform.util" />
    <orderEntry type="module" module-name="intellij.platform.util.ui" />
    <orderEntry type="module" module-name="intellij.platform.ide.core" />
    <orderEntry type="module" module-name="intellij.platform.statistics" />
    <orderEntry type="module" module-name="intellij.platform.lang" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.projectModel.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.projectModel" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.ide.util.io" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.testRunner" />
    <orderEntry type="module" module-name="intellij.php.coverage" />
  </component>
</module>

================================================
FILE: coverage/resources/intellij.pest.coverage.xml
================================================
<idea-plugin>
    <dependencies>
        <plugin id="com.jetbrains.php"/>
        <plugin id="com.pestphp.pest-intellij"/>
        <module name="intellij.php.coverage"/>
        <module name="intellij.platform.coverage"/>
    </dependencies>
    
    <extensions defaultExtensionNs="com.intellij">
        <programRunner implementation="com.intellij.pest.coverage.PestCoverageProgramRunner"/>
        <programRunner implementation="com.intellij.pest.coverage.features.mutate.PestMutateProgramRunner"/>
        <executor implementation="com.intellij.pest.coverage.features.mutate.PestMutateTestExecutor" order="first,after debug"/>
        <coverageEngine implementation="com.intellij.pest.coverage.PestCoverageEngine"/>
    </extensions>
</idea-plugin>


================================================
FILE: coverage/src/PestCoverageEnabledConfiguration.kt
================================================
package com.intellij.pest.coverage

import com.intellij.coverage.CoverageRunner
import com.intellij.execution.configurations.coverage.CoverageEnabledConfiguration
import com.intellij.php.coverage.PhpUnitCoverageRunner
import com.pestphp.pest.configuration.PestRunConfiguration

class PestCoverageEnabledConfiguration(
    configuration: PestRunConfiguration
) : CoverageEnabledConfiguration(configuration, CoverageRunner.getInstance(PhpUnitCoverageRunner::class.java)) {
    override fun coverageFileNameSeparator(): String = "@"
}


================================================
FILE: coverage/src/PestCoverageEngine.kt
================================================
package com.intellij.pest.coverage

import com.intellij.coverage.CoverageFileProvider
import com.intellij.coverage.CoverageRunner
import com.intellij.coverage.CoverageSuite
import com.intellij.execution.configurations.RunConfigurationBase
import com.intellij.execution.configurations.coverage.CoverageEnabledConfiguration
import com.intellij.openapi.project.Project
import com.intellij.php.coverage.PhpCoverageSuite
import com.intellij.php.coverage.PhpUnitCoverageEngine
import com.pestphp.pest.configuration.PestRunConfiguration

class PestCoverageEngine : PhpUnitCoverageEngine() {
    override fun isApplicableTo(conf: RunConfigurationBase<*>): Boolean {
        return conf is PestRunConfiguration
    }

    override fun createCoverageEnabledConfiguration(conf: RunConfigurationBase<*>): CoverageEnabledConfiguration {
        return PestCoverageEnabledConfiguration(conf as PestRunConfiguration)
    }

    @Deprecated("Deprecated in Java")
    override fun createCoverageSuite(
        covRunner: CoverageRunner,
        name: String,
        coverageDataFileProvider: CoverageFileProvider,
        config: CoverageEnabledConfiguration
    ): CoverageSuite? {
        if (config is PestCoverageEnabledConfiguration) {
            return PhpCoverageSuite(name, config.configuration.project, covRunner, coverageDataFileProvider, config.createTimestamp())
        }

        return null
    }

    override fun createCoverageSuite(
        name: String,
        project: Project,
        covRunner: CoverageRunner,
        coverageDataFileProvider: CoverageFileProvider,
        timestamp: Long,
        config: CoverageEnabledConfiguration
    ): CoverageSuite? {
        if (config is PestCoverageEnabledConfiguration) {
            return PhpCoverageSuite(name, project, covRunner, coverageDataFileProvider, timestamp)
        }

        return null
    }
}


================================================
FILE: coverage/src/PestCoverageProgramRunner.kt
================================================
package com.intellij.pest.coverage

import com.intellij.execution.configurations.RunProfile
import com.intellij.execution.configurations.RunProfileState
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.php.coverage.PhpCoverageRunner
import com.jetbrains.php.config.commandLine.PhpCommandSettings
import com.jetbrains.php.config.commandLine.PhpCommandSettingsBuilder
import com.jetbrains.php.config.interpreters.PhpInterpreter
import com.jetbrains.php.debug.xdebug.options.XdebugConfigurationOptionsManager
import com.jetbrains.php.phpunit.coverage.PhpUnitCoverageEngine.CoverageEngine
import com.jetbrains.php.run.PhpConfigurationOption
import com.jetbrains.php.run.PhpRunConfigurationHolder
import com.pestphp.pest.configuration.PestRunConfiguration
import com.pestphp.pest.features.parallel.addParallelArguments

open class PestCoverageProgramRunner : PhpCoverageRunner() {
    companion object {
        const val EXECUTOR_ID: String = "Coverage"
        const val RUNNER_ID: String = "PestCoverageRunner"
    }

    override fun canRun(executorId: String, profile: RunProfile): Boolean {
        return executorId == EXECUTOR_ID && profile is PestRunConfiguration
    }

    override fun createCoverageArguments(targetCoverage: String?): MutableList<String> {
        val coverageArguments: ArrayList<String> = ArrayList()
        coverageArguments.add("--coverage-clover")
        targetCoverage?.let { coverageArguments.add(it) }

        return coverageArguments
    }

    override fun getRunnerId(): String = RUNNER_ID

    override fun createState(
        env: ExecutionEnvironment,
        interpreter: PhpInterpreter,
        runConfigurationHolder: PhpRunConfigurationHolder<*>,
        coverageArguments: MutableList<String>,
        localCoverage: String,
        targetCoverage: String
    ): RunProfileState? {
        val runConfiguration = runConfigurationHolder.runConfiguration as PestRunConfiguration

        val command = createPestCoverageCommand(runConfiguration, interpreter, coverageArguments, localCoverage, targetCoverage)

        return runConfiguration.checkAndGetState(env, command)
    }

    fun createPestCoverageCommand(
        runConfiguration: PestRunConfiguration,
        interpreter: PhpInterpreter,
        coverageArguments: List<String>,
        localCoverage: String,
        targetCoverage: String
    ): PhpCommandSettings {
        val command = PhpCommandSettingsBuilder(runConfiguration.project, interpreter)
            .loadDebugExtension().build().apply {
                runConfiguration.applyTestArguments(this, coverageArguments)
            }

        val options = when (runConfiguration.pestSettings.pestRunnerSettings.coverageEngine) {
            CoverageEngine.XDEBUG -> XdebugConfigurationOptionsManager
                .getConfigurationOptionsProvider(runConfiguration.project, interpreter)
                .enableCoverage()
                .createXdebugConfigurations()
            CoverageEngine.PCOV -> listOf(PhpConfigurationOption("pcov.enabled", 1))
            else -> throw IllegalArgumentException("Unsupported coverage engine.")
        }
        command.addConfigurationOptions(options)
        addParallelArguments(runConfiguration, command)
        setAdditionalMapping(localCoverage, targetCoverage, command)

        return command
    }
}


================================================
FILE: coverage/src/features/mutate/PestMutateProgramRunner.kt
================================================
package com.intellij.pest.coverage.features.mutate

import com.intellij.execution.configurations.RunProfile
import com.intellij.execution.configurations.RunProfileState
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.execution.ui.RunContentDescriptor
import com.intellij.pest.coverage.PestCoverageProgramRunner
import com.pestphp.pest.PestBundle
import com.pestphp.pest.configuration.PestRunConfiguration
import com.pestphp.pest.features.parallel.postprocessExecutionResult
import com.pestphp.pest.statistics.PestUsagesCollector

private val MUTATE_ARGUMENTS: MutableList<String> = mutableListOf("--mutate")

open class PestMutateProgramRunner : PestCoverageProgramRunner() {
    companion object {
        const val RUNNER_ID: String = "PestMutateRunner"
    }

    override fun doExecute(state: RunProfileState, environment: ExecutionEnvironment): RunContentDescriptor? {
        PestUsagesCollector.logMutationTestExecution(environment.project)
        val contentDescriptor = super.doExecute(state, environment)
        if (contentDescriptor != null) {
            postprocessExecutionResult(contentDescriptor, environment, PestBundle.message("MUTATION_TESTING_IS_AVAILABLE_FROM_VERSION_3"))
        }
        return contentDescriptor
    }

    override fun canRun(executorId: String, profile: RunProfile): Boolean =
        executorId == PestMutateTestExecutor.EXECUTOR_ID && profile is PestRunConfiguration

    override fun createCoverageArguments(targetCoverage: String?): MutableList<String> = MUTATE_ARGUMENTS

    override fun getRunnerId(): String = RUNNER_ID
}

================================================
FILE: coverage/src/features/mutate/PestMutateTestExecutor.kt
================================================
package com.intellij.pest.coverage.features.mutate

import com.intellij.execution.Executor
import com.intellij.icons.AllIcons
import com.intellij.openapi.util.IconLoader.getDisabledIcon
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.util.text.TextWithMnemonic
import com.intellij.openapi.wm.ToolWindowId
import com.pestphp.pest.PestBundle
import com.pestphp.pest.PestIcons
import org.jetbrains.annotations.Nls
import org.jetbrains.annotations.NonNls
import javax.swing.Icon

internal class PestMutateTestExecutor : Executor() {
    companion object {
        const val EXECUTOR_ID: @NonNls String = "PestMutateTestExecutor"
        const val CONTEXT_ACTION_ID: @NonNls String = "PestRunMutate"
    }

    override fun getToolWindowId(): String = ToolWindowId.RUN

    override fun getToolWindowIcon(): Icon = AllIcons.Toolwindows.ToolWindowRun

    override fun getIcon(): Icon = PestIcons.RunWithMutate

    override fun getRerunIcon(): Icon = AllIcons.Actions.Rerun

    override fun getDisabledIcon(): Icon = getDisabledIcon(icon)

    override fun getDescription(): String = PestBundle.message("ACTION_RUN_SELECTED_CONFIGURATION_WITH_MUTATE_DESCRIPTION")

    override fun getActionName(): String = PestBundle.message("ACTION_PEST_MUTATE_TEXT")

    override fun getId(): String = EXECUTOR_ID

    override fun getStartActionText(): @Nls(capitalization = Nls.Capitalization.Title) String = PestBundle.message("RUN_PEST_WITH_MUTATE")

    override fun getStartActionText(configurationName: String): String {
        val configName = if (StringUtil.isEmpty(configurationName)) "" else " '${shortenNameIfNeeded(configurationName)}'"
        return TextWithMnemonic.parse(PestBundle.message("RUN_S_WITH_MUTATE")).replaceFirst("%s", configName).toString()
    }

    override fun getContextActionId(): String = CONTEXT_ACTION_ID

    override fun getHelpId(): String? = null
}

================================================
FILE: coverage/tests/BUILD.bazel
================================================
### auto-generated section `build intellij.pest.coverage.tests` start
load("@rules_jvm//:jvm.bzl", "jvm_library")

jvm_library(
  name = "tests",
  module_name = "intellij.pest.coverage.tests",
  visibility = ["//visibility:public"],
  srcs = glob([], allow_empty = True),
  runtime_deps = ["@community//platform/ide-core"]
)

jvm_library(
  name = "tests_test_lib",
  testonly = True,
  visibility = ["//visibility:public"],
  srcs = glob(["src/**/*.kt", "src/**/*.java", "src/**/*.form"], allow_empty = True),
  resources = glob(["testData/**/*"]),
  resource_strip_prefix = "testData",
  associates = [
    "//phpstorm/pest/coverage",
    "//phpstorm/pest/coverage:coverage_test_lib",
  ],
  deps = [
    "//phpstorm/pest:pest-tests",
    "//phpstorm/pest:pest-tests_test_lib",
    "@community//platform/lang-api:lang",
    "@community//platform/lang-api:lang_test_lib",
    "//phpstorm/php:php-impl",
    "//phpstorm/php:php-impl_test_lib",
    "//phpstorm/pest",
    "//phpstorm/pest:pest_test_lib",
    "@community//platform/core-api:core",
    "@community//platform/core-api:core_test_lib",
    "@community//platform/execution",
    "@community//platform/execution:execution_test_lib",
    "@community//platform/projectModel-api:projectModel",
    "@community//platform/projectModel-api:projectModel_test_lib",
    "@community//platform/projectModel-impl",
    "@community//platform/projectModel-impl:projectModel-impl_test_lib",
    "@community//platform/platform-util-io:ide-util-io",
    "@community//platform/ide-core",
    "@community//platform/smRunner",
    "@community//platform/smRunner:smRunner_test_lib",
    "@community//plugins/coverage-common:coverage",
    "@community//plugins/coverage-common:coverage_test_lib",
    "@community//platform/testRunner",
    "@community//platform/testRunner:testRunner_test_lib",
    "//phpstorm/coverage",
    "//phpstorm/coverage:coverage_test_lib",
  ],
  runtime_deps = [
    ":tests",
    "@community//platform/platform-util-io:ide-util-io_test_lib",
    "@community//platform/ide-core:ide-core_test_lib",
  ]
)
### auto-generated section `build intellij.pest.coverage.tests` end

### auto-generated section `iml intellij.pest.coverage.tests` start
exports_files([
  "intellij.pest.coverage.tests.iml",
], visibility = ["//visibility:public"])
### auto-generated section `iml intellij.pest.coverage.tests` end

### auto-generated section `test intellij.pest.coverage.tests` start
load("@community//build:tests-options.bzl", "jps_test")

jps_test(
  name = "tests_test",
  runtime_deps = [":tests_test_lib"]
)
### auto-generated section `test intellij.pest.coverage.tests` end

================================================
FILE: coverage/tests/intellij.pest.coverage.tests.iml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="true" />
      <sourceFolder url="file://$MODULE_DIR$/testData" type="java-test-resource" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="module" module-name="intellij.pest.tests" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.lang" scope="TEST" />
    <orderEntry type="module" module-name="intellij.php.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.pest" scope="TEST" />
    <orderEntry type="module" module-name="intellij.pest.coverage" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.core" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.execution" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.projectModel" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.projectModel.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.ide.util.io" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.ide.core" />
    <orderEntry type="module" module-name="intellij.platform.smRunner" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.coverage" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.testRunner" scope="TEST" />
    <orderEntry type="module" module-name="intellij.php.coverage" scope="TEST" />
  </component>
  <component name="TestModuleProperties" production-module="intellij.pest.coverage" />
</module>

================================================
FILE: coverage/tests/src/com/intellij/pest/coverage/PestCoverageProgramRunnerTest.kt
================================================
package com.intellij.pest.coverage

import com.intellij.coverage.CoverageDataManager
import com.intellij.coverage.CoverageHelper
import com.intellij.execution.PsiLocation
import com.intellij.execution.actions.ConfigurationContext
import com.intellij.psi.PsiElement
import com.intellij.testFramework.TestDataPath
import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy
import com.jetbrains.php.config.interpreters.PhpInterpreter
import com.jetbrains.php.config.interpreters.PhpInterpretersManagerImpl
import com.jetbrains.php.testFramework.PhpTestFrameworkConfiguration
import com.jetbrains.php.testFramework.PhpTestFrameworkSettingsManager
import com.pestphp.pest.PestFrameworkType
import com.pestphp.pest.PestLightCodeFixture
import com.pestphp.pest.configuration.PestRunConfiguration
import com.pestphp.pest.configuration.PestRunConfigurationProducer
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.pathString

@TestDataPath($$"$CONTENT_ROOT/testData")
class PestCoverageProgramRunnerTest : PestLightCodeFixture() {
    private lateinit var configurationsBackup: List<PhpTestFrameworkConfiguration>

    override fun getTestDataPath(): String {
        val intellijPath = Path.of(IdeaTestExecutionPolicy.getHomePathWithPolicy(), "phpstorm/pest/coverage/tests/testData")
        return if (intellijPath.exists()) {
            intellijPath.pathString
        } else {
            "testData"
        }
    }

    fun testCannotRunWrongExecutorId() = doTest {
        val configuration = createConfiguration(myFixture.file)
        assertFalse(PestCoverageProgramRunner().canRun(PestCoverageProgramRunner.EXECUTOR_ID + "1", configuration))
    }

    fun testCanRunFile() = doTest {
        val configuration = createConfiguration(myFixture.file)
        assertTrue(PestCoverageProgramRunner().canRun(PestCoverageProgramRunner.EXECUTOR_ID, configuration))
    }

    fun testCanRunFunction() = doTest {
        val testElement = myFixture.file?.firstChild?.lastChild?.firstChild ?: return@doTest
        val configuration = createConfiguration(testElement)
        assertTrue(PestCoverageProgramRunner().canRun(PestCoverageProgramRunner.EXECUTOR_ID, configuration))
    }

    fun testCanRunDirectory() = doTest {
        val testElement = myFixture.file?.containingDirectory ?: return@doTest
        val configuration = createConfiguration(testElement)
        assertTrue(PestCoverageProgramRunner().canRun(PestCoverageProgramRunner.EXECUTOR_ID, configuration))
    }

    fun testBuildFile() = doTest {
        val configuration = createConfiguration(myFixture.file)

        val pestCoverageCommandSettings = PestCoverageProgramRunner().createPestCoverageCommand(configuration, configuration.interpreter!!, emptyList(), "", "")

        val expected = "-dxdebug.coverage_enable=1 -dxdebug.mode=coverage randomPath --teamcity /src/ATest.php"
        assertEquals(expected, pestCoverageCommandSettings.createGeneralCommandLine().parametersList.list.joinToString(" "))
    }

    fun testBuildFunction() = doTest {
        val testElement = myFixture.file?.firstChild?.lastChild?.firstChild ?: return@doTest
        val configuration = createConfiguration(testElement)

        val pestCoverageCommandSettings = PestCoverageProgramRunner().createPestCoverageCommand(configuration, configuration.interpreter!!, emptyList(), "", "")

        val expected = "-dxdebug.coverage_enable=1 -dxdebug.mode=coverage randomPath --teamcity /src/ATest.php"
        assertEquals(
            expected,
            pestCoverageCommandSettings.createGeneralCommandLine().parametersList.list
                .joinToString(" ")
                .substringBefore(" --filter")
        )
    }

    fun testBuildDirectory() = doTest {
        val testElement = myFixture.file?.containingDirectory ?: return@doTest
        val configuration = createConfiguration(testElement)
        val pestCoverageCommandSettings = PestCoverageProgramRunner().createPestCoverageCommand(configuration, configuration.interpreter!!, emptyList(), "", "")

        val expected = "-dxdebug.coverage_enable=1 -dxdebug.mode=coverage randomPath --teamcity /src"
        assertEquals(expected, pestCoverageCommandSettings.createGeneralCommandLine().parametersList.list.joinToString(" "))
    }

    fun testBuildFileWithEnabledParallelTesting() = doTest {
        val configuration = createConfiguration(myFixture.file)
        configuration.pestSettings.pestRunnerSettings.parallelTestingEnabled = true

        val pestCoverageCommandSettings = PestCoverageProgramRunner().createPestCoverageCommand(configuration, configuration.interpreter!!, emptyList(), "", "")

        val expected = "-dxdebug.coverage_enable=1 -dxdebug.mode=coverage randomPath --teamcity /src/ATest.php --parallel --log-teamcity php://stdout"
        assertEquals(expected, pestCoverageCommandSettings.createGeneralCommandLine().parametersList.list.joinToString(" "))
    }

    fun testCreateCoverageSuiteOnRunningCoverageTests() = doTest {
        val configuration = createConfiguration(myFixture.file)
        CoverageHelper.resetCoverageSuit(configuration)
        assertSize(1, CoverageDataManager.getInstance(project).getSuites())
    }

    private fun createConfiguration(psiElement: PsiElement): PestRunConfiguration {
        createPestFrameworkConfiguration()
        val context = ConfigurationContext.createEmptyContextForLocation(PsiLocation.fromPsiElement(psiElement))
        val runConfiguration = PestRunConfigurationProducer().createConfigurationFromContext(context)?.configuration as? PestRunConfiguration
        runConfiguration!!.settings.commandLineSettings.interpreterSettings.interpreterName = getTestName(false)
        return runConfiguration
    }

    private fun doTest(block: () -> Unit) {
        myFixture.configureByFile("ATest.php")
        block()
    }

    override fun setUp() {
        super.setUp()
        val interpreter = PhpInterpreter().apply {
            name = getTestName(false)
            homePath = "$testDataPath/php"
        }
        PhpInterpretersManagerImpl.getInstance(project).addInterpreter(interpreter)
        configurationsBackup = PhpTestFrameworkSettingsManager.getInstance(project).getConfigurations(PestFrameworkType.Companion.instance)
    }

    override fun tearDown() {
        try {
            PhpTestFrameworkSettingsManager.getInstance(project).setConfigurations(PestFrameworkType.Companion.instance, configurationsBackup)
            PhpInterpretersManagerImpl.getInstance(project).interpreters = emptyList()
        } catch (e: Throwable) {
            addSuppressedException(e)
        } finally {
            super.tearDown()
        }
    }
}

================================================
FILE: coverage/tests/src/com/intellij/pest/coverage/features/mutate/PestMutateProgramRunnerTest.kt
================================================
package com.intellij.pest.coverage.features.mutate

import com.intellij.execution.PsiLocation
import com.intellij.execution.actions.ConfigurationContext
import com.intellij.psi.PsiElement
import com.intellij.testFramework.TestDataPath
import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy
import com.jetbrains.php.config.interpreters.PhpInterpreter
import com.jetbrains.php.config.interpreters.PhpInterpretersManagerImpl
import com.jetbrains.php.testFramework.PhpTestFrameworkConfiguration
import com.jetbrains.php.testFramework.PhpTestFrameworkSettingsManager
import com.pestphp.pest.PestFrameworkType
import com.pestphp.pest.PestLightCodeFixture
import com.pestphp.pest.configuration.PestRunConfiguration
import com.pestphp.pest.configuration.PestRunConfigurationProducer
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.pathString

@TestDataPath($$"$CONTENT_ROOT/testData/features/mutate")
class PestMutateProgramRunnerTest : PestLightCodeFixture() {
    private lateinit var configurationsBackup: List<PhpTestFrameworkConfiguration>

    override fun getTestDataPath(): String {
        val intellijPath = Path.of(IdeaTestExecutionPolicy.getHomePathWithPolicy(), "phpstorm/pest/coverage/tests/testData/features/mutate")
        return if (intellijPath.exists()) {
            intellijPath.pathString
        } else {
            "testData/features/mutate"
        }
    }

    fun testCannotRunWrongExecutorId() = doTest {
        val configuration = createConfiguration(myFixture.file)
        assertFalse(PestMutateProgramRunner().canRun(PestMutateTestExecutor.EXECUTOR_ID + "1", configuration))
    }

    fun testCanRunFile() = doTest {
        val configuration = createConfiguration(myFixture.file)
        assertTrue(PestMutateProgramRunner().canRun(PestMutateTestExecutor.EXECUTOR_ID, configuration))
    }

    fun testCanRunFunction() = doTest {
        val testElement = myFixture.file?.firstChild?.lastChild?.firstChild ?: return@doTest
        val configuration = createConfiguration(testElement)
        assertTrue(PestMutateProgramRunner().canRun(PestMutateTestExecutor.EXECUTOR_ID, configuration))
    }

    fun testCanRunDirectory() = doTest {
        val testElement = myFixture.file?.containingDirectory ?: return@doTest
        val configuration = createConfiguration(testElement)
        assertTrue(PestMutateProgramRunner().canRun(PestMutateTestExecutor.EXECUTOR_ID, configuration))
    }

    private fun createConfiguration(psiElement: PsiElement): PestRunConfiguration {
        createPestFrameworkConfiguration()
        val context = ConfigurationContext.createEmptyContextForLocation(PsiLocation.fromPsiElement(psiElement))
        val runConfiguration = PestRunConfigurationProducer().createConfigurationFromContext(context)?.configuration
            as? PestRunConfiguration
        runConfiguration!!.settings.commandLineSettings.interpreterSettings.interpreterName = getTestName(false)
        return runConfiguration
    }

    private fun doTest(block: () -> Unit) {
        myFixture.configureByFile("ATest.php")
        block()
    }

    override fun setUp() {
        super.setUp()
        val interpreter = PhpInterpreter().apply {
            name = getTestName(false)
            homePath = "$testDataPath/php"
        }
        PhpInterpretersManagerImpl.getInstance(project).addInterpreter(interpreter)
        configurationsBackup = PhpTestFrameworkSettingsManager.getInstance(project).getConfigurations(PestFrameworkType.instance)
    }

    override fun tearDown() {
        try {
            PhpTestFrameworkSettingsManager.getInstance(project).setConfigurations(PestFrameworkType.instance, configurationsBackup)
            PhpInterpretersManagerImpl.getInstance(project).interpreters = emptyList()
        } catch (e: Throwable) {
            addSuppressedException(e)
        } finally {
            super.tearDown()
        }
    }
}


================================================
FILE: coverage/tests/testData/ATest.php
================================================
<?php

test("foo", function() {});

================================================
FILE: coverage/tests/testData/features/mutate/ATest.php
================================================
<?php

test("foo", function() {});

================================================
FILE: coverage/tests/testData/features/mutate/php
================================================


================================================
FILE: coverage/tests/testData/php
================================================


================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists


================================================
FILE: gradle.properties
================================================
# IntelliJ Platform Artifacts Repositories
# -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html

pluginGroup = com.pestphp
pluginName = PEST PHP
pluginVersion = 1.12.0

# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
# for insight into build numbers and IntelliJ Platform versions.
pluginSinceBuild = 232.10072.32
pluginUntilBuild =

platformType = PS
platformVersion = LATEST-EAP-SNAPSHOT
platformDownloadSources = true
# https://plugins.jetbrains.com/plugin/6610-php/versions
platformBundledPlugins = com.jetbrains.php
platformBundledModules = intellij.platform.coverage

# Java language level used to compile sources and to generate the files for - Java 11 is required since 2020.3
javaVersion = 21

gradleVersion = 8.13
# Opt-out flag for bundling Kotlin standard library.
# See https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library for details.
# suppress inspection "UnusedProperty"
kotlin.stdlib.default.dependency = false
org.gradle.jvmargs=-Xmx2048m

================================================
FILE: gradlew
================================================
#!/bin/sh

#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

##############################################################################
#
#   Gradle start up script for POSIX generated by Gradle.
#
#   Important for running:
#
#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
#       noncompliant, but you have some other compliant shell such as ksh or
#       bash, then to run this script, type that shell name before the whole
#       command line, like:
#
#           ksh Gradle
#
#       Busybox and similar reduced shells will NOT work, because this script
#       requires all of these POSIX shell features:
#         * functions;
#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
#         * compound commands having a testable exit status, especially «case»;
#         * various built-in commands including «command», «set», and «ulimit».
#
#   Important for patching:
#
#   (2) This script targets any POSIX shell, so it avoids extensions provided
#       by Bash, Ksh, etc; in particular arrays are avoided.
#
#       The "traditional" practice of packing multiple parameters into a
#       space-separated string is a well documented source of bugs and security
#       problems, so this is (mostly) avoided, by progressively accumulating
#       options in "$@", and eventually passing that to Java.
#
#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
#       see the in-line comments for details.
#
#       There are tweaks for specific operating systems such as AIX, CygWin,
#       Darwin, MinGW, and NonStop.
#
#   (3) This script is generated from the Groovy template
#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
#       within the Gradle project.
#
#       You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################

# Attempt to set APP_HOME

# Resolve links: $0 may be a link
app_path=$0

# Need this for daisy-chained symlinks.
while
    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
    [ -h "$app_path" ]
do
    ls=$( ls -ld "$app_path" )
    link=${ls#*' -> '}
    case $link in             #(
      /*)   app_path=$link ;; #(
      *)    app_path=$APP_HOME$link ;;
    esac
done

APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit

APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

warn () {
    echo "$*"
} >&2

die () {
    echo
    echo "$*"
    echo
    exit 1
} >&2

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in                #(
  CYGWIN* )         cygwin=true  ;; #(
  Darwin* )         darwin=true  ;; #(
  MSYS* | MINGW* )  msys=true    ;; #(
  NONSTOP* )        nonstop=true ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar


# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD=$JAVA_HOME/jre/sh/java
    else
        JAVACMD=$JAVA_HOME/bin/java
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD=java
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
    case $MAX_FD in #(
      max*)
        MAX_FD=$( ulimit -H -n ) ||
            warn "Could not query maximum file descriptor limit"
    esac
    case $MAX_FD in  #(
      '' | soft) :;; #(
      *)
        ulimit -n "$MAX_FD" ||
            warn "Could not set maximum file descriptor limit to $MAX_FD"
    esac
fi

# Collect all arguments for the java command, stacking in reverse order:
#   * args from the command line
#   * the main class name
#   * -classpath
#   * -D...appname settings
#   * --module-path (only if needed)
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.

# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )

    JAVACMD=$( cygpath --unix "$JAVACMD" )

    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    for arg do
        if
            case $arg in                                #(
              -*)   false ;;                            # don't mess with options #(
              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
                    [ -e "$t" ] ;;                      #(
              *)    false ;;
            esac
        then
            arg=$( cygpath --path --ignore --mixed "$arg" )
        fi
        # Roll the args list around exactly as many times as the number of
        # args, so each arg winds up back in the position where it started, but
        # possibly modified.
        #
        # NB: a `for` loop captures its iteration list before it begins, so
        # changing the positional parameters here affects neither the number of
        # iterations, nor the values presented in `arg`.
        shift                   # remove old arg
        set -- "$@" "$arg"      # push replacement arg
    done
fi

# Collect all arguments for the java command;
#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
#     shell script including quotes and variable substitutions, so put them in
#     double quotes to make sure that they get re-expanded; and
#   * put everything else in single quotes, so that it's not re-expanded.

set -- \
        "-Dorg.gradle.appname=$APP_BASE_NAME" \
        -classpath "$CLASSPATH" \
        org.gradle.wrapper.GradleWrapperMain \
        "$@"

# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
#   set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#

eval "set -- $(
        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
        xargs -n1 |
        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
        tr '\n' ' '
    )" '"$@"'

exec "$JAVACMD" "$@"


================================================
FILE: gradlew.bat
================================================
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem      https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem

@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto execute

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar


@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: intellij.pest.iml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
      <sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" />
      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="module" module-name="intellij.platform.core" />
    <orderEntry type="module" module-name="intellij.platform.execution" />
    <orderEntry type="module" module-name="intellij.platform.execution.impl" />
    <orderEntry type="module" module-name="intellij.platform.ide.core.impl" />
    <orderEntry type="module" module-name="intellij.platform.ide.impl" />
    <orderEntry type="module" module-name="intellij.php" />
    <orderEntry type="module" module-name="intellij.platform.analysis" />
    <orderEntry type="module" module-name="intellij.platform.jps.model" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.lang.core" />
    <orderEntry type="module" module-name="intellij.platform.projectModel" />
    <orderEntry type="module" module-name="intellij.platform.remote.core" />
    <orderEntry type="module" module-name="intellij.platform.structureView.impl" />
    <orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.util" />
    <orderEntry type="module" module-name="intellij.platform.indexing" />
    <orderEntry type="module" module-name="intellij.php.impl" />
    <orderEntry type="module" module-name="intellij.platform.analysis.impl" />
    <orderEntry type="module" module-name="intellij.platform.editor.ui" />
    <orderEntry type="module" module-name="intellij.platform.smRunner" />
    <orderEntry type="module" module-name="intellij.platform.ide.util.io" />
    <orderEntry type="module" module-name="intellij.platform.ide.core" />
    <orderEntry type="module" module-name="intellij.platform.lang" />
    <orderEntry type="module" module-name="intellij.platform.lang.impl" />
    <orderEntry type="module" module-name="intellij.xml.psi.impl" />
    <orderEntry type="module" module-name="intellij.libraries.fastutil" />
    <orderEntry type="module" module-name="intellij.xml.dom.impl" />
    <orderEntry type="module" module-name="intellij.platform.core.ui" />
    <orderEntry type="module" module-name="intellij.platform.core.impl" />
    <orderEntry type="module" module-name="intellij.platform.util.text.matching" />
    <orderEntry type="module" module-name="intellij.platform.util.ui" />
    <orderEntry type="library" scope="TEST" name="io.mockk" level="project" />
    <orderEntry type="library" scope="TEST" name="io.mockk.jvm" level="project" />
    <orderEntry type="module" module-name="intellij.platform.statistics" />
    <orderEntry type="module" module-name="intellij.platform.testRunner" />
  </component>
</module>

================================================
FILE: intellij.pest.tests.iml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$/src/test/kotlin">
      <sourceFolder url="file://$MODULE_DIR$/src/test/kotlin" isTestSource="true" />
    </content>
    <content url="file://$MODULE_DIR$/src/test/resources">
      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="module" module-name="intellij.platform.core" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.execution" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.execution.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.ide.core.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.ide.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.php" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.analysis" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.jps.model" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.lang.core" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.projectModel" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.remote.core" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.structureView.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.util" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.indexing" scope="TEST" />
    <orderEntry type="module" module-name="intellij.php.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.analysis.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.editor.ui" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.smRunner" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.ide.util.io" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.ide.core" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.lang" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.lang.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.xml.psi.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.libraries.fastutil" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.coverage" scope="TEST" />
    <orderEntry type="module" module-name="intellij.xml.dom.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.core.ui" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.core.impl" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.util.text.matching" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.util.ui" scope="TEST" />
    <orderEntry type="library" scope="TEST" name="io.mockk" level="project" />
    <orderEntry type="library" scope="TEST" name="io.mockk.jvm" level="project" />
    <orderEntry type="module" module-name="intellij.platform.statistics" scope="TEST" />
    <orderEntry type="module" module-name="intellij.platform.testRunner" scope="TEST" />
    <orderEntry type="module" module-name="intellij.pest" scope="TEST" />
  </component>
  <component name="TestModuleProperties" production-module="intellij.pest" />
</module>

================================================
FILE: plugin-content.yaml
================================================
- name: lib/modules/intellij.pest.coverage.jar
  contentModules:
  - name: intellij.pest.coverage
- name: lib/pest.jar
  modules:
  - name: intellij.pest

================================================
FILE: settings.gradle.kts
================================================
rootProject.name = "pest-intellij"

pluginManagement {
    repositories {
        maven {
            url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
        }
        gradlePluginPortal()
    }
}

================================================
FILE: src/main/java/com/pestphp/pest/PestIcons.java
================================================
package com.pestphp.pest;

import com.intellij.ui.IconManager;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;

/**
 * NOTE THIS FILE IS AUTO-GENERATED
 * DO NOT EDIT IT BY HAND, run "Generate icon classes" configuration instead
 */
public final class PestIcons {
  private static @NotNull Icon load(@NotNull String path, int cacheKey, int flags) {
    return IconManager.getInstance().loadRasterizedIcon(path, PestIcons.class.getClassLoader(), cacheKey, flags);
  }
  /** 16x16 */ public static final @NotNull Icon Config = load("config.svg", 710701582, 2);
  /** 16x16 */ public static final @NotNull Icon Dataset = load("dataset.svg", -1986461428, 2);
  /** 16x16 */ public static final @NotNull Icon File = load("file.svg", -1158724446, 2);
  /** 16x16 */ public static final @NotNull Icon Logo = load("logo.svg", -2116012898, 2);

  public static final class METAINF {
    /** 16x16 */ public static final @NotNull Icon PluginIcon = load("META-INF/pluginIcon.svg", 1914567053, 0);
  }

  /** 16x16 */ public static final @NotNull Icon Run = load("run.svg", -452832596, 2);
  /** 16x16 */ public static final @NotNull Icon RunWithMutate = load("runWithMutate.svg", 226904416, 2);
}


================================================
FILE: src/main/java/com/pestphp/pest/configuration/PestRunConfigurationSettings.java
================================================
package com.pestphp.pest.configuration;

import com.intellij.util.xmlb.annotations.Property;
import com.intellij.util.xmlb.annotations.Transient;
import com.jetbrains.php.testFramework.run.PhpTestRunConfigurationSettings;
import com.jetbrains.php.testFramework.run.PhpTestRunnerSettings;
import org.jetbrains.annotations.NotNull;

public class PestRunConfigurationSettings extends PhpTestRunConfigurationSettings {
  @Override
  protected @NotNull PestRunnerSettings createDefault() {
    return new PestRunnerSettings();
  }

  @Property(surroundWithTag = false)
  public @NotNull PestRunnerSettings getPestRunnerSettings() {
    final PhpTestRunnerSettings settings = super.getRunnerSettings();
    if (settings instanceof PestRunnerSettings) {
      return (PestRunnerSettings)settings;
    }

    final PestRunnerSettings copy = PestRunnerSettings.fromPhpTestRunnerSettings(settings);
    setPestRunnerSettings(copy);
    return copy;
  }

  public void setPestRunnerSettings(PestRunnerSettings runnerSettings) {
    setRunnerSettings(runnerSettings);
  }

  /**
   * @deprecated Use {@link #getPestRunnerSettings()}
   **/
  @Deprecated
  @Transient
  @Override
  public @NotNull PhpTestRunnerSettings getRunnerSettings() {
    return super.getRunnerSettings();
  }
}


================================================
FILE: src/main/java/com/pestphp/pest/configuration/PhpTestRunConfiguration.java
================================================
package com.pestphp.pest.configuration;

import com.intellij.execution.BeforeRunTask;
import com.intellij.execution.configurations.ConfigurationFactory;
import com.intellij.openapi.project.Project;
import com.jetbrains.php.PhpTestFrameworkVersionDetector;
import com.jetbrains.php.testFramework.PhpTestFrameworkType;
import com.jetbrains.php.testFramework.run.PhpTestRunConfigurationHandler;
import com.jetbrains.php.testFramework.run.PhpTestRunnerSettingsValidator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;

public abstract class PhpTestRunConfiguration extends com.jetbrains.php.testFramework.run.PhpTestRunConfiguration {
    protected PhpTestRunConfiguration(Project project, ConfigurationFactory factory, String name, @NotNull PhpTestFrameworkType frameworkType, @NotNull PhpTestRunnerSettingsValidator validator, @NotNull PhpTestRunConfigurationHandler handler, @Nullable PhpTestFrameworkVersionDetector versionDetector) {
        super(project, factory, name, frameworkType, validator, handler, versionDetector);
    }

    @Override
    public void setBeforeRunTasks(@NotNull List<BeforeRunTask<?>> value) {
        super.setBeforeRunTasks(value);
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/FileUtil.kt
================================================
package com.pestphp.pest

import com.intellij.psi.PsiFile
import com.intellij.testFramework.LightVirtualFile

/**
 * Takes care of getting the path of a file even if it's a light file.
 */
val PsiFile.realPath: String
    get() {
        var virtualFile = this.viewProvider.virtualFile
        if (virtualFile is LightVirtualFile && virtualFile.originalFile != null) {
            virtualFile = virtualFile.originalFile
        }
        return virtualFile.path
    }

================================================
FILE: src/main/kotlin/com/pestphp/pest/PestBundle.kt
================================================
package com.pestphp.pest

import com.intellij.DynamicBundle
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.PropertyKey
import java.util.function.Supplier

@NonNls
private const val BUNDLE = "messages.pestBundle"

object PestBundle : DynamicBundle(BUNDLE) {
    @Suppress("SpreadOperator")
    @JvmStatic
    fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = getMessage(key, *params)

    @JvmStatic
    fun messagePointer(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): Supplier<String> {
        return getLazyMessage(key, *params)
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/PestComposerConfig.kt
================================================
package com.pestphp.pest

import com.intellij.execution.configurations.ConfigurationType
import com.jetbrains.php.testFramework.PhpTestFrameworkComposerConfig
import com.pestphp.pest.configuration.PestRunConfigurationType.Companion.instance

class PestComposerConfig : PhpTestFrameworkComposerConfig(PestFrameworkType.instance, PACKAGE, RELATIVE_PATH) {
    override fun getDefaultConfigName(): String {
        return "phpunit.xml"
    }

    override fun getConfigurationType(): ConfigurationType {
        return instance
    }

    companion object {
        private const val PACKAGE = "pestphp/pest"
        private const val RELATIVE_PATH = "pestphp/pest/bin/pest"
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/PestFrameworkType.kt
================================================
package com.pestphp.pest

import com.intellij.openapi.project.Project
import com.jetbrains.php.testFramework.PhpTestDescriptor
import com.jetbrains.php.testFramework.PhpTestFrameworkFormDecorator
import com.jetbrains.php.testFramework.PhpTestFrameworkFormDecorator.PhpDownloadableTestFormDecorator
import com.jetbrains.php.testFramework.PhpTestFrameworkType
import com.jetbrains.php.testFramework.ui.PhpTestFrameworkBaseConfigurableForm
import com.jetbrains.php.testFramework.ui.PhpTestFrameworkBySdkConfigurableForm
import com.jetbrains.php.testFramework.ui.PhpTestFrameworkConfigurableForm
import com.pestphp.pest.configuration.PestVersionDetector
import org.jetbrains.annotations.Nls
import org.jetbrains.annotations.NonNls
import javax.swing.Icon

/**
 * Registers a framework type for PHP.
 *
 * This class is used to show the menu in
 * `Preferences -> Languages & Frameworks -> PHP -> Test Frameworks`
 */
class PestFrameworkType : PhpTestFrameworkType() {
    private val pestUrl = "https://github.com/pestphp/pest/releases"

    override fun getDisplayName(): @Nls String {
        return PestBundle.message("FRAMEWORK_NAME")
    }

    override fun getID(): String {
        return ID
    }

    override fun getIcon(): Icon {
        return PestIcons.Logo
    }

    override fun getDecorator(): PhpTestFrameworkFormDecorator {
        return object : PhpDownloadableTestFormDecorator(pestUrl) {
            override fun decorate(
                project: Project,
                form: PhpTestFrameworkBaseConfigurableForm<*>
            ): PhpTestFrameworkConfigurableForm<*> {
                if (form !is PhpTestFrameworkBySdkConfigurableForm) {
                    form.setVersionDetector(PestVersionDetector.instance)
                }
                return super.decorate(project, form)
            }
        }
    }

    override fun getDescriptor(): PhpTestDescriptor {
        return PestTestDescriptor
    }

    companion object {
        @NonNls
        val ID = "Pest"
        val instance: PhpTestFrameworkType
            get() = getTestFrameworkType(ID)
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/PestFunctionsUtil.kt
================================================
package com.pestphp.pest

import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.jetbrains.php.PhpIndex
import com.jetbrains.php.lang.psi.elements.FieldReference
import com.jetbrains.php.lang.psi.elements.Function
import com.jetbrains.php.lang.psi.elements.FunctionReference
import com.jetbrains.php.lang.psi.elements.GroupStatement
import com.jetbrains.php.lang.psi.elements.MethodReference
import com.jetbrains.php.lang.psi.elements.PhpExpression
import com.jetbrains.php.lang.psi.elements.PhpNamespace
import com.jetbrains.php.lang.psi.elements.PhpPsiElement
import com.jetbrains.php.lang.psi.elements.Statement
import com.jetbrains.php.lang.psi.elements.impl.FunctionReferenceImpl
import com.jetbrains.php.lang.psi.resolve.types.PhpType

val PEST_TEST_CALL_TYPE = PhpType.from(
    "\\Pest\\PendingCalls\\TestCall", // for Pest versions >= 2.x
    "\\Pest\\PendingObjects\\TestCall" // for Pest versions 1.x
)

fun PsiElement?.isPestTestReference(isSmart: Boolean = false): Boolean {
    return when (this) {
        null -> false
        is MethodReference -> this.isPestTestMethodReference(isSmart)
        is FunctionReferenceImpl -> this.isPestTestFunction(isSmart)
        else -> false
    }
}

private val testNames = setOf("it", "test", "todo", "describe", "arch")
fun FunctionReferenceImpl.isPestTestFunction(isSmart: Boolean = false): Boolean {
    if (this.canonicalText !in testNames) return false
    return !isSmart || (this.resolveLocal().isEmpty() && PhpIndex.getInstance(project).getFunctionsByName(this.canonicalText).any { function ->
        PEST_TEST_CALL_TYPE.isConvertibleFromGlobal(project, function.type)
    })
}

fun FunctionReferenceImpl.isPestBeforeFunction(): Boolean {
    return this.canonicalText == "beforeEach"
}

fun FunctionReferenceImpl.isPestAfterFunction(): Boolean {
    return this.canonicalText == "afterEach"
}

private val allPestNames = setOf("it", "test", "todo", "beforeEach", "afterEach", "dataset", "describe", "arch")
fun FunctionReferenceImpl.isAnyPestFunction(): Boolean {
    return this.canonicalText in allPestNames
}

fun FunctionReferenceImpl.isDescribeFunction(): Boolean {
    return this.canonicalText == "describe"
}


fun MethodReference.isPestTestMethodReference(isSmart: Boolean = false): Boolean {
    return when (val reference = classReference) {
        is FunctionReferenceImpl -> reference.isPestTestFunction(isSmart)
        is MethodReference -> reference.isPestTestMethodReference(isSmart)
        is FieldReference -> reference.isPestTestMethodReference(isSmart)
        else -> false
    }
}

fun FieldReference.isPestTestMethodReference(isSmart: Boolean = false): Boolean {
    return when (val reference = classReference) {
        is FunctionReferenceImpl -> reference.isPestTestFunction(isSmart)
        is MethodReference -> reference.isPestTestMethodReference(isSmart)
        is FieldReference -> reference.isPestTestMethodReference(isSmart)
        else -> false
    }
}

fun PsiFile.getRoot(): List<PsiElement> {
    val element = this.firstChild

    return element.children.filterIsInstance<PhpNamespace>()
        .mapNotNull { it.statements }
        .getOrElse(
            0
        ) { element }
        .children
        .filterIsInstance<Statement>()
        .mapNotNull { it.firstChild }
}

/**
 * Traverses elements and recursively enters describe blocks, collecting items via the collector function.
 */
internal fun <T> collectFromDescribeBlocks(
    elements: List<PhpPsiElement>,
    collector: (PhpPsiElement) -> T?
): List<T> {
    val result = mutableListOf<T>()

    for (element in elements) {
        collector(element)?.let { result.add(it) }

        val funcRef = element as? FunctionReferenceImpl
        if (funcRef != null && funcRef.isDescribeFunction()) {
            val closure = (funcRef.parameters.getOrNull(1) as? PhpExpression)?.firstChild as? Function
            val body = closure?.children?.filterIsInstance<GroupStatement>()?.firstOrNull()
            val statements = body?.statements?.mapNotNull { it.firstChild }?.filterIsInstance<PhpPsiElement>() ?: emptyList()
            result.addAll(collectFromDescribeBlocks(statements, collector))
        }
    }

    return result
}

fun PsiFile.getPestTests(isSmart: Boolean = false): Set<FunctionReference> {
    return collectFromDescribeBlocks(this.getRootPhpPsiElements()) { element ->
        if (element.isPestTestReference(isSmart)) element as? FunctionReference else null
    }.toSet()
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/PestIconProvider.kt
================================================
package com.pestphp.pest

import com.intellij.ide.FileIconProvider
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiManager
import com.jetbrains.php.lang.psi.PhpFile
import com.pestphp.pest.features.datasets.isIndexedPestDatasetFile
import javax.swing.Icon

class PestIconProvider : FileIconProvider {
    override fun getIcon(vFile: VirtualFile, flags: Int, project: Project?): Icon? {
        if (project == null || DumbService.isDumb(project)) return null
        val file = PsiManager.getInstance(project).findFile(vFile) as? PhpFile ?: return null
        if (file.isIndexedPestTestFile()) {
            return PestIcons.File
        }
        if (file.isIndexedPestDatasetFile()) {
           return PestIcons.Dataset
        }
        if (file.isPestFile()) {
            return PestIcons.Logo
        }
        return null
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/PestNamingUtil.kt
================================================
package com.pestphp.pest

import com.intellij.psi.PsiElement
import com.intellij.psi.util.findParentOfType
import com.intellij.psi.util.parents
import com.intellij.remote.RemoteSdkProperties
import com.jetbrains.php.config.interpreters.PhpInterpretersManagerImpl
import com.jetbrains.php.lang.psi.elements.ArrayCreationExpression
import com.jetbrains.php.lang.psi.elements.ClassConstantReference
import com.jetbrains.php.lang.psi.elements.ClassReference
import com.jetbrains.php.lang.psi.elements.ConcatenationExpression
import com.jetbrains.php.lang.psi.elements.FunctionReference
import com.jetbrains.php.lang.psi.elements.MethodReference
import com.jetbrains.php.lang.psi.elements.ParameterListOwner
import com.jetbrains.php.lang.psi.elements.PhpPsiElement
import com.jetbrains.php.lang.psi.elements.PhpReference
import com.jetbrains.php.lang.psi.elements.Statement
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression
import com.jetbrains.php.lang.psi.elements.impl.FunctionReferenceImpl
import com.jetbrains.php.run.remote.PhpRemoteInterpreterManager
import com.jetbrains.php.util.pathmapper.PhpPathMapper
import com.pestphp.pest.runner.getLocationUrl
import java.util.Locale

fun FunctionReferenceImpl.getPestTestName(): String? {
    val testName = getParameter(0)?.stringValue ?: return tryGetArchTestName(this)

    val parent = this.findParentOfType<FunctionReferenceImpl>()
    val prepend = if (parent is FunctionReferenceImpl && parent.isDescribeFunction()) {
        parent.getPestTestName()
    } else {
        ""
    }

    return when (this.canonicalText) {
        "it" -> "${prepend}it $testName"
        "describe" -> "${prepend}`$testName` → "
        else -> "${prepend}$testName"
    }
}

private fun tryGetArchTestName(functionReference: FunctionReference): String? =
    if (functionReference.canonicalText == "arch") {
        getArchTestName(functionReference)
    } else {
        null
    }

private fun getArchTestName(functionReference: FunctionReference): String {
    val parents = functionReference.parents(false).takeWhile { it !is Statement }.toList()
    return parents.joinToString(separator = " → ") { element ->
        val name = if (element is PhpReference) element.canonicalText else element.text
        val parameters = if (element is ParameterListOwner) getParametersString(element) else ""
        "$name$parameters"
    }
}

private fun getParametersString(element: ParameterListOwner) =
    " " + when (val elem = element.parameters.firstOrNull()) {
        is ArrayCreationExpression -> elem.children.filterIsInstance<PhpPsiElement>().joinToString(prefix = "[", postfix = "]") { it.text }
        is StringLiteralExpression -> elem.text
        else -> ""
    }.replace("\"", "'")

val PsiElement.stringValue: String?
    get() = when (this) {
        is StringLiteralExpression -> this.contents
        is ConcatenationExpression -> this.contents
        is ClassConstantReference -> {
            val classRef = this.classReference
            if (classRef is ClassReference && this.isStatic && this.lastChild.text == "class") {
                classRef.fqn
                    ?.removePrefix("\\")
                    ?.replace("\\", "\\\\")
            } else null
        }
        else -> null
    }

val ConcatenationExpression.contents: String?
    get() {
        val left = this.leftOperand?.stringValue
        val right = this.rightOperand?.stringValue

        if (left === null || right === null) {
            return null
        }

        return left + right
    }

fun PsiElement?.getPestTestName(): String? {
    return when (this) {
        is MethodReference -> (this.classReference as? FunctionReference)?.getPestTestName()
        is FunctionReferenceImpl -> this.getPestTestName()
        else -> null
    }
}

fun PsiElement?.getInitialFunctionReference(): FunctionReference? {
    return when (this) {
        is MethodReference -> (this.classReference as? FunctionReference).getInitialFunctionReference()
        is FunctionReferenceImpl -> this
        else -> null
    }
}

fun PsiElement.toPestTestRegex(workingDirectory: String): String? {
    return this.getPestTestName()?.toPestTestRegex(
        workingDirectory,
        this.containingFile.virtualFile.path,
        PhpPathMapper.create(this.project)
    )
}

fun PsiElement.toPestFqn(): List<String> {
    val testName = this.getPestTestName() ?: return emptyList()

    val file = this.containingFile.virtualFile.path

    return PhpInterpretersManagerImpl.getInstance(this.project)
        .interpreters
        .asSequence()
        .map { it.phpSdkAdditionalData }
        .filter { it is RemoteSdkProperties }
        .mapNotNull {
            PhpRemoteInterpreterManager.getInstance()?.createPathMappings(
                this.project,
                it
            )
        }
        .map { it.convertToRemote(file) }
        .map { "pest_qn://$it::$testName" }
        .plus("${getLocationUrl(this.containingFile)}::$testName")
        .toList()
}

fun String.toPestTestRegex(rootPath: String, file: String, pathMapper: PhpPathMapper): String {
    val mappedWorkingDirectory = pathMapper.getRemoteFilePath(rootPath) ?: rootPath
    val mappedFile = pathMapper.getRemoteFilePath(file) ?: file

    // Follow the steps for class name generation
    // 1. Take the path of the PEST file from the cwd.
    val fqn = mappedFile.withoutFirstFileSeparator
        .removePrefix(mappedWorkingDirectory.withoutFirstFileSeparator)
        .withoutFirstFileSeparator
        // 2. Make the first folder's first letter uppercase.
        .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
        // 3. Remove file extension (.php) and compound suffixes (.test, .spec, etc.) from filename.
        .removeSuffix(".php")
        .let { path ->
            truncateAtFirstDot(path)
        }
        // 4. Make directory separators to namespace separators.
        .replace("\\", "\\\\")
        .replace("/", "\\\\")
        // 5. Remove unsupported characters (keep only alphanumeric and escaped backslashes).
        .replace(Regex("[^A-Za-z0-9\\\\]"), "")
        // 6. Add P as a namespace before the generated namespace.
        .let { "(P\\\\)?$it" }

    // Allow substring matching only for "describe" block execution
    val possibleEndOfLine = if (this.endsWith(" → ")) "" else "$"

    // Escape characters
    val testName = this
        .replace(" ", "\\s")
        .replace("(", "\\(")
        .replace(")", "\\)")
        .replace("[", "\\[")
        .replace("]", "\\]")
        .replace("^", "\\^")
        .replace("/", "\\/")
        .replace("?", "\\?")
        .replace("+", "\\+")

    // Match the description of a single data set
    val dataSet = """(data\sset\s".*"|\(.*\))"""

    return """^$fqn::$testName(\swith\s$dataSet(\s\/\s$dataSet)*(\s#\d+)?)?$possibleEndOfLine"""
}

private fun truncateAtFirstDot(path: String): String {
    val lastSep = maxOf(path.lastIndexOf('/'), path.lastIndexOf('\\'))
    return if (lastSep >= 0) {
        val dir = path.substring(0, lastSep + 1)
        val filename = path.substring(lastSep + 1).substringBefore('.')
        dir + filename
    }
    else {
        path.substringBefore('.')
    }
}

val String.withoutFirstFileSeparator: String
    get() {
        return this.removePrefix("/").removePrefix("\\")
    }


================================================
FILE: src/main/kotlin/com/pestphp/pest/PestNewTestFromClassAction.kt
================================================
package com.pestphp.pest

import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.jetbrains.php.phpunit.codeGeneration.PhpNewTestAction
import com.jetbrains.php.testFramework.PhpTestCreateInfo

open class PestNewTestFromClassAction: PhpNewTestAction(PestBundle.messagePointer("action.Pest.New.File.text"),
                                                   PestBundle.messagePointer("ACTIONS_NEW_PEST_TEST_ACTION_DESCRIPTION"),
                                                   PestIcons.Logo) {
    override fun getDefaultTestCreateInfo(project: Project, locationContext: VirtualFile?): PhpTestCreateInfo {
        return PestTestCreateInfo
    }
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/PestPluginDisposable.kt
================================================
package com.pestphp.pest

import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project

/**
 * The service is intended to be used instead of a project/application as a parent disposable.
 */
@Service(Service.Level.APP, Service.Level.PROJECT)
class PestPluginDisposable : Disposable {
    override fun dispose() {}

    companion object {
        @JvmStatic
        fun getInstance(): Disposable = ApplicationManager.getApplication().getService(PestPluginDisposable::class.java)

        @JvmStatic
        fun getInstance(project: Project): Disposable = project.getService(PestPluginDisposable::class.java)
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/PestSettings.kt
================================================
package com.pestphp.pest

import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.xmlb.XmlSerializerUtil
import com.pestphp.pest.parser.PestConfigurationFile
import com.pestphp.pest.parser.PestConfigurationFileParser

@Service(Service.Level.PROJECT)
@State(name = "PestSettings", storages = [Storage("pest.xml")])
class PestSettings : PersistentStateComponent<PestSettings> {
    var pestFilePath = "tests/Pest.php"
    var preferredTestFlavor =  TestFlavor.IT

    enum class TestFlavor {
        IT,
        TEST
    }

    override fun getState(): PestSettings {
        return this
    }

    override fun loadState(state: PestSettings) {
        XmlSerializerUtil.copyBean(state, this)
    }

    private val parser = PestConfigurationFileParser(this)

    fun getPestConfiguration(project: Project, virtualFile: VirtualFile? = null): PestConfigurationFile {
        return parser.parse(project, virtualFile)
    }

    companion object {
        fun getInstance(project: Project): PestSettings {
            return project.service()
        }
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/PestTestCreateInfo.kt
================================================
package com.pestphp.pest

import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
import com.jetbrains.php.lang.psi.elements.FunctionReference
import com.jetbrains.php.testFramework.PhpUnitAbstractTestCreateInfo
import com.pestphp.pest.inspections.convertTestNameToSentenceCase
import javax.swing.Icon

const val INTERNAL_PEST_FILE_TEMPLATE_NAME = "Pest file from class"

object PestTestCreateInfo : PhpUnitAbstractTestCreateInfo() {
    override fun getName(): String {
        return "Pest"
    }

    override fun getTemplateName(): String {
        return INTERNAL_PEST_FILE_TEMPLATE_NAME
    }

    override fun getIcon(): Icon {
        return PestIcons.Logo
    }

    override fun getTestMethodText(project: Project, classFqn: String, methodName: String): String {
        return "test('${convertTestNameToSentenceCase(methodName)}', function(){})"
    }

    override fun shouldPostprocessTemplateFile(): Boolean {
        return true
    }

    override fun postprocessTemplateFile(file: PsiFile) {
        val test = PsiTreeUtil.findChildOfType(file, FunctionReference::class.java)
        test?.parent?.delete()
    }
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/PestTestDescriptor.kt
================================================
package com.pestphp.pest

import com.intellij.util.SmartList
import com.jetbrains.php.lang.psi.elements.Method
import com.jetbrains.php.lang.psi.elements.PhpClass
import com.jetbrains.php.phpunit.PhpUnitTestDescriptor
import com.jetbrains.php.testFramework.PhpTestCreateInfo
import java.util.Collections

/**
 * findTests, findClasses, and findMethods return empty collections,
 * since Pest tests are function calls, not methods, and therefore are not located in PHP classes
 */
object PestTestDescriptor : PhpUnitTestDescriptor() {
    override fun findTests(clazz: PhpClass): MutableCollection<PhpClass> {
        return Collections.emptySet()
    }

    override fun findTests(method: Method): MutableCollection<Method> {
        return Collections.emptySet()
    }

    override fun findClasses(test: PhpClass, testName: String): MutableCollection<PhpClass> {
        return Collections.emptySet()
    }

    override fun findMethods(testMethod: Method): MutableCollection<Method> {
        return Collections.emptySet()
    }

    override fun getTestCreateInfos(): MutableCollection<PhpTestCreateInfo> {
        return SmartList(PestTestCreateInfo)
    }
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/PestTestFileUtil.kt
================================================
package com.pestphp.pest

import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiTreeUtil
import com.jetbrains.php.lang.psi.elements.AssignmentExpression
import com.jetbrains.php.lang.psi.elements.ClassConstantReference
import com.jetbrains.php.lang.psi.elements.ClassReference
import com.jetbrains.php.lang.psi.elements.FieldReference
import com.jetbrains.php.lang.psi.elements.Function
import com.jetbrains.php.lang.psi.elements.FunctionReference
import com.jetbrains.php.lang.psi.elements.MethodReference
import com.jetbrains.php.lang.psi.elements.ParameterList
import com.jetbrains.php.lang.psi.elements.Variable
import com.jetbrains.php.lang.psi.elements.impl.FunctionReferenceImpl
import com.jetbrains.php.lang.psi.resolve.types.PhpType

val CONFIGURATION_FUNCTIONS = listOf("pest", "uses")
val CONFIGURATION_METHODS = listOf("use", "uses", "extend", "extends")

fun PsiElement?.isThisVariableInPest(condition: (FunctionReferenceImpl) -> Boolean): Boolean {
    if ((this as? Variable)?.name != "this") return false

    var psiElement = this
    while (true) {
        val functionReference = getOuterFunctionReference(psiElement) ?: return false
        if (condition(functionReference)) {
            return true
        }
        psiElement = functionReference
    }
}

fun PsiElement?.isTestAsThisVariableInPest(condition: (FunctionReferenceImpl) -> Boolean): Boolean {
    val functionReference = this as? FunctionReference ?: return false

    if (functionReference.name != "test" || !functionReference.parameters.isEmpty()) return false

    return getOuterFunctionReference(this)?.let { functionReferenceImpl -> condition(functionReferenceImpl) } ?: false
}

private fun getOuterFunctionReference(element: PsiElement?): FunctionReferenceImpl? {
    val closure = PsiTreeUtil.getParentOfType(element, Function::class.java)

    if (closure == null || !closure.isClosure) return null

    val parameterList = closure.parent?.parent as? ParameterList ?: return null

    if (parameterList.parent !is FunctionReferenceImpl) return null

    return parameterList.parent as FunctionReferenceImpl
}

fun PsiFile.getAllBeforeThisAssignments(): List<AssignmentExpression> {
    return this.getRoot()
        .filterIsInstance<FunctionReferenceImpl>()
        .filter { it.isPestBeforeFunction() }
        .flatMap { it.getThisStatements() }
}

private val cacheKey = Key<CachedValue<List<AssignmentExpression>>>("com.pestphp.pest_assignments")
private fun FunctionReferenceImpl.getThisStatements(): List<AssignmentExpression> {
    return CachedValuesManager.getCachedValue(this, cacheKey) {
        val result = PsiTreeUtil.findChildrenOfType(
            this.parameterList?.getParameter(0),
            AssignmentExpression::class.java
        )
            .filter { ((it.variable as? FieldReference)?.classReference as? Variable)?.name == "this" }

        CachedValueProvider.Result.create(result, this)
    }
}

fun FunctionReference.getConfigurationPhpType(): PhpType? {
    if (this.name !in CONFIGURATION_METHODS) return PhpType()
    parameters.mapNotNull {
        val classRef = it as? ClassConstantReference ?: return@mapNotNull null

        if (classRef.name != "class") return@mapNotNull null

        (classRef.classReference as? ClassReference)?.fqn
    }.apply {
        if (this.isEmpty()) return null

        val res = PhpType()

        this.forEach {
            res.add(it)
        }

        return res
    }
}

fun FunctionReference.getPestConfigurationPhpType(): PhpType? {
    if (this is FunctionReferenceImpl && this.name in CONFIGURATION_FUNCTIONS) {
        return this.getConfigurationPhpType()
    }
    val classReference = (this as? MethodReference)?.classReference ?: return null
    if (classReference is FunctionReference) {
        val typeFromClassRef = classReference.getPestConfigurationPhpType()
        val typeFromParameters = this.getConfigurationPhpType()
        return PhpType().add(typeFromParameters).add(typeFromClassRef)
    }
    return null
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/PestTestRunLineMarkerProvider.kt
================================================
package com.pestphp.pest

import com.intellij.execution.lineMarker.RunLineMarkerContributor
import com.intellij.icons.AllIcons.RunConfigurations.TestState.Run
import com.intellij.icons.AllIcons.RunConfigurations.TestState.Run_run
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.jetbrains.php.lang.lexer.PhpTokenTypes
import com.jetbrains.php.lang.psi.PhpFile
import com.jetbrains.php.lang.psi.PhpPsiUtil
import com.jetbrains.php.lang.psi.elements.FunctionReference
import com.jetbrains.php.lang.psi.elements.Statement
import com.jetbrains.php.lang.psi.elements.impl.FunctionReferenceImpl

/**
 * Adds markers on the line on the left side for running a pest specific pest test.
 */
class PestTestRunLineMarkerProvider : RunLineMarkerContributor() {
    override fun getInfo(leaf: PsiElement): Info? {
        if (!leaf.containingFile.isPestTestFile(isSmart = true)) {
            return null
        }

        // Handle icons if the reference is a pest test.
        if (isPestTestReference(leaf)) {
            return getPestTest(
                leaf.parent as FunctionReferenceImpl,
                leaf.project,
            )
        }

        // Handle icon for running all tests in the file.
        if (PhpPsiUtil.isOfType(leaf, PhpTokenTypes.PHP_OPENING_TAG)) {
            return withExecutorActions(Run_run)
        }

        return null
    }

    private fun isPestTestReference(leaf: PsiElement): Boolean {
        if (PhpPsiUtil.isOfType(leaf, PhpTokenTypes.IDENTIFIER)) {
            (leaf.parent as? FunctionReferenceImpl)?.let { functionReference ->
                if (!functionReference.isAnyPestFunction()) {
                    return false
                }
                val statementChild = PhpPsiUtil.getParentOfClass(functionReference, true, Statement::class.java)?.firstChild
                val outerFunctionReference = PhpPsiUtil.getParentByCondition<FunctionReferenceImpl>(
                    statementChild,
                    { it is FunctionReferenceImpl },
                    PhpFile.INSTANCEOF
                )
                if (outerFunctionReference == null || outerFunctionReference.isDescribeFunction()) {
                    return statementChild is FunctionReference && statementChild.isPestTestReference(isSmart = true)
                }
            }
        }
        return false
    }

    private fun getPestTest(reference: FunctionReferenceImpl, project: Project): Info {
        val fqn = reference.toPestFqn()

        val icon = fqn.firstOrNull { getTestStateIcon(it, project, false) !== Run }
            ?.let { getTestStateIcon(it, project, false) } ?: Run

        return withExecutorActions(icon)
    }
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/PestUtil.kt
================================================
package com.pestphp.pest

import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.psi.search.ProjectScope
import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.util.indexing.FileBasedIndex
import com.jetbrains.php.composer.configData.ComposerConfigManager
import com.jetbrains.php.lang.psi.PhpExpressionCodeFragment
import com.jetbrains.php.lang.psi.PhpFile
import com.jetbrains.php.lang.psi.elements.PhpNamespace
import com.jetbrains.php.lang.psi.elements.PhpPsiElement
import com.jetbrains.php.lang.psi.elements.Statement
import com.jetbrains.php.phpunit.PhpUnitUtil
import com.jetbrains.php.testFramework.PhpTestFrameworkSettingsManager
import com.pestphp.pest.indexers.key

val PEST_TEST_FILE_KEY = Key<CachedValue<Boolean>>("isPestTestFile")
val PEST_TEST_FILE_SMART_KEY = Key<CachedValue<Boolean>>("smart isPestTestFile")

fun PsiFile.isPestTestFile(isSmart: Boolean = false): Boolean {
    if (this !is PhpFile || this is PhpExpressionCodeFragment) return false
    return CachedValuesManager.getCachedValue(this, if (isSmart) PEST_TEST_FILE_SMART_KEY else PEST_TEST_FILE_KEY) {
        val isPestTestFile = this.getRootPhpPsiElements().any { psiElement -> psiElement.isPestTestReference(isSmart) }
        CachedValueProvider.Result.create(isPestTestFile, this)
    }
}

fun PsiFile.isIndexedPestTestFile(): Boolean {
    return FileBasedIndex.getInstance().getValues(
        key,
        this.realPath,
        ProjectScope.getProjectScope(this.project)
    ).isNotEmpty() && this.isPestTestFile(isSmart = true)
}

fun PsiFile.isPestConfigurationFile(): Boolean {
    return PhpUnitUtil.isPhpUnitConfigurationFile(this)
}

fun Project.isPestEnabled(): Boolean {
    return PhpTestFrameworkSettingsManager
        .getInstance(this)
        .getConfigurations(PestFrameworkType.instance)
        .any { StringUtil.isNotEmpty(it.executablePath) }
}

fun PsiFile.getRootPhpPsiElements(): List<PhpPsiElement> {
    if (this !is PhpFile) return listOf()

    val element = this.firstChild

    return element.children.filterIsInstance<PhpNamespace>()
        .mapNotNull { it.statements }
        .getOrElse(
            0
        ) { element }
        .children
        .filterIsInstance<Statement>()
        .mapNotNull { it.firstChild }
        .filterIsInstance<PhpPsiElement>()
}

/**
 * Checks if the file is the `tests/Pest.php` file.
 */
fun PsiFile.isPestFile(): Boolean {
    val baseDir = getBaseDir(this.project, this.virtualFile) ?: return false

    val pestFilePath = PestSettings.getInstance(this.project).pestFilePath

    return this.virtualFile?.path == baseDir.path + "/" + pestFilePath
}

fun getBaseDir(project: Project, virtualFile: VirtualFile? = null): VirtualFile? {
    return ComposerConfigManager.getInstance(project).getConfig(virtualFile)?.parent
        ?: project.guessProjectDir()
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/annotator/PestAnnotator.kt
================================================
package com.pestphp.pest.annotator

import com.intellij.codeInsight.daemon.impl.HighlightRangeExtension
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.jetbrains.php.lang.psi.resolve.types.PhpParameterBasedTypeProvider

class PestAnnotator: Annotator, HighlightRangeExtension {
    override fun annotate(element: PsiElement, holder: AnnotationHolder) {
        if (PhpParameterBasedTypeProvider.isMeta(holder.currentAnnotationSession.file)) return
        element.accept(PestAnnotatorVisitor(holder))
    }

    override fun isForceHighlightParents(psiFile: PsiFile): Boolean {
        return false
    }
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/annotator/PestAnnotatorVisitor.kt
================================================
package com.pestphp.pest.annotator

import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.modcommand.ModCommandAction
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.indexing.FileBasedIndex
import com.jetbrains.php.lang.annotator.PhpAnnotatorVisitor.createErrorAnnotation
import com.jetbrains.php.lang.annotator.PhpDeleteElementQuickFix
import com.jetbrains.php.lang.inspections.controlFlow.PhpNavigateToElementQuickFix
import com.jetbrains.php.lang.psi.PhpFile
import com.jetbrains.php.lang.psi.PhpPsiUtil
import com.jetbrains.php.lang.psi.elements.FunctionReference
import com.jetbrains.php.lang.psi.elements.MethodReference
import com.jetbrains.php.lang.psi.elements.impl.MethodReferenceImpl
import com.jetbrains.php.lang.psi.visitors.PhpElementVisitor
import com.pestphp.pest.PestBundle
import com.pestphp.pest.features.customExpectations.KEY
import com.pestphp.pest.features.customExpectations.extendName
import com.pestphp.pest.getPestTestName
import com.pestphp.pest.getPestTests

class PestAnnotatorVisitor(
    private val holder: AnnotationHolder
) : PhpElementVisitor() {
    override fun visitPhpMethodReference(reference: MethodReference) {
        checkDuplicateCustomExpectations(reference)
    }

    private fun checkDuplicateCustomExpectations(reference: MethodReference) {
        if (reference !is MethodReferenceImpl) {
            return
        }
        val extendName = reference.extendName ?: return
        val duplicates = mutableListOf<MethodReference>()
        FileBasedIndex.getInstance().processValues(KEY, extendName, null, { file, offsets ->
            reference.manager.findFile(file)?.let { psiFile ->
                offsets.forEach { offset ->
                    val expectation = psiFile.findElementAt(offset)
                    val methodDescriptor = PhpPsiUtil.getParentOfClass(expectation, MethodReference::class.java)
                    if (methodDescriptor != null) {
                        duplicates.add(methodDescriptor)
                    }
                }
            }
            true
        }, GlobalSearchScope.allScope(reference.project))
        if (duplicates.size > 1) {
            val fixes = listOfNotNull(
                PhpDeleteElementQuickFix(reference.parent, PestBundle.message("QUICK_FIX_DELETE_CUSTOM_EXPECTATION", extendName)),
                getNavigateToCustomExpectationFix(duplicates, reference)
            )
            val builder = holder.newAnnotation(
                HighlightSeverity.WARNING,
                PestBundle.message("INSPECTION_DUPLICATE_CUSTOM_EXPECTATION")
            ).range(reference)
            fixes.forEach { fix -> builder.withFix(fix.asIntention()) }
            builder.create()
        }
    }

    private fun getNavigateToCustomExpectationFix(
        duplicates: List<MethodReference>,
        duplicate: MethodReference
    ): ModCommandAction? {
        val duplicateIndex = duplicates.indexOf(duplicate)
        if (duplicateIndex == -1) {
            return null
        }
        val nextElement = duplicates[(duplicateIndex + 1) % duplicates.size]
        return PhpNavigateToElementQuickFix(
            nextElement,
            PestBundle.message("INTENTION_NAVIGATE_TO_DUPLICATE_CUSTOM_EXPECTATION")
        )
    }

    override fun visitPhpFile(phpFile: PhpFile) {
        checkDuplicateTestNames(phpFile)
    }

    private fun checkDuplicateTestNames(file: PhpFile) {
        file.getPestTests(isSmart = true)
            .groupBy { it.getPestTestName() }
            .filterKeys { it != null }
            .filter { it.value.count() > 1 }
            .forEach { (_, tests) ->
                tests.forEachIndexed { index, test ->
                    val testName = test.getPestTestName() ?: return@forEachIndexed
                    createErrorAnnotation(holder, test, PestBundle.message("INSPECTION_DUPLICATE_TEST_NAME"),
                                          PhpDeleteElementQuickFix(test.parent, PestBundle.message("QUICK_FIX_DELETE_TEST", testName)),
                                          getNavigateToTestNameFix(tests, index))
                }
            }
    }

    private fun getNavigateToTestNameFix(duplicates: List<FunctionReference>, duplicateIndex: Int): ModCommandAction {
        val nextElement = duplicates[(duplicateIndex + 1) % duplicates.size]
        return PhpNavigateToElementQuickFix(
            nextElement,
            PestBundle.message("INTENTION_NAVIGATE_TO_DUPLICATE_TEST_NAME")
        )
    }
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/completion/InternalMembersCompletionProvider.kt
================================================
package com.pestphp.pest.completion

import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.util.ProcessingContext
import com.jetbrains.php.PhpIndex
import com.jetbrains.php.completion.PhpVariantsUtil
import com.jetbrains.php.lang.psi.elements.FieldReference
import com.jetbrains.php.lang.psi.elements.Variable
import com.pestphp.pest.isAnyPestFunction
import com.pestphp.pest.isThisVariableInPest

/**
 * Adds completion for private and protected methods of `$this` variable
 * when inside a pest test.
 */
class InternalMembersCompletionProvider : CompletionProvider<CompletionParameters>() {
    override fun addCompletions(
        parameters: CompletionParameters,
        context: ProcessingContext,
        result: CompletionResultSet
    ) {
        val fieldReference = parameters.position.parent as? FieldReference ?: return

        val variable = fieldReference.classReference as? Variable ?: return

        if (!variable.isThisVariableInPest { it.isAnyPestFunction() }) return

        val phpIndex = PhpIndex.getInstance(fieldReference.project)
        val classes = phpIndex.completeType(fieldReference.project, variable.type, null).types
            .filter { it.startsWith("\\") }
            .flatMap {
                phpIndex.getAnyByFQN(it)
            }

        classes.flatMap { phpClass ->
            phpClass.methods.filter { it.access.isProtected || (!it.access.isPrivate && it.isStatic) }
        }.forEach {
            result.addElement(PhpVariantsUtil.getLookupItem(it, null))
        }

        classes.flatMap { phpClass ->
            phpClass.fields.filter { it.modifier.isProtected }
        }.forEach {
            result.addElement(PhpVariantsUtil.getLookupItem(it, null))
        }
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/completion/PestCompletionContributor.kt
================================================
package com.pestphp.pest.completion

import com.intellij.codeInsight.completion.CompletionContributor
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.patterns.PlatformPatterns
import com.jetbrains.php.lang.lexer.PhpTokenTypes
import com.jetbrains.php.lang.psi.elements.FieldReference
import com.jetbrains.php.lang.psi.elements.MemberReference

/**
 * Registers the completion providers
 */
private class PestCompletionContributor : CompletionContributor() {
    init {
        extend(
            CompletionType.BASIC,
            PlatformPatterns.psiElement()
                .withElementType(PhpTokenTypes.IDENTIFIER)
                .withParent(FieldReference::class.java),
            InternalMembersCompletionProvider()
        )

        extend(
            CompletionType.BASIC,
            PlatformPatterns.psiElement()
                .withElementType(PhpTokenTypes.IDENTIFIER)
                .withParent(FieldReference::class.java),
            ThisFieldsCompletionProvider()
        )

        extend(
            CompletionType.BASIC,
            PlatformPatterns.psiElement()
                .withParent(MemberReference::class.java),
            PestCustomExtensionCompletionProvider()
        )
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/completion/PestCustomExtensionCompletionProvider.kt
================================================
@file:Suppress("UnstableApiUsage")

package com.pestphp.pest.completion

import com.intellij.codeInsight.AutoPopupController
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.codeInsight.lookup.LookupElementPresentation
import com.intellij.codeInsight.lookup.LookupElementRenderer
import com.intellij.psi.PsiFile
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.ProcessingContext
import com.intellij.util.indexing.FileBasedIndex
import com.jetbrains.php.PhpIcons
import com.jetbrains.php.completion.PhpCompletionUtil
import com.jetbrains.php.completion.insert.PhpInsertHandlerUtil
import com.jetbrains.php.lang.psi.PhpPsiUtil
import com.jetbrains.php.lang.psi.elements.MemberReference
import com.jetbrains.php.lang.psi.elements.MethodReference
import com.jetbrains.php.lang.psi.resolve.types.PhpType
import com.pestphp.pest.features.customExpectations.KEY
import com.pestphp.pest.features.customExpectations.expectationType
import com.pestphp.pest.features.customExpectations.toMethod

class PestCustomExtensionCompletionProvider : CompletionProvider<CompletionParameters>() {
    override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
        val memberReference = parameters.position.originalElement.parent as? MemberReference ?: return
        val project = parameters.position.project
        if (PhpType.intersectsGlobal(project, expectationType, memberReference.classReference?.globalType ?: PhpType.EMPTY)) {
            val index = FileBasedIndex.getInstance()
            index.getAllKeys(KEY, project).forEach { extensionName ->
                index.processValues(KEY, extensionName, null, { file, value ->
                    memberReference.manager.findFile(file)?.let { psiFile ->
                        val cheapRenderer = CustomExpectationRenderer()
                        val lookupElement = LookupElementBuilder.create(extensionName)
                            .withRenderer(cheapRenderer)
                            .withExpensiveRenderer(CustomExtensionExpensiveRenderer(cheapRenderer, psiFile, value.first()))
                            .withInsertHandler { context, _ ->
                                val expectation = psiFile.findElementAt(value.first())
                                val methodDescriptor =
                                    PhpPsiUtil.getParentOfClass(expectation, MethodReference::class.java)?.toMethod()
                                PhpInsertHandlerUtil.insertStringAtCaret(context.editor, "()")
                                if (methodDescriptor?.parameters?.isNotEmpty() == true) {
                                    PhpCompletionUtil.moveCaretRelativelyWithScroll(context.editor, -1)
                                    AutoPopupController.getInstance(project).autoPopupParameterInfo(context.editor, null)
                                }
                            }
                        result.addElement(lookupElement)
                    }
                    true
                }, GlobalSearchScope.projectScope(project))
            }
        }
    }
}

private class CustomExpectationRenderer : LookupElementRenderer<LookupElement>() {
    override fun renderElement(element: LookupElement, presentation: LookupElementPresentation) {
        presentation.icon = PhpIcons.METHOD
        presentation.itemText = element.lookupString
        presentation.isItemTextBold = true
    }
}

private class CustomExtensionExpensiveRenderer(
    private val cheapRenderer: CustomExpectationRenderer,
    private val targetFile: PsiFile,
    private val expectationOffset: Int
) : LookupElementRenderer<LookupElement>() {
    override fun renderElement(element: LookupElement, presentation: LookupElementPresentation) {
        cheapRenderer.renderElement(element, presentation)
        val expectation = targetFile.findElementAt(expectationOffset)
        PhpPsiUtil.getParentOfClass(expectation, MethodReference::class.java)?.toMethod()?.let {
            val params = it.parameters.map { p ->
                if (p.returnType.isEmpty) {
                    p.name
                } else {
                    "${p.name}: ${p.returnType}"
                }
            }
            presentation.tailText = "(${params.joinToString(", ")})"
            presentation.typeText = it.returnType.global(targetFile.project).toString()
        }
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/completion/ThisFieldsCompletionProvider.kt
================================================
package com.pestphp.pest.completion

import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import com.intellij.psi.util.elementType
import com.intellij.util.ProcessingContext
import com.jetbrains.php.PhpIcons
import com.jetbrains.php.lang.lexer.PhpTokenTypes
import com.jetbrains.php.lang.psi.elements.FieldReference
import com.jetbrains.php.lang.psi.elements.Variable
import com.pestphp.pest.getAllBeforeThisAssignments
import com.pestphp.pest.isAnyPestFunction
import com.pestphp.pest.isThisVariableInPest

/**
 * Adds completion for variable assignments from `beforeEach` when using `$this`
 * inside a pest test.
 */
internal class ThisFieldsCompletionProvider : CompletionProvider<CompletionParameters>(), GotoDeclarationHandler {
    override fun addCompletions(
        parameters: CompletionParameters,
        context: ProcessingContext,
        result: CompletionResultSet
    ) {
        val fieldReference = parameters.position.parent as? FieldReference ?: return

        val variable = fieldReference.classReference as? Variable ?: return

        if (!variable.isThisVariableInPest { it.isAnyPestFunction() }) return

        return (fieldReference.containingFile).getAllBeforeThisAssignments()
            .filter { it.variable?.name !== null }
            .forEach {
                result.addElement(
                    LookupElementBuilder.create(it.variable!!.name!!)
                        .withIcon(PhpIcons.FIELD)
                        .withTypeText(it.type.toStringRelativized("\\"))
                )
            }
    }

    override fun getGotoDeclarationTargets(
        sourceElement: PsiElement?,
        offset: Int,
        editor: Editor?
    ): Array<PsiElement> {
        if (sourceElement?.elementType != PhpTokenTypes.IDENTIFIER) {
            return PsiElement.EMPTY_ARRAY
        }

        val fieldReference = sourceElement?.parent as? FieldReference
            ?: return PsiElement.EMPTY_ARRAY

        if (fieldReference.classReference?.isThisVariableInPest { it.isAnyPestFunction() } != true) {
            return PsiElement.EMPTY_ARRAY
        }

        return (fieldReference.containingFile ?: return PsiElement.EMPTY_ARRAY).getAllBeforeThisAssignments()
            .filter { it.variable?.name == fieldReference.name }
            .mapNotNull { it.variable }
            .toTypedArray()
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/configuration/PestDebugRunner.kt
================================================
package com.pestphp.pest.configuration

import com.jetbrains.php.testFramework.run.PhpTestDebugRunner

/**
 * Add support for Php's debug runners.
 */
class PestDebugRunner private constructor() :
    PhpTestDebugRunner<PestRunConfiguration>(PestRunConfiguration::class.java) {
    override fun getRunnerId(): String {
        return "PestDebugRunner"
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/configuration/PestLocationProvider.kt
================================================
package com.pestphp.pest.configuration

import com.intellij.execution.Location
import com.intellij.execution.testframework.sm.runner.SMTestLocator
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.search.GlobalSearchScope
import com.jetbrains.php.lang.psi.PhpFile
import com.jetbrains.php.phpunit.PhpPsiLocationWithDataSet
import com.jetbrains.php.phpunit.PhpUnitQualifiedNameLocationProvider
import com.jetbrains.php.util.pathmapper.PhpLocalPathMapper
import com.jetbrains.php.util.pathmapper.PhpPathMapper
import com.pestphp.pest.features.parallel.convertRuntimeTestNameToRealTestName
import com.pestphp.pest.getPestTestName
import com.pestphp.pest.getPestTests
import com.pestphp.pest.runner.LocationInfo
import java.io.File

private const val PARALLEL_EXECUTION_URL_MARKER = "eval()'d code::"

/**
 * Adds support for goto test from test results.
 */
class PestLocationProvider(
    val pathMapper: PhpPathMapper,
    private val project: Project,
    private val configurationFileRootPath: String? = null
) : SMTestLocator {
    private val phpUnitLocationProvider = PhpUnitQualifiedNameLocationProvider.create(pathMapper)

    override fun getLocation(
        protocol: String,
        path: String,
        project: Project,
        scope: GlobalSearchScope
    ): MutableList<Location<PsiElement>> {
        val isParallelExecution = path.contains(PARALLEL_EXECUTION_URL_MARKER)
        if (protocol != PROTOCOL_ID && !isParallelExecution) {
            return phpUnitLocationProvider.getLocation(protocol, path, project, scope)
        }

        val locationInfo = if (isParallelExecution) getParallelLocationInfo(path) else getLocationInfo(path)
        val element = locationInfo?.let { findElement(it, project) } ?: return mutableListOf()

        return mutableListOf(
            PhpPsiLocationWithDataSet(
                project,
                element,
                getDataSet(locationInfo)
            )
        )
    }

    private fun getDataSet(locationInfo: LocationInfo): String? {
        return locationInfo.testName
    }

    private fun getLocationInfo(link: String): LocationInfo? {
        val location = link.split("::")
        return resolveLocationInfo(location)
    }

    private fun getParallelLocationInfo(link: String): LocationInfo? {
        val rawParallelLocation = link.substringAfter(PARALLEL_EXECUTION_URL_MARKER).split("::")
        val location = listOfNotNull(
            convertLocationHintClassNameToFileName(rawParallelLocation[0]),
            rawParallelLocation.getOrNull(1)?.let { runtimeTestName -> convertRuntimeTestNameToRealTestName(runtimeTestName) }
        )
        return resolveLocationInfo(location)
    }

    private fun resolveLocationInfo(location: List<String>): LocationInfo? {
        val fileUrl = calculateFileUrl(location[0])
        val testName = location.getOrNull(1)
        val file = this.pathMapper.getLocalFile(fileUrl) ?: PhpLocalPathMapper(project).getLocalFile(fileUrl)
        return file?.let { LocationInfo(it, testName) }
    }

    private fun findElement(locationInfo: LocationInfo, project: Project): PsiElement? {
        return this.getLocation(
            project,
            locationInfo.file,
            locationInfo.testName
        )
    }

    private fun getLocation(project: Project, virtualFile: VirtualFile, testName: String?): PsiElement? {
        val file = PsiManager.getInstance(project).findFile(virtualFile) ?: return null

        if (testName == null) {
            return file
        }

        return (file as PhpFile).getPestTests().firstOrNull { it.getPestTestName() == testName }
    }

    override fun getLocation(
        stacktraceLine: String,
        project: Project,
        scope: GlobalSearchScope
    ): MutableList<Location<PsiElement>> {
        return mutableListOf()
    }

    fun calculateFileUrl(locationOutput: String): String {
        val pathPrefix = configurationFileRootPath ?: project.basePath
        return if (pathPrefix != null && locationOutput.startsWith(pathPrefix)) {
            locationOutput // for Pest versions 1.x
        } else {
            "$pathPrefix/${locationOutput}" // for Pest versions >= 2.x
        }
    }

    companion object {
        const val PROTOCOL_ID = "pest_qn"
    }
}

private fun convertLocationHintClassNameToFileName(locationHintClassName: String): String {
    return locationHintClassName.removePrefix("\\P\\").replace("\\", File.separator) + ".php"
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/configuration/PestRerunFailedTestsAction.kt
================================================
package com.pestphp.pest.configuration

import com.intellij.execution.Executor
import com.intellij.execution.configurations.RunProfileState
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.execution.runners.ProgramRunner
import com.intellij.execution.testframework.actions.AbstractRerunFailedTestsAction
import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties
import com.intellij.openapi.ui.ComponentContainer
import com.intellij.psi.PsiElement
import com.intellij.psi.search.GlobalSearchScope
import com.jetbrains.php.composer.configData.ComposerConfigManager
import com.jetbrains.php.config.commandLine.PhpCommandSettings
import com.pestphp.pest.PestBundle
import com.pestphp.pest.features.parallel.PestParallelProgramRunner
import com.pestphp.pest.isPestTestReference
import com.pestphp.pest.notifications.OutdatedNotification
import com.pestphp.pest.toPestTestRegex

/**
 * Adds support for rerunning failed tests
 */
class PestRerunFailedTestsAction(
    componentContainer: ComponentContainer,
    properties: SMTRunnerConsoleProperties
) : AbstractRerunFailedTestsAction(componentContainer) {
    override fun getRunProfile(environment: ExecutionEnvironment): MyRunProfile? {
        val profile = myConsoleProperties.configuration

        if (profile !is PestRunConfiguration) {
            return null
        }

        val runConfiguration: PestRunConfiguration = profile
        return object : MyRunProfile(runConfiguration), PestRerunProfile {
            override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState? {
                val peerRunConfiguration = this.peer as PestRunConfiguration
                val project = peerRunConfiguration.project
                val interpreter = peerRunConfiguration.interpreter ?: return null

                val failed = getFailedTests(project)
                    .asSequence()
                    .filter { it.isLeaf }
                    .filter { it.parent != null }
                    .map { it.getLocation(project, GlobalSearchScope.allScope(project)) }
                    .mapNotNull { it?.psiElement }
                    .filter { it.isPestTestReference() }
                    .toList()

                val clone: PestRunConfiguration = peerRunConfiguration.clone() as PestRunConfiguration

                // If there are no failed tests found, it's prob.
                // because it's an pest version before the new printer
                if (failed.isEmpty()) {
                    OutdatedNotification().notify(
                        project,
                        PestBundle.message("NO_FAILED_TESTS_FOUND")
                    )

                    return peerRunConfiguration.getState(
                        environment,
                        clone.createCommand(
                            interpreter,
                            mutableMapOf(),
                            mutableListOf(),
                            false
                        ),
                        null
                    )
                }

                val command: PhpCommandSettings = clone.createCommand(
                    interpreter,
                    mutableMapOf(),
                    getArgumentsFromRunner(environment.runner),
                    false
                )

                val rootPath = ComposerConfigManager.getInstance(project).getConfig(null as PsiElement?)?.parent?.path ?: command.workingDirectory

                val testcases = failed.mapNotNull { it.toPestTestRegex(rootPath) }
                    .reduce { result, testName -> "$result|$testName" }

                command.addArgument(
                    "--filter=/$testcases/"
                )

                return peerRunConfiguration.getState(
                    environment,
                    command,
                    null
                )
            }
        }
    }

    init {
        init(properties)
    }

    private fun getArgumentsFromRunner(pestProgramRunner: ProgramRunner<*>): MutableList<String> {
        return when (pestProgramRunner) {
            is PestParallelProgramRunner -> pestProgramRunner.getArguments()
            else -> mutableListOf()
        }
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/configuration/PestRerunProfile.kt
================================================
package com.pestphp.pest.configuration

interface PestRerunProfile

================================================
FILE: src/main/kotlin/com/pestphp/pest/configuration/PestRunConfiguration.kt
================================================
package com.pestphp.pest.configuration

import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.execution.ExecutionException
import com.intellij.execution.Executor
import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.execution.configurations.RunConfiguration
import com.intellij.execution.configurations.RunProfileState
import com.intellij.execution.configurations.RuntimeConfigurationException
import com.intellij.execution.configurations.RuntimeConfigurationWarning
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.execution.testframework.actions.AbstractRerunFailedTestsAction
import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties
import com.intellij.execution.ui.ConsoleView
import com.intellij.openapi.options.SettingsEditor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.util.PathUtil
import com.intellij.util.TextFieldCompletionProvider
import com.jetbrains.php.PhpBundle
import com.jetbrains.php.config.commandLine.PhpCommandLinePathProcessor
import com.jetbrains.php.config.commandLine.PhpCommandSettings
import com.jetbrains.php.config.interpreters.PhpInterpreter
import com.jetbrains.php.run.PhpAsyncRunConfiguration
import com.jetbrains.php.run.PhpRunUtil
import com.jetbrains.php.run.remote.PhpRemoteInterpreterManager
import com.jetbrains.php.testFramework.PhpTestFrameworkConfiguration
import com.jetbrains.php.testFramework.PhpTestFrameworkSettingsManager
import com.jetbrains.php.testFramework.run.PhpTestRunConfigurationSettings
import com.jetbrains.php.testFramework.run.PhpTestRunnerConfigurationEditor
import com.jetbrains.php.testFramework.run.PhpTestRunnerSettings
import com.pestphp.pest.PestBundle
import com.pestphp.pest.PestFrameworkType
import com.pestphp.pest.PestIcons
import com.pestphp.pest.configuration.PestRunConfigurationProducer.Companion.VALIDATOR
import com.pestphp.pest.features.parallel.addParallelArguments
import com.pestphp.pest.getPestTestName
import com.pestphp.pest.getPestTests
import com.pestphp.pest.runner.PestConsoleProperties
import java.util.EnumMap
import kotlin.io.path.Path

class PestRunConfiguration(project: Project, factory: ConfigurationFactory) : PhpTestRunConfiguration(
    project,
    factory,
    PestBundle.message("FRAMEWORK_NAME"),
    PestFrameworkType.instance,
    VALIDATOR,
    PestRunConfigurationHandler.instance,
    PestVersionDetector.instance
), PhpAsyncRunConfiguration {
    override fun createSettings(): PestRunConfigurationSettings {
        return PestRunConfigurationSettings()
    }

    override fun getConfigurationEditor(): SettingsEditor<out RunConfiguration?> {
        val names = EnumMap<PhpTestRunnerSettings.Scope, String>(PhpTestRunnerSettings.Scope::class.java)
        val editor = this.getConfigurationEditor(names)

        editor.setRunnerOptionsDocumentation("https://pestphp.com/docs/installation")
        return PestTestRunConfigurationEditor(editor, this)
    }

    @Throws(ExecutionException::class)
    @Suppress("SwallowedException")
    fun checkAndGetState(env: ExecutionEnvironment, command: PhpCommandSettings): RunProfileState? {
        try {
            checkConfiguration()
        } catch (ignored: RuntimeConfigurationWarning) {
        } catch (exception: RuntimeConfigurationException) {
            throw ExecutionException(PestBundle.message("RUNTIME_CONFIGURATION_EXCEPTION_MESSAGE", exception.localizedMessage, this.name))
        }
        return this.getState(env, command, null)
    }

    override fun createMethodFieldCompletionProvider(
        editor: PhpTestRunnerConfigurationEditor
    ): TextFieldCompletionProvider {
        return object : TextFieldCompletionProvider() {
            override fun addCompletionVariants(text: String, offset: Int, prefix: String, result: CompletionResultSet) {
                val file = PhpRunUtil.findPsiFile(project, settings.runnerSettings.filePath)
                file?.getPestTests()
                    ?.mapNotNull { it.getPestTestName() }
                    ?.map { LookupElementBuilder.create(it).withIcon(PestIcons.File) }
                    ?.forEach { result.addElement(it) }
            }
        }
    }

    override fun createRerunAction(
        consoleView: ConsoleView,
        properties: SMTRunnerConsoleProperties
    ): AbstractRerunFailedTestsAction {
        return PestRerunFailedTestsAction(consoleView, properties)
    }

    override fun createTestConsoleProperties(executor: Executor): SMTRunnerConsoleProperties {
        val manager = PhpRemoteInterpreterManager.getInstance()


        val pathProcessor = when (this.interpreter?.isRemote) {
            true -> manager?.createPathMapper(this.project, interpreter!!.phpSdkAdditionalData)
            else -> null
        }

        return this.createTestConsoleProperties(
            executor,
            pathProcessor ?: PhpCommandLinePathProcessor.LOCAL
        )
    }

    private fun createTestConsoleProperties(
        executor: Executor,
        processor: PhpCommandLinePathProcessor
    ): PestConsoleProperties {
        val pathMapper = processor.createPathMapper(this.project)
        return PestConsoleProperties(
            this,
            executor,
            PestLocationProvider(pathMapper, this.project, this.getConfigurationFileRootPath())
        )
    }

    override fun suggestedName(): String? {
        val runner = this.settings.runnerSettings
        return when (val scope = runner.scope) {
            PhpTestRunnerSettings.Scope.Directory -> PathUtil.getFileName(StringUtil.notNullize(runner.directoryPath))
            PhpTestRunnerSettings.Scope.File -> PathUtil.getFileName(StringUtil.notNullize(runner.filePath))
            PhpTestRunnerSettings.Scope.Method -> {
                val file = PathUtil.getFileName(StringUtil.notNullize(runner.filePath))
                "$file::${runner.methodName}"
            }
            PhpTestRunnerSettings.Scope.ConfigurationFile -> PathUtil.getFileName(
                StringUtil.notNullize(runner.configurationFilePath)
            )
            else -> {
                assert(false) { "Unknown scope: $scope" }
                null
            }
        }
    }

    fun applyTestArguments(command: PhpCommandSettings, coverageArguments: List<String>) {
        val config = PhpTestFrameworkSettingsManager.getInstance(project)
            .getOrCreateByInterpreter(PestFrameworkType.instance, interpreter, true)
            ?: throw ExecutionException(PestBundle.message("DIALOG_MESSAGE_COULD_NOT_FIND_PHP_INTERPRETER"))

        val version = null

        val workingDirectory = getWorkingDirectory(project, settings, config)
            ?: throw ExecutionException(PhpBundle.message("php.interpreter.base.configuration.working.directory"))

        PestRunConfigurationHandler.instance.prepareCommand(
            project,
            command,
            config.executablePath!!,
            version
        )

        command.importCommandLineSettings(settings.commandLineSettings, workingDirectory)
        fillTestRunnerArguments(
            project,
            workingDirectory,
            settings.runnerSettings,
            coverageArguments,
            command,
            config,
            PestRunConfigurationHandler.instance
        )
    }

    override fun createCommand(
        interpreter: PhpInterpreter,
        env: MutableMap<String, String>,
        arguments: MutableList<String>,
        withDebugger: Boolean
    ): PhpCommandSettings {
        PestRunConfigurationHandler.instance.rootPath = getConfigurationFileRootPath()
        return super.createCommand(interpreter, env, arguments, withDebugger).apply {
            addParallelArguments(this@PestRunConfiguration, this)
        }
    }

    override fun getWorkingDirectory(
        project: Project,
        settings: PhpTestRunConfigurationSettings,
        config: PhpTestFrameworkConfiguration?
    ): String? {
        val cli = settings.commandLineSettings
        if (cli.workingDirectory?.isNotEmpty() == true) {
            return cli.workingDirectory
        }

        val configFileRootPath = getConfigurationFileRootPath()

        if (configFileRootPath.isNullOrEmpty()) {
            return super.getWorkingDirectory(project, settings, config)
        }

        return configFileRootPath
    }

    private fun getConfigurationFileRootPath(): String? {
        val configFile = getConfigurationFile(
            settings.runnerSettings,
            PhpTestFrameworkSettingsManager.getInstance(project)
                .getOrCreateByInterpreter(PestFrameworkType.instance, interpreter, true)
        ) ?: return null

        return VfsUtil.findFile(Path(configFile), false)?.parent?.path
    }

    val pestSettings: PestRunConfigurationSettings
        get() {
            return super.getSettings() as PestRunConfigurationSettings
        }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/configuration/PestRunConfigurationHandler.kt
================================================
package com.pestphp.pest.configuration

import com.intellij.execution.ExecutionException
import com.intellij.openapi.project.Project
import com.jetbrains.php.config.commandLine.PhpCommandSettings
import com.jetbrains.php.testFramework.run.PhpTestRunConfigurationHandler
import com.pestphp.pest.PestBundle
import com.pestphp.pest.toPestTestRegex

class PestRunConfigurationHandler : PhpTestRunConfigurationHandler {
    var rootPath: String? = null

    companion object {
        @JvmField
        val instance = PestRunConfigurationHandler()
    }

    override fun getConfigFileOption(): String {
        return "--configuration"
    }

    override fun prepareCommand(project: Project, commandSettings: PhpCommandSettings, exe: String, version: String?) {
        commandSettings.setScript(exe, false)
        commandSettings.addArgument("--teamcity")
        commandSettings.addEnv("IDE_PEST_EXE", exe)

        if (!version.isNullOrEmpty()) {
            commandSettings.addEnv("IDE_PEST_VERSION", version)
        }
    }

    @Throws(ExecutionException::class)
    override fun runType(
        project: Project,
        phpCommandSettings: PhpCommandSettings,
        type: String,
        workingDirectory: String
    ) {
        throw ExecutionException(PestBundle.message("CANNOT_RUN_PEST_WITH_TYPE_MESSAGE"))
    }

    override fun runDirectory(
        project: Project,
        phpCommandSettings: PhpCommandSettings,
        directory: String,
        workingDirectory: String
    ) {
        if (directory.isEmpty()) {
            return
        }
        phpCommandSettings.addPathArgument(directory)
    }

    override fun runFile(
        project: Project,
        phpCommandSettings: PhpCommandSettings,
        file: String,
        workingDirectory: String
    ) {
        if (file.isEmpty()) {
            return
        }
        phpCommandSettings.addPathArgument(file)
    }

    override fun runMethod(
        project: Project,
        phpCommandSettings: PhpCommandSettings,
        file: String,
        methodName: String,
        workingDirectory: String
    ) {
        if (file.isEmpty()) {
            return
        }
        val pathMapper = phpCommandSettings.pathProcessor.createPathMapper(project)

        val rootPath = this.rootPath ?: workingDirectory

        phpCommandSettings.addPathArgument(file)
        phpCommandSettings.addArgument("--filter")
        phpCommandSettings.addArgument("/${methodName.toPestTestRegex(rootPath, file, pathMapper)}/")
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/configuration/PestRunConfigurationProducer.kt
================================================
package com.pestphp.pest.configuration

import com.intellij.execution.actions.ConfigurationFromContext
import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.ide.highlighter.XmlFileType
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Condition
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.util.Function
import com.jetbrains.php.lang.PhpFileType
import com.jetbrains.php.lang.psi.PhpFile
import com.jetbrains.php.testFramework.run.PhpDefaultTestRunnerSettingsValidator
import com.jetbrains.php.testFramework.run.PhpTestConfigurationProducer
import com.pestphp.pest.getPestTestName
import com.pestphp.pest.isPestConfigurationFile
import com.pestphp.pest.isPestEnabled
import com.pestphp.pest.isPestTestFile
import com.pestphp.pest.isPestTestReference

class PestRunConfigurationProducer : PhpTestConfigurationProducer<PestRunConfiguration>(
    VALIDATOR,
    FILE_TO_SCOPE,
    METHOD_NAMER,
    METHOD
) {
    override fun getConfigurationFactory(): ConfigurationFactory = PestRunConfigurationType.instance

    override fun isEnabled(project: Project): Boolean = project.isPestEnabled()

    override fun getWorkingDirectory(element: PsiElement): VirtualFile? {
        if (element is PsiDirectory) {
            return element.parentDirectory?.virtualFile
        }

        return element.containingFile?.containingDirectory?.virtualFile
    }

    companion object {
        val METHOD = Condition<PsiElement> { element: PsiElement? ->
            element.isPestTestReference()
        }
        private val METHOD_NAMER = Function<PsiElement, String?> { element: PsiElement? ->
            element.getPestTestName()
        }
        private val FILE_TO_SCOPE = Function<PsiFile, PsiElement?> { file: PsiFile ->
            if (file.isPestTestFile()) file else null
        }
        val VALIDATOR = PhpDefaultTestRunnerSettingsValidator(
            setOf<FileType>(PhpFileType.INSTANCE, XmlFileType.INSTANCE).toList(),
            { file: PsiFile, _: String ->
                file.isPestConfigurationFile() || file.isPestTestFile()
            },
            false,
            false
        )
    }

    override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean {
        val file = self.sourceElement as? PhpFile ?: return false
        return file.isPestTestFile()
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/configuration/PestRunConfigurationType.kt
================================================
package com.pestphp.pest.configuration

import com.intellij.execution.configurations.ConfigurationTypeUtil.findConfigurationType
import com.intellij.execution.configurations.RunConfiguration
import com.intellij.execution.configurations.SimpleConfigurationType
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.NotNullLazyValue
import com.pestphp.pest.PestBundle
import com.pestphp.pest.PestIcons

class PestRunConfigurationType private constructor() :
    SimpleConfigurationType(
        "PestRunConfigurationType",
        PestBundle.message("FRAMEWORK_NAME"),
        PestBundle.message("FRAMEWORK_NAME"),
        NotNullLazyValue.createValue { PestIcons.Config }
    ),
    DumbAware {
    override fun createTemplateConfiguration(project: Project): RunConfiguration {
        return PestRunConfiguration(project, this)
    }

    companion object {
        @JvmStatic
        val instance: PestRunConfigurationType
            get() = findConfigurationType(PestRunConfigurationType::class.java)
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/configuration/PestRunnerSettings.kt
================================================
package com.pestphp.pest.configuration

import com.intellij.util.xmlb.annotations.Attribute
import com.intellij.util.xmlb.annotations.Tag
import com.jetbrains.php.phpunit.coverage.PhpUnitCoverageEngine.CoverageEngine
import com.jetbrains.php.testFramework.run.PhpTestRunnerSettings

@Tag("PestRunner")
class PestRunnerSettings : PhpTestRunnerSettings() {
    @Attribute("coverage_engine")
    var coverageEngine: CoverageEngine = CoverageEngine.XDEBUG
    @Attribute("parallel_testing_enabled")
    var parallelTestingEnabled: Boolean = false

    companion object {
        @JvmStatic
        fun fromPhpTestRunnerSettings(settings: PhpTestRunnerSettings): PestRunnerSettings {
            val pestSettings = PestRunnerSettings()

            pestSettings.scope = settings.scope
            pestSettings.selectedType = settings.selectedType
            pestSettings.directoryPath = settings.directoryPath
            pestSettings.filePath = settings.filePath
            pestSettings.methodName = settings.methodName
            pestSettings.isUseAlternativeConfigurationFile = settings.isUseAlternativeConfigurationFile
            pestSettings.configurationFilePath = settings.configurationFilePath
            pestSettings.testRunnerOptions = settings.testRunnerOptions

            return pestSettings
        }
    }

    override fun equals(other: Any?): Boolean {
        if (other !is PestRunnerSettings) return false
        return super.equals(other) && coverageEngine == other.coverageEngine && parallelTestingEnabled == other.parallelTestingEnabled
    }

    override fun hashCode(): Int {
        var result = super.hashCode()
        result = 31 * result + coverageEngine.hashCode()
        result = 31 * result + parallelTestingEnabled.hashCode()
        return result
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/configuration/PestTestRunConfigurationEditor.kt
================================================
package com.pestphp.pest.configuration

import com.intellij.openapi.editor.ReadOnlyModificationException
import com.intellij.openapi.options.SettingsEditor
import com.intellij.openapi.ui.ComboBox
import com.intellij.ui.components.JBCheckBox
import com.intellij.util.ui.UI
import com.jetbrains.php.phpunit.coverage.PhpUnitCoverageEngine.CoverageEngine
import com.jetbrains.php.testFramework.run.PhpTestRunConfigurationEditor
import com.pestphp.pest.PestBundle
import java.lang.reflect.InvocationTargetException
import javax.swing.BoxLayout
import javax.swing.JComponent
import javax.swing.JPanel

class PestTestRunConfigurationEditor(
    private val parentEditor: PhpTestRunConfigurationEditor,
    settings: PestRunConfiguration
) : SettingsEditor<PestRunConfiguration>() {
    private val myMainPanel = JPanel()
    private var coveragePanel = JPanel()
    private var parallelPanel = JPanel()
    private val coverageEngineComboBox = ComboBox(arrayOf(CoverageEngine.XDEBUG, CoverageEngine.PCOV))
    private val enabledParallelTestingCheckBox = JBCheckBox()

    init {
        coveragePanel = UI.PanelFactory.grid().add(
            UI.PanelFactory.panel(coverageEngineComboBox).withLabel(PestBundle.message("COVERAGE_ENGINE_LABEL_TEXT"))
        ).createPanel()
        parallelPanel = UI.PanelFactory.grid().add(
            UI.PanelFactory.panel(enabledParallelTestingCheckBox).withLabel(PestBundle.message("ENABLE_PARALLEL_TESTING_LABEL_TEXT"))
        ).createPanel()

        myMainPanel.layout = BoxLayout(myMainPanel, BoxLayout.Y_AXIS)
        myMainPanel.add(parentEditor.component)
        myMainPanel.add(coveragePanel)
        myMainPanel.add(parallelPanel)
        resetEditorFrom(settings)
    }

    override fun createEditor(): JComponent {
        return myMainPanel
    }

    private fun doApply(configuration: PestRunConfiguration) {
        val settings = configuration.settings as PestRunConfigurationSettings
        val runnerSettings = settings.pestRunnerSettings

        runnerSettings.coverageEngine = coverageEngineComboBox.selectedItem as CoverageEngine
        runnerSettings.parallelTestingEnabled = enabledParallelTestingCheckBox.isSelected
    }

    private fun doReset(configuration: PestRunConfiguration) {
        val settings = configuration.settings as PestRunConfigurationSettings
        val runnerSettings = settings.pestRunnerSettings

        coverageEngineComboBox.selectedItem = runnerSettings.coverageEngine
        enabledParallelTestingCheckBox.isSelected = runnerSettings.parallelTestingEnabled
    }

    override fun resetEditorFrom(settings: PestRunConfiguration) {
        doReset(settings)
        parentEditor.javaClass.declaredMethods.find { it.name == "resetEditorFrom" }!!.let {
            it.isAccessible = true
            it.invoke(parentEditor, settings)
        }
    }

    override fun applyEditorTo(settings: PestRunConfiguration) {
        parentEditor.javaClass.declaredMethods.find { it.name == "applyEditorTo" }!!.let {
            it.isAccessible = true
            try {
                it.invoke(parentEditor, settings)
            } catch (exception: InvocationTargetException) {
                // In case the method throws a read only error (happens in code with me) we ignore it.
                if (exception.cause is ReadOnlyModificationException) {
                    return@let
                }

                throw exception
            }
        }
        doApply(settings)
    }

    override fun getSnapshot(): PestRunConfiguration {
        val result = parentEditor.snapshot as PestRunConfiguration
        doApply(result)
        return result
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/configuration/PestVersionDetector.kt
================================================
package com.pestphp.pest.configuration

import com.intellij.execution.ExecutionException
import com.intellij.openapi.project.Project
import com.jetbrains.php.PhpTestFrameworkVersionDetector
import com.jetbrains.php.config.interpreters.PhpInterpreter
import com.pestphp.pest.PestBundle
import org.jetbrains.annotations.Nls

private val VERSION_REGEX = Regex("(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)")
private val VERSION_OPTIONS = arrayOf("--version", "--colors=never")

class PestVersionDetector : PhpTestFrameworkVersionDetector<String>() {
    override fun getPresentableName(): @Nls String {
        return PestBundle.message("FRAMEWORK_NAME")
    }

    override fun getTitle(): String {
        return PestBundle.message("GETTING_PEST_VERSION")
    }

    override fun getVersionOptions(): Array<String> {
        return VERSION_OPTIONS
    }

    public override fun parse(s: String): String {
        val version = if (s.startsWith("Pest")) {
            // for <2.0.0 versions
            s.removePrefix("Pest").substringBefore("\n").trim()
        } else {
            // for 2.* versions
            s.trim().removePrefix("Pest Testing Framework ").substringBeforeLast('.')
        }

        if (!version.matches(VERSION_REGEX)) {
            throw ExecutionException(PestBundle.message("PEST_CONFIGURATION_UI_CAN_NOT_PARSE_VERSION", s))
        }
        return version
    }

    override fun getVersion(project: Project, interpreter: PhpInterpreter, executable: String?): String {
        if (interpreter.isRemote) {
            throw ExecutionException(PestBundle.message("PEST_VERSION_IS_NOT_SUPPORTED_FOR_REMOTE_INTERPRETER"))
        }
        return super.getVersion(project, interpreter, executable)
    }

    companion object {
        val instance = PestVersionDetector()
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/features/configuration/ConfigurationInDirectoryReferenceProvider.kt
================================================
package com.pestphp.pest.features.configuration

import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.psi.PsiReferenceProvider
import com.intellij.util.ProcessingContext
import com.jetbrains.php.lang.psi.elements.FunctionReference
import com.jetbrains.php.lang.psi.elements.MethodReference
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression
import com.jetbrains.php.lang.psi.elements.impl.FunctionReferenceImpl
import com.jetbrains.php.lang.psi.elements.impl.MethodReferenceImpl
import com.pestphp.pest.CONFIGURATION_FUNCTIONS

class ConfigurationInDirectoryReferenceProvider: PsiReferenceProvider() {
    override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
        val inCall = element.parent.parent as MethodReferenceImpl

        if (inCall.canonicalText != "in") {
            return PsiReference.EMPTY_ARRAY
        }

        val usesCall = getConfigurationFunctionCall(inCall) as? FunctionReferenceImpl ?: return PsiReference.EMPTY_ARRAY
        if (usesCall.canonicalText !in CONFIGURATION_FUNCTIONS) {
            return PsiReference.EMPTY_ARRAY
        }

        val referenceSet = PhpFolderReferenceSet(element, element as StringLiteralExpression, this)

        return referenceSet
            .allReferences
            .toList()
            .toTypedArray()
    }
}

fun getConfigurationFunctionCall(inCall: MethodReference): FunctionReference? {
    val child = inCall.firstPsiChild
    if (child !is MethodReference) {
        if (child is FunctionReference) {
            return child
        }
        return null
    }
    return getConfigurationFunctionCall(child)
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/features/configuration/ConfigurationReferenceContributor.kt
================================================
package com.pestphp.pest.features.configuration

import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.PsiReferenceContributor
import com.intellij.psi.PsiReferenceRegistrar
import com.jetbrains.php.lang.psi.elements.ParameterList
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression
import com.jetbrains.php.lang.psi.elements.impl.MethodReferenceImpl

class ConfigurationReferenceContributor : PsiReferenceContributor() {
    override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
        registrar.registerReferenceProvider(
            PlatformPatterns.psiElement(StringLiteralExpression::class.java)
                .withParents(
                    ParameterList::class.java,
                    MethodReferenceImpl::class.java
                ),
            ConfigurationInDirectoryReferenceProvider()
        )
    }
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/features/configuration/PhpFolderReferenceSet.kt
================================================
package com.pestphp.pest.features.configuration

import com.intellij.openapi.util.Condition
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFileSystemItem
import com.intellij.psi.PsiReferenceProvider
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet
import com.jetbrains.php.lang.psi.elements.PhpPsiElement
import com.jetbrains.php.lang.psi.elements.impl.PhpFileReferenceSet

class PhpFolderReferenceSet(element: PsiElement, argument: PhpPsiElement, provider: PsiReferenceProvider) : PhpFileReferenceSet(element, argument, provider) {
    override fun getReferenceCompletionFilter(): Condition<PsiFileSystemItem> {
        return FileReferenceSet.DIRECTORY_FILTER
    }

    override fun computeDefaultContexts(): MutableCollection<PsiFileSystemItem> {
        val containingFile = this.element.containingFile.originalFile
        val directory = containingFile.virtualFile.parent

        val fileSystemItems = toFileSystemItems(directory)

        if (fileSystemItems.isNotEmpty()) {
            return fileSystemItems
        }

        return super.computeDefaultContexts()
    }
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/features/customExpectations/CustomExpectationIndex.kt
================================================
package com.pestphp.pest.features.customExpectations

import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.indexing.DataIndexer
import com.intellij.util.indexing.DefaultFileTypeSpecificInputFilter
import com.intellij.util.indexing.FileBasedIndex
import com.intellij.util.indexing.FileBasedIndexExtension
import com.intellij.util.indexing.FileContent
import com.intellij.util.indexing.ID
import com.intellij.util.io.DataExternalizer
import com.intellij.util.io.EnumeratorStringDescriptor
import com.intellij.util.io.KeyDescriptor
import com.jetbrains.php.lang.PhpFileType
import com.jetbrains.php.lang.psi.PhpFile
import com.jetbrains.php.lang.psi.elements.MethodReference
import com.jetbrains.php.lang.psi.elements.impl.MethodReferenceImpl
import com.jetbrains.php.lang.psi.stubs.indexes.PhpDepthLimitedRecursiveElementVisitor
import com.jetbrains.php.lang.psi.stubs.indexes.PhpInvokeCallsOffsetsIndex.IntArrayExternalizer
import it.unimi.dsi.fastutil.ints.IntArrayList
import it.unimi.dsi.fastutil.ints.IntList

val KEY = ID.create<String, IntList>("php.pest.custom_expectations")

class CustomExpectationIndex : FileBasedIndexExtension<String, IntList>() {

    override fun getName(): ID<String, IntList> {
        return KEY
    }

    override fun getVersion(): Int {
        return 7
    }

    override fun getIndexer(): DataIndexer<String, IntList, FileContent> {
        return DataIndexer { inputData ->
            val file = inputData.psiFile
            val map: MutableMap<String, IntList> = mutableMapOf()
            if (file is PhpFile) {
                file.accept(object : PhpDepthLimitedRecursiveElementVisitor() {
                    override fun visitPhpMethodReference(reference: MethodReference) {
                        if (reference is MethodReferenceImpl && reference.isPestExtendReference()) {
                            reference.extendName?.let {
                                if (it !in map) {
                                    map[it] = IntArrayList()
                                }
                                map[it]!!.add(reference.parameters[0].textOffset + 1)
                            }
                        }
                    }
                })
            }
            return@DataIndexer map
        }
    }

    override fun getKeyDescriptor(): KeyDescriptor<String> {
        return EnumeratorStringDescriptor.INSTANCE
    }

    override fun getValueExternalizer(): DataExternalizer<IntList> {
        return IntArrayExternalizer.INSTANCE
    }

    override fun getInputFilter(): FileBasedIndex.InputFilter {
        return object : DefaultFileTypeSpecificInputFilter(PhpFileType.INSTANCE) {
            override fun acceptInput(file: VirtualFile): Boolean {
                return !isPestStubFile(file)
            }
        }
    }

    override fun dependsOnFileContent(): Boolean {
        return true
    }

    private fun isPestStubFile(file: VirtualFile): Boolean {
        val path = file.path
        return path.contains("vendor") && path.contains("pestphp") && path.contains("stubs")
    }
}


================================================
FILE: src/main/kotlin/com/pestphp/pest/features/customExpectations/CustomExpectationNotifier.kt
================================================
package com.pestphp.pest.features.customExpectations

import com.intellij.psi.PsiFile
import com.intellij.util.messages.Topic
import com.pestphp.pest.features.customExpectations.generators.Method
import java.util.EventListener

interface CustomExpectationNotifier : EventListener {
    companion object {
        @Topic.ProjectLevel
        val TOPIC = Topic.create("Custom expectation", CustomExpectationNotifier::class.java)
    }

    fun changedExpectation(file: PsiFile, customExpectations: List<Method>)
}

================================================
FILE: src/main/kotlin/com/pestphp/pest/features/customExpectations/CustomExpectationParameterInfoHandler.kt
================================================
@file:Suppress("UnstableApiUsage")

package com.pestphp.pest.features.customExpectations

import com.intellij.lang.parameterInfo.CreateParameterInfoContext
import com.intellij.lang.parameterInfo.ParameterInfoHandlerWithTabActionSupport
import com.intellij.lang.parameterInfo.ParameterInfoUIContext
import com.intellij.lang.parameterInfo.UpdateParameterInfoContext
import com.intellij.model.psi.PsiSymbolReferenceService
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import com.intellij.util.IntPair
import com.intellij.util.containers.ContainerUtil
import com.jetbrains.php.lang.PhpParameterInfoHandler
import com.jetbrains.php.lang.lexer.PhpTokenTypes
import com.jetbrains.php.lang.psi.elements.FunctionReference
import com.jetbrains.php.lang.psi.elements.PhpPsiElement
import com.jetbrains.php.lang.psi.elements.Statement
import com.jetbrains.php.lang.psi.elements.impl.MethodReferenceImpl
import com.pestphp.pest.features.customExpectations.generators.Parameter
import com.pestphp.pest.features.customExpectations.symbols.PestCustomExpectationReference
import com.pestphp.pest.features.customExpectations.symbols.PestCustomExpectationSymbol

class CustomExpectationParameterInfoHandler : ParameterInfoHandlerWithTabActionSupport<FunctionReference, List<Parameter>, PsiElement> {
    override fun findElementForParameterInfo(context: CreateParameterInfoContext): FunctionReference? {
        val methodReference =
            PhpParameterInfoHandler.findAnchorForParameterInfo(context) as? MethodReferenceImpl ?: return null
        val references = PsiSymbolReferenceService.getService().getReferences(methodReference)
        val symbol = references.filterIsInstance<PestCustomExpectationReference>().flatMap { it.resolveReference() }
            .filterIsInstance<PestCustomExpectationSymbol>().firstOrNull() ?: return null
        context.itemsToShow = arrayOf(symbol.methodDescriptor.parameters)
        return methodReference
    }

    override fun showParameterInfo(element: FunctionReference, context: CreateParameterInfoContext) {
        context.showHint(element, element.textRange.startOffset, this)
    }

    override fun findElementForUpdatingParameterInfo(context: Up
Download .txt
gitextract_h0dnztv0/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature-request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── auto-close.yml
│       ├── build.yml
│       ├── qodana.yml
│       ├── release.yml
│       └── run-ui-tests.yml
├── .gitignore
├── .run/
│   ├── Run IDE with Plugin.run.xml
│   ├── Run Plugin Tests.run.xml
│   ├── Run Plugin Verification.run.xml
│   └── Run Qodana.run.xml
├── BUILD.bazel
├── CHANGELOG.md
├── CLAUDE.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── build.gradle.kts
├── coverage/
│   ├── BUILD.bazel
│   ├── intellij.pest.coverage.iml
│   ├── resources/
│   │   └── intellij.pest.coverage.xml
│   ├── src/
│   │   ├── PestCoverageEnabledConfiguration.kt
│   │   ├── PestCoverageEngine.kt
│   │   ├── PestCoverageProgramRunner.kt
│   │   └── features/
│   │       └── mutate/
│   │           ├── PestMutateProgramRunner.kt
│   │           └── PestMutateTestExecutor.kt
│   └── tests/
│       ├── BUILD.bazel
│       ├── intellij.pest.coverage.tests.iml
│       ├── src/
│       │   └── com/
│       │       └── intellij/
│       │           └── pest/
│       │               └── coverage/
│       │                   ├── PestCoverageProgramRunnerTest.kt
│       │                   └── features/
│       │                       └── mutate/
│       │                           └── PestMutateProgramRunnerTest.kt
│       └── testData/
│           ├── ATest.php
│           ├── features/
│           │   └── mutate/
│           │       ├── ATest.php
│           │       └── php
│           └── php
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── intellij.pest.iml
├── intellij.pest.tests.iml
├── plugin-content.yaml
├── settings.gradle.kts
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/
    │   │       └── pestphp/
    │   │           └── pest/
    │   │               ├── PestIcons.java
    │   │               └── configuration/
    │   │                   ├── PestRunConfigurationSettings.java
    │   │                   └── PhpTestRunConfiguration.java
    │   ├── kotlin/
    │   │   └── com/
    │   │       └── pestphp/
    │   │           └── pest/
    │   │               ├── FileUtil.kt
    │   │               ├── PestBundle.kt
    │   │               ├── PestComposerConfig.kt
    │   │               ├── PestFrameworkType.kt
    │   │               ├── PestFunctionsUtil.kt
    │   │               ├── PestIconProvider.kt
    │   │               ├── PestNamingUtil.kt
    │   │               ├── PestNewTestFromClassAction.kt
    │   │               ├── PestPluginDisposable.kt
    │   │               ├── PestSettings.kt
    │   │               ├── PestTestCreateInfo.kt
    │   │               ├── PestTestDescriptor.kt
    │   │               ├── PestTestFileUtil.kt
    │   │               ├── PestTestRunLineMarkerProvider.kt
    │   │               ├── PestUtil.kt
    │   │               ├── annotator/
    │   │               │   ├── PestAnnotator.kt
    │   │               │   └── PestAnnotatorVisitor.kt
    │   │               ├── completion/
    │   │               │   ├── InternalMembersCompletionProvider.kt
    │   │               │   ├── PestCompletionContributor.kt
    │   │               │   ├── PestCustomExtensionCompletionProvider.kt
    │   │               │   └── ThisFieldsCompletionProvider.kt
    │   │               ├── configuration/
    │   │               │   ├── PestDebugRunner.kt
    │   │               │   ├── PestLocationProvider.kt
    │   │               │   ├── PestRerunFailedTestsAction.kt
    │   │               │   ├── PestRerunProfile.kt
    │   │               │   ├── PestRunConfiguration.kt
    │   │               │   ├── PestRunConfigurationHandler.kt
    │   │               │   ├── PestRunConfigurationProducer.kt
    │   │               │   ├── PestRunConfigurationType.kt
    │   │               │   ├── PestRunnerSettings.kt
    │   │               │   ├── PestTestRunConfigurationEditor.kt
    │   │               │   └── PestVersionDetector.kt
    │   │               ├── features/
    │   │               │   ├── configuration/
    │   │               │   │   ├── ConfigurationInDirectoryReferenceProvider.kt
    │   │               │   │   ├── ConfigurationReferenceContributor.kt
    │   │               │   │   └── PhpFolderReferenceSet.kt
    │   │               │   ├── customExpectations/
    │   │               │   │   ├── CustomExpectationIndex.kt
    │   │               │   │   ├── CustomExpectationNotifier.kt
    │   │               │   │   ├── CustomExpectationParameterInfoHandler.kt
    │   │               │   │   ├── CustomExpectationRemoveGeneratedFileStartupActivity.kt
    │   │               │   │   ├── ListMethodDataExternalizer.kt
    │   │               │   │   ├── MethodDataExternalizer.kt
    │   │               │   │   ├── expectationUtil.kt
    │   │               │   │   ├── externalizers/
    │   │               │   │   │   ├── ListDataExternalizer.kt
    │   │               │   │   │   ├── MethodDataExternalizer.kt
    │   │               │   │   │   ├── ParameterDataExternalizer.kt
    │   │               │   │   │   └── PhpTypeDataExternalizer.kt
    │   │               │   │   ├── generators/
    │   │               │   │   │   ├── ExpectationGenerator.kt
    │   │               │   │   │   ├── Method.kt
    │   │               │   │   │   └── Parameter.kt
    │   │               │   │   └── symbols/
    │   │               │   │       ├── PestCustomExpectationReference.kt
    │   │               │   │       ├── PestCustomExpectationReferenceProvider.kt
    │   │               │   │       ├── PestCustomExpectationRenameUsageSearcher.kt
    │   │               │   │       ├── PestCustomExpectationSymbol.kt
    │   │               │   │       ├── PestCustomExpectationSymbolDeclaration.kt
    │   │               │   │       ├── PestCustomExpectationSymbolDeclarationProvider.kt
    │   │               │   │       └── PestCustomExpectationUsageSearcher.kt
    │   │               │   ├── datasets/
    │   │               │   │   ├── DatasetIndex.kt
    │   │               │   │   ├── DatasetReference.kt
    │   │               │   │   ├── DatasetReferenceContributor.kt
    │   │               │   │   ├── DatasetReferenceProvider.kt
    │   │               │   │   ├── DatasetUtil.kt
    │   │               │   │   ├── InvalidDatasetNameCaseInspection.kt
    │   │               │   │   └── InvalidDatasetReferenceInspection.kt
    │   │               │   ├── parallel/
    │   │               │   │   ├── PestParallelProgramRunner.kt
    │   │               │   │   ├── PestParallelSMTEventsAdapter.kt
    │   │               │   │   └── PestParallelTestExecutor.kt
    │   │               │   └── snapshotTesting/
    │   │               │       ├── SnapshotLineMarkerProvider.kt
    │   │               │       └── SnapshotUtil.kt
    │   │               ├── goto/
    │   │               │   ├── PestDatasetUsagesGotoHandler.kt
    │   │               │   ├── PestGotoTargetPresentationProvider.kt
    │   │               │   ├── PestTestFinder.kt
    │   │               │   └── PestTestGoToSymbolContributor.kt
    │   │               ├── indexers/
    │   │               │   └── PestTestIndex.kt
    │   │               ├── inspections/
    │   │               │   ├── ChangeMultipleExpectCallsToChainableQuickFix.kt
    │   │               │   ├── ChangeTestNameCasingQuickFix.kt
    │   │               │   ├── InvalidTestNameCaseInspection.kt
    │   │               │   ├── MissingScreenshotSnapshotInspection.kt
    │   │               │   ├── MultipleExpectChainableInspection.kt
    │   │               │   ├── PestAssertionCanBeSimplifiedInspection.kt
    │   │               │   ├── PestTestFailedLineInspection.kt
    │   │               │   ├── SuppressExpressionResultUnusedInspection.kt
    │   │               │   └── SuppressUndefinedPropertyInspection.kt
    │   │               ├── notifications/
    │   │               │   └── OutdatedNotification.kt
    │   │               ├── parser/
    │   │               │   ├── PestConfigurationFile.kt
    │   │               │   └── PestConfigurationFileParser.kt
    │   │               ├── runner/
    │   │               │   ├── LocationInfo.kt
    │   │               │   ├── PestConsoleProperties.kt
    │   │               │   ├── PestFailedLineManager.kt
    │   │               │   ├── PestPressToContinueAction.kt
    │   │               │   ├── PestPromptConsoleFolding.kt
    │   │               │   └── PestTestStackTraceParser.kt
    │   │               ├── statistics/
    │   │               │   └── PestUsagesCollector.kt
    │   │               ├── structureView/
    │   │               │   ├── PestStructureViewElement.kt
    │   │               │   └── PestStructureViewExtension.kt
    │   │               ├── surrounders/
    │   │               │   ├── ExpectStatementSurrounder.kt
    │   │               │   └── StatementSurroundDescriptor.kt
    │   │               ├── templates/
    │   │               │   ├── PestConfigNewDatasetFileAction.kt
    │   │               │   ├── PestConfigNewFileAction.kt
    │   │               │   ├── PestDescribePostfixTemplate.kt
    │   │               │   ├── PestItPostfixTemplate.kt
    │   │               │   ├── PestPostfixTemplateProvider.kt
    │   │               │   └── PestRootTemplateContextType.kt
    │   │               └── types/
    │   │                   ├── HigherOrderExtendTypeProvider.kt
    │   │                   ├── InnerTestTypeProvider.kt
    │   │                   ├── ThisExtendTypeProvider.kt
    │   │                   ├── ThisFieldTypeProvider.kt
    │   │                   └── ThisTypeProvider.kt
    │   └── resources/
    │       ├── META-INF/
    │       │   └── plugin.xml
    │       ├── fileTemplates/
    │       │   └── internal/
    │       │       ├── Pest It.php.ft
    │       │       ├── Pest Scoped Dataset.php.ft
    │       │       ├── Pest Shared Dataset.php.ft
    │       │       ├── Pest Test.php.ft
    │       │       └── Pest file from class.php.ft
    │       ├── inspectionDescriptions/
    │       │   ├── InvalidDatasetNameCaseInspection.html
    │       │   ├── InvalidDatasetReferenceInspection.html
    │       │   ├── InvalidTestNameCaseInspection.html
    │       │   ├── MissingScreenshotSnapshotInspection.html
    │       │   ├── MultipleExpectChainableInspection.html
    │       │   ├── PestAssertionCanBeSimplifiedInspection.html
    │       │   └── PestTestFailedLineInspection.html
    │       ├── liveTemplates/
    │       │   └── PestPHP.xml
    │       ├── log4j.properties
    │       ├── messages/
    │       │   └── pestBundle.properties
    │       └── postfixTemplates/
    │           ├── PestDescribePostfixTemplate/
    │           │   ├── after.php.template
    │           │   ├── before.php.template
    │           │   └── description.html
    │           └── PestItPostfixTemplate/
    │               ├── after.php.template
    │               ├── before.php.template
    │               └── description.html
    └── test/
        ├── kotlin/
        │   └── com/
        │       └── pestphp/
        │           └── pest/
        │               ├── PestIconProviderTest.kt
        │               ├── PestLightCodeFixture.kt
        │               ├── PestTestRunLineMarkerProviderTest.kt
        │               ├── annotator/
        │               │   └── PestAnnotatorTest.kt
        │               ├── codeInsight/
        │               │   └── typeInference/
        │               │       └── PestTypeInferenceTest.kt
        │               ├── configuration/
        │               │   ├── PestLocationProviderTest.kt
        │               │   ├── PestRunConfigurationTest.kt
        │               │   ├── PestVersionDetectorTest.kt
        │               │   ├── PestVersionParserTest.kt
        │               │   ├── pest/
        │               │   │   └── PestConfigurationFileTest.kt
        │               │   └── uses/
        │               │       └── PestConfigurationFileTest.kt
        │               ├── customExpectations/
        │               │   ├── ListMethodDataExternalizerTest.kt
        │               │   ├── MethodDataExternalizerTest.kt
        │               │   └── generators/
        │               │       └── ExpectationGeneratorTest.kt
        │               ├── features/
        │               │   ├── configuration/
        │               │   │   ├── PestCompletionTest.kt
        │               │   │   └── UsesCompletionTest.kt
        │               │   ├── datasets/
        │               │   │   ├── DatasetCompletionTest.kt
        │               │   │   ├── DatasetGoToTest.kt
        │               │   │   ├── DatasetIndexTest.kt
        │               │   │   ├── DatasetReferenceTest.kt
        │               │   │   ├── DatasetUsagesTest.kt
        │               │   │   ├── InvalidDatasetNameCaseInspectionTest.kt
        │               │   │   └── InvalidDatasetReferenceInspectionTest.kt
        │               │   ├── parallel/
        │               │   │   ├── PestParallelProgramRunnerTest.kt
        │               │   │   └── PestParallelSMTEventsAdapterTest.kt
        │               │   └── snapshotTesting/
        │               │       ├── SnapshotLineMarkerProviderTest.kt
        │               │       └── SnapshotUtilTest.kt
        │               ├── generateTest/
        │               │   └── PestNewTestFromClassActionTest.kt
        │               ├── goto/
        │               │   └── PestTestFinderTest.kt
        │               ├── higherOrderExpectations/
        │               │   ├── HigherOrderExpectationAssertionCompletionTest.kt
        │               │   └── HigherOrderExpectationCompletionTest.kt
        │               ├── indexers/
        │               │   └── PestTestIndexTest.kt
        │               ├── inspections/
        │               │   ├── InvalidTestNameCaseInspectionTest.kt
        │               │   ├── MissingScreenshotSnapshotInspectionTest.kt
        │               │   ├── MultipleExpectChainableInspectionTest.kt
        │               │   ├── PestAssertionCanBeSimplifiedInspectionTest.kt
        │               │   ├── PestTestFailedLineInspectionTest.kt
        │               │   └── PhpStormInspectionsTest.kt
        │               ├── runner/
        │               │   ├── PestPressToContinueActionTest.kt
        │               │   └── PestTestStackTraceParserTest.kt
        │               ├── surrounders/
        │               │   ├── ExpectStatementSurrounderTest.kt
        │               │   └── SurroundTestCase.kt
        │               ├── templates/
        │               │   └── PestPostfixTemplateProviderTest.kt
        │               ├── types/
        │               │   ├── BaseTypeTestCase.kt
        │               │   ├── ExpectCallCompletionTest.kt
        │               │   ├── FunctionTypeTest.kt
        │               │   ├── ThisFieldCompletionTest.kt
        │               │   ├── ThisFieldTypeTest.kt
        │               │   └── ThisTypeTest.kt
        │               └── utilTests/
        │                   ├── GetPestTestNameTests.kt
        │                   ├── GetPestTestsTest.kt
        │                   ├── IsPestTestFileTest.kt
        │                   ├── IsPestTestFunctionTest.kt
        │                   ├── PestUtilTest.kt
        │                   ├── ToPestFqnTests.kt
        │                   └── ToPestTestRegexTests.kt
        └── resources/
            └── com/
                └── pestphp/
                    └── pest/
                        ├── Dataset.php
                        ├── Pest.php
                        ├── PestTestRunLineMarkerProviderTest/
                        │   ├── AssignmentFunctionCallNamedTest.php
                        │   ├── AssignmentFunctionCallNamedTestWithoutPest.php
                        │   ├── FunctionCallNamedTestAsArgument.php
                        │   ├── FunctionCallNamedTestInsideDescribeBlock.php
                        │   ├── FunctionCallNamedTestInsideTest.php
                        │   ├── FunctionCallNamedTestWithoutPest.php
                        │   ├── MethodCallNamedItAndVariableTest.php
                        │   ├── NamedDataSets.php
                        │   ├── PestItFunctionCallWithDescriptionAndClosure.php
                        │   ├── PestItFunctionCallWithRedefinition.php
                        │   └── contextProject/
                        │       └── tests/
                        │           └── Test.php
                        ├── PestUtil/
                        │   ├── Login.integration.test.php
                        │   ├── Login.test.php
                        │   ├── MethodCallNamedIt.php
                        │   ├── MethodCallNamedItAndVariableTest.php
                        │   ├── MethodCallNamedTest.php
                        │   ├── NestedDescribeFunctionCalls.php
                        │   ├── PestArchFunctionCall.php
                        │   ├── PestDescribeBlock.php
                        │   ├── PestDescribeBlockAndTestFunctionEndOfLine.php
                        │   ├── PestItFunctionCallWithConcatString.php
                        │   ├── PestItFunctionCallWithDescriptionAndClosure.php
                        │   ├── PestItFunctionCallWithDescriptionAndHigherOrder.php
                        │   ├── PestTestFunctionCallWithCircumflex.php
                        │   ├── PestTestFunctionCallWithConcatString.php
                        │   ├── PestTestFunctionCallWithDescriptionAndClosure.php
                        │   ├── PestTestFunctionCallWithDescriptionAndHigherOrder.php
                        │   ├── PestTestFunctionCallWithNamesapce.php
                        │   ├── PestTestFunctionCallWithParenthesis.php
                        │   ├── PestTestWithPlusAndQuestionMark.php
                        │   ├── User.spec.php
                        │   └── dir.name/
                        │       └── Test.php
                        ├── SimpleHigherOrderNotTest.php
                        ├── SimpleHigherOrderTestWithName.php
                        ├── SimpleScript.php
                        ├── TestWithDataset.php
                        ├── annotator/
                        │   ├── DuplicateCustomExpectation.afterDelete.php
                        │   ├── DuplicateCustomExpectation.afterNavigate.php
                        │   ├── DuplicateCustomExpectation.php
                        │   ├── DuplicateTestName.afterDelete.php
                        │   ├── DuplicateTestName.afterNavigate.php
                        │   ├── DuplicateTestName.php
                        │   ├── DuplicateTestNameInDescribeBlock.php
                        │   ├── NoDuplicateCustomExpectation.php
                        │   ├── NoDuplicateTestName.php
                        │   └── stub/
                        │       └── Functions.php
                        ├── codeInsight/
                        │   └── typeInference/
                        │       ├── ThisInInnerClosure.php
                        │       └── ThisInSubproject/
                        │           └── Test.php
                        ├── configuration/
                        │   ├── FileWithPestTest.php
                        │   ├── locationProvider/
                        │   │   ├── DescribeBlock/
                        │   │   │   └── subdir/
                        │   │   │       └── Test.php
                        │   │   ├── DescribeBlockIt/
                        │   │   │   └── subdir/
                        │   │   │       └── Test.php
                        │   │   ├── SubprojectFor1xVersion/
                        │   │   │   └── subdir/
                        │   │   │       └── Test.php
                        │   │   └── SubprojectFor2xVersion/
                        │   │       └── subdir/
                        │   │           └── Test.php
                        │   ├── pest/
                        │   │   ├── tests/
                        │   │   │   ├── DIRFeature/
                        │   │   │   │   └── FeatureTest.php
                        │   │   │   ├── DynamicFeature/
                        │   │   │   │   └── FeatureTest.php
                        │   │   │   ├── Feature/
                        │   │   │   │   └── FeatureTest.php
                        │   │   │   ├── GlobPattern/
                        │   │   │   │   ├── DirectoryTest.php
                        │   │   │   │   ├── FileTest.php
                        │   │   │   │   └── FileWithRelativePathTest.php
                        │   │   │   ├── GroupedFeature/
                        │   │   │   │   └── GroupedFeatureTest.php
                        │   │   │   ├── Pest.php
                        │   │   │   └── Unit/
                        │   │   │       ├── PestExtendUnitTest.php
                        │   │   │       └── UnitTest.php
                        │   │   └── tests2/
                        │   │       └── Unit/
                        │   │           └── UnitTest.php
                        │   ├── php
                        │   └── uses/
                        │       ├── DIRFeature/
                        │       │   └── FeatureTest.php
                        │       ├── DynamicFeature/
                        │       │   └── FeatureTest.php
                        │       ├── Feature/
                        │       │   └── FeatureTest.php
                        │       ├── GlobPattern/
                        │       │   ├── DirectoryTest.php
                        │       │   ├── FileTest.php
                        │       │   └── FileWithRelativePathTest.php
                        │       ├── GroupedFeature/
                        │       │   └── GroupedFeatureTest.php
                        │       ├── Pest.php
                        │       └── Unit/
                        │           ├── UnitTest.php
                        │           └── UsesUnitTest.php
                        ├── customExpectations/
                        │   ├── CustomExpectation.php
                        │   ├── CustomExpectationWithParameter.php
                        │   ├── CustomThisExpectation.php
                        │   ├── CustomUserExpectation.php
                        │   ├── UnfinishedCustomExpectation.php
                        │   ├── generators/
                        │   │   └── ExpectationGenerator/
                        │   │       └── GeneratedWithMethod.php
                        │   └── subFolder/
                        │       └── CustomExpectation.php
                        ├── features/
                        │   ├── configuration/
                        │   │   ├── pest/
                        │   │   │   ├── CompleteFakePestInFolder.php
                        │   │   │   ├── CompleteInFolder.php
                        │   │   │   └── Test.php
                        │   │   └── uses/
                        │   │       ├── CompleteFakeInFolder.php
                        │   │       ├── CompleteInFolder.php
                        │   │       └── Test.php
                        │   ├── datasets/
                        │   │   ├── AutocompleteDatasetTest.php
                        │   │   ├── DatasetInDescribeBlock.php
                        │   │   ├── DatasetInDescribeBlockCompletion.php
                        │   │   ├── DatasetInDescribeBlockReference.php
                        │   │   ├── DatasetInsideDescribeBlockTest.php
                        │   │   ├── DatasetNoArgsTest.php
                        │   │   ├── DatasetOnNonPestTest.php
                        │   │   ├── DatasetOnNonPestTestCompletion.php
                        │   │   ├── DatasetReference.php
                        │   │   ├── DatasetTest.php
                        │   │   ├── Datasets.php
                        │   │   ├── DoubleWithDatasetReference.php
                        │   │   ├── InvalidDatasetInDescribeBlockTest.php
                        │   │   ├── InvalidDatasetNameCase.after.php
                        │   │   ├── InvalidDatasetNameCase.php
                        │   │   ├── InvalidDatasetTest.php
                        │   │   ├── NotDatasetReference.php
                        │   │   ├── SharedDatasetReference.php
                        │   │   └── ValidDatasetNameCase.php
                        │   └── parallel/
                        │       ├── ATest.php
                        │       └── php
                        ├── generateTest/
                        │   ├── testWithNamespace.after.php
                        │   └── testWithNamespace.php
                        ├── goto/
                        │   ├── PestTestFinder/
                        │   │   ├── App/
                        │   │   │   └── User.php
                        │   │   └── test/
                        │   │       └── App/
                        │   │           ├── MockTest.php
                        │   │           ├── UserDescribeTest.php
                        │   │           └── UserTest.php
                        │   └── datasetUsages/
                        │       ├── DatasetDeclaration.php
                        │       └── DatasetUsage.php
                        ├── higherOrderExpectations/
                        │   ├── .phpstorm.meta.php
                        │   ├── ExpectMethodAssertionCompletion.php
                        │   ├── ExpectMethodAssertionCompletionChained.php
                        │   ├── ExpectMethodAssertionCompletionChainedAssertions.php
                        │   ├── ExpectMethodCompletion.php
                        │   ├── ExpectMethodCompletionChained.php
                        │   ├── ExpectMethodCompletionChainedAssertions.php
                        │   ├── ExpectPropertyAssertionCompletion.php
                        │   ├── ExpectPropertyAssertionCompletionChained.php
                        │   ├── ExpectPropertyAssertionCompletionChainedAssertions.php
                        │   ├── ExpectPropertyCompletion.php
                        │   ├── ExpectPropertyCompletionChained.php
                        │   ├── ExpectPropertyCompletionChainedAssertions.php
                        │   └── stubs.php
                        ├── indexers/
                        │   └── PestTestIndexTest/
                        │       ├── FileWithDescribeBlockTest.php
                        │       ├── FileWithPestTest.php
                        │       ├── FileWithPestTodosTest.php
                        │       └── FileWithoutPestTest.php
                        ├── inspections/
                        │   ├── ExpectCallsWithOtherStatementsBetween.php
                        │   ├── InvalidTestNameAndDatasetName.after.php
                        │   ├── InvalidTestNameAndDatasetName.php
                        │   ├── InvalidTestNameCase.after.php
                        │   ├── InvalidTestNameCase.php
                        │   ├── ManyExpectCall.after.php
                        │   ├── ManyExpectCall.php
                        │   ├── MultipleExpectCall.after.php
                        │   ├── MultipleExpectCall.php
                        │   ├── MultipleExpectCallsWithOtherStatementsBetween.after.php
                        │   ├── MultipleExpectCallsWithOtherStatementsBetween.php
                        │   ├── SingleExpectCall.php
                        │   ├── ValidHigherOrderTestNameCase.php
                        │   ├── ValidItTestNameWithoutSpaces.php
                        │   ├── ValidTestNameCase.php
                        │   ├── ValidTestNameWhenWrongCasingOnOneWord.php
                        │   ├── assertionCanBeSimplified/
                        │   │   ├── ToBeWithFalse.after.php
                        │   │   ├── ToBeWithFalse.php
                        │   │   ├── ToBeWithNull.after.php
                        │   │   ├── ToBeWithNull.php
                        │   │   ├── ToBeWithTrue.after.php
                        │   │   ├── ToBeWithTrue.php
                        │   │   ├── ToHaveCountWithZero.after.php
                        │   │   └── ToHaveCountWithZero.php
                        │   ├── pestTestFailedLine/
                        │   │   ├── AnonymousFunction.php
                        │   │   ├── FailedOneLine.php
                        │   │   ├── LambdaFunction.php
                        │   │   ├── MismatchLine.php
                        │   │   ├── MultipleStatementsInOneLine.php
                        │   │   ├── OutRange.php
                        │   │   ├── SingleLeafElementReported.php
                        │   │   ├── TypeBefore.php
                        │   │   ├── TypeInside.php
                        │   │   ├── WithDataSet.php
                        │   │   ├── WithDataSetAndKeys.php
                        │   │   ├── WithDataSetAndSeveralFails.php
                        │   │   └── WithNamedDataSet.php
                        │   ├── phpstorm/
                        │   │   └── MultipleClassesDeclarationsInPestFileTest.php
                        │   └── screenshotProject/
                        │       └── tests/
                        │           ├── .pest/
                        │           │   └── snapshots/
                        │           │       └── Feature/
                        │           │           ├── ScreenshotSnapshot/
                        │           │           │   └── it_browser_testing.snap
                        │           │           ├── ScreenshotSnapshotComplexName/
                        │           │           │   └── it_1__2_3_4_.snap
                        │           │           ├── ScreenshotSnapshotMultiple/
                        │           │           │   ├── it_test.snap
                        │           │           │   └── it_test2.snap
                        │           │           └── nested/
                        │           │               └── ScreenshotSnapshotNested/
                        │           │                   └── nested.snap
                        │           └── Feature/
                        │               ├── MissingScreenshotSnapshot.php
                        │               ├── MissingScreenshotSnapshotComplexName.php
                        │               ├── MissingScreenshotSnapshotMultiple.php
                        │               ├── ScreenshotSnapshot.php
                        │               ├── ScreenshotSnapshotComplexName.php
                        │               ├── ScreenshotSnapshotMultiple.php
                        │               └── nested/
                        │                   ├── MissingScreenshotSnapshotNested.php
                        │                   └── ScreenshotSnapshotNested.php
                        ├── runner/
                        │   └── pestTestStacktraceParser/
                        │       ├── Multiline.php
                        │       ├── OneLine.php
                        │       ├── OneLineRemote.php
                        │       ├── OutRangeLineNumber.php
                        │       └── WrongLineNumber.php
                        ├── snapshotTesting/
                        │   ├── allSnapshotAssertions.php
                        │   ├── nonSnapshotAssertions.php
                        │   ├── snapshotAssertionUseStatement.php
                        │   ├── snapshotTest.php
                        │   └── tests/
                        │       └── __snapshots__/
                        │           └── snapshotTest__it_renders_correctly__1.txt
                        ├── stubs.php
                        ├── templates/
                        │   ├── describe.after.php
                        │   ├── describe.php
                        │   ├── it.after.php
                        │   └── it.php
                        ├── types/
                        │   ├── TestCase.php
                        │   ├── expect/
                        │   │   ├── expectCallCompletion.php
                        │   │   ├── expectCallCompletionChainedNotMethod.php
                        │   │   ├── expectCallCompletionChainedNotProperty.php
                        │   │   ├── expectExtendCallOnNonExpectFunction.php
                        │   │   ├── expectExtendReturnType.php
                        │   │   ├── expectInvalidExtendNoReturnType.php
                        │   │   └── extendCallOnChainedExpectation.php
                        │   ├── function/
                        │   │   └── testTest.php
                        │   ├── this/
                        │   │   ├── beforeEach.php
                        │   │   ├── itShortLambdaTest.php
                        │   │   ├── itTest.php
                        │   │   └── testTest.php
                        │   └── thisField/
                        │       ├── afterEach.php
                        │       ├── afterEachNamespace.php
                        │       ├── beforeEach.php
                        │       ├── beforeEachCompletion.php
                        │       ├── beforeEachNamespace.php
                        │       └── beforeEachNamespaceCompletion.php
                        └── utilTests/
                            ├── ClassNameResolutionInNamespaceTest.php
                            ├── ClassNameResolutionTest.php
                            └── SimpleTest.php
Download .txt
SYMBOL INDEX (224 symbols across 47 files)

FILE: src/main/java/com/pestphp/pest/PestIcons.java
  class PestIcons (line 12) | public final class PestIcons {
    method load (line 13) | private static @NotNull Icon load(@NotNull String path, int cacheKey, ...
    class METAINF (line 21) | public static final class METAINF {

FILE: src/main/java/com/pestphp/pest/configuration/PestRunConfigurationSettings.java
  class PestRunConfigurationSettings (line 9) | public class PestRunConfigurationSettings extends PhpTestRunConfiguratio...
    method createDefault (line 10) | @Override
    method getPestRunnerSettings (line 15) | @Property(surroundWithTag = false)
    method setPestRunnerSettings (line 27) | public void setPestRunnerSettings(PestRunnerSettings runnerSettings) {
    method getRunnerSettings (line 34) | @Deprecated

FILE: src/main/java/com/pestphp/pest/configuration/PhpTestRunConfiguration.java
  class PhpTestRunConfiguration (line 15) | public abstract class PhpTestRunConfiguration extends com.jetbrains.php....
    method PhpTestRunConfiguration (line 16) | protected PhpTestRunConfiguration(Project project, ConfigurationFactor...
    method setBeforeRunTasks (line 20) | @Override

FILE: src/test/resources/com/pestphp/pest/PestTestRunLineMarkerProviderTest/AssignmentFunctionCallNamedTest.php
  function test (line 3) | function test($description, $closure = null): \Pest\PendingCalls\TestCall {

FILE: src/test/resources/com/pestphp/pest/PestTestRunLineMarkerProviderTest/AssignmentFunctionCallNamedTestWithoutPest.php
  function test (line 3) | function test(Bar $a) {

FILE: src/test/resources/com/pestphp/pest/PestTestRunLineMarkerProviderTest/FunctionCallNamedTestAsArgument.php
  function test (line 3) | function test($description, $closure = null): \Pest\PendingCalls\TestCall {
  function foo (line 6) | function foo($x) {

FILE: src/test/resources/com/pestphp/pest/PestTestRunLineMarkerProviderTest/FunctionCallNamedTestWithoutPest.php
  function test (line 3) | function test(Bar $a) {

FILE: src/test/resources/com/pestphp/pest/PestTestRunLineMarkerProviderTest/MethodCallNamedItAndVariableTest.php
  function it (line 3) | function it($description, $closure = null): \Pest\PendingCalls\TestCall {

FILE: src/test/resources/com/pestphp/pest/PestTestRunLineMarkerProviderTest/PestItFunctionCallWithRedefinition.php
  function it (line 3) | function it($description, $closure = null): \Pest\PendingCalls\TestCall {

FILE: src/test/resources/com/pestphp/pest/annotator/NoDuplicateTestName.php
  class A (line 11) | class A {
  class B (line 14) | class B {
  class C (line 25) | class C {

FILE: src/test/resources/com/pestphp/pest/annotator/stub/Functions.php
  function test (line 3) | function test($description, $closure) {

FILE: src/test/resources/com/pestphp/pest/codeInsight/typeInference/ThisInInnerClosure.php
  function someFoo (line 9) | function someFoo($closure) {
  type T (line 13) | trait T {
    method foo (line 14) | function foo() {

FILE: src/test/resources/com/pestphp/pest/configuration/pest/tests/Pest.php
  class BaseTestCase (line 3) | class BaseTestCase
    method baseTestFunc (line 5) | public function baseTestFunc(){}
  class FeatureTestCase (line 8) | class FeatureTestCase
    method featureTestFunc (line 10) | public function featureTestFunc(){}
  class SomeBaseTrait (line 13) | class SomeBaseTrait
    method someBaseTraitFunc (line 15) | public function someBaseTraitFunc(){}

FILE: src/test/resources/com/pestphp/pest/configuration/pest/tests/Unit/PestExtendUnitTest.php
  class SomeTrait (line 3) | class SomeTrait {
    method traitFunc (line 4) | public function traitFunc(){}

FILE: src/test/resources/com/pestphp/pest/configuration/uses/Pest.php
  class BaseTestCase (line 3) | class BaseTestCase
    method baseTestFunc (line 5) | public function baseTestFunc(){}
  class FeatureTestCase (line 8) | class FeatureTestCase
    method featureTestFunc (line 10) | public function featureTestFunc(){}
  class SomeBaseTrait (line 13) | class SomeBaseTrait
    method someBaseTraitFunc (line 15) | public function someBaseTraitFunc(){}

FILE: src/test/resources/com/pestphp/pest/configuration/uses/Unit/UsesUnitTest.php
  class SomeTrait (line 3) | class SomeTrait {
    method traitFunc (line 4) | public function traitFunc(){}

FILE: src/test/resources/com/pestphp/pest/customExpectations/CustomUserExpectation.php
  class User (line 5) | class User {

FILE: src/test/resources/com/pestphp/pest/customExpectations/generators/ExpectationGenerator/GeneratedWithMethod.php
  class Expectation (line 8) | final class Expectation {}

FILE: src/test/resources/com/pestphp/pest/generateTest/testWithNamespace.php
  class A (line 3) | class A  {
    method foo (line 4) | function foo(): int {

FILE: src/test/resources/com/pestphp/pest/goto/PestTestFinder/App/User.php
  class User (line 5) | class User {
    method getName (line 6) | public function getName(): String
    method isPestDeveloper (line 11) | public function isPestDeveloper(): bool
    method isPest (line 16) | public function isPest(): bool
    method is (line 21) | public function is(): bool

FILE: src/test/resources/com/pestphp/pest/goto/PestTestFinder/test/App/MockTest.php
  class Mock (line 5) | class Mock {
    method getMock (line 6) | public function getMock() {

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectMethodAssertionCompletion.php
  class Example (line 3) | class Example {
    method getTest (line 4) | public function getTest(): string
    method getOtherExample (line 9) | public function getOtherExample(): string

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectMethodAssertionCompletionChained.php
  class Example (line 3) | class Example {
    method getDate (line 4) | public function getDate(): DateTime

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectMethodAssertionCompletionChainedAssertions.php
  class Example (line 3) | class Example {
    method getTest (line 4) | public function getTest(): string
    method getOtherExample (line 9) | public function getOtherExample(): string

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectMethodCompletion.php
  class Example (line 3) | class Example {
    method getTest (line 4) | public function getTest(): string
    method getOtherExample (line 9) | public function getOtherExample(): string

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectMethodCompletionChained.php
  class Chained (line 3) | class Chained
    method getTimestamp (line 5) | public function getTimestamp()
  class Example (line 10) | class Example
    method getDate (line 12) | public function getDate(): Chained

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectMethodCompletionChainedAssertions.php
  class Example (line 3) | class Example {
    method getTest (line 4) | public function getTest(): string
    method getOtherExample (line 9) | public function getOtherExample(): string

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectPropertyAssertionCompletion.php
  class Example (line 3) | class Example {

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectPropertyAssertionCompletionChained.php
  class Example (line 3) | class Example {
    method __construct (line 6) | public function __construct()

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectPropertyAssertionCompletionChainedAssertions.php
  class Example (line 3) | class Example {

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectPropertyCompletion.php
  class Example (line 3) | class Example {

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectPropertyCompletionChained.php
  class Chained (line 3) | class Chained
    method getTimestamp (line 5) | public function getTimestamp()
  class Example (line 10) | class Example {
    method __construct (line 13) | public function __construct()

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/ExpectPropertyCompletionChainedAssertions.php
  class Example (line 3) | class Example {

FILE: src/test/resources/com/pestphp/pest/higherOrderExpectations/stubs.php
  function expect (line 5) | function expect($value = null)
  class Expectation (line 20) | final class Expectation
    method __construct (line 50) | public function __construct($value)
    method and (line 62) | public function and($value): Expectation
    method json (line 70) | public function json(): Expectation
    method dd (line 82) | public function dd(...$arguments): void
    method ray (line 98) | public function ray(...$arguments): self
    method not (line 110) | public function not(): OppositeExpectation
    method each (line 118) | public function each(callable $callback = null): Each
    method sequence (line 140) | public function sequence(...$callbacks): Expectation
    method match (line 182) | public function match($subject, array $expressions): Expectation
    method unless (line 224) | public function unless($condition, callable $callback): Expectation
    method when (line 241) | public function when($condition, callable $callback): Expectation
    method toBe (line 263) | public function toBe($expected): Expectation
    method toBeEmpty (line 273) | public function toBeEmpty(): Expectation
    method toBeTrue (line 283) | public function toBeTrue(): Expectation
    method toBeTruthy (line 293) | public function toBeTruthy(): Expectation
    method toBeFalse (line 303) | public function toBeFalse(): Expectation
    method toBeFalsy (line 313) | public function toBeFalsy(): Expectation
    method toBeGreaterThan (line 325) | public function toBeGreaterThan($expected): Expectation
    method toBeGreaterThanOrEqual (line 337) | public function toBeGreaterThanOrEqual($expected): Expectation
    method toBeLessThan (line 349) | public function toBeLessThan($expected): Expectation
    method toBeLessThanOrEqual (line 361) | public function toBeLessThanOrEqual($expected): Expectation
    method toContain (line 373) | public function toContain(...$needles): Expectation
    method toStartWith (line 389) | public function toStartWith(string $expected): Expectation
    method toEndWith (line 399) | public function toEndWith(string $expected): Expectation
    method toHaveLength (line 409) | public function toHaveLength(int $number): Expectation
    method toHaveCount (line 439) | public function toHaveCount(int $count): Expectation
    method toHaveProperty (line 451) | public function toHaveProperty(string $name, $value = null): Expectation
    method toHaveProperties (line 470) | public function toHaveProperties(iterable $names): Expectation
    method toEqual (line 484) | public function toEqual($expected): Expectation
    method toEqualCanonicalizing (line 502) | public function toEqualCanonicalizing($expected): Expectation
    method toEqualWithDelta (line 515) | public function toEqualWithDelta($expected, float $delta): Expectation
    method toBeIn (line 527) | public function toBeIn(iterable $values): Expectation
    method toBeInfinite (line 537) | public function toBeInfinite(): Expectation
    method toBeInstanceOf (line 549) | public function toBeInstanceOf($class): Expectation
    method toBeArray (line 560) | public function toBeArray(): Expectation
    method toBeBool (line 570) | public function toBeBool(): Expectation
    method toBeCallable (line 580) | public function toBeCallable(): Expectation
    method toBeFloat (line 590) | public function toBeFloat(): Expectation
    method toBeInt (line 600) | public function toBeInt(): Expectation
    method toBeIterable (line 610) | public function toBeIterable(): Expectation
    method toBeNumeric (line 620) | public function toBeNumeric(): Expectation
    method toBeObject (line 630) | public function toBeObject(): Expectation
    method toBeResource (line 640) | public function toBeResource(): Expectation
    method toBeScalar (line 650) | public function toBeScalar(): Expectation
    method toBeString (line 660) | public function toBeString(): Expectation
    method toBeJson (line 670) | public function toBeJson(): Expectation
    method toBeNan (line 681) | public function toBeNan(): Expectation
    method toBeNull (line 691) | public function toBeNull(): Expectation
    method toHaveKey (line 704) | public function toHaveKey($key, $value = null): Expectation
    method toHaveKeys (line 732) | public function toHaveKeys(array $keys): Expectation
    method toBeDirectory (line 744) | public function toBeDirectory(): Expectation
    method toBeReadableDirectory (line 754) | public function toBeReadableDirectory(): Expectation
    method toBeWritableDirectory (line 764) | public function toBeWritableDirectory(): Expectation
    method toBeFile (line 774) | public function toBeFile(): Expectation
    method toBeReadableFile (line 784) | public function toBeReadableFile(): Expectation
    method toBeWritableFile (line 794) | public function toBeWritableFile(): Expectation
    method toMatchArray (line 806) | public function toMatchArray($array): Expectation
    method toMatchObject (line 837) | public function toMatchObject($object): Expectation
    method toMatch (line 861) | public function toMatch(string $expression): Expectation
    method toMatchConstraint (line 871) | public function toMatchConstraint(Constraint $constraint): Expectation
    method toThrow (line 883) | public function toThrow($exception, string $exceptionMessage = null): ...
    method export (line 933) | private function export($value): string
    method __call (line 950) | public function __call(string $method, array $parameters)
    method __get (line 966) | public function __get(string $name)

FILE: src/test/resources/com/pestphp/pest/inspections/pestTestFailedLine/AnonymousFunction.php
  function myAssert (line 10) | function myAssert(callable $a) {

FILE: src/test/resources/com/pestphp/pest/inspections/pestTestFailedLine/LambdaFunction.php
  function myAssert (line 9) | function myAssert(callable $a) {

FILE: src/test/resources/com/pestphp/pest/inspections/pestTestFailedLine/SingleLeafElementReported.php
  function myAssert (line 11) | function myAssert(callable $a) {

FILE: src/test/resources/com/pestphp/pest/inspections/phpstorm/MultipleClassesDeclarationsInPestFileTest.php
  class TestingClass (line 8) | class TestingClass {
  class AnotherTestingClass (line 12) | class AnotherTestingClass {

FILE: src/test/resources/com/pestphp/pest/runner/pestTestStacktraceParser/Multiline.php
  function foo (line 7) | function foo() {
  function boo (line 11) | function boo() {

FILE: src/test/resources/com/pestphp/pest/stubs.php
  class TestCall (line 7) | class TestCall {
    method with (line 8) | public function with(Closure|iterable|string ...$data): self
  function test (line 12) | function test(?string $description = null, ?Closure $closure = null): Hi...
  function it (line 16) | function it(string $description, ?Closure $closure = null): TestCall
  function describe (line 20) | function describe(string $description, $tests): TestCall
  function expect (line 24) | function expect($value = null)
  class Expectation (line 35) | final class Expectation
    method __construct (line 42) | public function __construct($value)
    method and (line 52) | public function and($value): Expectation
    method not (line 60) | public function not(): Expectation
    method toBe (line 72) | public function toBe($expected): Expectation
    method toBeEmpty (line 82) | public function toBeEmpty(): Expectation
    method toBeTrue (line 92) | public function toBeTrue(): Expectation
    method toBeFalse (line 102) | public function toBeFalse(): Expectation
    method toBeGreaterThan (line 114) | public function toBeGreaterThan($expected): Expectation
    method toBeGreaterThanOrEqual (line 126) | public function toBeGreaterThanOrEqual($expected): Expectation
    method toBeLessThan (line 138) | public function toBeLessThan($expected): Expectation
    method toBeLessThanOrEqual (line 150) | public function toBeLessThanOrEqual($expected): Expectation
    method toContain (line 162) | public function toContain($needle): Expectation
    method toStartWith (line 176) | public function toStartWith(string $expected): Expectation
    method toEndWith (line 186) | public function toEndWith(string $expected): Expectation
    method toHaveCount (line 196) | public function toHaveCount(int $count): Expectation
    method toHaveProperty (line 208) | public function toHaveProperty(string $name, $value = null): Expectation
    method toEqual (line 227) | public function toEqual($expected): Expectation
    method toEqualCanonicalizing (line 245) | public function toEqualCanonicalizing($expected): Expectation
    method toEqualWithDelta (line 258) | public function toEqualWithDelta($expected, float $delta): Expectation
    method toBeInfinite (line 268) | public function toBeInfinite(): Expectation
    method toBeInstanceOf (line 280) | public function toBeInstanceOf($class): Expectation
    method toBeArray (line 291) | public function toBeArray(): Expectation
    method toBeBool (line 301) | public function toBeBool(): Expectation
    method toBeCallable (line 311) | public function toBeCallable(): Expectation
    method toBeFloat (line 321) | public function toBeFloat(): Expectation
    method toBeInt (line 331) | public function toBeInt(): Expectation
    method toBeIterable (line 341) | public function toBeIterable(): Expectation
    method toBeNumeric (line 351) | public function toBeNumeric(): Expectation
    method toBeObject (line 361) | public function toBeObject(): Expectation
    method toBeResource (line 371) | public function toBeResource(): Expectation
    method toBeScalar (line 381) | public function toBeScalar(): Expectation
    method toBeString (line 391) | public function toBeString(): Expectation
    method toBeJson (line 401) | public function toBeJson(): Expectation
    method toBeNan (line 412) | public function toBeNan(): Expectation
    method toBeNull (line 422) | public function toBeNull(): Expectation
    method toHaveKey (line 435) | public function toHaveKey($key, $value = null): Expectation
    method toHaveKeys (line 457) | public function toHaveKeys(array $keys): Expectation
    method toBeDirectory (line 469) | public function toBeDirectory(): Expectation
    method toBeReadableDirectory (line 479) | public function toBeReadableDirectory(): Expectation
    method toBeWritableDirectory (line 489) | public function toBeWritableDirectory(): Expectation
    method toBeFile (line 499) | public function toBeFile(): Expectation
    method toBeReadableFile (line 509) | public function toBeReadableFile(): Expectation
    method toBeWritableFile (line 519) | public function toBeWritableFile(): Expectation
    method toMatchArray (line 531) | public function toMatchArray($array): Expectation
    method toMatchObject (line 562) | public function toMatchObject($object): Expectation
    method toMatch (line 586) | public function toMatch(string $expression): Expectation
    method toMatchConstraint (line 596) | public function toMatchConstraint(Constraint $constraint): Expectation
    method export (line 608) | private function export($value): string
    method __get (line 622) | public function __get(string $name)

FILE: src/test/resources/com/pestphp/pest/types/TestCase.php
  class TestCase (line 5) | abstract class TestCase {
    method expectException (line 11) | public function expectException($exception) {}
    method expectExceptionCode (line 16) | public function expectExceptionCode($code){}
    method someProtectedMethod (line 18) | protected function someProtectedMethod(){}
    method someStaticMethod (line 20) | public static function someStaticMethod(){}

FILE: src/test/resources/com/pestphp/pest/types/thisField/afterEach.php
  class Foo (line 3) | class Foo {
    method b (line 6) | public function b(){}

FILE: src/test/resources/com/pestphp/pest/types/thisField/afterEachNamespace.php
  class Foo (line 5) | class Foo {
    method b (line 8) | public function b(){}

FILE: src/test/resources/com/pestphp/pest/types/thisField/beforeEach.php
  class Foo (line 3) | class Foo {
    method b (line 6) | public function b(){}

FILE: src/test/resources/com/pestphp/pest/types/thisField/beforeEachNamespace.php
  class Foo (line 5) | class Foo {
    method b (line 8) | public function b(){}

FILE: src/test/resources/com/pestphp/pest/utilTests/ClassNameResolutionInNamespaceTest.php
  class B (line 4) | class B {

FILE: src/test/resources/com/pestphp/pest/utilTests/ClassNameResolutionTest.php
  class A (line 3) | class A {
Condensed preview — 461 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (625K chars).
[
  {
    "path": ".editorconfig",
    "chars": 122,
    "preview": "[*]\nindent_size = 4\n\n[{*.kt,*.kts}]\nij_kotlin_code_style_defaults = KOTLIN_OFFICIAL\nij_kotlin_continuation_indent_size ="
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 20,
    "preview": "github: olivernybroe"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 190,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\nPlease report a "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.md",
    "chars": 136,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\nCreate a disc"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 147,
    "preview": "<!-- Description of what has been changed or added in this pr and why -->\n\n- [ ] Added or updated tests\n- [ ] Updated `C"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 267,
    "preview": "# Dependabot configuration:\n# https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configur"
  },
  {
    "path": ".github/workflows/auto-close.yml",
    "chars": 539,
    "preview": "on:\n  issues:\n    types: [opened, edited]\n\njobs:\n  auto_close_issues:\n    runs-on: ubuntu-latest\n    steps:\n      - name"
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 5559,
    "preview": "# GitHub Actions Workflow created for testing and preparing the plugin release in following steps:\n# - validate Gradle W"
  },
  {
    "path": ".github/workflows/qodana.yml",
    "chars": 663,
    "preview": "name: Qodana\non:\n  workflow_dispatch:\n  pull_request:\n    branches:\n      - main\n  push:\n    branches:\n      - main\n\njob"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 2798,
    "preview": "# GitHub Actions Workflow created for handling the release process based on the draft release prepared\n# with the Build "
  },
  {
    "path": ".github/workflows/run-ui-tests.yml",
    "chars": 1641,
    "preview": "# GitHub Actions Workflow for launching UI tests on Linux, Windows, and Mac in the following steps:\n# - prepare and laun"
  },
  {
    "path": ".gitignore",
    "chars": 37,
    "preview": ".gradle\nbuild\n.idea\n.intellijPlatform"
  },
  {
    "path": ".run/Run IDE with Plugin.run.xml",
    "chars": 1023,
    "preview": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"Run PhpStorm with Plugin\" type="
  },
  {
    "path": ".run/Run Plugin Tests.run.xml",
    "chars": 1006,
    "preview": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"Run Tests\" type=\"GradleRunConfi"
  },
  {
    "path": ".run/Run Plugin Verification.run.xml",
    "chars": 1182,
    "preview": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"Run Verifications\" type=\"Gradle"
  },
  {
    "path": ".run/Run Qodana.run.xml",
    "chars": 1152,
    "preview": "<component name=\"ProjectRunConfigurationManager\">\n    <configuration default=\"false\" name=\"Run Qodana\" type=\"GradleRunCo"
  },
  {
    "path": "BUILD.bazel",
    "chars": 8776,
    "preview": "### auto-generated section `build intellij.pest` start\nload(\"@rules_jvm//:jvm.bzl\", \"jvm_library\")\n\njvm_library(\n  name "
  },
  {
    "path": "CHANGELOG.md",
    "chars": 10605,
    "preview": "<!-- Keep a Changelog guide -> https://keepachangelog.com -->\n\n# PEST IntelliJ Changelog\n\n## Unreleased\n\n### Added\n\n- Ad"
  },
  {
    "path": "CLAUDE.md",
    "chars": 285,
    "preview": "# Pest Plugin\n\n## Mock Usage Guidelines\n\nPrefer MockK to other mocking approaches.\n\nWhen using MockK, prefer explicit st"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 469,
    "preview": "# Contributing to Pest IntelliJ\n\nThank you for wanting to contribute!\n\n## What should I know before getting started?\nThe"
  },
  {
    "path": "LICENSE.md",
    "chars": 1088,
    "preview": "MIT License\n\nCopyright (c) Oliver Nybroe olivernybroe@gmail.com\n\nPermission is hereby granted, free of charge, to any pe"
  },
  {
    "path": "README.md",
    "chars": 2941,
    "preview": "<p align=\"center\">\n    <img src=\"/art/banner.png\" width=\"914\" title=\"PEST IntelliJ Banner\">\n    <p align=\"center\">\n     "
  },
  {
    "path": "build.gradle.kts",
    "chars": 4230,
    "preview": "import org.jetbrains.intellij.platform.gradle.ProductMode\nimport org.jetbrains.changelog.Changelog\nimport org.jetbrains."
  },
  {
    "path": "coverage/BUILD.bazel",
    "chars": 2449,
    "preview": "### auto-generated section `build intellij.pest.coverage` start\nload(\"@rules_jvm//:jvm.bzl\", \"jvm_library\")\n\njvm_library"
  },
  {
    "path": "coverage/intellij.pest.coverage.iml",
    "chars": 1834,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" "
  },
  {
    "path": "coverage/resources/intellij.pest.coverage.xml",
    "chars": 753,
    "preview": "<idea-plugin>\n    <dependencies>\n        <plugin id=\"com.jetbrains.php\"/>\n        <plugin id=\"com.pestphp.pest-intellij\""
  },
  {
    "path": "coverage/src/PestCoverageEnabledConfiguration.kt",
    "chars": 532,
    "preview": "package com.intellij.pest.coverage\n\nimport com.intellij.coverage.CoverageRunner\nimport com.intellij.execution.configurat"
  },
  {
    "path": "coverage/src/PestCoverageEngine.kt",
    "chars": 1865,
    "preview": "package com.intellij.pest.coverage\n\nimport com.intellij.coverage.CoverageFileProvider\nimport com.intellij.coverage.Cover"
  },
  {
    "path": "coverage/src/PestCoverageProgramRunner.kt",
    "chars": 3353,
    "preview": "package com.intellij.pest.coverage\n\nimport com.intellij.execution.configurations.RunProfile\nimport com.intellij.executio"
  },
  {
    "path": "coverage/src/features/mutate/PestMutateProgramRunner.kt",
    "chars": 1605,
    "preview": "package com.intellij.pest.coverage.features.mutate\n\nimport com.intellij.execution.configurations.RunProfile\nimport com.i"
  },
  {
    "path": "coverage/src/features/mutate/PestMutateTestExecutor.kt",
    "chars": 1905,
    "preview": "package com.intellij.pest.coverage.features.mutate\n\nimport com.intellij.execution.Executor\nimport com.intellij.icons.All"
  },
  {
    "path": "coverage/tests/BUILD.bazel",
    "chars": 2634,
    "preview": "### auto-generated section `build intellij.pest.coverage.tests` start\nload(\"@rules_jvm//:jvm.bzl\", \"jvm_library\")\n\njvm_l"
  },
  {
    "path": "coverage/tests/intellij.pest.coverage.tests.iml",
    "chars": 1858,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" "
  },
  {
    "path": "coverage/tests/src/com/intellij/pest/coverage/PestCoverageProgramRunnerTest.kt",
    "chars": 6694,
    "preview": "package com.intellij.pest.coverage\n\nimport com.intellij.coverage.CoverageDataManager\nimport com.intellij.coverage.Covera"
  },
  {
    "path": "coverage/tests/src/com/intellij/pest/coverage/features/mutate/PestMutateProgramRunnerTest.kt",
    "chars": 3932,
    "preview": "package com.intellij.pest.coverage.features.mutate\n\nimport com.intellij.execution.PsiLocation\nimport com.intellij.execut"
  },
  {
    "path": "coverage/tests/testData/ATest.php",
    "chars": 34,
    "preview": "<?php\n\ntest(\"foo\", function() {});"
  },
  {
    "path": "coverage/tests/testData/features/mutate/ATest.php",
    "chars": 34,
    "preview": "<?php\n\ntest(\"foo\", function() {});"
  },
  {
    "path": "coverage/tests/testData/features/mutate/php",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "coverage/tests/testData/php",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 200,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "gradle.properties",
    "chars": 1031,
    "preview": "# IntelliJ Platform Artifacts Repositories\n# -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html\n\nplu"
  },
  {
    "path": "gradlew",
    "chars": 8047,
    "preview": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "gradlew.bat",
    "chars": 2674,
    "preview": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \""
  },
  {
    "path": "intellij.pest.iml",
    "chars": 3179,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" "
  },
  {
    "path": "intellij.pest.tests.iml",
    "chars": 3818,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" "
  },
  {
    "path": "plugin-content.yaml",
    "chars": 153,
    "preview": "- name: lib/modules/intellij.pest.coverage.jar\n  contentModules:\n  - name: intellij.pest.coverage\n- name: lib/pest.jar\n "
  },
  {
    "path": "settings.gradle.kts",
    "chars": 218,
    "preview": "rootProject.name = \"pest-intellij\"\n\npluginManagement {\n    repositories {\n        maven {\n            url = uri(\"https:/"
  },
  {
    "path": "src/main/java/com/pestphp/pest/PestIcons.java",
    "chars": 1203,
    "preview": "package com.pestphp.pest;\n\nimport com.intellij.ui.IconManager;\nimport org.jetbrains.annotations.NotNull;\n\nimport javax.s"
  },
  {
    "path": "src/main/java/com/pestphp/pest/configuration/PestRunConfigurationSettings.java",
    "chars": 1273,
    "preview": "package com.pestphp.pest.configuration;\n\nimport com.intellij.util.xmlb.annotations.Property;\nimport com.intellij.util.xm"
  },
  {
    "path": "src/main/java/com/pestphp/pest/configuration/PhpTestRunConfiguration.java",
    "chars": 1232,
    "preview": "package com.pestphp.pest.configuration;\n\nimport com.intellij.execution.BeforeRunTask;\nimport com.intellij.execution.conf"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/FileUtil.kt",
    "chars": 467,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.psi.PsiFile\nimport com.intellij.testFramework.LightVirtualFile\n\n/**\n * Tak"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestBundle.kt",
    "chars": 626,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.DynamicBundle\nimport org.jetbrains.annotations.NonNls\nimport org.jetbrains"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestComposerConfig.kt",
    "chars": 680,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.execution.configurations.ConfigurationType\nimport com.jetbrains.php.testFr"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestFrameworkType.kt",
    "chars": 2091,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.openapi.project.Project\nimport com.jetbrains.php.testFramework.PhpTestDesc"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestFunctionsUtil.kt",
    "chars": 4495,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiFile\nimport com.jetbrains.php.Ph"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestIconProvider.kt",
    "chars": 953,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.ide.FileIconProvider\nimport com.intellij.openapi.project.DumbService\nimpor"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestNamingUtil.kt",
    "chars": 7382,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.util.findParentOfType\nimport com.in"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestNewTestFromClassAction.kt",
    "chars": 693,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.vfs.VirtualFile\nimport"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestPluginDisposable.kt",
    "chars": 743,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.openapi.Disposable\nimport com.intellij.openapi.application.ApplicationMana"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestSettings.kt",
    "chars": 1364,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.openapi.components.PersistentStateComponent\nimport com.intellij.openapi.co"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestTestCreateInfo.kt",
    "chars": 1192,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.openapi.project.Project\nimport com.intellij.psi.PsiFile\nimport com.intelli"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestTestDescriptor.kt",
    "chars": 1163,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.util.SmartList\nimport com.jetbrains.php.lang.psi.elements.Method\nimport co"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestTestFileUtil.kt",
    "chars": 4226,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.openapi.util.Key\nimport com.intellij.psi.PsiElement\nimport com.intellij.ps"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestTestRunLineMarkerProvider.kt",
    "chars": 2712,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.execution.lineMarker.RunLineMarkerContributor\nimport com.intellij.icons.Al"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/PestUtil.kt",
    "chars": 3148,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.project.guessProjectDi"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/annotator/PestAnnotator.kt",
    "chars": 735,
    "preview": "package com.pestphp.pest.annotator\n\nimport com.intellij.codeInsight.daemon.impl.HighlightRangeExtension\nimport com.intel"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/annotator/PestAnnotatorVisitor.kt",
    "chars": 4573,
    "preview": "package com.pestphp.pest.annotator\n\nimport com.intellij.lang.annotation.AnnotationHolder\nimport com.intellij.lang.annota"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/completion/InternalMembersCompletionProvider.kt",
    "chars": 1885,
    "preview": "package com.pestphp.pest.completion\n\nimport com.intellij.codeInsight.completion.CompletionParameters\nimport com.intellij"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/completion/PestCompletionContributor.kt",
    "chars": 1248,
    "preview": "package com.pestphp.pest.completion\n\nimport com.intellij.codeInsight.completion.CompletionContributor\nimport com.intelli"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/completion/PestCustomExtensionCompletionProvider.kt",
    "chars": 4676,
    "preview": "@file:Suppress(\"UnstableApiUsage\")\n\npackage com.pestphp.pest.completion\n\nimport com.intellij.codeInsight.AutoPopupContro"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/completion/ThisFieldsCompletionProvider.kt",
    "chars": 2694,
    "preview": "package com.pestphp.pest.completion\n\nimport com.intellij.codeInsight.completion.CompletionParameters\nimport com.intellij"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/configuration/PestDebugRunner.kt",
    "chars": 360,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.jetbrains.php.testFramework.run.PhpTestDebugRunner\n\n/**\n * Add suppor"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/configuration/PestLocationProvider.kt",
    "chars": 4585,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.execution.Location\nimport com.intellij.execution.testframewo"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/configuration/PestRerunFailedTestsAction.kt",
    "chars": 4265,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.execution.Executor\nimport com.intellij.execution.configurati"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/configuration/PestRerunProfile.kt",
    "chars": 66,
    "preview": "package com.pestphp.pest.configuration\n\ninterface PestRerunProfile"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/configuration/PestRunConfiguration.kt",
    "chars": 9086,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.codeInsight.completion.CompletionResultSet\nimport com.intell"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/configuration/PestRunConfigurationHandler.kt",
    "chars": 2509,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.execution.ExecutionException\nimport com.intellij.openapi.pro"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/configuration/PestRunConfigurationProducer.kt",
    "chars": 2557,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.execution.actions.ConfigurationFromContext\nimport com.intell"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/configuration/PestRunConfigurationType.kt",
    "chars": 1081,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.execution.configurations.ConfigurationTypeUtil.findConfigura"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/configuration/PestRunnerSettings.kt",
    "chars": 1794,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.util.xmlb.annotations.Attribute\nimport com.intellij.util.xml"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/configuration/PestTestRunConfigurationEditor.kt",
    "chars": 3651,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.openapi.editor.ReadOnlyModificationException\nimport com.inte"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/configuration/PestVersionDetector.kt",
    "chars": 1812,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.execution.ExecutionException\nimport com.intellij.openapi.pro"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/configuration/ConfigurationInDirectoryReferenceProvider.kt",
    "chars": 1697,
    "preview": "package com.pestphp.pest.features.configuration\n\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiReference"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/configuration/ConfigurationReferenceContributor.kt",
    "chars": 875,
    "preview": "package com.pestphp.pest.features.configuration\n\nimport com.intellij.patterns.PlatformPatterns\nimport com.intellij.psi.P"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/configuration/PhpFolderReferenceSet.kt",
    "chars": 1135,
    "preview": "package com.pestphp.pest.features.configuration\n\nimport com.intellij.openapi.util.Condition\nimport com.intellij.psi.PsiE"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/CustomExpectationIndex.kt",
    "chars": 3089,
    "preview": "package com.pestphp.pest.features.customExpectations\n\nimport com.intellij.openapi.vfs.VirtualFile\nimport com.intellij.ut"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/CustomExpectationNotifier.kt",
    "chars": 511,
    "preview": "package com.pestphp.pest.features.customExpectations\n\nimport com.intellij.psi.PsiFile\nimport com.intellij.util.messages."
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/CustomExpectationParameterInfoHandler.kt",
    "chars": 4497,
    "preview": "@file:Suppress(\"UnstableApiUsage\")\n\npackage com.pestphp.pest.features.customExpectations\n\nimport com.intellij.lang.param"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/CustomExpectationRemoveGeneratedFileStartupActivity.kt",
    "chars": 1552,
    "preview": "package com.pestphp.pest.features.customExpectations\n\nimport com.intellij.openapi.application.runWriteAction\nimport com."
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/ListMethodDataExternalizer.kt",
    "chars": 875,
    "preview": "package com.pestphp.pest.features.customExpectations\n\nimport com.intellij.util.io.DataExternalizer\nimport com.pestphp.pe"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/MethodDataExternalizer.kt",
    "chars": 2113,
    "preview": "package com.pestphp.pest.features.customExpectations\n\nimport com.intellij.util.io.DataExternalizer\nimport com.intellij.u"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/expectationUtil.kt",
    "chars": 3856,
    "preview": "package com.pestphp.pest.features.customExpectations\n\nimport com.intellij.openapi.project.Project\nimport com.intellij.ps"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/externalizers/ListDataExternalizer.kt",
    "chars": 718,
    "preview": "package com.pestphp.pest.features.customExpectations.externalizers\n\nimport com.intellij.util.io.DataExternalizer\nimport "
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/externalizers/MethodDataExternalizer.kt",
    "chars": 1138,
    "preview": "package com.pestphp.pest.features.customExpectations.externalizers\n\nimport com.intellij.util.io.DataExternalizer\nimport "
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/externalizers/ParameterDataExternalizer.kt",
    "chars": 1228,
    "preview": "package com.pestphp.pest.features.customExpectations.externalizers\n\nimport com.intellij.util.io.DataExternalizer\nimport "
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/externalizers/PhpTypeDataExternalizer.kt",
    "chars": 874,
    "preview": "package com.pestphp.pest.features.customExpectations.externalizers\n\nimport com.intellij.util.io.DataExternalizer\nimport "
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/generators/ExpectationGenerator.kt",
    "chars": 1400,
    "preview": "package com.pestphp.pest.features.customExpectations.generators\n\nimport com.intellij.openapi.project.Project\nimport com."
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/generators/Method.kt",
    "chars": 1351,
    "preview": "package com.pestphp.pest.features.customExpectations.generators\n\nimport com.intellij.openapi.project.Project\nimport com."
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/generators/Parameter.kt",
    "chars": 1020,
    "preview": "package com.pestphp.pest.features.customExpectations.generators\n\nimport com.jetbrains.php.lang.psi.resolve.types.PhpType"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/symbols/PestCustomExpectationReference.kt",
    "chars": 1800,
    "preview": "@file:Suppress(\"UnstableApiUsage\")\n\npackage com.pestphp.pest.features.customExpectations.symbols\n\nimport com.intellij.mo"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/symbols/PestCustomExpectationReferenceProvider.kt",
    "chars": 2041,
    "preview": "@file:Suppress(\"UnstableApiUsage\")\n\npackage com.pestphp.pest.features.customExpectations.symbols\n\nimport com.intellij.mo"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/symbols/PestCustomExpectationRenameUsageSearcher.kt",
    "chars": 2276,
    "preview": "@file:Suppress(\"UnstableApiUsage\")\n\npackage com.pestphp.pest.features.customExpectations.symbols\n\nimport com.intellij.fi"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/symbols/PestCustomExpectationSymbol.kt",
    "chars": 2232,
    "preview": "@file:Suppress(\"UnstableApiUsage\")\n\npackage com.pestphp.pest.features.customExpectations.symbols\n\nimport com.intellij.fi"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/symbols/PestCustomExpectationSymbolDeclaration.kt",
    "chars": 894,
    "preview": "@file:Suppress(\"UnstableApiUsage\")\n\npackage com.pestphp.pest.features.customExpectations.symbols\n\nimport com.intellij.mo"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/symbols/PestCustomExpectationSymbolDeclarationProvider.kt",
    "chars": 1474,
    "preview": "@file:Suppress(\"UnstableApiUsage\")\n\npackage com.pestphp.pest.features.customExpectations.symbols\n\nimport com.intellij.mo"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/customExpectations/symbols/PestCustomExpectationUsageSearcher.kt",
    "chars": 2614,
    "preview": "@file:Suppress(\"UnstableApiUsage\")\n\npackage com.pestphp.pest.features.customExpectations.symbols\n\nimport com.intellij.fi"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/datasets/DatasetIndex.kt",
    "chars": 2384,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.openapi.vfs.VirtualFile\nimport com.intellij.util.indexin"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/datasets/DatasetReference.kt",
    "chars": 3425,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiElementResolve"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/datasets/DatasetReferenceContributor.kt",
    "chars": 909,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.patterns.PlatformPatterns\nimport com.intellij.psi.PsiRef"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/datasets/DatasetReferenceProvider.kt",
    "chars": 977,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiReference\nimpo"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/datasets/DatasetUtil.kt",
    "chars": 1525,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiFile\nimport co"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/datasets/InvalidDatasetNameCaseInspection.kt",
    "chars": 3585,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.codeInspection.ProblemsHolder\nimport com.intellij.modcom"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/datasets/InvalidDatasetReferenceInspection.kt",
    "chars": 2587,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.codeIns"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/parallel/PestParallelProgramRunner.kt",
    "chars": 6157,
    "preview": "package com.pestphp.pest.features.parallel\n\nimport com.intellij.execution.ExecutionException\nimport com.intellij.executi"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/parallel/PestParallelSMTEventsAdapter.kt",
    "chars": 948,
    "preview": "package com.pestphp.pest.features.parallel\n\nimport com.intellij.execution.testframework.sm.runner.SMTRunnerEventsAdapter"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/parallel/PestParallelTestExecutor.kt",
    "chars": 1901,
    "preview": "package com.pestphp.pest.features.parallel\n\nimport com.intellij.execution.Executor\nimport com.intellij.icons.AllIcons\nim"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/snapshotTesting/SnapshotLineMarkerProvider.kt",
    "chars": 1490,
    "preview": "package com.pestphp.pest.features.snapshotTesting\n\nimport com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo\nimpo"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/features/snapshotTesting/SnapshotUtil.kt",
    "chars": 4294,
    "preview": "package com.pestphp.pest.features.snapshotTesting\n\nimport com.intellij.openapi.project.guessProjectDir\nimport com.intell"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/goto/PestDatasetUsagesGotoHandler.kt",
    "chars": 2012,
    "preview": "package com.pestphp.pest.goto\n\nimport com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler\nimport com.inte"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/goto/PestGotoTargetPresentationProvider.kt",
    "chars": 946,
    "preview": "package com.pestphp.pest.goto\n\nimport com.intellij.codeInsight.navigation.GotoTargetPresentationProvider\nimport com.inte"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/goto/PestTestFinder.kt",
    "chars": 4273,
    "preview": "package com.pestphp.pest.goto\n\nimport com.intellij.openapi.util.Pair\nimport com.intellij.psi.PsiElement\nimport com.intel"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/goto/PestTestGoToSymbolContributor.kt",
    "chars": 3944,
    "preview": "package com.pestphp.pest.goto\n\nimport com.intellij.ide.projectView.PresentationData\nimport com.intellij.navigation.Choos"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/indexers/PestTestIndex.kt",
    "chars": 2412,
    "preview": "package com.pestphp.pest.indexers\n\nimport com.intellij.openapi.vfs.VirtualFile\nimport com.intellij.util.indexing.DataInd"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/inspections/ChangeMultipleExpectCallsToChainableQuickFix.kt",
    "chars": 2227,
    "preview": "package com.pestphp.pest.inspections\n\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.codeInspectio"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/inspections/ChangeTestNameCasingQuickFix.kt",
    "chars": 1550,
    "preview": "package com.pestphp.pest.inspections\n\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.codeInspectio"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/inspections/InvalidTestNameCaseInspection.kt",
    "chars": 1753,
    "preview": "package com.pestphp.pest.inspections\n\nimport com.intellij.codeInspection.ProblemsHolder\nimport com.intellij.psi.PsiEleme"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/inspections/MissingScreenshotSnapshotInspection.kt",
    "chars": 2679,
    "preview": "package com.pestphp.pest.inspections\n\nimport com.intellij.codeInspection.ProblemsHolder\nimport com.intellij.openapi.vfs."
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/inspections/MultipleExpectChainableInspection.kt",
    "chars": 2198,
    "preview": "package com.pestphp.pest.inspections\n\nimport com.intellij.codeInspection.ProblemsHolder\nimport com.intellij.psi.PsiEleme"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/inspections/PestAssertionCanBeSimplifiedInspection.kt",
    "chars": 6368,
    "preview": "package com.pestphp.pest.inspections\n\nimport com.intellij.codeInspection.ProblemsHolder\nimport com.intellij.modcommand.A"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/inspections/PestTestFailedLineInspection.kt",
    "chars": 981,
    "preview": "package com.pestphp.pest.inspections\n\nimport com.intellij.codeInspection.ProblemsHolder\nimport com.intellij.psi.PsiEleme"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/inspections/SuppressExpressionResultUnusedInspection.kt",
    "chars": 1039,
    "preview": "package com.pestphp.pest.inspections\n\nimport com.intellij.codeInspection.InspectionSuppressor\nimport com.intellij.codeIn"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/inspections/SuppressUndefinedPropertyInspection.kt",
    "chars": 1272,
    "preview": "package com.pestphp.pest.inspections\n\nimport com.intellij.codeInspection.InspectionSuppressor\nimport com.intellij.codeIn"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/notifications/OutdatedNotification.kt",
    "chars": 660,
    "preview": "package com.pestphp.pest.notifications\n\nimport com.intellij.notification.Notification\nimport com.intellij.notification.N"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/parser/PestConfigurationFile.kt",
    "chars": 207,
    "preview": "package com.pestphp.pest.parser\n\nimport com.jetbrains.php.lang.psi.resolve.types.PhpType\n\ndata class PestConfigurationFi"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/parser/PestConfigurationFileParser.kt",
    "chars": 5473,
    "preview": "package com.pestphp.pest.parser\n\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.project.guessPr"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/runner/LocationInfo.kt",
    "chars": 153,
    "preview": "package com.pestphp.pest.runner\n\nimport com.intellij.openapi.vfs.VirtualFile\n\nclass LocationInfo(\n    val file: VirtualF"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/runner/PestConsoleProperties.kt",
    "chars": 2614,
    "preview": "package com.pestphp.pest.runner\n\nimport com.intellij.execution.Executor\nimport com.intellij.execution.configurations.Run"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/runner/PestFailedLineManager.kt",
    "chars": 3391,
    "preview": "package com.pestphp.pest.runner\n\nimport com.intellij.execution.TestStateStorage\nimport com.intellij.openapi.components.S"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/runner/PestPressToContinueAction.kt",
    "chars": 3536,
    "preview": "package com.pestphp.pest.runner\n\nimport com.intellij.execution.impl.ConsoleViewImpl\nimport com.intellij.execution.testfr"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/runner/PestPromptConsoleFolding.kt",
    "chars": 1072,
    "preview": "package com.pestphp.pest.runner\n\nimport com.intellij.execution.ConsoleFolding\nimport com.intellij.execution.ui.ConsoleVi"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/runner/PestTestStackTraceParser.kt",
    "chars": 2386,
    "preview": "package com.pestphp.pest.runner\n\nimport com.intellij.execution.testframework.sm.runner.ui.TestStackTraceParser\nimport co"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/statistics/PestUsagesCollector.kt",
    "chars": 799,
    "preview": "package com.pestphp.pest.statistics\n\nimport com.intellij.internal.statistic.eventLog.EventLogGroup\nimport com.intellij.i"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/structureView/PestStructureViewElement.kt",
    "chars": 1376,
    "preview": "package com.pestphp.pest.structureView\n\nimport com.intellij.ide.projectView.PresentationData\nimport com.intellij.ide.str"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/structureView/PestStructureViewExtension.kt",
    "chars": 956,
    "preview": "package com.pestphp.pest.structureView\n\nimport com.intellij.ide.structureView.StructureViewExtension\nimport com.intellij"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/surrounders/ExpectStatementSurrounder.kt",
    "chars": 1053,
    "preview": "package com.pestphp.pest.surrounders\n\nimport com.intellij.lang.surroundWith.Surrounder\nimport com.intellij.openapi.edito"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/surrounders/StatementSurroundDescriptor.kt",
    "chars": 1058,
    "preview": "package com.pestphp.pest.surrounders\n\nimport com.intellij.lang.surroundWith.SurroundDescriptor\nimport com.intellij.lang."
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/templates/PestConfigNewDatasetFileAction.kt",
    "chars": 2694,
    "preview": "package com.pestphp.pest.templates\n\nimport com.intellij.ide.actions.CreateFileFromTemplateDialog\nimport com.intellij.ide"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/templates/PestConfigNewFileAction.kt",
    "chars": 2934,
    "preview": "package com.pestphp.pest.templates\n\nimport com.intellij.ide.actions.CreateFileFromTemplateAction\nimport com.intellij.ide"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/templates/PestDescribePostfixTemplate.kt",
    "chars": 980,
    "preview": "package com.pestphp.pest.templates\n\nimport com.intellij.openapi.editor.Document\nimport com.intellij.psi.PsiElement\nimpor"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/templates/PestItPostfixTemplate.kt",
    "chars": 1012,
    "preview": "package com.pestphp.pest.templates\n\nimport com.intellij.openapi.editor.Document\nimport com.intellij.psi.PsiElement\nimpor"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/templates/PestPostfixTemplateProvider.kt",
    "chars": 889,
    "preview": "package com.pestphp.pest.templates\n\nimport com.intellij.codeInsight.template.postfix.templates.PostfixTemplate\nimport co"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/templates/PestRootTemplateContextType.kt",
    "chars": 1231,
    "preview": "package com.pestphp.pest.templates\n\nimport com.intellij.codeInsight.template.TemplateActionContext\nimport com.intellij.c"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/types/HigherOrderExtendTypeProvider.kt",
    "chars": 2104,
    "preview": "package com.pestphp.pest.types\n\nimport com.intellij.openapi.project.DumbService\nimport com.intellij.openapi.project.Proj"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/types/InnerTestTypeProvider.kt",
    "chars": 813,
    "preview": "package com.pestphp.pest.types\n\nimport com.intellij.openapi.project.DumbService\nimport com.intellij.psi.PsiElement\nimpor"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/types/ThisExtendTypeProvider.kt",
    "chars": 1151,
    "preview": "package com.pestphp.pest.types\n\nimport com.intellij.openapi.project.DumbService\nimport com.intellij.openapi.project.Proj"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/types/ThisFieldTypeProvider.kt",
    "chars": 1885,
    "preview": "package com.pestphp.pest.types\n\nimport com.intellij.openapi.project.DumbService\nimport com.intellij.openapi.project.Proj"
  },
  {
    "path": "src/main/kotlin/com/pestphp/pest/types/ThisTypeProvider.kt",
    "chars": 2918,
    "preview": "package com.pestphp.pest.types\n\nimport com.intellij.openapi.project.DumbService\nimport com.intellij.openapi.project.Proj"
  },
  {
    "path": "src/main/resources/META-INF/plugin.xml",
    "chars": 11260,
    "preview": "<idea-plugin allow-bundled-update=\"true\">\n    <id>com.pestphp.pest-intellij</id>\n    <name>Pest</name>\n    <vendor>JetBr"
  },
  {
    "path": "src/main/resources/fileTemplates/internal/Pest It.php.ft",
    "chars": 74,
    "preview": "<?php\n#parse(\"PHP File Header.php\")\n\nit('#[[$END$]]#', function () {\n\n});\n"
  },
  {
    "path": "src/main/resources/fileTemplates/internal/Pest Scoped Dataset.php.ft",
    "chars": 93,
    "preview": "<?php\n#parse(\"PHP File Header.php\")\n\ndataset('#[[$DATASET_NAME$]]#', [\n    '#[[$END$]]#'\n]);\n"
  },
  {
    "path": "src/main/resources/fileTemplates/internal/Pest Shared Dataset.php.ft",
    "chars": 93,
    "preview": "<?php\n#parse(\"PHP File Header.php\")\n\ndataset('#[[$DATASET_NAME$]]#', [\n    '#[[$END$]]#'\n]);\n"
  },
  {
    "path": "src/main/resources/fileTemplates/internal/Pest Test.php.ft",
    "chars": 76,
    "preview": "<?php\n#parse(\"PHP File Header.php\")\n\ntest('#[[$END$]]#', function () {\n\n});\n"
  },
  {
    "path": "src/main/resources/fileTemplates/internal/Pest file from class.php.ft",
    "chars": 124,
    "preview": "<?php\n#parse(\"PHP File Header.php\")\n\n#if (${NAMESPACE})\nnamespace ${NAMESPACE};\n#end\n\ntest('#[[$END$]]#', function () {\n"
  },
  {
    "path": "src/main/resources/inspectionDescriptions/InvalidDatasetNameCaseInspection.html",
    "chars": 85,
    "preview": "<html lang=\"en\">\n<body>\nReports invalid names for pest dataset cases.\n</body>\n</html>"
  },
  {
    "path": "src/main/resources/inspectionDescriptions/InvalidDatasetReferenceInspection.html",
    "chars": 76,
    "preview": "<html lang=\"en\">\n<body>\nReports a non-existent Pest dataset.\n</body>\n</html>"
  },
  {
    "path": "src/main/resources/inspectionDescriptions/InvalidTestNameCaseInspection.html",
    "chars": 82,
    "preview": "<html lang=\"en\">\n<body>\nReports invalid names for pest test cases.\n</body>\n</html>"
  },
  {
    "path": "src/main/resources/inspectionDescriptions/MissingScreenshotSnapshotInspection.html",
    "chars": 158,
    "preview": "<html lang=\"en\">\n<body>\nReports missing visual regression snapshot files for <code>$var->assertScreenshotMatches()</code"
  },
  {
    "path": "src/main/resources/inspectionDescriptions/MultipleExpectChainableInspection.html",
    "chars": 111,
    "preview": "<html lang=\"en\">\n<body>\nReports multiple expectations that can be converted to chainable calls.\n</body>\n</html>"
  },
  {
    "path": "src/main/resources/inspectionDescriptions/PestAssertionCanBeSimplifiedInspection.html",
    "chars": 105,
    "preview": "<html lang=\"en\">\n<body>\nReports assertion call to be replaced with more specific analogue\n</body>\n</html>"
  },
  {
    "path": "src/main/resources/inspectionDescriptions/PestTestFailedLineInspection.html",
    "chars": 322,
    "preview": "<html>\n<body>\n<p>Reports failed function calls or assertions in Pest tests. It helps detect the failed line in code fast"
  },
  {
    "path": "src/main/resources/liveTemplates/PestPHP.xml",
    "chars": 746,
    "preview": "<templateSet group=\"PestPHP\">\n    <template name=\"it\" value=\"it('$NAME$', function() {&#10;    $END$&#10;});\" descriptio"
  },
  {
    "path": "src/main/resources/log4j.properties",
    "chars": 144,
    "preview": "log4j.rootLogger=INFO,stdout\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.layout=org.apa"
  },
  {
    "path": "src/main/resources/messages/pestBundle.properties",
    "chars": 3776,
    "preview": "CREATE_NEW_PEST_TEST=Create New Pest Test\\u2026\nCREATE_NEW_PEST_TEST_DESCRIPTION=Creates a new Pest test based on a file"
  },
  {
    "path": "src/main/resources/postfixTemplates/PestDescribePostfixTemplate/after.php.template",
    "chars": 51,
    "preview": "<?php\ndescribe(\"can describe this\", function() {\n};"
  },
  {
    "path": "src/main/resources/postfixTemplates/PestDescribePostfixTemplate/before.php.template",
    "chars": 42,
    "preview": "<?php\n<spot>\"can describe this\"</spot>$key"
  },
  {
    "path": "src/main/resources/postfixTemplates/PestDescribePostfixTemplate/description.html",
    "chars": 95,
    "preview": "<html lang=\"en\">\n<body>\n<p>\n    Wraps a string into a pest describe block.\n</p>\n</body>\n</html>"
  },
  {
    "path": "src/main/resources/postfixTemplates/PestItPostfixTemplate/after.php.template",
    "chars": 41,
    "preview": "<?php\nit(\"can test this\", function() {\n};"
  },
  {
    "path": "src/main/resources/postfixTemplates/PestItPostfixTemplate/before.php.template",
    "chars": 38,
    "preview": "<?php\n<spot>\"can test this\"</spot>$key"
  },
  {
    "path": "src/main/resources/postfixTemplates/PestItPostfixTemplate/description.html",
    "chars": 88,
    "preview": "<html lang=\"en\">\n<body>\n<p>\n    Wraps a string into a pest it test.\n</p>\n</body>\n</html>"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/PestIconProviderTest.kt",
    "chars": 2358,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.openapi.util.Iconable.ICON_FLAG_VISIBILITY\nimport com.intellij.psi.PsiMana"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/PestLightCodeFixture.kt",
    "chars": 4483,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.openapi.util.io.FileUtil\nimport com.intellij.psi.PsiFile\nimport com.intell"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/PestTestRunLineMarkerProviderTest.kt",
    "chars": 4337,
    "preview": "package com.pestphp.pest\n\nimport com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl\nimport com.intellij.executi"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/annotator/PestAnnotatorTest.kt",
    "chars": 2771,
    "preview": "package com.pestphp.pest.annotator\n\nimport com.pestphp.pest.PestBundle\nimport com.pestphp.pest.PestLightCodeFixture\n\ncla"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/codeInsight/typeInference/PestTypeInferenceTest.kt",
    "chars": 5905,
    "preview": "package com.pestphp.pest.codeInsight.typeInference\n\nimport com.intellij.openapi.application.WriteAction\nimport com.intel"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/configuration/PestLocationProviderTest.kt",
    "chars": 2229,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.psi.search.GlobalSearchScope\nimport com.intellij.testFramewo"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/configuration/PestRunConfigurationTest.kt",
    "chars": 4320,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.execution.PsiLocation\nimport com.intellij.execution.actions."
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/configuration/PestVersionDetectorTest.kt",
    "chars": 789,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.execution.ExecutionException\nimport com.jetbrains.php.config"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/configuration/PestVersionParserTest.kt",
    "chars": 1292,
    "preview": "package com.pestphp.pest.configuration\n\nimport com.intellij.execution.ExecutionException\nimport com.pestphp.pest.PestBun"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/configuration/pest/PestConfigurationFileTest.kt",
    "chars": 2032,
    "preview": "package com.pestphp.pest.configuration.pest\n\nimport com.pestphp.pest.PestLightCodeFixture\n\nclass PestConfigurationFileTe"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/configuration/uses/PestConfigurationFileTest.kt",
    "chars": 1882,
    "preview": "package com.pestphp.pest.configuration.uses\n\nimport com.pestphp.pest.PestLightCodeFixture\n\nclass PestConfigurationFileTe"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/customExpectations/ListMethodDataExternalizerTest.kt",
    "chars": 5415,
    "preview": "package com.pestphp.pest.customExpectations\n\nimport com.intellij.util.io.DataOutputStream\nimport com.jetbrains.php.lang."
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/customExpectations/MethodDataExternalizerTest.kt",
    "chars": 3164,
    "preview": "package com.pestphp.pest.customExpectations\n\nimport com.intellij.util.io.DataOutputStream\nimport com.jetbrains.php.lang."
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/customExpectations/generators/ExpectationGeneratorTest.kt",
    "chars": 998,
    "preview": "package com.pestphp.pest.customExpectations.generators\n\nimport com.jetbrains.php.lang.psi.resolve.types.PhpType\nimport c"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/features/configuration/PestCompletionTest.kt",
    "chars": 1428,
    "preview": "package com.pestphp.pest.features.configuration\n\nimport com.intellij.testFramework.TestDataPath\nimport com.pestphp.pest."
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/features/configuration/UsesCompletionTest.kt",
    "chars": 1425,
    "preview": "package com.pestphp.pest.features.configuration\n\nimport com.intellij.testFramework.TestDataPath\nimport com.pestphp.pest."
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/features/datasets/DatasetCompletionTest.kt",
    "chars": 1171,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.testFramework.TestDataPath\nimport com.pestphp.pest.PestL"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/features/datasets/DatasetGoToTest.kt",
    "chars": 2440,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.codeInsight.navigation.actions.GotoDeclarationAction\nimp"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/features/datasets/DatasetIndexTest.kt",
    "chars": 1981,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.psi.search.GlobalSearchScope\nimport com.intellij.testFra"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/features/datasets/DatasetReferenceTest.kt",
    "chars": 3150,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.testFramework.TestDataPath\nimport com.jetbrains.php.lang"
  },
  {
    "path": "src/test/kotlin/com/pestphp/pest/features/datasets/DatasetUsagesTest.kt",
    "chars": 1283,
    "preview": "package com.pestphp.pest.features.datasets\n\nimport com.intellij.testFramework.TestDataPath\nimport com.jetbrains.php.lang"
  }
]

// ... and 261 more files (download for full content)

About this extraction

This page contains the full source code of the pestphp/pest-intellij GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 461 files (542.8 KB), approximately 141.5k tokens, and a symbol index with 224 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!