Skip to content

Commit

Permalink
Merge pull request #10 from jaksonlin/render-report-to-code
Browse files Browse the repository at this point in the history
Render report to code
  • Loading branch information
jaksonlin authored Oct 11, 2024
2 parents bede827 + cdebe59 commit a27105c
Show file tree
Hide file tree
Showing 34 changed files with 809 additions and 126 deletions.
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ dependencies {
// Add Gradle Tooling API dependency
implementation(fileTree("lib") { include("*.jar") })
implementation("com.github.javaparser:javaparser-core:3.24.2") // Add JavaParser dependency
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.18.0")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.0")
implementation("com.fasterxml.jackson.core:jackson-databind:2.18.0")
// IntelliJ Platform Gradle Plugin Dependencies Extension - read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-dependencies-extension.html
intellijPlatform {
create(providers.gradleProperty("platformType"), providers.gradleProperty("platformVersion"))
Expand Down
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ pluginGroup = com.github.jaksonlin.pitestintellij
pluginName = pitest-intellij
pluginRepositoryUrl = https://github.com/jaksonlin/pitest-intellij
# SemVer format -> https://semver.org
pluginVersion = 0.0.1
pluginVersion = 0.1.0

# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
pluginSinceBuild = 233
pluginSinceBuild = 223
pluginUntilBuild = 242.*

# IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension
platformType = IC
platformVersion = 2023.3.2
platformVersion = 2022.3

# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.jetbrains.php:203.4449.22, org.intellij.scala:2023.3.27@EAP
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ package com.github.jaksonlin.pitestintellij
import com.intellij.DynamicBundle
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.PropertyKey
import java.util.*

@NonNls
private const val BUNDLE = "messages.MyBundle"

object MyBundle : DynamicBundle(BUNDLE) {

init {
val defaultLocale = Locale("en", "US")
Locale.setDefault(defaultLocale)
}
@JvmStatic
fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) =
getMessage(key, *params)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,16 @@
package com.github.jaksonlin.pitestintellij.actions
import com.github.jaksonlin.pitestintellij.commands.PrepareEnvironmentCommand
import com.github.jaksonlin.pitestintellij.commands.BuildPitestCommandCommand
import com.github.jaksonlin.pitestintellij.commands.HandlePitestResultCommand
import com.github.jaksonlin.pitestintellij.commands.PitestContext
import com.github.jaksonlin.pitestintellij.commands.RunPitestCommand

import com.github.jaksonlin.pitestintellij.services.PitestService
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.PlatformDataKeys
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.Task
import com.intellij.openapi.components.service

class RunPitestAction : AnAction() {
private val pitestService = service<PitestService>()
override fun actionPerformed(e: AnActionEvent) {
val targetProject = e.project ?: return
val testVirtualFile = e.getData(PlatformDataKeys.VIRTUAL_FILE) ?: return

val context = PitestContext(testVirtualFile = testVirtualFile)

val commands = listOf(
PrepareEnvironmentCommand(targetProject, context),
BuildPitestCommandCommand(targetProject, context),
RunPitestCommand(targetProject, context),
HandlePitestResultCommand(targetProject, context),
)

object : Task.Backgroundable(targetProject, "Running pitest", true) {
override fun run(indicator: ProgressIndicator) {
for (command in commands) {
if (indicator.isCanceled) { break }
command.execute()
}
}
}.queue()
pitestService.runPitest(targetProject, testVirtualFile.path)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.jaksonlin.pitestintellij.commands

import PitestCommand
import com.github.jaksonlin.pitestintellij.context.PitestContext
import com.intellij.openapi.project.Project

class BuildPitestCommandCommand (project: Project, context: PitestContext) : PitestCommand(project, context) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.github.jaksonlin.pitestintellij.commands


class CommandCancellationException(message: String) : Exception(message) {

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.github.jaksonlin.pitestintellij.commands

import PitestCommand
import com.github.jaksonlin.pitestintellij.context.PitestContext
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.project.Project
import com.github.jaksonlin.pitestintellij.ui.PitestOutputDialog
import java.io.File
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import com.github.jaksonlin.pitestintellij.ui.PitestOutputDialog
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.github.jaksonlin.pitestintellij.commands.PitestContext
import com.github.jaksonlin.pitestintellij.commands.dumpPitestContext
import com.github.jaksonlin.pitestintellij.context.PitestContext
import com.github.jaksonlin.pitestintellij.context.dumpPitestContext
import com.github.jaksonlin.pitestintellij.services.PitestService
import com.github.jaksonlin.pitestintellij.services.RunHistoryManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.components.service
import java.util.concurrent.atomic.AtomicReference

abstract class PitestCommand(protected val project: Project, protected val context: PitestContext) {
abstract fun execute()

protected val runHistoryManager = service<RunHistoryManager>()
protected fun showInputDialog(message: String, title: String): String? {
val result = AtomicReference<String?>()
ApplicationManager.getApplication().invokeAndWait({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.jaksonlin.pitestintellij.commands

import PitestCommand
import com.github.jaksonlin.pitestintellij.context.PitestContext
import com.github.jaksonlin.pitestintellij.util.FileUtils
import com.github.jaksonlin.pitestintellij.util.GradleUtils
import com.github.jaksonlin.pitestintellij.util.JavaFileProcessor
Expand All @@ -11,31 +12,30 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import java.io.File
import java.nio.file.Path
import java.nio.file.Paths

class PrepareEnvironmentCommand(project: Project, context: PitestContext) : PitestCommand(project, context) {
private val javaFileProcessor = JavaFileProcessor()

override fun execute() {
val testVirtualFile = ReadAction.compute<VirtualFile?, Throwable> {
context.testVirtualFile
LocalFileSystem.getInstance().findFileByPath(context.testFilePath!!)
}
if (testVirtualFile == null) {
showError("Cannot find test file")
throw IllegalStateException("Cannot find test file")
}
val targetTestClassFilePath = testVirtualFile.path

collectTargetTestClassName(targetTestClassFilePath)
collectTargetTestClassName(context.testFilePath!!)
collectJavaInfo(testVirtualFile)
collectSourceRoots()
collectResourceDirectories()

collectTargetClassThatWeTest(context.sourceRoots)
prepareReportDirectory(testVirtualFile)
collectTargetClassThatWeTest(context.sourceRoots!!)
prepareReportDirectory(testVirtualFile, context.targetClassFullyQualifiedName!!)

setupPitestLibDependencies(context.resourceDirectories!!)
collectClassPathFileForPitest(context.reportDirectory!!, context.targetClassPackageName!!, context.resourceDirectories)
Expand Down Expand Up @@ -71,10 +71,10 @@ class PrepareEnvironmentCommand(project: Project, context: PitestContext) : Pite
}

private fun collectSourceRoots() {
context.sourceRoots = ReadAction.compute<List<Path>, Throwable> {
context.sourceRoots = ReadAction.compute<List<String>, Throwable> {
ModuleManager.getInstance(project).modules.flatMap { module ->
ModuleRootManager.getInstance(module).contentRoots.map { contentRoot ->
Paths.get(contentRoot.path)
Paths.get(contentRoot.path).toString()
}
}
}
Expand All @@ -87,11 +87,12 @@ class PrepareEnvironmentCommand(project: Project, context: PitestContext) : Pite
context.resourceDirectories = resourceDirectories
}

private fun collectTargetClassThatWeTest(sourceRoots:List<Path>) {
private fun collectTargetClassThatWeTest(sourceRoots:List<String>) {
// The user input dialog and file operations don't need to be in ReadAction
val targetClass = showInputDialog("Please enter the name of the class that you want to test", "Enter target class")
// when user input content but cancel, targetClass is not null we should break the process
if (targetClass.isNullOrBlank()) {
return
throw CommandCancellationException("User cancelled the operation")
}
val targetClassInfo = FileUtils.findTargetClassFile(sourceRoots, targetClass)
if (targetClassInfo == null) {
Expand All @@ -106,9 +107,12 @@ class PrepareEnvironmentCommand(project: Project, context: PitestContext) : Pite
}
context.targetClassFullyQualifiedName = classInfo.fullyQualifiedName
context.targetClassPackageName = classInfo.packageName
context.targetClassName = classInfo.className
context.targetClassSourceRoot = targetClassInfo.sourceRoot.toString()
context.targetClassFilePath = targetClassInfo.file.normalize().toString().replace("\\", "/")
}
private fun prepareReportDirectory(testVirtualFile: VirtualFile){

private fun prepareReportDirectory(testVirtualFile: VirtualFile, className: String){
// prepare the report directory
val parentModulePath = ReadAction.compute<String, Throwable> {

Expand All @@ -120,8 +124,7 @@ class PrepareEnvironmentCommand(project: Project, context: PitestContext) : Pite

GradleUtils.getUpperModulePath(project, projectModule)
}

context.reportDirectory = Paths.get(parentModulePath, "build", "reports", "pitest").toString()
context.reportDirectory = Paths.get(parentModulePath, "build", "reports", "pitest", className).toString()
File(context.reportDirectory!!).mkdirs()

}
Expand All @@ -142,8 +145,8 @@ class PrepareEnvironmentCommand(project: Project, context: PitestContext) : Pite
}
showOutput("Classpath file content: $classPathFileContent", "Classpath file content")
context.classpathFileDirectory = Paths.get(reportDirectory, targetPackageName).toString()
File(context.classpathFileDirectory).mkdirs()
context.classpathFile = Paths.get(context.classpathFileDirectory, "classpath.txt").toString()
File(context.classpathFileDirectory!!).mkdirs()
context.classpathFile = Paths.get(context.classpathFileDirectory!!, "classpath.txt").toString()
File(context.classpathFile!!).writeText(classPathFileContent)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.jaksonlin.pitestintellij.commands

import PitestCommand
import com.github.jaksonlin.pitestintellij.context.PitestContext
import com.github.jaksonlin.pitestintellij.util.ProcessExecutor
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.project.Project
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.github.jaksonlin.pitestintellij.commands

import PitestCommand
import com.github.jaksonlin.pitestintellij.context.PitestContext
import com.github.jaksonlin.pitestintellij.services.RunHistoryManager
import com.intellij.openapi.project.Project

class StoreHistoryCommand (project: Project, context: PitestContext) : PitestCommand(project, context) {

override fun execute() {
runHistoryManager.saveRunHistory(context)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.github.jaksonlin.pitestintellij.components
import com.github.jaksonlin.pitestintellij.MyBundle
import com.github.jaksonlin.pitestintellij.observers.RunHistoryObserver
import com.intellij.ui.treeStructure.Tree
import javax.swing.SwingUtilities
import javax.swing.tree.DefaultMutableTreeNode
import javax.swing.tree.DefaultTreeModel
import javax.swing.tree.TreePath

class ObservableTree:Tree(), RunHistoryObserver {

override fun onRunHistoryChanged(eventObj:Any?) {
when (eventObj) {
null -> initializeMutationTree(emptyList())
is Pair<*, *> -> updateMutationTree(eventObj as? Pair<String, String> ?: return)
is List<*> -> initializeMutationTree(eventObj as? List<Pair<String, String>> ?: return)
else -> return
}
}

private fun initializeMutationTree(nodeNameList: List<Pair<String, String>>) {
val treeModel = buildTreeModel(nodeNameList)
model = treeModel
}

private fun buildTreeModel(nodeNameList: List<Pair<String, String>>): DefaultTreeModel {
val root = DefaultMutableTreeNode(MyBundle.message("mutation.tree.root"))

nodeNameList.forEach {
val packageName = it.first
val packageNode = getOrCreatePackageNode(root, packageName)
val newNode = DefaultMutableTreeNode(it.second)
packageNode.add(newNode)
}

return DefaultTreeModel(root)
}

private fun getOrCreatePackageNode(root: DefaultMutableTreeNode, packageName: String): DefaultMutableTreeNode {
var currentNode = root
packageName.split('.').forEach { packagePart ->
var childNode = currentNode.children().asSequence()
.filterIsInstance<DefaultMutableTreeNode>()
.find { it.userObject == packagePart }

if (childNode == null) {
childNode = DefaultMutableTreeNode(packagePart)
currentNode.add(childNode)
}
currentNode = childNode
}
return currentNode
}

private fun updateMutationTree(pair: Pair<String, String>) {
val root = model.root as DefaultMutableTreeNode
val packageName = pair.first
val packageNode = getOrCreatePackageNode(root, packageName)
val newNode = DefaultMutableTreeNode(pair.second)
packageNode.add(newNode)
SwingUtilities.invokeLater {
expandPath(TreePath(packageNode.path)) // expand the package node
updateUI()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
package com.github.jaksonlin.pitestintellij.commands
package com.github.jaksonlin.pitestintellij.context

import com.github.jaksonlin.pitestintellij.util.ProcessResult
import com.intellij.openapi.vfs.VirtualFile
import java.nio.file.Path

data class PitestContext(
var testVirtualFile: VirtualFile? = null,
var testFilePath: String? = null,
var fullyQualifiedTargetTestClassName: String? = null,
var javaHome: String? = null,
var sourceRoots: List<Path> = emptyList(),
var sourceRoots: List<String>? = null,
var targetClassFullyQualifiedName: String? = null,
var targetClassPackageName: String? = null,
var targetClassSourceRoot:String?=null,
var targetClassFilePath: String?=null,
var targetClassName:String?=null,
var reportDirectory: String? = null,
var classpathFile: String? = null,
var classpathFileDirectory: String? = null,
var command: List<String> = emptyList(),
var processResult: ProcessResult? = null,
@Transient var processResult: ProcessResult? = null,
var pitestDependencies: String? = null,
var resourceDirectories: List<String>? = null
var resourceDirectories: List<String>? = null,
val timestamp: Long,
)



fun dumpPitestContext(context: PitestContext): String {
return """
testVirtualFile: ${context.testVirtualFile}
testVirtualFile: ${context.testFilePath}
fullyQualifiedTargetTestClassName: ${context.fullyQualifiedTargetTestClassName}
javaHome: ${context.javaHome}
sourceRoots: ${context.sourceRoots}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.github.jaksonlin.pitestintellij.mediators

interface IMutationMediator {
fun processMutationResult(mutationTargetClassFilePath:String, mutationReportFilePath: String)
fun register(clientUI: IMutationReportUI)
}

interface IMutationReportUI {
fun updateMutationResult(mutationClassFilePath:String, mutationTestResult: Map<Int, Pair<String, Boolean>>)
}


Loading

0 comments on commit a27105c

Please sign in to comment.