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
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
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() { $END$ });\" 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.