├── example ├── settings.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ └── test │ │ └── java │ │ └── com │ │ └── tngtech │ │ └── jgiven │ │ └── plugin │ │ └── example │ │ ├── model │ │ └── SomeModel.java │ │ ├── ThenStage.java │ │ ├── WhenStage.java │ │ ├── GivenStage.java │ │ └── DummyTest.java └── build.gradle ├── src ├── test │ ├── resources │ │ ├── mockito-extensions │ │ │ └── org.mockito.plugins.MockMaker │ │ └── testData │ │ │ └── findUsages │ │ │ ├── common │ │ │ ├── StateA.java │ │ │ ├── SomeOtherReference.java │ │ │ └── SomeReference.java │ │ │ ├── NoJGiven.java │ │ │ ├── ForClass.java │ │ │ ├── ForJavaLang.java │ │ │ └── ForName.java │ └── java │ │ └── com │ │ └── tngtech │ │ └── jgiven │ │ ├── BaseTestCase.kt │ │ ├── reference │ │ ├── ScenarioStateUsageProviderIntegrationTest.kt │ │ └── ReferenceProviderTest.kt │ │ ├── scenario │ │ └── state │ │ │ ├── ScenarioStateAnnotationProviderTest.kt │ │ │ ├── JGivenUsageProviderTest.kt │ │ │ └── StateReferenceProcessorTest.kt │ │ ├── LibraryTestUtil.kt │ │ └── resolution │ │ ├── TypeIsTooGenericCalculatorTest.kt │ │ ├── ResolutionHandlerTest.kt │ │ └── ResolutionProviderTest.kt └── main │ ├── resources │ ├── icons │ │ └── jgiven.png │ └── META-INF │ │ └── plugin.xml │ └── java │ └── com │ └── tngtech │ └── jgiven │ ├── resolution │ ├── Resolution.kt │ ├── TypeIsTooGenericCalculator.kt │ ├── AnnotationValueProvider.kt │ ├── ResolutionHandler.kt │ └── ResolutionProvider.kt │ ├── Icons.kt │ ├── util │ ├── AnnotationProvider.kt │ └── PsiElementUtil.kt │ ├── scenario │ └── state │ │ ├── ReferenceFactory.kt │ │ ├── JGivenUsageProvider.kt │ │ ├── StateReferenceProcessor.kt │ │ ├── ScenarioStateAnnotationProvider.kt │ │ └── ScenarioStateReferenceProvider.kt │ ├── usage │ ├── filter │ │ ├── JGivenSettings.kt │ │ ├── ScenarioStateFilteringRuleProvider.kt │ │ └── FilterByJGivenStateAction.kt │ └── implicit │ │ └── ImplicitScenarioStateUsageProvider.kt │ ├── JGivenUseScopeEnlarger.kt │ ├── reference │ ├── JGivenUsageTypeProvider.kt │ └── ReferenceProvider.kt │ ├── line │ └── marker │ │ ├── JGivenLineMarkerInfo.kt │ │ └── LineMarkerProvider.kt │ └── Annotations.kt ├── README ├── findUsages.png ├── installation.png └── lineMarker.png ├── gradle.properties ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── NOTICE ├── Development.md ├── .github ├── dependabot.yml └── workflows │ └── build.yml ├── CONTRIBUTING.md ├── README.md ├── DCO ├── gradlew.bat ├── CODE-OF-CONDUCT.md ├── gradlew └── LICENSE /example/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'plugin.example' 2 | -------------------------------------------------------------------------------- /src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker: -------------------------------------------------------------------------------- 1 | mock-maker-inline -------------------------------------------------------------------------------- /README/findUsages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TNG/jgiven-intellij-plugin/HEAD/README/findUsages.png -------------------------------------------------------------------------------- /README/installation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TNG/jgiven-intellij-plugin/HEAD/README/installation.png -------------------------------------------------------------------------------- /README/lineMarker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TNG/jgiven-intellij-plugin/HEAD/README/lineMarker.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | jetbrainsPublishUsername=user 2 | jetbrainsPublishPassword=password 3 | jetbrainsPublishChannel= -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jgiven-intellij-plugin' 2 | rootProject.buildFileName = 'build.gradle.kts' -------------------------------------------------------------------------------- /src/test/resources/testData/findUsages/common/StateA.java: -------------------------------------------------------------------------------- 1 | package a; 2 | 3 | public class StateA { 4 | } 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TNG/jgiven-intellij-plugin/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/icons/jgiven.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TNG/jgiven-intellij-plugin/HEAD/src/main/resources/icons/jgiven.png -------------------------------------------------------------------------------- /example/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TNG/jgiven-intellij-plugin/HEAD/example/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | *.*~ 3 | *.iml 4 | .idea 5 | build 6 | .gradle 7 | classes 8 | .gradletasknamecache 9 | copy 10 | test-system 11 | test-config 12 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/resolution/Resolution.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.resolution 2 | 3 | enum class Resolution { 4 | AUTO, NAME, TYPE 5 | } 6 | -------------------------------------------------------------------------------- /example/src/test/java/com/tngtech/jgiven/plugin/example/model/SomeModel.java: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.plugin.example.model; 2 | 3 | public class SomeModel { 4 | } 5 | -------------------------------------------------------------------------------- /src/test/resources/testData/findUsages/NoJGiven.java: -------------------------------------------------------------------------------- 1 | package a; 2 | 3 | import com.tngtech.jgiven.annotation.ScenarioState; 4 | import a.StateA; 5 | 6 | class NoJGiven { 7 | private String a; 8 | } -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | jgiven-intellij-plugin 2 | Copyright 2017 and onwards Matthias Klaß 3 | 4 | This product includes software developed at 5 | TNG Technology Consulting GmbH (https://www.tngtech.com/). -------------------------------------------------------------------------------- /Development.md: -------------------------------------------------------------------------------- 1 | Development Related Stuff 2 | ========================== 3 | 4 | Releasing the Plugin 5 | -------------------- 6 | 7 | * Generate the plugin with `./gradlew buildPlugin` 8 | * Upload the plugin to the marketplace 9 | -------------------------------------------------------------------------------- /src/test/resources/testData/findUsages/ForClass.java: -------------------------------------------------------------------------------- 1 | package a; 2 | 3 | import com.tngtech.jgiven.annotation.ScenarioState; 4 | import a.StateA; 5 | 6 | class ForClass { 7 | @ScenarioState 8 | private StateA stateA; 9 | } -------------------------------------------------------------------------------- /src/test/resources/testData/findUsages/ForJavaLang.java: -------------------------------------------------------------------------------- 1 | package a; 2 | 3 | import com.tngtech.jgiven.annotation.ScenarioState; 4 | import a.StateA; 5 | 6 | class ForClass { 7 | @ScenarioState 8 | private String myString; 9 | } -------------------------------------------------------------------------------- /example/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | repositories { 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | testImplementation 'com.tngtech.jgiven:jgiven-junit:1.3.0' 9 | testImplementation 'junit:junit:4.13.2' 10 | } 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gradle" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | - package-ecosystem: "gradle" 8 | directory: "/example" 9 | schedule: 10 | interval: "daily" 11 | -------------------------------------------------------------------------------- /src/test/resources/testData/findUsages/ForName.java: -------------------------------------------------------------------------------- 1 | package a; 2 | 3 | import com.tngtech.jgiven.annotation.ScenarioState; 4 | import a.StateA; 5 | 6 | class ForName { 7 | @ScenarioState(resolution = ScenarioState.Resolution.NAME) 8 | private StateA stateB; 9 | } -------------------------------------------------------------------------------- /src/test/resources/testData/findUsages/common/SomeOtherReference.java: -------------------------------------------------------------------------------- 1 | package a; 2 | 3 | import com.tngtech.jgiven.annotation.ScenarioState; 4 | import a.StateA; 5 | 6 | class ForClassTypeReference { 7 | @ScenarioState 8 | private StateA state; 9 | 10 | @ScenarioState 11 | private String myOtherString; 12 | } -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/Icons.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven 2 | 3 | import com.intellij.openapi.util.IconLoader 4 | 5 | object Icons { 6 | private const val JGIVEN_PNG = "/icons/jgiven.png" 7 | val JGIVEN = load(JGIVEN_PNG) 8 | 9 | private fun load(path: String) = IconLoader.getIcon(path, Icons::class.java) 10 | } 11 | -------------------------------------------------------------------------------- /src/test/resources/testData/findUsages/common/SomeReference.java: -------------------------------------------------------------------------------- 1 | package a; 2 | 3 | import com.tngtech.jgiven.annotation.ScenarioState; 4 | import a.StateA; 5 | 6 | class SomeReference { 7 | @ScenarioState(resolution = ScenarioState.Resolution.NAME) 8 | private StateA stateB; 9 | 10 | @ScenarioState 11 | private String myString; 12 | } -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/util/AnnotationProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.util 2 | 3 | import com.intellij.codeInsight.AnnotationUtil 4 | import com.intellij.psi.PsiAnnotation 5 | import com.intellij.psi.PsiModifierListOwner 6 | 7 | class AnnotationProvider { 8 | fun findAnnotation(listOwner: PsiModifierListOwner?, annotationNames: Collection) = 9 | AnnotationUtil.findAnnotation(listOwner, annotationNames, false) 10 | } 11 | -------------------------------------------------------------------------------- /example/src/test/java/com/tngtech/jgiven/plugin/example/ThenStage.java: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.plugin.example; 2 | 3 | import com.tngtech.jgiven.Stage; 4 | import com.tngtech.jgiven.annotation.ScenarioState; 5 | import com.tngtech.jgiven.plugin.example.model.SomeModel; 6 | 7 | public class ThenStage extends Stage { 8 | @ScenarioState 9 | SomeModel model; 10 | 11 | public ThenStage the_resulting_meal_is_a_pancake() { 12 | return this; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/util/PsiElementUtil.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.util 2 | 3 | import com.intellij.psi.PsiElement 4 | 5 | inline fun findParentOfTypeOn(element: PsiElement?): E? { 6 | element ?: return null 7 | 8 | var current: PsiElement? = element 9 | while(current != null) { 10 | if (current is E) { 11 | return current 12 | } 13 | current = current.parent 14 | } 15 | return null 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/scenario/state/ReferenceFactory.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.scenario.state 2 | 3 | import com.intellij.psi.* 4 | import com.intellij.psi.impl.light.LightMemberReference 5 | 6 | class ReferenceFactory(private val manager: PsiManager) { 7 | 8 | fun referenceFor(field: PsiField): PsiReference = 9 | object : LightMemberReference(manager, field, PsiSubstitutor.EMPTY) { 10 | override fun getElement(): PsiElement = field 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/usage/filter/JGivenSettings.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.usage.filter 2 | 3 | import com.intellij.openapi.components.ServiceManager 4 | import com.intellij.openapi.components.State 5 | import com.intellij.openapi.components.Storage 6 | 7 | @State(name = "JGivenSettings", storages = [Storage("JGivenSettings.xml")]) 8 | class JGivenSettings { 9 | var isJGivenFilteringEnabled = true 10 | 11 | companion object { 12 | val instance: JGivenSettings 13 | get() = ServiceManager.getService(JGivenSettings::class.java) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/src/test/java/com/tngtech/jgiven/plugin/example/WhenStage.java: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.plugin.example; 2 | 3 | import com.tngtech.jgiven.Stage; 4 | import com.tngtech.jgiven.annotation.ScenarioState; 5 | import com.tngtech.jgiven.plugin.example.model.SomeModel; 6 | 7 | public class WhenStage extends Stage { 8 | @ScenarioState 9 | SomeModel model; 10 | 11 | public WhenStage the_cook_mangles_everything_to_a_dough() { 12 | return this; 13 | } 14 | 15 | public WhenStage the_cook_fries_the_dough_in_a_pan() { 16 | return this; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/src/test/java/com/tngtech/jgiven/plugin/example/GivenStage.java: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.plugin.example; 2 | 3 | import com.tngtech.jgiven.Stage; 4 | import com.tngtech.jgiven.annotation.ScenarioState; 5 | import com.tngtech.jgiven.plugin.example.model.SomeModel; 6 | 7 | public class GivenStage extends Stage { 8 | @ScenarioState 9 | SomeModel model; 10 | 11 | public GivenStage an_egg() { 12 | return this; 13 | } 14 | 15 | public GivenStage some_milk() { 16 | return this; 17 | } 18 | 19 | public GivenStage the_ingredient(String flour) { 20 | return this; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/resolution/TypeIsTooGenericCalculator.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.resolution 2 | 3 | import com.intellij.psi.PsiType 4 | import com.intellij.psi.util.PsiTypesUtil 5 | 6 | class TypeIsTooGenericCalculator { 7 | fun typeIsTooGeneric(type: PsiType): Boolean { 8 | val clazz = PsiTypesUtil.getPsiClass(type) ?: return true 9 | val qualifiedName = clazz.qualifiedName 10 | return (qualifiedName == null 11 | || qualifiedName.startsWith("java.lang") 12 | || qualifiedName.startsWith("java.io") 13 | || qualifiedName.startsWith("java.util")) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v3.5.3 12 | - uses: gradle/wrapper-validation-action@v1.1.0 13 | - name: set up JDK 17 14 | uses: actions/setup-java@v3.11.0 15 | with: 16 | java-version: 17 17 | distribution: 'adopt' 18 | - name: Build with Gradle 19 | run: ./gradlew buildPlugin test 20 | - name: Archive plugin 21 | uses: actions/upload-artifact@v3.1.2 22 | with: 23 | name: jgiven-intellij-plugin.zip 24 | path: build/distributions/jgiven-intellij-plugin.zip 25 | -------------------------------------------------------------------------------- /example/src/test/java/com/tngtech/jgiven/plugin/example/DummyTest.java: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.plugin.example; 2 | 3 | import com.tngtech.jgiven.junit.ScenarioTest; 4 | import org.junit.Test; 5 | 6 | public class DummyTest extends ScenarioTest { 7 | @Test 8 | public void a_pancake_can_be_fried_out_of_an_egg_milk_and_flour() { 9 | given().an_egg(). 10 | and().some_milk(). 11 | and().the_ingredient( "flour" ); 12 | 13 | when().the_cook_mangles_everything_to_a_dough(). 14 | and().the_cook_fries_the_dough_in_a_pan(); 15 | 16 | then().the_resulting_meal_is_a_pancake(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/resolution/AnnotationValueProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.resolution 2 | 3 | import com.intellij.psi.PsiAnnotation 4 | import com.intellij.psi.PsiExpression 5 | 6 | class AnnotationValueProvider { 7 | 8 | fun getAnnotationValue(annotation: PsiAnnotation, annotationKey: String): PsiExpression? { 9 | val attributes = annotation.parameterList.attributes 10 | return attributes 11 | .filter { a -> annotationKey.equals(a.name!!, ignoreCase = true) } 12 | .map { it.value } 13 | .filter { v -> v is PsiExpression } 14 | .map { v -> v as PsiExpression } 15 | .firstOrNull() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/JGivenUseScopeEnlarger.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven 2 | 3 | import com.intellij.psi.PsiElement 4 | import com.intellij.psi.search.GlobalSearchScope 5 | import com.intellij.psi.search.SearchScope 6 | import com.intellij.psi.search.UseScopeEnlarger 7 | import com.tngtech.jgiven.scenario.state.ScenarioStateAnnotationProvider 8 | 9 | class JGivenUseScopeEnlarger : UseScopeEnlarger() { 10 | private val scenarioStateAnnotationProvider = ScenarioStateAnnotationProvider() 11 | 12 | override fun getAdditionalUseScope(element: PsiElement): SearchScope? { 13 | return when { 14 | scenarioStateAnnotationProvider.isJGivenScenarioState(element) -> GlobalSearchScope.everythingScope(element.project) 15 | else -> null 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/reference/JGivenUsageTypeProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.reference 2 | 3 | import com.intellij.psi.PsiElement 4 | import com.intellij.usages.impl.rules.UsageType 5 | import com.intellij.usages.impl.rules.UsageTypeProvider 6 | import com.tngtech.jgiven.scenario.state.ScenarioStateAnnotationProvider 7 | 8 | class JGivenUsageTypeProvider( 9 | private val scenarioStateAnnotationProvider: ScenarioStateAnnotationProvider = ScenarioStateAnnotationProvider() 10 | ) : UsageTypeProvider { 11 | val usageType = UsageType {"JGiven Scenario State"} 12 | override fun getUsageType(element: PsiElement) = 13 | when { 14 | scenarioStateAnnotationProvider.isJGivenScenarioState(element) -> usageType 15 | else -> null 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/resolution/ResolutionHandler.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.resolution 2 | 3 | import com.intellij.psi.PsiField 4 | 5 | class ResolutionHandler( 6 | private val resolutionProvider: ResolutionProvider = ResolutionProvider() 7 | ) { 8 | 9 | fun resolutionMatches(field: PsiField, fieldToSearch: PsiField): Boolean { 10 | val fieldResolution = resolutionProvider.getResolutionFrom(field) 11 | val resolution = resolutionProvider.getResolutionFrom(fieldToSearch) 12 | if (resolution !== fieldResolution) { 13 | return false 14 | } 15 | return if (resolution !== Resolution.NAME) { 16 | field.type.presentableText.equals(fieldToSearch.type.presentableText, ignoreCase = true) 17 | } else field.name == fieldToSearch.name 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/scenario/state/JGivenUsageProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.scenario.state 2 | 3 | import com.intellij.psi.PsiField 4 | import com.tngtech.jgiven.resolution.ResolutionHandler 5 | 6 | class JGivenUsageProvider( 7 | private val scenarioStateProvider: ScenarioStateAnnotationProvider, 8 | private val resolutionHandler: ResolutionHandler, 9 | private val referenceFactory: ReferenceFactory 10 | ) { 11 | fun createReferenceIfJGivenUsage(fieldToSearch: PsiField, field: PsiField) = 12 | when { 13 | scenarioStateProvider.isJGivenScenarioState(field) 14 | && fieldToSearch != field 15 | && resolutionHandler.resolutionMatches(field, fieldToSearch) -> referenceFactory.referenceFor(field) 16 | else -> null 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/scenario/state/StateReferenceProcessor.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.scenario.state 2 | 3 | import com.intellij.psi.PsiField 4 | import com.intellij.psi.PsiReference 5 | import com.intellij.util.Processor 6 | import java.util.* 7 | 8 | class StateReferenceProcessor(private val fieldToSearch: PsiField, private val maxNumberOfResults: Int, private val usageProvider: JGivenUsageProvider) : Processor { 9 | private val results = ArrayList() 10 | 11 | override fun process(field: PsiField): Boolean { 12 | val reference = usageProvider.createReferenceIfJGivenUsage(fieldToSearch, field) 13 | if (reference != null) { 14 | results.add(reference) 15 | } 16 | return results.size < maxNumberOfResults || maxNumberOfResults == ScenarioStateReferenceProvider.ANY_NUMBER_OF_RESULTS 17 | } 18 | 19 | fun getResults(): List = results 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/tngtech/jgiven/BaseTestCase.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven 2 | 3 | import com.intellij.testFramework.LightProjectDescriptor 4 | import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase 5 | 6 | abstract class BaseTestCase : LightJavaCodeInsightFixtureTestCase() { 7 | 8 | private lateinit var libraryTestUtil: LibraryTestUtil 9 | 10 | protected abstract val testDataSubDirectory: String 11 | 12 | @Throws(Exception::class) 13 | public override fun setUp() { 14 | super.setUp() 15 | libraryTestUtil = LibraryTestUtil(module).addJGiven() 16 | } 17 | 18 | @Throws(Exception::class) 19 | public override fun tearDown() { 20 | libraryTestUtil.removeLibraries() 21 | super.tearDown() 22 | } 23 | 24 | override fun getTestDataPath(): String { 25 | return BaseTestCase::class.java.getResource("/testData/$testDataSubDirectory").path 26 | } 27 | 28 | override fun getProjectDescriptor() = LightProjectDescriptor() 29 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are very welcome. The following will provide some helpful guidelines. 4 | 5 | ## Follow the Code of Conduct 6 | 7 | Contributors must follow the Code of Conduct outlined at [CODE-OF-CONDUCT.md](CODE-OF-CONDUCT.md). 8 | 9 | ## How to contribute 10 | 11 | We love pull requests. Here is a quick guide: 12 | 13 | 1. You need to have a JDK (at least version 1.8) installed. 14 | 2. Fork the repo (see https://help.github.com/articles/fork-a-repo). 15 | 3. Create a new branch from master. 16 | 4. Ensure that you have a clean state by running `./gradlew clean build`. 17 | 5. Add your change together with a test (tests are not needed for refactorings and documentation changes). 18 | 6. Run `./gradlew clean build` again and ensure all tests are passing. 19 | 7. Create a Pull Request 20 | 21 | ### Commits 22 | 23 | Commit messages should be clear and fully elaborate the context and the reason of a change. 24 | If your commit refers to an issue, please post-fix it with the issue number, e.g. 25 | 26 | ``` 27 | Issue: #123 28 | ``` 29 | 30 | Furthermore, commits should be signed off according to the [DCO](DCO). 31 | 32 | ### Pull Requests 33 | 34 | If your Pull Request resolves an issue, please add a respective line to the end, like 35 | 36 | ``` 37 | Resolves #123 38 | ``` 39 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/usage/implicit/ImplicitScenarioStateUsageProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.usage.implicit 2 | 3 | import com.intellij.codeInsight.daemon.ImplicitUsageProvider 4 | import com.intellij.psi.PsiElement 5 | import com.intellij.psi.PsiField 6 | import com.tngtech.jgiven.scenario.state.ScenarioStateAnnotationProvider 7 | import com.tngtech.jgiven.scenario.state.ScenarioStateReferenceProvider 8 | 9 | class ImplicitScenarioStateUsageProvider : ImplicitUsageProvider { 10 | private val scenarioStateAnnotationProvider = ScenarioStateAnnotationProvider() 11 | private val scenarioStateReferenceProvider = ScenarioStateReferenceProvider() 12 | 13 | override fun isImplicitUsage(element: PsiElement) = isImplicitRead(element) || isImplicitWrite(element) 14 | 15 | override fun isImplicitRead(element: PsiElement) = 16 | (scenarioStateAnnotationProvider.isProvidedScenarioState(element) 17 | && hasAtLeastOneReference(element as PsiField)) 18 | 19 | override fun isImplicitWrite(element: PsiElement) = 20 | (scenarioStateAnnotationProvider.isExpectedScenarioState(element) 21 | && hasAtLeastOneReference(element as PsiField)) 22 | 23 | private fun hasAtLeastOneReference(element: PsiField) = 24 | !scenarioStateReferenceProvider.findReferences(element, 1).isEmpty() 25 | } 26 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # AndFHEM - Open Source Android application to control a FHEM home automation 3 | # server. 4 | # 5 | # Copyright (c) 2011, Matthias Klass or third-party contributors as 6 | # indicated by the @author tags or express copyright attribution 7 | # statements applied by the authors. All third-party contributions are 8 | # distributed under license by Red Hat Inc. 9 | # 10 | # This copyrighted material is made available to anyone wishing to use, modify, 11 | # copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GENERAL PUBLIC LICENSE 16 | # for more details. 17 | # 18 | # You should have received a copy of the GNU GENERAL PUBLIC LICENSE 19 | # along with this distribution; if not, write to: 20 | # Free Software Foundation, Inc. 21 | # 51 Franklin Street, Fifth Floor 22 | # Boston, MA 02110-1301 USA 23 | # 24 | 25 | #Sat Dec 06 12:56:10 CET 2014 26 | distributionBase=GRADLE_USER_HOME 27 | distributionPath=wrapper/dists 28 | zipStoreBase=GRADLE_USER_HOME 29 | zipStorePath=wrapper/dists 30 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip 31 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/scenario/state/ScenarioStateAnnotationProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.scenario.state 2 | 3 | import com.intellij.psi.PsiElement 4 | import com.intellij.psi.PsiField 5 | import com.intellij.psi.PsiModifierListOwner 6 | import com.tngtech.jgiven.Annotations 7 | import com.tngtech.jgiven.util.AnnotationProvider 8 | 9 | class ScenarioStateAnnotationProvider( 10 | private val annotationProvider: AnnotationProvider = AnnotationProvider() 11 | ) { 12 | 13 | fun isJGivenScenarioState(psiElement: PsiElement?) = 14 | psiElement != null && isFieldAnnotatedWithAnyOf(psiElement, Annotations.JGIVEN_SCENARIO_STATE_CLASS_NAMES) 15 | 16 | private fun isFieldAnnotatedWithAnyOf(psiElement: PsiElement, classNames: Collection) = 17 | psiElement is PsiField && annotationProvider.findAnnotation(psiElement as PsiModifierListOwner, classNames) != null 18 | 19 | fun isProvidedScenarioState(psiElement: PsiElement) = 20 | isFieldAnnotatedWithAnyOf(psiElement, Annotations.PROVIDED_SCENARIO_STATE_CLASS_NAMES) 21 | 22 | fun isExpectedScenarioState(psiElement: PsiElement) = 23 | isFieldAnnotatedWithAnyOf(psiElement, Annotations.EXPECTED_SCENARIO_STATE_CLASS_NAMES) 24 | 25 | fun getJGivenAnnotationOn(field: PsiField) = 26 | annotationProvider.findAnnotation(field, Annotations.JGIVEN_SCENARIO_STATE_CLASS_NAMES) 27 | } 28 | -------------------------------------------------------------------------------- /example/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # AndFHEM - Open Source Android application to control a FHEM home automation 3 | # server. 4 | # 5 | # Copyright (c) 2011, Matthias Klass or third-party contributors as 6 | # indicated by the @author tags or express copyright attribution 7 | # statements applied by the authors. All third-party contributions are 8 | # distributed under license by Red Hat Inc. 9 | # 10 | # This copyrighted material is made available to anyone wishing to use, modify, 11 | # copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GENERAL PUBLIC LICENSE 16 | # for more details. 17 | # 18 | # You should have received a copy of the GNU GENERAL PUBLIC LICENSE 19 | # along with this distribution; if not, write to: 20 | # Free Software Foundation, Inc. 21 | # 51 Franklin Street, Fifth Floor 22 | # Boston, MA 02110-1301 USA 23 | # 24 | 25 | #Sat Dec 06 12:56:10 CET 2014 26 | distributionBase=GRADLE_USER_HOME 27 | distributionPath=wrapper/dists 28 | zipStoreBase=GRADLE_USER_HOME 29 | zipStorePath=wrapper/dists 30 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip 31 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/line/marker/JGivenLineMarkerInfo.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.line.marker 2 | 3 | import com.intellij.codeInsight.daemon.MergeableLineMarkerInfo 4 | import com.intellij.codeInsight.daemon.impl.MarkerType 5 | import com.intellij.openapi.editor.markup.GutterIconRenderer 6 | import com.intellij.psi.PsiElement 7 | import com.intellij.util.Function 8 | import java.util.function.Supplier 9 | import javax.swing.Icon 10 | 11 | class JGivenLineMarkerInfo(element: PsiElement, icon: Icon, markerType: MarkerType, private val text: String, supplier:Supplier) : MergeableLineMarkerInfo( 12 | element, element.textRange, icon, markerType.tooltip, markerType.navigationHandler, GutterIconRenderer.Alignment.LEFT, supplier 13 | ) { 14 | 15 | override fun canMergeWith(info: MergeableLineMarkerInfo<*>): Boolean { 16 | if (info !is JGivenLineMarkerInfo) return false 17 | val otherElement = info.getElement() 18 | val myElement = element 19 | return otherElement != null && myElement != null 20 | } 21 | 22 | override fun getCommonIcon(infos: List>): Icon { 23 | return myIcon 24 | } 25 | 26 | @Suppress("UNCHECKED_CAST") 27 | override fun getCommonTooltip(infos: List>): Function { 28 | return { _: PsiElement -> text } as (Function) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | JGivenPlugin 3 | JGiven 4 | 0.0.21 5 | 6 | Provides support for navigation between JGiven scenario states. 7 | 8 | The plugin now supports IntelliJ version 2024.2. 9 | 10 | TNG Technology Consulting GmbH 11 | 12 | 13 | 14 | com.intellij.modules.java 15 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/reference/ReferenceProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.reference 2 | 3 | import com.intellij.openapi.application.ApplicationManager 4 | import com.intellij.openapi.application.QueryExecutorBase 5 | import com.intellij.psi.PsiField 6 | import com.intellij.psi.PsiReference 7 | import com.intellij.psi.search.GlobalSearchScope 8 | import com.intellij.psi.search.searches.ReferencesSearch 9 | import com.intellij.util.Processor 10 | import com.tngtech.jgiven.scenario.state.ScenarioStateAnnotationProvider 11 | import com.tngtech.jgiven.scenario.state.ScenarioStateReferenceProvider 12 | 13 | class ReferenceProvider( 14 | private val scenarioStateProvider: ScenarioStateAnnotationProvider = ScenarioStateAnnotationProvider(), 15 | private val scenarioStateReferenceProvider: ScenarioStateReferenceProvider = ScenarioStateReferenceProvider() 16 | ) : QueryExecutorBase() { 17 | 18 | override fun processQuery(queryParameters: ReferencesSearch.SearchParameters, consumer: Processor) { 19 | val element = queryParameters.elementToSearch 20 | 21 | ApplicationManager.getApplication().runReadAction { 22 | val scope = queryParameters.effectiveSearchScope 23 | if (scenarioStateProvider.isJGivenScenarioState(element) && scope is GlobalSearchScope) { 24 | val field = element as PsiField 25 | val references = scenarioStateReferenceProvider.findReferences(field) 26 | references.forEach { consumer.process(it) } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/resolution/ResolutionProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.resolution 2 | 3 | import com.intellij.psi.PsiField 4 | import com.tngtech.jgiven.scenario.state.ScenarioStateAnnotationProvider 5 | 6 | class ResolutionProvider( 7 | private val scenarioStateProvider: ScenarioStateAnnotationProvider = ScenarioStateAnnotationProvider(), 8 | private val annotationValueProvider: AnnotationValueProvider = AnnotationValueProvider(), 9 | private val typeIsTooGeneric: TypeIsTooGenericCalculator = TypeIsTooGenericCalculator() 10 | ) { 11 | 12 | 13 | fun getResolutionFrom(field: PsiField): Resolution? { 14 | val annotation = scenarioStateProvider.getJGivenAnnotationOn(field) ?: return null 15 | 16 | val annotationValue = annotationValueProvider.getAnnotationValue(annotation, FIELD_RESOLUTION) 17 | 18 | return annotationValue?.text 19 | ?.let { value -> 20 | Resolution.values() 21 | .firstOrNull { it !== Resolution.AUTO && value.contains(it.name) } 22 | } 23 | ?: getResolutionForFieldType(field) 24 | } 25 | 26 | /** 27 | * Calculate default resolution. See {[com.tngtech.jgiven.impl.inject.ScenarioStateField.getResolution]} 28 | */ 29 | @Suppress("KDocUnresolvedReference") 30 | private fun getResolutionForFieldType(field: PsiField) = when { 31 | typeIsTooGeneric.typeIsTooGeneric(field.type) -> Resolution.NAME 32 | else -> Resolution.TYPE 33 | } 34 | 35 | companion object { 36 | const val FIELD_RESOLUTION = "resolution" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/Annotations.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven 2 | 3 | import com.intellij.openapi.project.Project 4 | import com.intellij.psi.JavaPsiFacade 5 | import com.intellij.psi.PsiClass 6 | import com.intellij.psi.search.GlobalSearchScope 7 | import java.util.* 8 | 9 | object Annotations { 10 | private const val EXPECTED_SCENARIO_STATE = "com.tngtech.jgiven.annotation.ExpectedScenarioState" 11 | private const val PROVIDED_SCENARIO_STATE = "com.tngtech.jgiven.annotation.ProvidedScenarioState" 12 | private const val SCENARIO_STATE = "com.tngtech.jgiven.annotation.ScenarioState" 13 | 14 | val JGIVEN_SCENARIO_STATE_CLASS_NAMES: Collection = Arrays.asList( 15 | EXPECTED_SCENARIO_STATE, PROVIDED_SCENARIO_STATE, SCENARIO_STATE 16 | ) 17 | val PROVIDED_SCENARIO_STATE_CLASS_NAMES: Collection = Arrays.asList( 18 | PROVIDED_SCENARIO_STATE, SCENARIO_STATE 19 | ) 20 | val EXPECTED_SCENARIO_STATE_CLASS_NAMES: Collection = Arrays.asList( 21 | EXPECTED_SCENARIO_STATE, SCENARIO_STATE 22 | ) 23 | 24 | private fun findPsiClass(fqClassname: String, javaPsiFacade: JavaPsiFacade, project: Project) = 25 | javaPsiFacade.findClass(fqClassname, GlobalSearchScope.allScope(project)) 26 | 27 | fun getScenarioStateClasses(project: Project) = 28 | getClassesFor(project, JGIVEN_SCENARIO_STATE_CLASS_NAMES) 29 | 30 | private fun getClassesFor(project: Project, classNames: Collection): Collection = 31 | classNames 32 | .mapNotNull { findPsiClass(it, JavaPsiFacade.getInstance(project), project) } 33 | .toSet() 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/usage/filter/ScenarioStateFilteringRuleProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.usage.filter 2 | 3 | import com.intellij.openapi.actionSystem.AnAction 4 | import com.intellij.openapi.project.Project 5 | import com.intellij.usages.ConfigurableUsageTarget 6 | import com.intellij.usages.UsageView 7 | import com.intellij.usages.impl.UsageViewImpl 8 | import com.intellij.usages.rules.UsageFilteringRule 9 | import com.intellij.usages.rules.UsageFilteringRuleProvider 10 | import com.tngtech.jgiven.scenario.state.ScenarioStateAnnotationProvider 11 | 12 | class ScenarioStateFilteringRuleProvider : UsageFilteringRuleProvider { 13 | private val scenarioStateAnnotationProvider = ScenarioStateAnnotationProvider() 14 | 15 | @Deprecated("Use instead getApplicableRules", ReplaceWith("getApplicableRules()")) 16 | override fun getActiveRules(project: Project): Array { 17 | return emptyArray() 18 | } 19 | 20 | @Deprecated("Use instead UsageFilteringRule.getActionId", ReplaceWith("UsageFilteringRule.getActionId()")) 21 | override fun createFilteringActions(view: UsageView): Array { 22 | return when { 23 | isNormalFindUsagesDialogAndNotShowUsages(view) -> arrayOf( 24 | FilterByJGivenStateAction(scenarioStateAnnotationProvider, view) 25 | ) 26 | else -> emptyArray() 27 | } 28 | } 29 | 30 | private fun isNormalFindUsagesDialogAndNotShowUsages(usageView: UsageView): Boolean { 31 | return canShowSettings(usageView) 32 | } 33 | 34 | private fun canShowSettings(usageView: UsageView): Boolean { 35 | if (usageView !is UsageViewImpl) { 36 | return false 37 | } 38 | return usageView.targets 39 | .any { it is ConfigurableUsageTarget } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Build Status](https://github.com/TNG/jgiven-intellij-plugin/workflows/Build/badge.svg) 2 | [![License](https://img.shields.io/github/license/TNG/jgiven-intellij-plugin.svg )](https://raw.githubusercontent.com/TNG/jgiven-intellij-plugin/master/LICENSE) 3 | 4 | JGiven Plugin for IntelliJ IDEA 5 | =============================== 6 | 7 | [IntelliJ IDEA](https://www.jetbrains.com/idea/) plugin to support both navigating between scenario states and 8 | finding usages of scenario states within [JGiven](http://jgiven.org/) test stages. 9 | 10 | Features 11 | -------- 12 | 13 | * All scenario states with usages are annotated
14 | ![Line Marker Preview](README/lineMarker.png) 15 | 16 | * When looking for usages of a scenario state field, IntelliJ will also show all other fields referencing this scenario state. 17 | To make those lists more readable, an additional usage type for JGiven scenario states is available. 18 | Within this list, all non scenario state usages can be filtered out by clicking the JGiven icon.
19 | ![Find Usages](README/findUsages.png) 20 | 21 | Building 22 | -------- 23 | 24 | Checkout all source files and run ``./gradlew buildPlugin`` from within the checkout directory. 25 | 26 | The installable artifact can be found at ``build/distributions/jgiven-intellij-plugin.zip``. 27 | 28 | Installation 29 | ------------ 30 | 31 | The plugin is available from within the [JetBrains plugin repository](https://plugins.jetbrains.com/plugin/9670-jgiven). Thus, either download the plugin directly 32 | from within the IDE ("Browse repositories") or build the plugin manually and install it from your local disk. 33 | 34 | * Open up the ``Settings`` dialog (``File > Settings`` or hit ``Ctrl+Alt+S``). 35 | * Select ``Plugins`` from the tree 36 | * Hit ``Install plugin from disk`` and select the zip file you just created (see ``Building``). 37 | * Restart IntelliJ 38 | 39 | 40 | ![Installation](README/installation.png) 41 | 42 | License 43 | ------- 44 | 45 | Licensed under the Apache License, Version 2.0. 46 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/scenario/state/ScenarioStateReferenceProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.scenario.state 2 | 3 | import com.intellij.openapi.fileTypes.StdFileTypes 4 | import com.intellij.openapi.project.Project 5 | import com.intellij.psi.PsiField 6 | import com.intellij.psi.PsiManager 7 | import com.intellij.psi.PsiReference 8 | import com.intellij.psi.search.GlobalSearchScope 9 | import com.intellij.psi.search.searches.AnnotatedElementsSearch 10 | import com.intellij.util.Processor 11 | import com.tngtech.jgiven.Annotations 12 | import com.tngtech.jgiven.resolution.ResolutionHandler 13 | 14 | class ScenarioStateReferenceProvider { 15 | private val scenarioStateProvider = ScenarioStateAnnotationProvider() 16 | private val resolutionHandler = ResolutionHandler() 17 | 18 | @JvmOverloads 19 | fun findReferences(field: PsiField, maxNumberOfResults: Int = ANY_NUMBER_OF_RESULTS): List { 20 | val project = field.project 21 | val manager = PsiManager.getInstance(project) 22 | val usageProvider = JGivenUsageProvider(scenarioStateProvider, resolutionHandler, ReferenceFactory(manager)) 23 | val processor = StateReferenceProcessor(field, maxNumberOfResults, usageProvider) 24 | 25 | val scope = GlobalSearchScope.everythingScope(project).intersectWith(javaFilesScope(project)) 26 | 27 | findPsiFields(project, scope, processor) 28 | return processor.getResults() 29 | } 30 | 31 | private fun javaFilesScope(project: Project): GlobalSearchScope { 32 | return GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScope.allScope(project), StdFileTypes.JAVA) 33 | } 34 | 35 | private fun findPsiFields(project: Project, scope: GlobalSearchScope, processor: Processor) { 36 | Annotations.getScenarioStateClasses(project) 37 | .forEach { AnnotatedElementsSearch.searchPsiFields(it, scope).forEach(processor) } 38 | } 39 | 40 | companion object { 41 | const val ANY_NUMBER_OF_RESULTS = -1 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/tngtech/jgiven/reference/ScenarioStateUsageProviderIntegrationTest.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.reference 2 | 3 | import com.google.common.collect.Iterables 4 | import com.intellij.usageView.UsageInfo 5 | import com.tngtech.jgiven.BaseTestCase 6 | import org.assertj.core.api.Assertions.assertThat 7 | import java.io.File 8 | 9 | class ScenarioStateUsageProviderIntegrationTest : BaseTestCase() { 10 | 11 | private val usageFilesForAllTests: Set 12 | get() = File("$testDataPath/common").listFiles()!! 13 | .map { it.name } 14 | .map { name -> "common/$name" } 15 | .toSet() 16 | 17 | fun test_find_Usages_for_type() { 18 | configureByFile("ForClass.java") 19 | 20 | val usages = findUsages() 21 | 22 | assertThat(getOnlyUsageFilename(usages)).contains("SomeOtherReference.java") 23 | } 24 | 25 | fun test_find_Usages_for_name() { 26 | configureByFile("ForName.java") 27 | 28 | val usages = findUsages() 29 | 30 | assertThat(getOnlyUsageFilename(usages)).contains("SomeReference.java") 31 | } 32 | 33 | fun test_find_Usages_for_java_lang_reference_resolves_by_name_and_not_by_type() { 34 | configureByFile("ForJavaLang.java") 35 | 36 | val usages = findUsages() 37 | 38 | assertThat(getOnlyUsageFilename(usages)).contains("SomeReference.java") 39 | } 40 | 41 | fun test_find_no_usages_if_JGiven_is_not_present() { 42 | myFixture.configureByFile("NoJGiven.java") 43 | 44 | val usages = findUsages() 45 | 46 | assertThat(usages).isEmpty() 47 | } 48 | 49 | private fun getOnlyUsageFilename(usages: Collection) = 50 | Iterables.getOnlyElement(usages).file!!.name 51 | 52 | private fun findUsages(): Collection { 53 | val element = myFixture.elementAtCaret 54 | return myFixture.findUsages(element) 55 | } 56 | 57 | override val testDataSubDirectory = "findUsages" 58 | 59 | private fun configureByFile(filename: String) { 60 | val files = listOf(filename) + usageFilesForAllTests 61 | val loadedFiles = myFixture.configureByFiles(*files.toTypedArray()) 62 | assertThat(loadedFiles).hasSameSizeAs(files) 63 | } 64 | } -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/usage/filter/FilterByJGivenStateAction.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.usage.filter 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent 4 | import com.intellij.openapi.actionSystem.ToggleAction 5 | import com.intellij.usages.ReadWriteAccessUsageInfo2UsageAdapter 6 | import com.intellij.usages.Usage 7 | import com.intellij.usages.UsageView 8 | import com.intellij.usages.rules.UsageFilteringRuleProvider 9 | import com.tngtech.jgiven.Icons.JGIVEN 10 | import com.tngtech.jgiven.scenario.state.ScenarioStateAnnotationProvider 11 | import java.util.* 12 | import java.util.function.Consumer 13 | import java.util.stream.Collectors 14 | 15 | internal class FilterByJGivenStateAction(private val scenarioStateAnnotationProvider: ScenarioStateAnnotationProvider, private val usageView: UsageView) : ToggleAction("JGiven", "Filter by JGiven Scenario State", JGIVEN) { 16 | private var excludedUsages: Set = HashSet() 17 | override fun isSelected(e: AnActionEvent): Boolean { 18 | return JGivenSettings.instance.isJGivenFilteringEnabled 19 | } 20 | 21 | override fun setSelected(event: AnActionEvent, state: Boolean) { 22 | JGivenSettings.instance.isJGivenFilteringEnabled = state 23 | val project = event.project ?: return 24 | val scenarioStateUsages = usageView.usages 25 | .filter { usage: Usage? -> 26 | usage is ReadWriteAccessUsageInfo2UsageAdapter && 27 | scenarioStateAnnotationProvider.isJGivenScenarioState(usage.element) 28 | } 29 | .toSet() 30 | if (state) { 31 | excludedUsages.stream() 32 | .filter { u: Usage -> !scenarioStateUsages.contains(u) } 33 | .forEach { usage: Usage? -> usageView.appendUsage(usage!!) } 34 | } else { 35 | excludedUsages = usageView.usages.stream() 36 | .filter { o: Usage -> scenarioStateUsages.contains(o) } 37 | .collect(Collectors.toSet()) 38 | excludedUsages.forEach(Consumer { usage: Usage? -> usageView.removeUsage(usage!!) }) 39 | } 40 | project.messageBus.syncPublisher(UsageFilteringRuleProvider.RULES_CHANGED).run() 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/tngtech/jgiven/scenario/state/ScenarioStateAnnotationProviderTest.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.scenario.state 2 | 3 | import com.intellij.psi.PsiAnnotation 4 | import com.intellij.psi.PsiElement 5 | import com.intellij.psi.PsiField 6 | import com.tngtech.jgiven.Annotations 7 | import com.tngtech.jgiven.util.AnnotationProvider 8 | import org.assertj.core.api.Assertions.assertThat 9 | import org.junit.Before 10 | import org.junit.Rule 11 | import org.junit.Test 12 | import org.mockito.Mock 13 | import org.mockito.Mockito.`when` 14 | import org.mockito.Mockito.mock 15 | import org.mockito.junit.MockitoJUnit 16 | import org.mockito.junit.MockitoRule 17 | 18 | class ScenarioStateAnnotationProviderTest { 19 | @Rule 20 | @JvmField 21 | var mockitoRule: MockitoRule = MockitoJUnit.rule() 22 | 23 | @Mock 24 | private lateinit var annotationProvider: AnnotationProvider 25 | 26 | private lateinit var scenarioStateAnnotationProvider: ScenarioStateAnnotationProvider 27 | 28 | @Before 29 | fun setUp() { 30 | scenarioStateAnnotationProvider = ScenarioStateAnnotationProvider(annotationProvider) 31 | } 32 | 33 | @Test 34 | fun determine_JGiven_ScenarioState() { 35 | val field = mock(PsiField::class.java) 36 | `when`(annotationProvider.findAnnotation(field, Annotations.JGIVEN_SCENARIO_STATE_CLASS_NAMES)).thenReturn(mock(PsiAnnotation::class.java)) 37 | 38 | val result = scenarioStateAnnotationProvider.isJGivenScenarioState(field) 39 | 40 | assertThat(result).isTrue() 41 | } 42 | 43 | @Test 44 | fun determine_JGiven_if_element_is_not_a_field() { 45 | val element = mock(PsiElement::class.java) 46 | 47 | val result = scenarioStateAnnotationProvider.isJGivenScenarioState(element) 48 | 49 | assertThat(result).isFalse() 50 | } 51 | 52 | @Test 53 | fun determine_JGiven_if_element_is_not_a_scenario_state() { 54 | val field = mock(PsiField::class.java) 55 | `when`(annotationProvider.findAnnotation(field, Annotations.JGIVEN_SCENARIO_STATE_CLASS_NAMES)).thenReturn(null) 56 | 57 | val result = scenarioStateAnnotationProvider.isJGivenScenarioState(field) 58 | 59 | assertThat(result).isFalse() 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/tngtech/jgiven/line/marker/LineMarkerProvider.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.line.marker 2 | 3 | import com.google.common.collect.Iterables 4 | import com.intellij.codeInsight.daemon.impl.LineMarkerNavigator 5 | import com.intellij.codeInsight.daemon.impl.MarkerType 6 | import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator 7 | import com.intellij.ide.util.DefaultPsiElementCellRenderer 8 | import com.intellij.psi.PsiElement 9 | import com.intellij.psi.PsiField 10 | import com.intellij.psi.PsiIdentifier 11 | import com.tngtech.jgiven.Icons 12 | import com.tngtech.jgiven.scenario.state.ScenarioStateReferenceProvider 13 | import com.tngtech.jgiven.util.findParentOfTypeOn 14 | import java.awt.event.MouseEvent 15 | 16 | class LineMarkerProvider : com.intellij.codeInsight.daemon.LineMarkerProvider { 17 | private val scenarioStateReferenceProvider = ScenarioStateReferenceProvider() 18 | 19 | override fun getLineMarkerInfo(element: PsiElement) = collectMarkerFor(element) 20 | 21 | private fun collectMarkerFor(element: PsiElement): JGivenLineMarkerInfo? { 22 | val field = findParentOfTypeOn(element) ?: return null 23 | if (element !is PsiIdentifier || element.getParent() !is PsiField) { 24 | return null 25 | } 26 | val references = allReferencingFields(field) 27 | return when { 28 | references.isEmpty() -> null 29 | else -> JGivenLineMarkerInfo(element, Icons.JGIVEN, MarkerType("jgiven", { "JGiven States" }, navigatorToElements()), "JGiven States") { "JGiven States" } 30 | } 31 | } 32 | 33 | private fun navigatorToElements(): LineMarkerNavigator { 34 | return object : LineMarkerNavigator() { 35 | 36 | override fun browse(e: MouseEvent, element: PsiElement) { 37 | val field = findParentOfTypeOn(element) ?: return 38 | val references = allReferencingFields(field) 39 | PsiElementListNavigator.openTargets(e, Iterables.toArray(references, PsiField::class.java), 40 | "JGiven States", "", DefaultPsiElementCellRenderer()) 41 | } 42 | } 43 | } 44 | 45 | private fun allReferencingFields(element: PsiField) = 46 | scenarioStateReferenceProvider.findReferences(element, 20) 47 | .mapNotNull { findParentOfTypeOn(it.element) } 48 | .toList() 49 | 50 | } 51 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | ## Sign your work - the Developer's Certificate of Origin 2 | The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify the below (from developercertificate.org): 3 | 4 | > Developer's Certificate of Origin 1.1 5 | > 6 | > By making a contribution to this project, I certify that: 7 | > 8 | > (a) The contribution was created in whole or in part by me and I 9 | > have the right to submit it under the open source license 10 | > indicated in the file; or 11 | > 12 | > (b) The contribution is based upon previous work that, to the best 13 | > of my knowledge, is covered under an appropriate open source 14 | > license and I have the right under that license to submit that 15 | > work with modifications, whether created in whole or in part 16 | > by me, under the same open source license (unless I am 17 | > permitted to submit under a different license), as indicated 18 | > in the file; or 19 | > 20 | > (c) The contribution was provided directly to me by some other 21 | > person who certified (a), (b) or (c) and I have not modified 22 | > it. 23 | > 24 | > (d) I understand and agree that this project and the contribution 25 | > are public and that a record of the contribution (including all 26 | > personal information I submit with it, including my sign-off) is 27 | > maintained indefinitely and may be redistributed consistent with 28 | > this project or the open source license(s) involved. 29 | 30 | #### DCO Sign-Off Methods 31 | 32 | The DCO requires a sign-off message in the following format appear on each commit in the pull request: 33 | 34 | > Signed-off-by: Random J Developer 35 | 36 | using your real name (sorry, no pseudonyms or anonymous contributions.) 37 | 38 | The DCO text can either be manually added to your commit body, or you can add either **-s** or **--signoff** to your usual git commit commands. If you forget to add the sign-off you can also amend a previous commit with the sign-off by running **git commit --amend -s**. If you've pushed your changes to Github already you'll need to force push your branch after this with **git push -f**. 39 | 40 | 41 | #### Alternative Sign-Off Methods in rare cases 42 | 43 | 44 | If it is really no option for you to disclose your real name and email address, there might be a chance that you can get your contribution accepted. In this case please contact the maintainers directly and verify the adherence to the DCO of the contribution manually. This might include quite some legal overhead for both parties. 45 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/test/java/com/tngtech/jgiven/LibraryTestUtil.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven 2 | 3 | import com.intellij.openapi.command.WriteCommandAction 4 | import com.intellij.openapi.module.Module 5 | import com.intellij.openapi.roots.ModuleRootModificationUtil 6 | import com.intellij.openapi.roots.libraries.Library 7 | import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar 8 | import com.intellij.openapi.util.Ref 9 | import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess 10 | import com.intellij.testFramework.PsiTestUtil 11 | import com.tngtech.jgiven.annotation.ScenarioState 12 | import java.io.File 13 | 14 | class LibraryTestUtil constructor(private val myModule: Module) { 15 | 16 | private val references = ArrayList>() 17 | 18 | private fun addJarContaining(clazz: Class<*>): LibraryTestUtil { 19 | val path = getJarPath(clazz) 20 | addLibraryAt(path) 21 | return this 22 | } 23 | 24 | private fun getJarPath(clazz: Class<*>): String { 25 | val className = clazz.name.replace('.', '/') + ".class" 26 | val classPath = clazz.classLoader.getResource(className)?.toString() 27 | ?: throw IllegalArgumentException("Class $clazz not found") 28 | return if (classPath.startsWith("jar")) { 29 | classPath.substringAfter("jar:file:").substringBefore('!') 30 | } else { 31 | throw IllegalArgumentException("Class $clazz is not in a jar file") 32 | 33 | } 34 | } 35 | 36 | 37 | fun addJGiven(): LibraryTestUtil { 38 | try { 39 | return addJarContaining(ScenarioState::class.java) 40 | }catch(e: IllegalArgumentException){ 41 | throw IllegalArgumentException("JGiven jar not found. Please add it to the classpath") 42 | } 43 | } 44 | 45 | private fun addLibraryAt(path: String) { 46 | val parts = path.split("/".toRegex()).filterNot { it.isEmpty() }.toTypedArray() 47 | val file = File(path) 48 | VfsRootAccess.allowRootAccess(myModule, parts[0]) 49 | val fileName = file.name 50 | ModuleRootModificationUtil.updateModel(myModule) { model -> 51 | references.add(Ref.create(PsiTestUtil.addLibrary( 52 | model, fileName, file.parent, fileName 53 | ))) 54 | } 55 | } 56 | 57 | internal fun removeLibraries() { 58 | WriteCommandAction.runWriteCommandAction(null) { 59 | val table = LibraryTablesRegistrar.getInstance().getLibraryTable(myModule.project) 60 | val model = table.modifiableModel 61 | references.forEach { reference -> model.removeLibrary(reference.get()) } 62 | model.commit() 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/test/java/com/tngtech/jgiven/scenario/state/JGivenUsageProviderTest.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.scenario.state 2 | 3 | import com.intellij.psi.PsiField 4 | import com.intellij.psi.PsiReference 5 | import com.tngtech.jgiven.resolution.ResolutionHandler 6 | import org.assertj.core.api.Assertions.assertThat 7 | import org.junit.Rule 8 | import org.junit.Test 9 | import org.mockito.InjectMocks 10 | import org.mockito.Mock 11 | import org.mockito.Mockito.`when` 12 | import org.mockito.Mockito.mock 13 | import org.mockito.junit.MockitoJUnit 14 | import org.mockito.junit.MockitoRule 15 | 16 | class JGivenUsageProviderTest { 17 | @Rule 18 | @JvmField 19 | var mockitoRule: MockitoRule = MockitoJUnit.rule() 20 | 21 | @Mock 22 | private lateinit var scenarioStateProvider: ScenarioStateAnnotationProvider 23 | @Mock 24 | private lateinit var resolutionHandler: ResolutionHandler 25 | @Mock 26 | private lateinit var referenceFactory: ReferenceFactory 27 | @Mock 28 | private lateinit var fieldToSearch: PsiField 29 | @Mock 30 | private lateinit var field: PsiField 31 | 32 | @InjectMocks 33 | private lateinit var usageProvider: JGivenUsageProvider 34 | 35 | @Test 36 | fun should_return_usage() { 37 | val reference = mock(PsiReference::class.java) 38 | `when`(scenarioStateProvider.isJGivenScenarioState(field)).thenReturn(true) 39 | `when`(resolutionHandler.resolutionMatches(field, fieldToSearch)).thenReturn(true) 40 | `when`(referenceFactory.referenceFor(field)).thenReturn(reference) 41 | 42 | val result = usageProvider.createReferenceIfJGivenUsage(fieldToSearch, field) 43 | 44 | assertThat(result).isEqualTo(reference) 45 | } 46 | 47 | @Test 48 | fun should_return_no_usage_if_field_not_a_scenario_state() { 49 | `when`(scenarioStateProvider.isJGivenScenarioState(field)).thenReturn(false) 50 | 51 | val result = usageProvider.createReferenceIfJGivenUsage(fieldToSearch, field) 52 | 53 | assertThat(result).isNull() 54 | } 55 | 56 | @Test 57 | fun should_return_no_usage_if_resolutions_dont_match() { 58 | `when`(scenarioStateProvider.isJGivenScenarioState(field)).thenReturn(true) 59 | `when`(resolutionHandler.resolutionMatches(field, fieldToSearch)).thenReturn(false) 60 | 61 | val result = usageProvider.createReferenceIfJGivenUsage(fieldToSearch, field) 62 | 63 | assertThat(result).isNull() 64 | } 65 | 66 | @Test 67 | fun should_return_no_usage_if_fields_are_equal() { 68 | `when`(scenarioStateProvider.isJGivenScenarioState(field)).thenReturn(true) 69 | `when`(resolutionHandler.resolutionMatches(field, fieldToSearch)).thenReturn(true) 70 | 71 | val result = usageProvider.createReferenceIfJGivenUsage(fieldToSearch, fieldToSearch) 72 | 73 | assertThat(result).isNull() 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/com/tngtech/jgiven/scenario/state/StateReferenceProcessorTest.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.scenario.state 2 | 3 | import com.intellij.psi.PsiField 4 | import com.intellij.psi.PsiReference 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.junit.Rule 7 | import org.junit.Test 8 | import org.mockito.Mock 9 | import org.mockito.Mockito.`when` 10 | import org.mockito.Mockito.mock 11 | import org.mockito.junit.MockitoJUnit 12 | import org.mockito.junit.MockitoRule 13 | 14 | class StateReferenceProcessorTest { 15 | 16 | @Rule 17 | @JvmField 18 | var mockitoRule: MockitoRule = MockitoJUnit.rule() 19 | 20 | @Mock 21 | private lateinit var usageProvider: JGivenUsageProvider 22 | @Mock 23 | private lateinit var fieldToSearch: PsiField 24 | 25 | @Test 26 | fun should_add_reference() { 27 | val field = mock(PsiField::class.java) 28 | val processor = referenceProcessorFor(2) 29 | val reference = mock(PsiReference::class.java) 30 | `when`(usageProvider.createReferenceIfJGivenUsage(fieldToSearch, field)).thenReturn(reference) 31 | 32 | val result = processor.process(field) 33 | 34 | assertThat(processor.getResults()).containsOnly(reference) 35 | assertThat(result).isTrue() 36 | } 37 | 38 | @Test 39 | fun should_not_add_reference() { 40 | val field = mock(PsiField::class.java) 41 | val processor = referenceProcessorFor(1) 42 | `when`(usageProvider.createReferenceIfJGivenUsage(fieldToSearch, field)).thenReturn(null) 43 | 44 | processor.process(field) 45 | 46 | assertThat(processor.getResults()).isEmpty() 47 | } 48 | 49 | @Test 50 | fun should_return_false_if_enough_results_have_been_read() { 51 | val field1 = mock(PsiField::class.java) 52 | val reference1 = mock(PsiReference::class.java) 53 | `when`(usageProvider.createReferenceIfJGivenUsage(fieldToSearch, field1)).thenReturn(reference1) 54 | val processor = referenceProcessorFor(1) 55 | 56 | val result = processor.process(field1) 57 | 58 | assertThat(result).isFalse() 59 | } 60 | 61 | @Test 62 | fun should_handle_any_number_of_max_results() { 63 | val field1 = mock(PsiField::class.java) 64 | val reference1 = mock(PsiReference::class.java) 65 | `when`(usageProvider.createReferenceIfJGivenUsage(fieldToSearch, field1)).thenReturn(reference1) 66 | val processor = referenceProcessorFor(ScenarioStateReferenceProvider.ANY_NUMBER_OF_RESULTS) 67 | 68 | val result = processor.process(field1) 69 | 70 | assertThat(result).isTrue() 71 | } 72 | 73 | private fun referenceProcessorFor(maxNumberOfResults: Int): StateReferenceProcessor { 74 | return StateReferenceProcessor(fieldToSearch, maxNumberOfResults, usageProvider) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at public-maven-repo@tngtech.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | -------------------------------------------------------------------------------- /src/test/java/com/tngtech/jgiven/resolution/TypeIsTooGenericCalculatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.resolution 2 | 3 | import com.intellij.psi.PsiClass 4 | import com.intellij.psi.PsiClassType 5 | import com.intellij.psi.PsiType 6 | import com.tngtech.java.junit.dataprovider.DataProvider 7 | import com.tngtech.java.junit.dataprovider.DataProviderRunner 8 | import com.tngtech.java.junit.dataprovider.UseDataProvider 9 | import org.assertj.core.api.Assertions.assertThat 10 | import org.junit.Test 11 | import org.junit.runner.RunWith 12 | import org.mockito.Mockito.`when` 13 | import org.mockito.Mockito.mock 14 | import java.io.BufferedReader 15 | import java.util.stream.Stream 16 | 17 | @RunWith(DataProviderRunner::class) 18 | class TypeIsTooGenericCalculatorTest { 19 | 20 | @Test 21 | @UseDataProvider("tooComplexProvider") 22 | fun should_determine_whether_type_is_too_complex(testCase: TestCase) { 23 | mockPsiClassWith(testCase.typeMock, testCase.qualifiedName) 24 | 25 | val result = TypeIsTooGenericCalculator().typeIsTooGeneric(testCase.typeMock) 26 | 27 | assertThat(result).isEqualTo(testCase.expectedResult) 28 | } 29 | 30 | private fun mockPsiClassWith(psiType: PsiType?, qualifiedName: String?) { 31 | if (psiType is PsiClassType) { 32 | val clazz = mock(PsiClass::class.java) 33 | `when`(clazz.qualifiedName).thenReturn(qualifiedName) 34 | `when`(psiType.resolve()).thenReturn(clazz) 35 | } 36 | } 37 | 38 | class TestCase( 39 | val typeMock: PsiType, 40 | val qualifiedName: String?, 41 | val expectedResult: Boolean 42 | ) { 43 | override fun toString(): String { 44 | return "TestCase{" + 45 | "qualifiedName='" + qualifiedName + '\''.toString() + 46 | ", expectedResult=" + expectedResult + 47 | '}'.toString() 48 | } 49 | } 50 | 51 | companion object { 52 | @Suppress("unused") 53 | @DataProvider 54 | @JvmStatic 55 | fun tooComplexProvider() = listOf( 56 | TestCase(typeMock = mock(PsiClassType::class.java), 57 | qualifiedName = String::class.java.name, 58 | expectedResult = true), 59 | TestCase(typeMock = mock(PsiClassType::class.java), 60 | qualifiedName = Integer::class.java.name, 61 | expectedResult = true), 62 | TestCase(typeMock = mock(PsiClassType::class.java), 63 | qualifiedName = List::class.java.name, 64 | expectedResult = true), 65 | TestCase(typeMock = mock(PsiClassType::class.java), 66 | qualifiedName = Stream::class.java.name, 67 | expectedResult = true), 68 | TestCase(typeMock = mock(PsiClassType::class.java), 69 | qualifiedName = BufferedReader::class.java.name, 70 | expectedResult = true), 71 | TestCase(typeMock = mock(PsiType::class.java), 72 | qualifiedName = "some_qualified_name", 73 | expectedResult = true), 74 | TestCase(typeMock = mock(PsiClassType::class.java), 75 | qualifiedName = null, 76 | expectedResult = true), 77 | TestCase(typeMock = mock(PsiClassType::class.java), 78 | qualifiedName = "myClass", 79 | expectedResult = false) 80 | ) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/com/tngtech/jgiven/resolution/ResolutionHandlerTest.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.resolution 2 | 3 | import com.intellij.psi.PsiField 4 | import com.intellij.psi.PsiType 5 | import com.tngtech.jgiven.resolution.Resolution.NAME 6 | import com.tngtech.jgiven.resolution.Resolution.TYPE 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.Before 9 | import org.junit.Rule 10 | import org.junit.Test 11 | import org.mockito.Mock 12 | import org.mockito.Mockito.`when` 13 | import org.mockito.Mockito.mock 14 | import org.mockito.junit.MockitoJUnit 15 | import org.mockito.junit.MockitoRule 16 | 17 | class ResolutionHandlerTest { 18 | 19 | @Rule 20 | @JvmField 21 | var mockitoRule: MockitoRule = MockitoJUnit.rule() 22 | 23 | @Mock 24 | private lateinit var resolutionProvider: ResolutionProvider 25 | @Mock 26 | private lateinit var field1: PsiField 27 | @Mock 28 | private lateinit var field2: PsiField 29 | 30 | private lateinit var resolutionHandler: ResolutionHandler 31 | 32 | @Before 33 | fun setUp() { 34 | resolutionHandler = ResolutionHandler(resolutionProvider) 35 | } 36 | 37 | @Test 38 | fun should_handle_equal_field_names() { 39 | `when`(resolutionProvider.getResolutionFrom(field1)).thenReturn(NAME) 40 | `when`(resolutionProvider.getResolutionFrom(field2)).thenReturn(NAME) 41 | `when`(field1.name).thenReturn("field") 42 | `when`(field2.name).thenReturn("field") 43 | 44 | val result = resolutionHandler.resolutionMatches(field1, field2) 45 | 46 | assertThat(result).isTrue() 47 | } 48 | 49 | @Test 50 | fun should_handle_not_equal_field_names() { 51 | `when`(resolutionProvider.getResolutionFrom(field1)).thenReturn(NAME) 52 | `when`(resolutionProvider.getResolutionFrom(field2)).thenReturn(NAME) 53 | `when`(field1.name).thenReturn("field1") 54 | `when`(field2.name).thenReturn("field2") 55 | 56 | val result = resolutionHandler.resolutionMatches(field1, field2) 57 | 58 | assertThat(result).isFalse() 59 | } 60 | 61 | @Test 62 | fun should_handle_equal_types() { 63 | `when`(resolutionProvider.getResolutionFrom(field1)).thenReturn(TYPE) 64 | `when`(resolutionProvider.getResolutionFrom(field2)).thenReturn(TYPE) 65 | mockPresentableTextWith(field1, "type") 66 | mockPresentableTextWith(field2, "type") 67 | 68 | val result = resolutionHandler.resolutionMatches(field1, field2) 69 | 70 | assertThat(result).isTrue() 71 | } 72 | 73 | @Test 74 | fun should_handle_not_equal_types() { 75 | `when`(resolutionProvider.getResolutionFrom(field1)).thenReturn(TYPE) 76 | `when`(resolutionProvider.getResolutionFrom(field2)).thenReturn(TYPE) 77 | mockPresentableTextWith(field1, "type1") 78 | mockPresentableTextWith(field2, "type2") 79 | 80 | val result = resolutionHandler.resolutionMatches(field1, field2) 81 | 82 | assertThat(result).isFalse() 83 | } 84 | 85 | @Test 86 | fun should_handle_different_resolution() { 87 | `when`(resolutionProvider.getResolutionFrom(field1)).thenReturn(NAME) 88 | `when`(resolutionProvider.getResolutionFrom(field2)).thenReturn(TYPE) 89 | 90 | val result = resolutionHandler.resolutionMatches(field1, field2) 91 | 92 | assertThat(result).isFalse() 93 | } 94 | 95 | private fun mockPresentableTextWith(field: PsiField, text: String) { 96 | val type = mock(PsiType::class.java) 97 | `when`(field.type).thenReturn(type) 98 | `when`(type.presentableText).thenReturn(text) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/test/java/com/tngtech/jgiven/reference/ReferenceProviderTest.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.reference 2 | 3 | import com.intellij.mock.MockApplication 4 | import com.intellij.openapi.Disposable 5 | import com.intellij.openapi.application.ApplicationManager 6 | import com.intellij.psi.PsiField 7 | import com.intellij.psi.PsiReference 8 | import com.intellij.psi.search.GlobalSearchScope 9 | import com.intellij.psi.search.LocalSearchScope 10 | import com.intellij.psi.search.searches.ReferencesSearch 11 | import com.intellij.util.Processor 12 | import com.tngtech.jgiven.scenario.state.ScenarioStateAnnotationProvider 13 | import com.tngtech.jgiven.scenario.state.ScenarioStateReferenceProvider 14 | import org.junit.Before 15 | import org.junit.Rule 16 | import org.junit.Test 17 | import org.mockito.Mock 18 | import org.mockito.Mockito.* 19 | import org.mockito.junit.MockitoJUnit 20 | import org.mockito.junit.MockitoRule 21 | import java.util.* 22 | 23 | class ReferenceProviderTest { 24 | @Rule 25 | @JvmField 26 | var mockitoRule: MockitoRule = MockitoJUnit.rule() 27 | 28 | @Mock 29 | private lateinit var scenarioStateProvider: ScenarioStateAnnotationProvider 30 | @Mock 31 | private lateinit var scenarioStateReferenceProvider: ScenarioStateReferenceProvider 32 | @Mock 33 | private lateinit var processor: Processor 34 | 35 | private lateinit var referenceProvider: ReferenceProvider 36 | 37 | @Before 38 | fun setUp() { 39 | val disposable = mock(Disposable::class.java) 40 | ApplicationManager.setApplication(MockApplication(disposable), disposable) 41 | 42 | referenceProvider = ReferenceProvider(scenarioStateProvider, scenarioStateReferenceProvider) 43 | } 44 | 45 | @Test 46 | fun should_process_reference() { 47 | // given 48 | val reference1 = mock(PsiReference::class.java) 49 | val reference2 = mock(PsiReference::class.java) 50 | 51 | val field = mock(PsiField::class.java) 52 | val searchParameters = mock(ReferencesSearch.SearchParameters::class.java) 53 | `when`(searchParameters.elementToSearch).thenReturn(field) 54 | `when`(searchParameters.effectiveSearchScope).thenReturn(mock(GlobalSearchScope::class.java)) 55 | `when`(scenarioStateReferenceProvider.findReferences(field)).thenReturn(Arrays.asList(reference1, reference2)) 56 | `when`(scenarioStateProvider.isJGivenScenarioState(field)).thenReturn(true) 57 | 58 | // when 59 | referenceProvider.processQuery(searchParameters, processor) 60 | 61 | // then 62 | verify(processor).process(reference1) 63 | verify(processor).process(reference2) 64 | } 65 | 66 | @Test 67 | fun should_not_process_reference_if_search_scope_is_not_global() { 68 | // given 69 | val field = mock(PsiField::class.java) 70 | val searchParameters = mock(ReferencesSearch.SearchParameters::class.java) 71 | `when`(searchParameters.elementToSearch).thenReturn(field) 72 | `when`(searchParameters.effectiveSearchScope).thenReturn(mock(LocalSearchScope::class.java)) 73 | `when`(scenarioStateProvider.isJGivenScenarioState(field)).thenReturn(true) 74 | 75 | // when 76 | referenceProvider.processQuery(searchParameters, processor) 77 | 78 | // then 79 | verifyNoInteractions(processor) 80 | } 81 | 82 | @Test 83 | fun should_not_process_reference_if_element_is_not_a_JGiven_scenario_state() { 84 | // given 85 | val field = mock(PsiField::class.java) 86 | val searchParameters = mock(ReferencesSearch.SearchParameters::class.java) 87 | `when`(searchParameters.elementToSearch).thenReturn(field) 88 | `when`(searchParameters.effectiveSearchScope).thenReturn(mock(GlobalSearchScope::class.java)) 89 | `when`(scenarioStateProvider.isJGivenScenarioState(field)).thenReturn(false) 90 | 91 | // when 92 | referenceProvider.processQuery(searchParameters, processor) 93 | 94 | // then 95 | verifyNoInteractions(processor) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/test/java/com/tngtech/jgiven/resolution/ResolutionProviderTest.kt: -------------------------------------------------------------------------------- 1 | package com.tngtech.jgiven.resolution 2 | 3 | import com.intellij.psi.PsiAnnotation 4 | import com.intellij.psi.PsiExpression 5 | import com.intellij.psi.PsiField 6 | import com.intellij.psi.PsiType 7 | import com.tngtech.jgiven.scenario.state.ScenarioStateAnnotationProvider 8 | import org.assertj.core.api.Assertions.assertThat 9 | import org.junit.Before 10 | import org.junit.Rule 11 | import org.junit.Test 12 | import org.mockito.Mock 13 | import org.mockito.Mockito.`when` 14 | import org.mockito.Mockito.mock 15 | import org.mockito.junit.MockitoJUnit 16 | import org.mockito.junit.MockitoRule 17 | 18 | class ResolutionProviderTest { 19 | 20 | @Rule 21 | @JvmField 22 | var mockitoRule: MockitoRule = MockitoJUnit.rule() 23 | 24 | @Mock 25 | private lateinit var scenarioStateProvider: ScenarioStateAnnotationProvider 26 | @Mock 27 | private lateinit var annotationValueProvider: AnnotationValueProvider 28 | @Mock 29 | private lateinit var typeIsTooGenericCalculator: TypeIsTooGenericCalculator 30 | @Mock 31 | private lateinit var field: PsiField 32 | 33 | private lateinit var resolutionProvider: ResolutionProvider 34 | 35 | @Before 36 | fun setUp() { 37 | `when`(field.type).thenReturn(mock(PsiType::class.java)) 38 | resolutionProvider = ResolutionProvider(scenarioStateProvider, annotationValueProvider, typeIsTooGenericCalculator) 39 | } 40 | 41 | @Test 42 | fun handle_NAME_resolution() { 43 | mockAnnotationValueWith("NAME", field) 44 | 45 | val result = resolutionProvider.getResolutionFrom(field) 46 | 47 | assertThat(result).isEqualTo(Resolution.NAME) 48 | } 49 | 50 | @Test 51 | fun handle_TYPE_resolution() { 52 | mockAnnotationValueWith("TYPE", field) 53 | 54 | val result = resolutionProvider.getResolutionFrom(field) 55 | 56 | assertThat(result).isEqualTo(Resolution.TYPE) 57 | } 58 | 59 | @Test 60 | fun handle_AUTO_resolution_not_being_too_generic() { 61 | mockAnnotationValueWith("AUTO", field) 62 | `when`(typeIsTooGenericCalculator.typeIsTooGeneric(field.type)).thenReturn(false) 63 | 64 | val result = resolutionProvider.getResolutionFrom(field) 65 | 66 | assertThat(result).isEqualTo(Resolution.TYPE) 67 | } 68 | 69 | @Test 70 | fun handle_AUTO_resolution_being_too_generic() { 71 | mockAnnotationValueWith("AUTO", field) 72 | `when`(typeIsTooGenericCalculator.typeIsTooGeneric(field.type)).thenReturn(true) 73 | 74 | val result = resolutionProvider.getResolutionFrom(field) 75 | 76 | assertThat(result).isEqualTo(Resolution.NAME) 77 | } 78 | 79 | @Test 80 | fun handle_not_present_resolution_being_too_generic() { 81 | mockAnnotationValueWith(field, null) 82 | `when`(typeIsTooGenericCalculator.typeIsTooGeneric(field.type)).thenReturn(true) 83 | 84 | val result = resolutionProvider.getResolutionFrom(field) 85 | 86 | assertThat(result).isEqualTo(Resolution.NAME) 87 | } 88 | 89 | @Test 90 | fun handle_not_present_resolution_not_being_too_generic() { 91 | mockAnnotationValueWith(field, null) 92 | `when`(typeIsTooGenericCalculator.typeIsTooGeneric(field.type)).thenReturn(false) 93 | 94 | val result = resolutionProvider.getResolutionFrom(field) 95 | 96 | assertThat(result).isEqualTo(Resolution.TYPE) 97 | } 98 | 99 | private fun mockAnnotationValueWith(name: String, field: PsiField) { 100 | val annotationValueExpression = mock(PsiExpression::class.java) 101 | `when`(annotationValueExpression.text).thenReturn(name) 102 | mockAnnotationValueWith(field, annotationValueExpression) 103 | } 104 | 105 | private fun mockAnnotationValueWith(field: PsiField, valueExpression: PsiExpression?) { 106 | val annotation = mock(PsiAnnotation::class.java) 107 | `when`(scenarioStateProvider.getJGivenAnnotationOn(field)).thenReturn(annotation) 108 | `when`(annotationValueProvider.getAnnotationValue(annotation, ResolutionProvider.FIELD_RESOLUTION)).thenReturn(valueExpression) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="-Xmx512m" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------