diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 40b65d5c7..2e58a4f1a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,71 +37,91 @@ to include test generation using Grazie in the runIdeForUiTests process, you nee ## Language Support Documentation -# CONTRIBUTORS.md +The TestSpark plugin supports automatic test generation for various programming languages (currently Java and Kotlin) +and aims to support even more programming languages in the future. -## Language Support Documentation - -The TestSpark plugin supports automatic test generation for various Java and Kotlin programming languages and aims to support even more programming languages in the future. - -This document provides an overview of the existing implementation for Java and Kotlin support and guidelines for adding support for additional programming languages. +This document provides an overview of the existing implementation of Kotlin and Java support and guidelines for adding +more programming languages. ## Key Components ### 1. PSI Parsers -The first step is to enable the collection of the appropriate information for the code under test. This part is responsible for working with the PSI (Program Structure Interface) generated by IntelliJ IDEA. It helps parse the part where the cursor is located, provides a choice of the code elements that are available for testing at its position, and then finds all the needed dependencies to make the prompt complete with all the necessary knowledge about the code under test. +The first step is to enable the collection of the appropriate information for the code under test. This part is +responsible for working with the PSI (Program Structure Interface) generated by IntelliJ IDEA. It helps parse the part +where the cursor is located, provides a choice of the code elements that are available for testing at cursor's position. +Then find all the needed dependencies to make the prompt complete with all the necessary knowledge about the code under +test. This part is the most granular but complex at the same time. -The main reason for this is to include dependencies only for the languages we need. This avoids errors if the user does not have some languages that our plugin supports. For example, if we work with a Python project, we don't want to depend on Kotlin because it will cause an error if Kotlin isn't present. Additionally, we want to incrementally add dependencies on other languages for faster startup. For example, we do not want to fetch the dependency on Java when we work with TypeScript. Other benefits include better organization, easier maintenance, and clearer separation of concerns. As a side-bonus, the addition of new languages will be easier. +The main reason for this is to include dependencies only for the languages we need. This avoids errors if the user does +not have some languages that our plugin supports. _For example, if we work with a Python project, we don't want to depend +on Kotlin because it will cause an error if Kotlin isn't present._ + +Additionally, we want to incrementally add dependencies on other languages for faster startup. +_For example, we do not want to fetch the dependency on Java when we work with TypeScript._ +Other benefits include better organization, easier maintenance, and clearer separation of +concerns. As a side-bonus, the addition of new languages will be easier. **Module Dependencies:** - **langwrappers**: This is a foundational module for language extensions. -- ****: Depends on the `langwrappers` module to implement the ``-specific `PsiHelper` and `PsiHelperProvider`. -- **src/**: Depends on `langwrappers` because we want to use `PsiHelper` and other interfaces regardless of the current language. Depends on ``, to make `plugin.xml` aware of the implementations of the Extension Point. +- ****: Depends on the `langwrappers` module to implement the ``-specific `PsiHelper` + and `PsiHelperProvider`. +- **src/**: Depends on `langwrappers` because we want to use `PsiHelper` and other interfaces regardless of the current + language. Depends on ``, to make `plugin.xml` aware of the implementations of the Extension Point. **Plugin Dependencies:** -- The main `plugin.xml` file declares the `psiHelperProvider` extension point using the `com.intellij.lang.LanguageExtensionPoint` class. +- The main `plugin.xml` file declares the `psiHelperProvider` extension point using + the `com.intellij.lang.LanguageExtensionPoint` class. - The language-specific modules extend this extension point to register their implementations. -- When the project is opened, we load the EPs needed to work with the current project. Then, using the `PsiHelperProvider` interface, we can get the appropriate `PsiHelper` class per file. +- When the project is opened, we load the EPs needed to work with the current project. Then, using + the `PsiHelperProvider` interface, we can get the appropriate `PsiHelper` class per file. **Implementation Details:** - **Common Module (`langwrappers`)**: - Contains the `PsiHelper` interface, which provides the necessary methods to interact with `psiFile`. - - The `PsiHelperProvider` class includes a companion object to fetch the appropriate `PsiHelper` implementation based on the file's language. + - The `PsiHelperProvider` class includes a companion object to fetch the appropriate `PsiHelper` implementation + based on the file's language. - ** Module**: - - Implements the `PsiHelper` and `PsiHelperProvider` classes, which provide -specific logic. + - Implements the `PsiHelper` and `PsiHelperProvider` classes, which provide -specific + logic. - Declares the extension point in `testspark-.xml`. -To add new languages, create a separate module for this language and register its implementation as an extension of the `psiHelperProvider` EP. Then follow the template provided above. +To add new languages, create a separate module for this language and register its implementation as an extension of +the `psiHelperProvider` EP. Then follow the template provided above. ### 2. Prompt Generation When we know how to parse the code, we need to construct the prompt. -For each language, adjust the prompt that goes to the LLM. Ensure that the language, framework platform, and mocking framework are defined correctly in: +For each language, adjust the prompt that goes to the LLM. Ensure that the language, framework platform, and mocking +framework are defined correctly in: ```kotlin -data class PromptConfiguration( - val desiredLanguage: String, - val desiredTestingPlatform: String, - val desiredMockingFramework: String, +data class PromptConfiguration( + val desiredLanguage: String, + val desiredTestingPlatform: String, + val desiredMockingFramework: String, ) ``` -Additionally, check that all the dependencies (collected by `PsiHelper` for the current strategy) are passed properly. `PromptGenerator` and `PromptBuilder` are responsible for this job. +Additionally, check that all the dependencies (collected by `PsiHelper` for the current strategy) are passed +properly. `PromptGenerator` and `PromptBuilder` are responsible for this job. ### 3. Parsing LLM Response When the LLM response to our prompt is received, we have to parse it. -We want to retrieve test functions from the response, collect them separately (and all together) in the tmp folder, and check for compilation. +We want to retrieve test case, all the test functions and additional information like imports or supporting functions +from the response. The current structure of this part is located in: + - `kotlin/org/jetbrains/research/testspark/core/test` - `kotlin/org/jetbrains/research/testspark/tools` @@ -118,16 +138,26 @@ Before showing the code to the user, it should be checked for compilation. - `TestCompiler`: Compiles a list of test cases and returns the compilation result. -### 5. UI Representation +Here one should specify the appropriate compilation strategy for each language. With all the dependencies and build paths. -Once we parse the code generated by the LLM and confirm that the code is compilable, it should be presented in the UI. +### 5. UI Representation -There are special interfaces that help to work with already parsed test classes and are specified for each language: +Once the code generated by the LLM is checked for the compilation, it should be presented in the UI. -- `TestCaseDisplayService`: Service responsible for the UI representation. +- `TestCaseDisplayService`: Service responsible for the representation of all the UI components. - `TestSuiteView`: Interface specific for working with buttons. - `TestClassCodeAnalyzer`: Interface for retrieving information from test class code. - `TestClassCodeGenerator`: Interface for generating and formatting test class code. + +### 6. Running and saving tests + +We should be able to run all the tests in the UI and then save them to the desired folder. + +- `TestPersistentStorage`: Interface representing a contract for saving generated tests to a specified file system location. + +For Kotlin and Java, the `TestProcessor` implementation also allows saving the JaCoCo report to see the code coverage of +the test that will be saved. + --- ## Plugin Configuration File