Coder Social home page Coder Social logo

jetbrains-research / testspark Goto Github PK

View Code? Open in Web Editor NEW
30.0 1.0 5.0 841.32 MB

TestSpark - a plugin for generating unit tests. TestSpark natively integrates different AI-based test generation tools and techniques in the IDE. Started by SERG TU Delft. Currently under implementation by JetBrains Research (ICTL) for research purposes.

License: MIT License

Java 0.91% Kotlin 99.07% Shell 0.02%

testspark's Introduction

TestSpark

Build Version Downloads

TestSpark Logo TestSpark White Logo

Table of contents

Description

TestSpark is a plugin for generating unit tests. TestSpark natively integrates different AI-based test generation tools and techniques in the IDE.

TestSpark currently supports two test generation strategies:

  • LLM-based test generation (using OpenAI and JetBrains internal AI Assistant platform)
  • Local search-based test generation (using EvoSuite)

LLM-based test generation

For this type of test generation, TestSpark sends request to different Large Language Models. Also, it automatically checks if tests are valid before presenting it to users.

This feature needs a token from OpenAI platform or the AI Assistant platform.

  • Supports Java (any version).
  • Generates unit tests for capturing failures.
  • Generate tests for Java classes, methods, and single lines.

Local search-based test generation

For this type of test generation, TestSpark uses EvoSuite, which is the most powerful search-based local test generator.

  • Supports up to Java 11.
  • Generates tests for different test criteria: line coverage, branch coverage, I/O diversity, exception coverage, mutation score.
  • Generates unit tests for capturing failures.
  • Generate tests for Java classes, methods, and single lines.

Initially implemented by CISELab at SERG @ TU Delft, TestSpark is currently developed and maintained by ICTL at JetBrains Research.

DISCLAIMER

TestSpark is currently designed to serve as an experimental tool. Please keep in mind that tests generated by TestSpark are meant to augment your existing test suites. They are not meant to replace writing tests manually.

If you are running the plugin for the first time, checkout the Settings section.

Installation

  • Using IDE built-in plugin system:

    Settings/Preferences > Plugins > Marketplace > Search for "TestSpark" > Install Plugin

  • Manually:

    Download the latest release and install it manually using Settings/Preferences > Plugins > โš™๏ธ > Install plugin from disk...

Usage

Generating Tests

To initiate the generation process, right-click on the part of the code for which tests need to be generated and select TestSpark.

TestSpark option TestSpark option dark

Main Page

After that, a window will open where users need to configure generation settings.

Main page Main page dark

Firstly users need to select the test generator (LLM-based test generator or EvoSuite, which is a Local search-based test generator).

Test generator Test generator dark

Also, in this window, it is necessary to select the part of the code for which tests need to be generated. The selection consists of no more than three items -- class/interface, method/constructor (if applicable), line (if applicable).

Part of the code Part of the code dark

After clicking the Next button, the plugin provides the opportunity to configure the basic parameters of the selected generator. Advanced parameter settings can be done in Settings. All settings, both in Settings and in this window, are saved, so you can disable the ability to configure generators before each generation process to perform this process more quickly.

LLM Setup Page

In the case of LLM, two additional pages are provided for basic settings.
In the first page, users configure LLM Platform, LLM Token, LLM Model, LLM JUnit version, and Prompt Selection. More detailed descriptions of each item can be found in Settings.

LLM setup page LLM setup page dark

LLM Samples Page

After that, in the next page, you can provide some test samples for LLM.
Tests can be entered manually.

Manually samples Manually samples

Also, tests can be chosen tests from the current project.

Chosen samples Chosen samples dark

Test Cases can be modified, reset to their initial state, and deleted.

Interaction with samples Interaction with samples dark

EvoSuite Setup Page

For EvoSuite, you need to enter the local path to Java 11 and select the generation algorithm, after which the generation process will start.

EvoSuite page EvoSuite page dark

Generation Process

After configuring the test generators, click the OK button, after which the generation process will start, and a list of generated test cases will appear on the right side of the IDE.

Generated tests Generated tests dark

During the test generation, users can observe the current state of the generation process.

Generation state Generation state dark

Working with Test Cases

After receiving the results, the user can interact with the test cases in various ways. They can view the result (whether it's passed or failed), also select, delete, modify, reset, like/dislike, fix by LLM and execute the tests to update the results.
Hitting the "Apply to test suite" button will add the selected tests to a test class of your choice.
Additionally, the top row of the tool window has buttons for selecting all tests, deselecting all tests, running all tests and removing them. The user also has an overview of how many tests they currently have selected and passed.

Quick buttons Quick buttons dark

Select Test

Users can select test cases.

Select test case Select test case dark

Remove Test

Users can remove test cases.

Remove test case Remove test case dark

Modify Test

Users can modify the code of test cases.

Modify test case Modify test case dark

Reset Test

Users can reset the code to its original.

Reset test case Reset test case dark

Reset to Last Run

Users can reset the code to the last run.

Reset to last run Reset to last run dark

Run Test

Users can run the test to update the execution result.
Effortlessly identify passed and failed test cases with green and red color highlights for instant result comprehension is available. In case of failure, it is possible to find out the current error.

Run test Run test dark

Copy Test

Users can copy the test.

Copy test Copy test dark

Like/Dislike Test

Users can like/dislike the test for future analysis and improvement of the generation process.

Like test Like test dark

Send a Request to LLM

Users can send a request to LLM with modification which users prefer for the test case. Users can choose a default query, the list of which is set up in the Settings.

Send a template request to LLM Send a template request to LLM dark

Users can also manually punch in a new request.

Send a request to LLM Send a request to LLM dark

Coverage

Coverage Table

Once a test suite is generated, basic statistics about it can be seen in the tool window, coverage tab. The statistics include line coverage, branch coverage, weak mutation coverage. The table adjusts dynamically - it only calculates the statistics for the selected tests in the test suite.

Progress bar Progress bar dark

Coverage Visualisation

Once test are generated, the lines which are covered by the tests will be highlighted (default color: green). The gutter next to the lines will have a green rectangle as well. If the rectangle is clicked, a popup will show the names of the tests which cover the selected line. If any of the test names are clicked, the corresponding test in the toolwindow will be highlighted with the same accent color. The effect lasts 10 seconds. Coverage visualisation adjusts dynamically - it only shows results for the tests that are selected in the TestSpark tab.

Test highlight Test highlight dark

Integrating Tests into the Project

The tests can be added to an existing file:

Tests adding to an exiting file Tests adding to an exiting file dark

Or to a new file:

Tests adding to a new file Tests adding to a new file_dark

Settings

The plugin is configured mainly through the Settings menu. The plugin settings can be found under Settings > Tools > TestSpark. Here, the user is able to select options for the plugin:

Plugin settings Plugin settings dark

First time configuration

Before running the plugin for the first time, we highly recommend going to the Environment settings section of TestSpark settings. The settings include compilation path (path to compiled code) and compilation command. Both commands have defaults. However, we recommend especially that you check compilation command. For this command the user requires maven, gradle or any other builder program which can be accessed via command. Leaving this field with a faulty value may cause unintended behaviour.

Setup Setup dark

Accessibility Features

The plugin supports changing the color for coverage visualisation and killed mutants visualisation (one setting for both). To change the color, go to Settings > Tools > TestSpark and use the color picker under Accessibility settings:

Color picker Color picker dark

The plugin has been designed with translation in mind. The vast majority of the plugins labels, tooltips, messages, etc. is stored in .property files. For more information on translation, refer to the contributing readme.

EvoSuite Settings

The settings submenu Settings > Tools > TestSpark > EvoSuite allows the user to tweak EvoSuite parameters to their liking.
At the moment EvoSuite can be executed only with Java 11, so if the user has a more modern version by default, it is necessary to download Java 11 and set the path to the java file.

Java setup Java setup dark

To accelerate the test generation process, users can disable the display of the EvoSuite Setup Page.

EvoSuite setup page EvoSuite setup page dark

EvoSuite has hundreds of parameters, not all can be packed in a settings menu. However, the most commonly used and rational settings were added here:

EvoSuite settings EvoSuite settings dark

LLM Settings

The settings submenu Settings > Tools > TestSpark > LLM allows the user to tweak LLM parameters to their liking.

LLM settings LLM settings dark

Selecting a platform to interact with the LLM. By default, only OpenAI is available, but for JetBrains employees there is an option to interact via Graize. More details in the TestSpark for JetBrains employees section.

LLM platform LLM platform dark

Users have to set their own token for LLM, the plugin does not provide a default option.

LLM token LLM token dark

Once the correct token is entered, it will be possible to select an LLM model for test generation.

LLM model LLM model dark

In addition to the token, users are recommended to configure settings for the LLM process.

LLM parameters LLM parameters dark

To expedite the test generation process, users can disable the display of the LLM Setup Page.

LLM setup page LLM setup page dark

Additionally, they can also disable the display of the LLM Samples Page.

LLM test samples page ![LLM test samples page dark

Users can customize the list of default requests to the LLM in test cases.

LLM default requests LLM default requests dark

The plugin uses JUnit to generate tests. It is possible to select the JUnit version and prioritize the versions used by the current project.

LLM JUnit version LLM JUnit version dark

Users have the opportunity to adjust the prompt that is sent to the LLM platform.

To create a request to the LLM, it is necessary to provide a prompt which contains information about the details of the generation. The most necessary data are located in the mandatory section, without them the prompt is not valid.
Users can modify, create new templates, delete and use different variants in practice.

LLM prompt LLM prompt dark

โ— Pro tip: don't forget to hit the "save" button at the bottom. โ—

Telemetry (opt-in)

One of the biggest future plans of our client is to leverage the data that is gathered by TestSparkโ€™s telemetry. This will help them with future research, including the development of an interactive way of using EvoSuite. The general idea behind this feature is to learn from the stored user corrections in order to improve test generation.
To opt into telemetry, go to Settings > Tools > TestSpark and tick the Enable telemetry checkbox. If you want, change the directory where telemetry is stored.

Telemetry Telemetry dark

TestSpark for JetBrains employees

JetBrains employees have the ability to send queries to OpenAI models through the Grazie platform.

Using Grazie platform

Pass Space username and token as properties

  1. To include test generation using Grazie in the build process, you need to pass Space username and token as properties:
    gradle buildPlugin -Dspace.username=<USERNAME> -Dspace.pass=<TOKEN>.

  2. To include test generation using Grazie in the runIdeForUiTests process, you need to pass Space username and token as properties:
    gradle runIdeForUiTests -Dspace.username=<USERNAME> -Dspace.pass=<TOKEN>.

  3. <TOKEN> is generated by Space, which has access to Automatically generating unit tests maven packages.

Using gradle.properties

Store Space username and token in ~/.gradle/gradle.properties

...
spaceUsername=<USERNAME>
spacePassword=<TOKEN>
...

LLM Settings with Grazie

LLM Settings with Grazie platform option:

LLM grazie settings LLM grazie settings dark

Contribution

The plugin is Open-Source and publicly hosted on github. Anyone can look into the code and suggest changes. You can find the plugin page here.
In addition, learn more about the structure of the plugin here.

Licence


Plugin based on the IntelliJ Platform Plugin Template.

testspark's People

Contributors

actions-user avatar apanichella avatar arksap2002 avatar bolkhod avatar jzelenjak avatar kirilvasilev16 avatar lyuben-todorov avatar martinmladenov avatar mitchellolsthoorn avatar nikolaisviridov avatar pderakhshanfar avatar sergeydatskiv avatar vladislav0art avatar vovak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

testspark's Issues

Incorrect state of the default prompt

Describe the bug
Here are some information about other methods and classes used by the class under test. Only use them for creating objects, not your own ideas. is doubled in the prompt.

To Reproduce
Steps to reproduce the behavior:

  1. Generate tests for method, which contains another structure usage.
  2. Print the prompt
  3. See error

Expected behavior
Complete absence of message or single

Integrate new test generation tools

Description

TestSpark is an extendable tool, and any test generator that has CLI can be integrated into the TestSpark UI. Please read the this document to learn more about contributing to this project. TestSpark can help researchers to provide a user-friendly environment for applying their new test generators.

java.lang.Throwable: Slow operations are prohibited on EDT. See SlowOperations.assertSlowOperationsAreAllowed javadoc.

Describe the bug

java.lang.Throwable: Slow operations are prohibited on EDT. See SlowOperations.assertSlowOperationsAreAllowed javadoc.
	at com.intellij.openapi.diagnostic.Logger.error(Logger.java:376)
	at com.intellij.util.SlowOperations.assertSlowOperationsAreAllowed(SlowOperations.java:106)
	at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexDataImpl.ensureIsUpToDate(WorkspaceFileIndexDataImpl.kt:142)
	at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexDataImpl.getFileInfo(WorkspaceFileIndexDataImpl.kt:87)
	at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexImpl.getFileInfo(WorkspaceFileIndexImpl.kt:245)
	at com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexImpl.findFileSetWithCustomData(WorkspaceFileIndexImpl.kt:228)
	at com.intellij.openapi.roots.impl.ProjectFileIndexImpl.getModuleForFile(ProjectFileIndexImpl.java:100)
	at com.intellij.openapi.roots.impl.ProjectFileIndexImpl.getModuleForFile(ProjectFileIndexImpl.java:93)
	at org.jetbrains.research.testspark.tools.Pipeline.<init>(Pipeline.kt:43)
	at org.jetbrains.research.testspark.tools.llm.Llm.createLLMPipeline(Llm.kt:135)
	at org.jetbrains.research.testspark.tools.llm.Llm.generateTestsForClass(Llm.kt:79)
	at org.jetbrains.research.testspark.tools.Manager$Companion.generateTestsForClassByLlm(Manager.kt:53)
	at org.jetbrains.research.testspark.actions.TestSparkAction$TestSparkActionWindow.startLLMGeneration(TestSparkAction.kt:343)
	at org.jetbrains.research.testspark.actions.TestSparkAction$TestSparkActionWindow.addListeners$lambda$9(TestSparkAction.kt:315)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1972)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2313)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:279)
	at java.desktop/java.awt.Component.processMouseEvent(Component.java:6657)
	at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3385)
	at java.desktop/java.awt.Component.processEvent(Component.java:6422)
	at java.desktop/java.awt.Container.processEvent(Container.java:2266)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5027)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4855)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4969)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4583)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4524)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2310)
	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2809)
...

To Reproduce
Steps to reproduce the behavior:

  1. Run the generation

`NullPointerException` occurs for test generation of a line using EvoSuite

Describe the bug

I tried to generated tests for the following class:

public class Calc {
    public int sum(int a, int b) {
        return a + b; // line 3
    }

    public int multiply(int a, int b) {
        return a * b;
    }
}

I launched generation for the line 3 using EvoSuite with DYNOMOSA and it resulted in the following Exception:

java.lang.NullPointerException
	at org.jetbrains.research.testspark.services.TestsExecutionResultService.getError(TestsExecutionResultService.kt:75)
	at org.jetbrains.research.testspark.display.TestCasePanelFactory.getError(TestCasePanelFactory.kt:547)
	at org.jetbrains.research.testspark.display.TopButtonsPanelFactory.updateTopLabels(TopButtonsPanelFactory.kt:62)
	at org.jetbrains.research.testspark.services.TestCaseDisplayService.displayTestCases(TestCaseDisplayService.kt:147)
	at org.jetbrains.research.testspark.services.ReportLockingService.receiveReport(ReportLockingService.kt:32)
	at org.jetbrains.research.testspark.tools.Display.run$lambda$0(Manager.kt:135)
	// the following entries are internals of intellij openapi:
	at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:208)
	at com.intellij.openapi.application.TransactionGuardImpl.access$100(TransactionGuardImpl.java:21)
	at com.intellij.openapi.application.TransactionGuardImpl$1.run(TransactionGuardImpl.java:190)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:861)
	at com.intellij.openapi.application.impl.ApplicationImpl$4.run(ApplicationImpl.java:478)
	at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:79)
	at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:121)
	at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:41)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:789)
	at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:740)
	at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:734)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:759)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.kt:685)
	at com.intellij.ide.IdeEventQueue._dispatchEvent$lambda$10(IdeEventQueue.kt:589)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWithoutImplicitRead(ApplicationImpl.java:1485)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.kt:589)
	at com.intellij.ide.IdeEventQueue.access$_dispatchEvent(IdeEventQueue.kt:67)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:369)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:368)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:787)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:368)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:363)
	at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$1(IdeEventQueue.kt:992)
	at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:105)
	at com.intellij.ide.IdeEventQueueKt.performActivity(IdeEventQueue.kt:992)
	at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$7(IdeEventQueue.kt:363)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:861)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:405)

To Reproduce

Steps to reproduce the behavior:

  1. Copy the class to be tested above.
  2. Right click on the line 3 and select TestSpark.
  3. Select EvoSuite and the 3rd line for testing.
  4. Select DYNOMOSA (the problem might persist for other algorithms) and start generation.

Caution: not every execution results in this exception. I managed to reproduce it 3/6 times.

Expected behavior

Tests for a line should be generated with no errors.

Screenshots
1
2

3-1
3-2

Additional context

It might be specific for Windows 10, I did not test it on Unix-based systems.

Imports of the final test suite are incomplete

Describe the bug
Among N iterations of the feedback cycle TestSpark collects all of the test cases that were compilable on every iteration but the resulting test suite will contain only the imports that were provided by the LLM on the last iteration:

To Reproduce
Steps to reproduce the behavior (it is easier to reproduce on the headless mode):

  1. Select a complex project under test.
  2. Start LLM test generation and retry until the LLM generates 2 test suites on different iterations with different sets of imports.
  3. The final test suite may contain the test cases from the both generation test suites on the step 2. by some imports may be missing.

Expected behavior
We need to collect a union of the imports in the final test suite. It is okay to have redundant imports but it is not okay to have duplicated or missing imports.

Additional context

See the following LLM responses during the feedback cycle. There 2 test suites DBAppTest generated, both with some compilable test cases but the resulting test suite has missing imports (see after below):

``java
package test;

import app.DBApp;
import exceptions.DBAppException;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import java.util.Hashtable;

public class DBAppTest {
    
    @Test
    public void getMyTablesTest() {
        DBApp dbApp = new DBApp();
        Assert.assertNotNull(dbApp.getMyTables());
    }

    @Test
    public void initTest() {
        DBApp dbApp = new DBApp();
        dbApp.init();
        // If function runs successfully we can assert the the size of tables is not zero
        Assert.assertNotEquals(0, dbApp.getMyTables().size());
    }

    @Test(expected = DBAppException.class)
    public void createTableTest() throws DBAppException, IOException {
        DBApp dbApp = new DBApp();
        Hashtable<String, String> htblColNameType = new Hashtable<>();
        htblColNameType.put("id", "java.lang.Integer");
        htblColNameType.put("name", "java.lang.String");
        
        Hashtable<String, String> htblColNameMin = new Hashtable<>();
        htblColNameMin.put("name", "AAAAA");
        
        Hashtable<String, String> htblColNameMax = new Hashtable<>();
        htblColNameMax.put("name", "zzzzz");
        
        dbApp.createTable("staff", "id", htblColNameType, htblColNameMin, htblColNameMax); 
    }

    @Test(expected = DBAppException.class)
    public void insertIntoTableInvalidNameTest() throws DBAppException {
        DBApp dbApp = new DBApp();
        Hashtable<String, Object> htblColNameValue = new Hashtable<>();
        htblColNameValue.put("id", 1);
        htblColNameValue.put("name", "John");
        
        dbApp.insertIntoTable("student", htblColNameValue);
    }


    @Test(expected = DBAppException.class)
    public void insertIntoTableCorrectNameTest() throws DBAppException {
        DBApp dbApp = new DBApp();
        Hashtable<String, Object> htblColNameValue = new Hashtable<>();
        htblColNameValue.put("id", 1);
        htblColNameValue.put("name", "John");
        
        dbApp.insertIntoTable("staff", htblColNameValue);
    }

    @Test(expected = DBAppException.class)
    public void updateTableInvalidNameTest() throws DBAppException {
        DBApp dbApp = new DBApp();
        Hashtable<String, Object> htblColNameValue = new Hashtable<>();
        htblColNameValue.put("name", "Mike");
        
        dbApp.updateTable("student", "1", htblColNameValue);
    }
    
    @Test(expected = DBAppException.class)
    public void deleteFromTableInvalidNameTest() throws DBAppException {
        DBApp dbApp = new DBApp();
        Hashtable<String, Object> htblColNameValue = new Hashtable<>();
        htblColNameValue.put("name", "Mike");
        
        dbApp.deleteFromTable("student", htblColNameValue); 
    }

    @Test(expected = DBAppException.class)
    public void selectFromTableInvalidNameTest() throws DBAppException {
        DBApp dbApp = new DBApp();
        String[] strarrOperators = {"<"};
        dbApp.selectFromTable(new SQLTerm[]{}, strarrOperators); 
    }

    @Test(expected = DBAppException.class)
    public void selectFromTableCorrectNameTest() throws DBAppException {
        DBApp dbApp = new DBApp();
        String[] strarrOperators = {"<"};
        SQLTerm[] arrSQLTerms = new SQLTerm[1];
        arrSQLTerms[0] = new SQLTerm();
        arrSQLTerms[0].strTableName = "staff";
        arrSQLTerms[0].strColumnName = "id";
        arrSQLTerms[0].strOperator = "<";
        arrSQLTerms[0].objValue = "500";
        
        dbApp.selectFromTable(arrSQLTerms, strarrOperators);
    }
}
``
================================================================================
I'm sorry for the confusion. If the SQLTerm class is not visible or accessible, we need to adapt the testing approach. Unfortunately, without having the respective SQLTerm class (we only have its named reference in the DBApp class), it's not possible to construct its objects to use in selectFromTable tests. It seems like SQLTerm is a part of the project but not part of app package. 

The creation and usage of the SQLTerm instances in test cases for the 'selectFromTable' method could be adjusted according to real structure, fields and accessibility of the SQLTerm class which is not present within the details provided for the scenario. 

However, I can show you how you can detect that SQLTerm class is imported correctly. I'll use placeholders for that. These placeholders should be replaced by real SQLTerm invocations:

``java
import placeholderPackage.SQLTerm; // Correct import statement for SQLTerm

@Test(expected = DBAppException.class)
public void selectFromTableInvalidNameTest() throws DBAppException {
    DBApp dbApp = new DBApp();
    String[] strarrOperators = {"<"};
    SQLTerm term = buildSQLTerm(); // Helper method that creates SQLTerm instance
    dbApp.selectFromTable(new SQLTerm[]{term}, strarrOperators); 
}

protected SQLTerm buildSQLTerm() {
    SQLTerm term = new SQLTerm();
    // Add all necessary attribute assignments to correctly construct SQLTerm instance. 
    // This depends on SQLTerm class definition which isn't provided in the prompt.
    return term;
}
``
In above code, you need to replace 'placeholderPackage' with a real package where SQLTerm exists and you need to implement 'buildSQLTerm' method according to 'SQLTerm' construction requirements.

For the accurate tests, I would need more information about the `SQLTerm` class, how it's structured and how it's used in normal operation of the database application you're testing. This includes information about its constructors and methods, as well as the expected results of those methods in normal use. This kind of information is essential to write accurate and effective tests.
=================================================================================
My apologies for the misunderstanding. Below is the fixed version:

``java
import placeholderPackage.SQLTerm; // Correct import statement for SQLTerm
import java.lang.DBAppException;

@Test(expected = DBAppException.class)
public void selectFromTableInvalidNameTest() throws DBAppException {
    DBApp dbApp = new DBApp();
    String[] strarrOperators = {"<"};
    SQLTerm term = buildSQLTerm(); // Helper method that creates SQLTerm instance
    dbApp.selectFromTable(new SQLTerm[]{term}, strarrOperators); 
}

protected SQLTerm buildSQLTerm() {
    SQLTerm term = new SQLTerm();
    // Add all necessary attribute assignments to correctly construct SQLTerm instance. 
    // This depends on SQLTerm class definition which isn't provided in the prompt.
    return term;
}
``
In the import statements at the top of the script, replace `placeholderPackage` with the actual package where your `SQLTerm` class is located.

In the `buildSQLTerm` function, you should replace the comments section with code to populate your `SQLTerm` instance using the appropriate attributes and methods from that class. Unfortunately, as I don't have the specific details of the `SQLTerm` class, I am unable to provide specifics for this part.
===================================================================================
My sincere apologies for the errors in the previous example, and thank you for your patience. Please see the corrected version below.

``java
import app.DBApp;
import exceptions.DBAppException;
import org.junit.Test;
import java.util.Hashtable;
//make sure to import SQLTerm, since the correct import statement is not given, placeholder is used
import placeholderPackage.SQLTerm;

public class DBAppTest {
    
    // other test methods ....
    
    @Test(expected = DBAppException.class)
    public void selectFromTableInvalidNameTest() throws DBAppException {
        DBApp dbApp = new DBApp();
        String[] strarrOperators = {"<"};
        SQLTerm term = buildSQLTerm();
        dbApp.selectFromTable(new SQLTerm[]{term}, strarrOperators); 
    }

    private SQLTerm buildSQLTerm() {
        // Assuming example creation of SQLTerm
        SQLTerm term = new SQLTerm(); // Replace this line with the correct initialization of SQLTerm.
        // term.setStrTableName("staff");  // example setters
        // term.setStrColumnName ("id");  // based on SQLTerm class
        // term.setStrOperator ("<");
        // term.setObjValue ("500");   
        return term;
    }
}
``

In the code above, the `"placeholderPackage"` import is a placeholder for the actual import statement for SQLTerm class.

The `buildSQLTerm()` method is a helper method that returns an instance of SQLTerm. The implementation of this method would depend on the constructor(s) or setter methods available in the SQLTerm class, which is not provided in the class under test or the prompt. Replace it with your actual SQLTerm construction logic.
=========================================================================================

The final collected test with the missing imports:

package app;

import app.DBApp;
import exceptions.DBAppException;
import org.junit.Test;

import java.util.Hashtable;

import placeholderPackage.SQLTerm;

public class GeneratedTest {


    // other test methods ....

    @Test
    public void getMyTablesTest() {
        DBApp dbApp = new DBApp();
        Assert.assertNotNull(dbApp.getMyTables());
    }

    @Test
    public void initTest() {
        DBApp dbApp = new DBApp();
        dbApp.init();
        // If function runs successfully we can assert the the size of tables is not zero
        Assert.assertNotEquals(0, dbApp.getMyTables().size());
    }

    @Test
    public void createTableTest() throws DBAppException, IOException {
        DBApp dbApp = new DBApp();
        Hashtable<String, String> htblColNameType = new Hashtable<>();
        htblColNameType.put("id", "java.lang.Integer");
        htblColNameType.put("name", "java.lang.String");

        Hashtable<String, String> htblColNameMin = new Hashtable<>();
        htblColNameMin.put("name", "AAAAA");

        Hashtable<String, String> htblColNameMax = new Hashtable<>();
        htblColNameMax.put("name", "zzzzz");

        dbApp.createTable("staff", "id", htblColNameType, htblColNameMin, htblColNameMax);
    }

    @Test
    public void insertIntoTableInvalidNameTest() throws DBAppException {
        DBApp dbApp = new DBApp();
        Hashtable<String, Object> htblColNameValue = new Hashtable<>();
        htblColNameValue.put("id", 1);
        htblColNameValue.put("name", "John");

        dbApp.insertIntoTable("student", htblColNameValue);
    }

    @Test
    public void insertIntoTableCorrectNameTest() throws DBAppException {
        DBApp dbApp = new DBApp();
        Hashtable<String, Object> htblColNameValue = new Hashtable<>();
        htblColNameValue.put("id", 1);
        htblColNameValue.put("name", "John");

        dbApp.insertIntoTable("staff", htblColNameValue);
    }

    @Test
    public void updateTableInvalidNameTest() throws DBAppException {
        DBApp dbApp = new DBApp();
        Hashtable<String, Object> htblColNameValue = new Hashtable<>();
        htblColNameValue.put("name", "Mike");

        dbApp.updateTable("student", "1", htblColNameValue);
    }

    @Test
    public void deleteFromTableInvalidNameTest() throws DBAppException {
        DBApp dbApp = new DBApp();
        Hashtable<String, Object> htblColNameValue = new Hashtable<>();
        htblColNameValue.put("name", "Mike");

        dbApp.deleteFromTable("student", htblColNameValue);
    }

}

The compilation error of the test suite is the following, although the compilation of each individual test cases was successful:

'/home/ubuntu/projects/tga-pipeline/artifacts/generation-2/augmented-prompt-full/TestSpark/0/database-engine-8314bfdec0/app/GeneratedTest.java:9: error: package placeholderPackage does not existimport placeholderPackage.SQLTerm;                         ^/home/ubuntu/projects/tga-pipeline/artifacts/generation-2/augmented-prompt-full/TestSpark/0/database-engine-8314bfdec0/app/GeneratedTest.java:31: error: cannot find symbol    public void createTableTest() throws DBAppException, IOException {                                                         ^  symbol:   class IOException  location: class GeneratedTest/home/ubuntu/projects/tga-pipeline/artifacts/generation-2/augmented-prompt-full/TestSpark/0/database-engine-8314bfdec0/app/GeneratedTest.java:19: error: cannot find symbol        Assert.assertNotNull(dbApp.getMyTables());        ^  symbol:   variable Assert  location: class GeneratedTest/home/ubuntu/projects/tga-pipeline/artifacts/generation-2/augmented-prompt-full/TestSpark/0/database-engine-8314bfdec0/app/GeneratedTest.java:27: error: cannot find symbol        Assert.assertNotEquals(0, dbApp.getMyTables().size());        ^  symbol:   variable Assert  location: class GeneratedTest4 errors'
Compiled class not found at '/home/ubuntu/projects/tga-pipeline/artifacts/generation-2/augmented-prompt-full/TestSpark/0/database-engine-8314bfdec0/app/GeneratedTest.class'

Implement new objectives for EvoSuite that can be useful in IDE

Description

Currently, we have adapted DynaMOSA (the default algorithm in EvoSuite) to support single-line test generation. We are looking at scenarios that enable users to generate tests using EvoSuite for more specific testing objectives.
For example, given the fact that EvoSuite is a white-box test generator, the user should be able to generate a test that covers a specific line while a specific condition is fulfilled. IntelliJ has such a similar feature in debug mode where the users can set up a condition in a breakpoint so that the execution stops in the breakpoint only when the provided conditions are fulfilled:
image

We can also provide such functionality for test generation. Such a scenario can also improve EvoSuite's fault detection capability. For instance, the user adds a condition (e.g., objec1 == null) that leads to an exception in the target line and ask for test generation for this objective. This feature can help developers in debugging the code and replicating the reported issues.

EvoSuite error: EvoSuiteprocesserro๏ผš Exception creating connection to ${LOCAL_IP_ADDRESS}

Describe the bug
As computer security restricted , it will block all inbound request with almost ports by default. Which means, the computer can't visit the URI even by itself besides localhost.

To Reproduce
Steps to reproduce the behavior:

  1. Go to 'TestSpark'
  2. Click on 'EvoSuite generator', whatever class or method code type.
  3. Click next, see error

Expected behavior
Test spark can provide the configuration to change the evosuite service with localhost, not the IP. otherwise, provide a way to customized the port for evosuite service.

Additional context
As the exception is including specific local IP in message, so I guess that's limited by our computer inbound restriction. localhost should be fine if testspark provided such way to connect.

`IllegalArgumentException` on the generation using LLM test generation with JetBrains AI Assistant

Describe the bug
Once I opened TestSpark modal window, selected LLM as a generator, then selected AI Assistant JetBrains without modifications of chat model (i.e. leaving GPT-4), I received an error (see trace below), however it was not expected.

To Reproduce
Steps to reproduce the behavior:

  1. Select LLM as a test generator in the modal window.
  2. Select AI Assistant JetBrains.
  3. Start test generation.
  4. See error.

Expected behavior
Successful test generation. Seams like the default chat model is set to an empty string, although the GPT-4 is rendered on UI.

Stack trace

java.lang.IllegalArgumentException:  is not available option for profile. Available options are: [GPT-4, GPT-4-32k, GPT-4-Turbo, ChatGPT, ChatGPT-16k]
	at org.jetbrains.research.testSpark.grazie.TestGeneration.generate(TestGeneration.kt:31)
	at org.jetbrains.research.grazie.Request$request$1.invokeSuspend(Request.kt:20)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:280)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
	at org.jetbrains.research.grazie.Request.request(Request.kt:19)
	at org.jetbrains.research.testspark.tools.llm.generation.grazie.GrazieRequestManager.send(GrazieRequestManager.kt:31)
	at org.jetbrains.research.testspark.tools.llm.generation.RequestManager.request(RequestManager.kt:43)
	at org.jetbrains.research.testspark.tools.llm.generation.RequestManager.request$default(RequestManager.kt:30)
	at org.jetbrains.research.testspark.services.LLMChatService.testGenerationRequest(LLMChatService.kt:47)
	at org.jetbrains.research.testspark.tools.llm.generation.LLMProcessManager.runTestGenerator(LLMProcessManager.kt:112)
	at org.jetbrains.research.testspark.tools.Pipeline$runTestGeneration$1.run(Pipeline.kt:66)
	at com.intellij.openapi.progress.impl.CoreProgressManager.startTask(CoreProgressManager.java:428)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.startTask(ProgressManagerImpl.java:115)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcessWithProgressAsynchronously$6(CoreProgressManager.java:478)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$4(ProgressRunner.java:251)
	at com.intellij.openapi.progress.ProgressManager.lambda$runProcess$0(ProgressManager.java:71)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:186)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$13(CoreProgressManager.java:604)
	at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:679)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:635)
	at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:603)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:61)
	at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:173)
	at com.intellij.openapi.progress.ProgressManager.runProcess(ProgressManager.java:71)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$5(ProgressRunner.java:251)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$launchTask$18(ProgressRunner.java:465)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:702)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:699)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(Executors.java:699)
	at java.base/java.lang.Thread.run(Thread.java:833)
Screenshot 2024-02-16 at 15 49 45

Fix error message window size

Describe the bug
No message in the error window

To Reproduce
Steps to reproduce the behavior:

  1. Generate tests, sometimes, you'll see an error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
In the file
Screenshot 2023-12-01 at 4 04 56 PM

Unsual response from LLM that results in test suite parsing failure

Describe the bug
I have attached an archive that contains a class Calc1 in Calc1.java, I tried to generated a test suite via LLM for this class with the default parameters, but it resulted in a warning of inability to parse a test suite, although the test suite was present in the response.

To Reproduce
Steps to reproduce the behavior:

  1. Add all the files from the attached archive in an Intellij Project.
  2. Open Calc1.java class.
  3. Generate a test suite for the entire class with all the parameters defaulted (+ no test sample).
  4. From time to time the warning will occur.

Expected behavior
The test suite must be parsed with no errors. I suspect that the error occurs because the LLM's response contains several "```" blocks. The 1st one is being parsed but it does not contain the test suite.

Occurred warning
"Large Language Model could not generate any tests for this class. Asking the AI assistance to fix its mistake.LLM response: The class Parent extends GrandParent. I will consider that those classes do not have methods to be tested as most of their methods are probably private, protected or package-private since none of the classes, Parent or GrandParent, are declared with a public access modifier. The provided Calc1 class implements two interfaces, Calculator and Printable. Here is my assumptions about those interfaces: Calculator: public interface Calculator { int multiply(int a, int b); int plus(int a, int b); } Printable: public interface Printable { void print(); } Since interfaces methods are by definition public, all methods will be tested by our unit tests. The source code for unit tests: java import org.junit.Test; import static org.junit.Assert.assertEquals; public class Calc1Test { @Test public void multiplyTwoPositiveNumbersTest() { Calc1 calc1 = new Calc1(); int result = calc1.multiply(2, 3); assertEquals("Multiplication result should be 6", 6, result); } @Test public void multiplyPositiveAndZeroNumbersTest() { Calc1 calc1 = new Calc1(); int result = calc1.multiply(2, 0); assertEquals("Multiplication result should be 0", 0, result); } @Test public void plusTwoPositiveNumbersTest() { Calc1 calc1 = new Calc1(); int result = calc1.plus(2, 3); assertEquals("Sum result should be 5", 5, result); } @Test public void plusPositiveAndZeroNumbersTest() { Calc1 calc1 = new Calc1(); int result = calc1.plus(2, 0); assertEquals("Sum result should be 2", 2, result); } @Test public void parentPrintTest() { Calc1 calc1 = new Calc1(); calc1.parentPrint(); // The test for this method cannot assert anything since the method does not return anything // The output can be verified manually, or it needs extra library to capture the console output } @Test public void printTest() { Calc1 calc1 = new Calc1(); calc1.print(); // The test for this method cannot assert anything since the method does not return anything // The output can be verified manually, or it needs extra library to capture the console output } } As written in the comments, while the tests for parentPrint and print definitely will execute those lines of code, there isn't a way to assert anything within the test since the methods do not return anything. To actually test those methods you would need a library capable of capturing console output like System Rules or extra mocking when using Mockito to mock the System.out print stream and then verify the interaction. But it goes beyond the scope of this request."

Additional context
Here is the archive with the project:
Archive.zip

Imports of a compilable test case may be incorrect

Describe the bug
[Experiments were conducted on the headless-mode branch]

The set of imports in a .java-file of a test case does not match the set of imports in the compiled .class-file which may lead to the fact that a compiled .class-file of a corresponding .java-file exists, yet the .java-file is not compilable because the set of imports differ (likely, the .java-file contains the imports copied from the final version of a test suite, i.e. it does not preserve its own import set).

To Reproduce
Steps to reproduce the behavior:

  1. Likely, the reproduction is possible if all N iterations of a feedback cycle were used and yet some test cases end up non compilable.

Expected behavior
Each compilable test case must contain the set of imports that yielded this test case compilable, i.e. the set of imports in .class-file must match the set of imports in the output .java-file.

Screenshots
Here is a Java class with a set of imports A:
Screenshot 2024-04-24 at 13 47 18

Here is the corresponding compiled .class-file with a set of imports B:
Screenshot 2024-04-24 at 13 47 27

The sets of imports are not equal: A != B.

Additional context
See an archive attached (the screenshots are collected on a test case from this archive). It contains a project on which such an execution occurred. The folder generated-artifacts contains the TestSpark output during test generation, LLM response, and sent prompts.

epubcheck-49aacb238c.zip

"Live Learning Model" instead of "Large Language Model" in comments

Describe the bug
There several files where there is an incorrect comment "Live Learning Model" instead of "Large Language Model":

  1. CONTRIBUTING.md
  2. OpenAIRequestManager

The same thing for one of SettingsArguments.kt file with a excerpt "Longest Lasting Message".

Expected behavior
Correct comment with "Large Language Model" excerpt.

Faulty behavior of "Modify with LLM" functionality when token is absent

Describe the bug
Once I successfully generate tests with LLM (in my case it was Gradzie), I delete the LLM token from the settings menu and try to send any request to the LLM for a modification of any test case. As the result I end up having 2 notification messages: a warning about the empty LLM response and an error about absence of the LLM token, although only the error must have been shown. Apart from that, the next subsequent request to the LLM through the same test case will result in infinite awaiting for the LLM response (which will never come) and will block any actions for the considered test case (i.e. any other action buttons of the test case will not work).

Screenshot 2024-03-19 at 21 54 00

To Reproduce
Steps to reproduce the behavior:

  1. Add a valid LLM token.
  2. Generate tests for any class/method/line.
  3. Remove the token in the settings menu.
  4. Select any test case and insert any request into the input field.
  5. Send the request via "send" button of the test case (you will see 2 notifications, the warning and the error).
  6. Send any other request through the "send" button of the same test case (you will see an infinite spin load, no action buttons respond anymore).

Expected behavior
The send request should say that token is not present/invalid. No blocking of the action buttons should appear.

Screenshots
Screenshot 2024-03-19 at 21 48 36

Additional context
I tested it on the development branch.

The prompt reduction not working due to the LLM chat history (context) not being purged of the previous initial prompt

Describe the bug
The prompt reduction does not work because of the LLM chat history (aka chat context) not being purged of the previous prompt, if that previous prompt was the initial prompt containing the class under test definition. I other words, if the very first prompt causes "prompt too long" error and then it is reduced by TestSpark to the sufficient length it still trigger the "prompt too long" error since it will be sent together with the initial non-reduced prompt (see the Additional context section below).

To Reproduce
Steps to reproduce the behavior:

  1. Select any project that causes the token overflow by its initial prompt, yet the reduced version of this prompt is sufficient.
  2. Execute LLM-based unit test generation for this project.
  3. Observe the "Prompt too long" error even for the reduced prompt.

Expected behavior
If the very first initial prompt causes the "prompt too long" error it should be removed from the chat history, then once the reduced version of this prompt is ready, it should be the only prompt in the chat history.

Important: only the initial prompt must be deleted from the chat history if it causes the token overflow. If the overflow occurs for any other subsequent prompt it means the the cumulative length of the whole context caused the overflow; this situation should be addressed differently (many strategies possible).

Screenshots

  1. Here in the RequestManager we only notify the caller about the "prompt too long" error, yet we need to check both: 1) the just sent prompt is the initial one, and 2) this prompt caused token overflow => in this case we remove it from the chat history by chatHistory.removeLast():
Screenshot 2024-04-30 at 12 12 58
  1. [Please, ignore the ProjectUnderTestFileCreator] Here it becomes clear the the implementation always assumes that the prompt causing the token overflow is always the initial prompt which is not always true, as it is possible that the accumulated lengths of the messages in the chat history may yield "prompt too long" error (i.e. the sequence of all messages present in the history). TestSpark does not distinguish these two cases but they are qualitatively different and should be tackled separately.
    screenshot_2024-04-30312

Additional context
Here is the additional examples from the conversation we have with @pderakhshanfar about this issue:

I) Here is an example:
Imagine the token limit is 10 tokens. Let the 1st prompt containing the CUT impl and the semantic information require 8 tokens, and we sent this initial prompt (let's call it A) to an LLM. Assume that there is a compilation error and we send the 2nd prompt (called B) with the compilation error, this prompt requires 3 tokens => we end up having the "prompt too long error" because we send the entire context (1st and 2nd prompts) of total token length 11. TestSpark spots the "prompt too long" error and tried to reduce the prompt size of the initial prompt A (see 1st image), let's call the reduced prompt A' of the token length 5. Thereafter, TestSpark sends this A' prompt to the LLM (with the entire context containing A and B), i.e. the token length of the sent context is 8+3+5=16 > 10 => the "prompt too long" occurs again => assume TestSpark cannot reduce the prompt size anymore => abort execution => only the compilable test cases produced by the LLM after receiving prompt A may be collected.
So, the sequence of prompts in the context is as follows:
A -> [LLM response to A] -> B -> A' (<- such a consequent sequence of reduced prompts A', A'', A''' will be equal to the number of available prompt reduction steps).

The example is given to show that the current implementation of prompt reduction always assumes that the very first prompt alone caused the "prompt too long" error, although it is actually the entire context which was the reason of the token overflow. On my opinion, it is a logical bug.

On the 2nd image you may see that the messageToPrompt is being set to the initial prompt with the CUT definition and reduced additional semantic info.

II) There is another example:
Assume token limit is 10.
Let's call the LLM context to be C.
Initial prompt A has the token length of 11 => it causes the "prompt too long" error (context is populated with the initial prompt before the sent request: C = { A }).
TestSpark reduces the prompt to A' of token length 7 and sends it again => C = { A, A' } , i.e. the context token length is 11+7=18>10 => the "prompt too long" error again, although the prompt A' alone is suitable to be sent as an initial prompt if A were to be discarded. This is because we never cleaned up the context and essentially sent both prompts together.
The above scenario is possible because once the "prompt too long" error occurs, the RequestManager only notifies about the error but does not clean the context chatHistory (see the 1st image). This one is definitely a bug.

Integration with HuggingFace platform

Description

We would like to add the integration between TestSpark and the HuggingFace platform to allow the use of more (smaller) models for test generation. Using models should be possible both using Inference APIs and also using models locally.

Challenges

Many models in this platform are not as powerful as the GPT models, and hence, we also need some prior evaluation based on the existing models to find the most suitable way of using these models in TestSpark. Can we integrate as part of our LLM-based test generation approach? Or they can be used, for instance, to improve the tests generated by our local test generators.

Number of passed tests is not updated properly on tests deletion

Describe the bug

After test generation and execution (i.e. after click on the "Run all" button) the number of passed tests is N/N. If I delete any of the test instances the total number of tests will be updated, but the number of passed tests will not, i.e. it will display as N/N-1 near the "Passed" label.

To Reproduce
Steps to reproduce the behavior:

  1. Generate N tests
  2. Click "Run all" button (assuming it result in N/N passed tests)
  3. Delete any test instance -> you get N/N-1 passed tests

Expected behavior
Number of passed tests should not exceed the number of total test cases.

Screenshots

Here I generated 8 tests and then deleted 2 of them:

1

Next I delete 2 more tests resulting in 4 remaining tests:

2

Additional context
Execution platform: Windows 10.

`NullPointerException` on "Run all" button click

Describe the bug
After test generation and a click of "Run all" button the following NullPointerException occurred:

java.lang.NullPointerException
	at org.jetbrains.research.testspark.display.TestCasePanelFactory.updateUI(TestCasePanelFactory.kt:335)
	at org.jetbrains.research.testspark.display.TestCasePanelFactory.runTest$lambda$13(TestCasePanelFactory.kt:474)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:789)
	at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:740)
	at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:734)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:759)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.kt:685)
	at com.intellij.ide.IdeEventQueue._dispatchEvent$lambda$10(IdeEventQueue.kt:589)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWithoutImplicitRead(ApplicationImpl.java:1485)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.kt:589)
	at com.intellij.ide.IdeEventQueue.access$_dispatchEvent(IdeEventQueue.kt:67)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:369)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:368)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:787)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:368)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:363)
	at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$1(IdeEventQueue.kt:992)
	at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:105)
	at com.intellij.ide.IdeEventQueueKt.performActivity(IdeEventQueue.kt:992)
	at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$7(IdeEventQueue.kt:363)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:861)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:405)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)

To Reproduce
The following steps do not insure reproduction of the above exception but these are the steps I took in order to raise the exception.
Steps to reproduce the behavior:

  1. Generate tests for a class.
  2. Click the "Run all" button inside TestSpark sidebar.
  3. Check whether the exception is raised.

Expected behavior
Tests should be run with no errors.

Screenshots
Once I encounter the same error again I will update the issue.

Additional context
The described above steps do not guarantee reproduction of the bug.

`NullPointerException` during attempt of LLM test generation on a custom project

Describe the bug
I merely try to execute an LLM unit test generation on the file org.csc.java.spring2023.multithreading.CustomThreadPool (see zip-archive with the project attached) and it results in the following error:

java.lang.NullPointerException: getText(...) must not be null
	at org.jetbrains.research.testspark.tools.llm.generation.PromptManager.getSignatureString(PromptManager.kt:170)
	at org.jetbrains.research.testspark.tools.llm.generation.PromptManager.createMethodRepresentation(PromptManager.kt:115)
	at org.jetbrains.research.testspark.tools.llm.generation.PromptManager.createClassRepresentation(PromptManager.kt:126)
	at org.jetbrains.research.testspark.tools.llm.generation.PromptManager.generatePrompt$lambda$4(PromptManager.kt:57)
	at com.intellij.openapi.application.impl.RwLockHolder.runReadAction(RwLockHolder.kt:271)
	at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:845)
	at org.jetbrains.research.testspark.tools.llm.generation.PromptManager.generatePrompt(PromptManager.kt:53)
	at org.jetbrains.research.testspark.tools.llm.generation.LLMProcessManager.runTestGenerator(LLMProcessManager.kt:90)
	at org.jetbrains.research.testspark.tools.Pipeline$runTestGeneration$1.run(Pipeline.kt:67)
	at com.intellij.openapi.progress.impl.CoreProgressManager.startTask(CoreProgressManager.java:477)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.startTask(ProgressManagerImpl.java:133)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcessWithProgressAsynchronously$6(CoreProgressManager.java:528)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$4(ProgressRunner.java:250)
	at com.intellij.openapi.progress.ProgressManager.lambda$runProcess$0(ProgressManager.java:100)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$1(CoreProgressManager.java:221)
	at com.intellij.platform.diagnostic.telemetry.helpers.TraceKt.use(trace.kt:46)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:220)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$13(CoreProgressManager.java:660)
	at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:735)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:691)
	at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:659)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:79)
	at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:202)
	at com.intellij.openapi.progress.ProgressManager.runProcess(ProgressManager.java:100)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$5(ProgressRunner.java:250)
	at com.intellij.openapi.progress.impl.ProgressRunner$ProgressRunnable.run(ProgressRunner.java:500)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:702)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:699)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(Executors.java:699)
	at java.base/java.lang.Thread.run(Thread.java:840)

csc-java-course-spring-2023-thread-pool-Vladislav0Art.zip

To Reproduce
Steps to reproduce the behavior:

  1. Open the project and select corretto-11 JDK (JDK might no be important).
  2. Navigate to the mentioned file (maybe it can be reproduced for any file)
  3. Execute the LLM test generation.
  4. See error

Expected behavior
Successful test generation.

Screenshots

Screenshot 2024-03-22 at 15 24 39

`org.jetbrains.research.testspark.services.JavaClassBuilderService` does not support `@ExtendWith` from JUnit5

Describe the bug
It is not a bug but lack of a functionality. The JavaClassBuilderService class has the following in its printUpperPart method:

if (runWith.isNotBlank()) {
     testText += "@RunWith($runWith)\n"
}

i.e. there is a hard coded RunWith annotation although it should vary depending on the JUnit version used. It can be implemented via RunWithAnnotationMeta provided in JUnitVersion class.

It may be implemented somehow as follows:

if (runWith.isNotBlank()) {
    val annotation = junitVersion.runWithAnnotationMeta.annotationName
    testText += "@${annotation}($runWith)\n"
}

Implement an adaptive test library detection

Description

Currently, TestSpark only supports JUnit4/5 and Mockito 5. However, these versions should be identified according to the dependencies of the project under test and settings.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.