Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kex Integration #294

Open
wants to merge 49 commits into
base: development
Choose a base branch
from

Conversation

edwin1729
Copy link

@edwin1729 edwin1729 commented Jul 12, 2024

Integrating Kex (Symbolic Execution) into TestSpark

Generates test cases using Kex and displays them in the TestSpark tool window

Summary of changes

The integration of kex follows the example of EvoSuite and LLM for teh most part, so I highlight just the kex specific parts.

  • A third party java parser is used for preprocessing of generated test files. For each generated test class, the fields @before @test annotated methods are rewritten into a single test method
  • TestGenerationData.otherInfo contains all the helper methods and a static initializer. This shows up in each test case in tool window for compilation and exactly once in the generated test file if "apply to test suite" is chosen
  • To make the test cases in the tool window readable even with the large amount of helper code
    Automatic folding (hiding behind ...) of all code other than test annotated methods in the tool window is implemented. This is using the PsiFile for each test case
  • There are additional fields added to the implementations of PsiMethodWrapper (and implementations) because kex requires specification of the method for which tests are generated in a specific format. Namely it involves FQNs and an example is given here: org.example.Matrix::product(org.example.Matrix,java.util.function.BinaryOperator,java.util.function.BinaryOperator):org.example.Matrix
    Note also that types have been erased. Kex expects JVM types which is easy to get from Java types but not from kotlin. For this reason kotlin is not yet supported by kex.
  • Kex is released as zip file, so it is downloaded and unpacked into the OS-specific cache directory (~/.cache on unix, LOCALAPPDATA in windows). Also note it doesn't currently support ARM linux (but does support ARM mac)
  • Kex uses .class files to generate tests, so the build directory for the correct module is obtained from IJ API

Needs debugging and testing
* load kex-runner jar from github (build.gradle.kts toplevel)
* setup code for kex properties
* KexErrorManager based on LLMErrorManager
* KexProcessManager based on EvoSuiteProcessManager
* Basic UI element (button for running kex)
* kex works only for the class codeType (todo funciton and line if possible)
* read resource files kex.policy and modules.info
use a provided kex path for now instead of downloading jar and adding dependency
use ProcessBuilder (jdk) instead of OSProcessHandler (IJ sdk)
use kex.py instead of building java command directly
generate Report objects by reading generated java classes
Deleted stuff:
running Kex through through OSProcessHandler (IJ sdk)
running Kex with kex.py
downloading kex from github in build.gradle.kts
@edwin1729 edwin1729 changed the title Edwin1729/improvement/kex integration Kex Integration Jul 12, 2024
@edwin1729 edwin1729 force-pushed the edwin1729/improvement/kex-integration branch from e623ee7 to 237e549 Compare July 24, 2024 07:49
@edwin1729 edwin1729 force-pushed the edwin1729/improvement/kex-integration branch from 935b0c9 to b766057 Compare July 24, 2024 12:01
@arksap2002 arksap2002 self-requested a review August 23, 2024 11:43
@arksap2002 arksap2002 added the Ready for review PR redy for review label Aug 23, 2024
Copy link
Collaborator

@arksap2002 arksap2002 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some error during the test generation, should I set up something in the settings?
The error stack:

java.io.FileNotFoundException: /Users/arkadii.sapozhnikov/.cache/JetBrains/TestSpark/kex/runtime-deps/modules.info (No such file or directory)
	at java.base/java.io.FileInputStream.open0(Native Method)
	at java.base/java.io.FileInputStream.open(FileInputStream.java:216)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
	at kotlin.io.FilesKt__FileReadWriteKt.forEachLine(FileReadWrite.kt:190)
	at kotlin.io.FilesKt__FileReadWriteKt.readLines(FileReadWrite.kt:219)
	at kotlin.io.FilesKt__FileReadWriteKt.readLines$default(FileReadWrite.kt:217)
	at org.jetbrains.research.testspark.tools.kex.KexSettingsArguments.setAddOpensArgs(KexSettingsArguments.kt:42)
	at org.jetbrains.research.testspark.tools.kex.KexSettingsArguments.buildCommand(KexSettingsArguments.kt:26)
	at org.jetbrains.research.testspark.tools.kex.generation.KexProcessManager.runTestGenerator(KexProcessManager.kt:126)
	at org.jetbrains.research.testspark.tools.Pipeline$runTestGeneration$1.run(Pipeline.kt:95)
	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)

@edwin1729
Copy link
Author

I have some error during the test generation, should I set up something in the settings? The error stack:

Not sure why this is happening. That file was supposed to be downloaded from the github release. Could you maybe try this alternative to using the .cache directory, while I try to fix the problem? The kex path can be specified as a setting from the IDE in settings->TestSpark->kex->kexPath. Please make an empty directory called kex (anywhere) and provide the absolute path. The kex executables, etc, will be downloaded here.

@arksap2002
Copy link
Collaborator

Thank you so much for fixing the previous error. I have 2 more comments:

  1. I have an error in the line: val editor = languageTextField.editor!!. I think, we have to check for null before applying !!
java.lang.NullPointerException
	at org.jetbrains.research.testspark.display.TestCasePanelFactory.foldHelperCode(TestCasePanelFactory.kt:378)
	at org.jetbrains.research.testspark.display.TestCasePanelFactory.access$foldHelperCode(TestCasePanelFactory.kt:76)
	at org.jetbrains.research.testspark.display.TestCasePanelFactory$getMiddlePanel$1.childAdded(TestCasePanelFactory.kt:259)
	at com.intellij.psi.impl.PsiManagerImpl.notifyPsiTreeChangeListener(PsiManagerImpl.java:398)
	at com.intellij.psi.impl.PsiManagerImpl.fireEvent(PsiManagerImpl.java:357)
	at com.intellij.psi.impl.PsiManagerImpl.childAdded(PsiManagerImpl.java:270)
	at com.intellij.pom.tree.events.impl.ChangeInfoImpl.childAdded(ChangeInfoImpl.java:100)
	at com.intellij.pom.tree.events.impl.ChangeInfoImpl.fireEvent(ChangeInfoImpl.java:81)
	at com.intellij.pom.tree.events.impl.TreeChangeImpl.fireEvents(TreeChangeImpl.java:143)
	at com.intellij.pom.tree.events.impl.TreeChangeEventImpl.fireEvents(TreeChangeEventImpl.java:130)
	at com.intellij.pom.wrappers.PsiEventWrapperAspect.update(PsiEventWrapperAspect.java:32)
	at com.intellij.pom.core.impl.PomModelImpl.updateDependentAspects(PomModelImpl.java:167)
	at com.intellij.psi.impl.source.PostprocessReformattingAspectImpl$LangPomModel.updateDependentAspects(PostprocessReformattingAspectImpl.java:87)
	at com.intellij.pom.core.impl.PomModelImpl.lambda$runTransaction$1(PomModelImpl.java:129)
	at com.intellij.psi.impl.DebugUtil.performPsiModification(DebugUtil.java:535)
	at com.intellij.pom.core.impl.PomModelImpl.lambda$runTransaction$2(PomModelImpl.java:103)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeNonCancelableSection$3(CoreProgressManager.java:269)
	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.lambda$computeInNonCancelableSection$4(CoreProgressManager.java:277)
	at com.intellij.openapi.progress.Cancellation.computeInNonCancelableSection(Cancellation.java:57)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computeInNonCancelableSection(CoreProgressManager.java:277)
	at com.intellij.openapi.progress.impl.CoreProgressManager.executeNonCancelableSection(CoreProgressManager.java:268)
	at com.intellij.pom.core.impl.PomModelImpl.runTransaction(PomModelImpl.java:92)
	at com.intellij.psi.impl.source.tree.ChangeUtil.prepareAndRunChangeAction(ChangeUtil.java:141)
	at com.intellij.psi.impl.source.tree.CompositeElement.addChild(CompositeElement.java:586)
	at com.intellij.psi.formatter.FormatterUtil.addWhiteSpace(FormatterUtil.java:447)
	at com.intellij.psi.formatter.FormatterUtil.replaceWhiteSpace(FormatterUtil.java:341)
	at com.intellij.psi.impl.source.codeStyle.PsiBasedFormatterModelWithShiftIndentInside.replaceWithPsiInLeaf(PsiBasedFormatterModelWithShiftIndentInside.java:107)
	at com.intellij.psi.formatter.PsiBasedFormattingModel.replaceWithPSI(PsiBasedFormattingModel.java:94)
	at com.intellij.psi.formatter.PsiBasedFormattingModel.replaceWhiteSpace(PsiBasedFormattingModel.java:53)
	at com.intellij.formatting.engine.FormatProcessorUtils.replaceWhiteSpace(FormatProcessorUtils.java:31)
	at com.intellij.formatting.engine.ApplyChangesState.doIteration(ApplyChangesState.java:160)
	at com.intellij.formatting.engine.State.iteration(State.java:25)
	at com.intellij.formatting.engine.StateProcessor.iteration(StateProcessor.java:26)
	at com.intellij.formatting.FormatProcessor.iteration(FormatProcessor.java:92)
	at com.intellij.formatting.FormatterImpl$MyFormattingTask.iteration(FormatterImpl.java:681)
	at com.intellij.formatting.FormatterImpl.execute(FormatterImpl.java:260)
	at com.intellij.formatting.FormatterImpl.format(FormatterImpl.java:228)
	at com.intellij.psi.impl.source.codeStyle.CodeFormatterFacade.processRange(CodeFormatterFacade.java:115)
	at com.intellij.psi.impl.source.codeStyle.CodeFormatterFacade.processElement(CodeFormatterFacade.java:62)
	at com.intellij.formatting.service.CoreFormattingService.formatElement(CoreFormattingService.java:53)
	at com.intellij.formatting.service.FormattingServiceUtil.formatElement(FormattingServiceUtil.java:67)
	at com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl.reformat(CodeStyleManagerImpl.java:83)
	at com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl.reformat(CodeStyleManagerImpl.java:67)
	at org.jetbrains.research.testspark.helpers.java.JavaClassBuilderHelper.formatCode$lambda$0(JavaClassBuilderHelper.kt:123)
	at com.intellij.openapi.command.WriteCommandAction.lambda$runWriteCommandAction$4(WriteCommandAction.java:338)
	at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.lambda$doRunWriteCommandAction$1(WriteCommandAction.java:144)
	at com.intellij.openapi.application.impl.RwLockHolder.runWriteAction(RwLockHolder.kt:344)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:883)
	at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.lambda$doRunWriteCommandAction$2(WriteCommandAction.java:142)
	at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:225)
	at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:187)
	at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.doRunWriteCommandAction(WriteCommandAction.java:151)
	at com.intellij.openapi.command.WriteCommandAction$BuilderImpl.lambda$run$0(WriteCommandAction.java:122)
	at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:209)
	at com.intellij.openapi.application.TransactionGuardImpl.access$100(TransactionGuardImpl.java:22)
	at com.intellij.openapi.application.TransactionGuardImpl$1.run(TransactionGuardImpl.java:191)
	at com.intellij.openapi.application.impl.RwLockHolder.runIntendedWriteActionOnCurrentThread(RwLockHolder.kt:204)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:830)
	at com.intellij.openapi.application.impl.ApplicationImpl$2.run(ApplicationImpl.java:419)
	at com.intellij.openapi.application.impl.LaterInvocator$1.run(LaterInvocator.java:101)
	at com.intellij.openapi.application.impl.RwLockHolder.runWithEnabledImplicitRead(RwLockHolder.kt:138)
	at com.intellij.openapi.application.impl.RwLockHolder.runWithImplicitRead(RwLockHolder.kt:129)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWithImplicitRead(ApplicationImpl.java:1152)
	at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:81)
	at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:123)
	at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:43)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:792)
	at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:739)
	at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:733)
	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:761)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.kt:698)
	at com.intellij.ide.IdeEventQueue._dispatchEvent$lambda$12(IdeEventQueue.kt:593)
	at com.intellij.openapi.application.impl.RwLockHolder.runWithoutImplicitRead(RwLockHolder.kt:105)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.kt:593)
	at com.intellij.ide.IdeEventQueue.access$_dispatchEvent(IdeEventQueue.kt:77)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:362)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:361)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:843)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:361)
	at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:356)
	at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$1(IdeEventQueue.kt:1021)
	at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:106)
	at com.intellij.ide.IdeEventQueueKt.performActivity(IdeEventQueue.kt:1021)
	at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$7(IdeEventQueue.kt:356)
	at com.intellij.openapi.application.impl.RwLockHolder.runIntendedWriteActionOnCurrentThread(RwLockHolder.kt:209)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:830)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:398)
	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)
  1. Could you, please, disable the "line" option, if Kex is selected.
Screenshot 2024-08-27 at 5 42 38 PM
  1. Also, could you please check, if the class to test is in Java language.; so, if the file in a Java file. Maybe, it's better to disable Kex in case of other language.

@edwin1729
Copy link
Author

edwin1729 commented Aug 27, 2024

3. Also, could you please check, if the class to test is in Java language.; so, if the file in a Java file. Maybe, it's better to disable Kex in case of other language.

I'd like to postpone this for later. Kex generates tests from the compiled .class files. So in theory it can also generate tests for kotlin code. I just need to figure out how to translate kotlin types to jvm types. After that kex will also work for kotlin. Maybe I'll do that in another PR

@arksap2002
Copy link
Collaborator

Closes #328

@arksap2002 arksap2002 added In progress PR is in progress and removed Ready for review PR redy for review labels Sep 3, 2024
@arksap2002 arksap2002 self-requested a review September 18, 2024 14:03
@arksap2002 arksap2002 added improvement New feature Ready for review PR redy for review and removed In progress PR is in progress labels Sep 18, 2024
@Vladislav0Art Vladislav0Art removed the Ready for review PR redy for review label Oct 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
improvement New feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants