westt 8 months ago
commit
8f3f45db43

+ 38 - 0
.gitignore

@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 8 - 0
.idea/encodings.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/src/main/java/com/frk/mycode/ParseXML.java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
+  </component>
+</project>

+ 6 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="SerializableHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true" />
+  </profile>
+</component>

+ 13 - 0
.idea/misc.xml

@@ -0,0 +1,13 @@
+<project version="4">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>

+ 124 - 0
.idea/uiDesigner.xml

@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Palette2">
+    <group name="Swing">
+      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+      </item>
+      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
+        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+        <initial-values>
+          <property name="text" value="Button" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="RadioButton" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="CheckBox" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="Label" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+          <preferred-size width="-1" height="20" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+      </item>
+    </group>
+  </component>
+</project>

+ 149 - 0
pom.xml

@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.example</groupId>
+    <artifactId>openclover</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.openclover</groupId>
+            <artifactId>clover-maven-plugin</artifactId>
+            <version>4.4.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.openclover</groupId>
+            <artifactId>clover</artifactId>
+            <version>4.4.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.12</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>2.1.1</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.json/json -->
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20210307</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.83</version>
+        </dependency>
+            <dependency>
+                <groupId>ca.mcgill.sable</groupId>
+                <artifactId>soot</artifactId>
+                <version>4.1.0</version>
+            </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.36</version> <!-- 请根据需要选择合适的版本 -->
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>1.7.36</version> <!-- 请根据需要选择合适的版本 -->
+        </dependency>
+
+
+        <!-- https://mvnrepository.com/artifact/org.jacoco/jacoco-maven-plugin -->
+        <dependency>
+            <groupId>org.jacoco</groupId>
+            <artifactId>jacoco-maven-plugin</artifactId>
+            <version>0.8.7</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.28</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jsoup</groupId>
+            <artifactId>jsoup</artifactId>
+            <version>1.8.3</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <version>0.8.6</version>
+                <executions>
+                    <execution>
+                        <id>prepare-agent</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>report</id>
+                        <phase>test</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                        <configuration>
+                            <!--定义输出的文件夹-->
+                            <outputDirectory>target/jacoco-report</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.openclover</groupId>
+                <artifactId>clover-maven-plugin</artifactId>
+                <version>4.4.1</version>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>instrument</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <generatePdf>false</generatePdf>
+                    <generateXml>true</generateXml>
+                    <generateHtml>true</generateHtml>
+                    <generateJson>true</generateJson>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.5</version>
+            </plugin>
+<!--            <plugin>-->
+<!--                <artifactId>maven-failsafe-plugin</artifactId>-->
+<!--                <version>2.2</version>-->
+<!--            </plugin>-->
+        </plugins>
+    </build>
+
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.openclover</groupId>
+                <artifactId>clover-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </reporting>
+
+</project>

+ 428 - 0
splitByAI.ipynb

@@ -0,0 +1,428 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "### Control Flow Graph (CFG) Representation for the `generateBoard()` method in `EightQueens` class\n",
+      "\n",
+      "#### Nodes:\n",
+      "1. `Queen[] start = new Queen[8];` - Declaration and initialization of Queen array.\n",
+      "2. `Random gen = new Random();` - Initialization of Random generator object.\n",
+      "3. `int i = 0;` - Initialization of loop variable.\n",
+      "4. `i < 8;` - Loop condition check.\n",
+      "5. `start[i] = new Queen(gen.nextInt(8), i);` - Assigning new Queen object to array element during each iteration.\n",
+      "6. `i++;` - Increment of loop variable.\n",
+      "7. `return start;` - Return the array of Queen objects.\n",
+      "8. `End of generateBoard()` - Exit point of the method.\n",
+      "\n",
+      "#### Edges:\n",
+      "- `Edge 1`: Node 1 to Node 2 - Sequence of operations.\n",
+      "- `Edge 2`: Node 2 to Node 3 - Sequence transitioning to loop initialization.\n",
+      "- `Edge 3`: Node 3 to Node 4 - Moves from loop initialization to loop condition check.\n",
+      "- `Edge 4`: Node 4 to Node 5 (Condition: true) - If condition is true, execute loop body.\n",
+      "- `Edge 5`: Node 5 to Node 6 - Sequence inside loop, after execution moves to increment statement.\n",
+      "- `Edge 6`: Node 6 to Node 4 - After incrementing, control goes back to loop condition check.\n",
+      "- `Edge 7`: Node 4 to Node 7 (Condition: false) - If loop condition fails, flow exits loop and returns array.\n",
+      "- `Edge 8`: Node 7 to Node 8 - Control exits the method.\n",
+      "\n",
+      "#### Conditions:\n",
+      "- Node 4 (`i < 8;`): Determines whether the loop should continue or exit.\n",
+      "\n",
+      "#### Loops:\n",
+      "- **Loop Start**: Node 3 (`int i = 0;`)\n",
+      "- **Loop End**: Node 7 (`return start;`)\n",
+      "- **Condition**: `i < 8;` - Ensures loop iterates through the indices of the array.\n",
+      "\n",
+      "This CFG allows tracing the execution flow in the `generateBoard()` method, helping to understand the iterative process that populates the `Queen[]` array with newly created `Queen` objects, where each object is placed randomly on the board while its index maintains the column placement. This CFG is particularly useful for debugging or extending the method due to its clear representation of each computational step and control transfer.\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "import glob\n",
+    "import re\n",
+    "import os\n",
+    "from openai import OpenAI\n",
+    "\n",
+    "api_key = 'sk-ZLMKmXkh5EAlsGE9431f6c690cE6498c847f48C7D7FbAfA6'\n",
+    "api_base = \"https://openkey.cloud/v1\"\n",
+    "client = OpenAI(api_key=api_key, base_url=api_base)\n",
+    "test_methods = \"\"\"\n",
+    "package net.mooctest;\n",
+    "/**\n",
+    " * @file EightQueens.java\n",
+    " * @author nsquires\n",
+    " * Solves the eight queens problem using various AI techniques\n",
+    " */\n",
+    "import java.util.*;\n",
+    "import java.text.NumberFormat;\n",
+    "\n",
+    "public class EightQueens {\n",
+    "\t\n",
+    "\tpublic EightQueens(){\n",
+    "\t}\n",
+    "\t\n",
+    "\t/**\n",
+    "\t * The starter board\n",
+    "\t * @return Queen[]\n",
+    "\t */\n",
+    "\tpublic Queen[] generateBoard(){\n",
+    "\t\tQueen[] start = new Queen[8];\n",
+    "\t\tRandom gen = new Random();\n",
+    "\t\t\n",
+    "\t\tfor(int i=0; i<8; i++){\n",
+    "\t\t\tstart[i] = new Queen(gen.nextInt(8),i);\n",
+    "\t\t}\n",
+    "\t\treturn start;\n",
+    "\t}\n",
+    "}\n",
+    "\n",
+    "\"\"\"\n",
+    "\n",
+    "def getCFG(java_code):     \n",
+    "    prompt = f\"\"\"\n",
+    "Please generate a Control Flow Graph (CFG) from the following Java code. The CFG should include detailed information about:\n",
+    "\n",
+    "1. Nodes: Identify each independent statement or expression as a node.\n",
+    "   - Purpose: Nodes represent points of computation or decision in the code.\n",
+    "\n",
+    "2. Edges: Describe the control flow transitions between nodes.\n",
+    "   - Purpose: Edges show how execution moves from one node to another, including conditions that influence the flow.\n",
+    "\n",
+    "3. Conditions: Specify the conditions for decision-making statements (if, switch, loops).\n",
+    "   - Purpose: Conditions determine the branching in the flow of execution.\n",
+    "\n",
+    "4. Loops: Identify the start and end of loops, and describe their iteration conditions.\n",
+    "   - Purpose: Loops are critical for understanding repeated execution and potential paths within the code.\n",
+    "\n",
+    "Please format the CFG as follows:\n",
+    "- Nodes: List all nodes with a brief description.\n",
+    "- Edges: List all edges with starting and ending node identifiers and the condition (if applicable).\n",
+    "- Conditions: List all conditions associated with their nodes.\n",
+    "- Loops: Describe all loops with their starting node, ending node, and condition.\n",
+    "\n",
+    "Java Code:\n",
+    "{java_code}\n",
+    "\n",
+    "\"\"\"\n",
+    "    response = client.chat.completions.create(\n",
+    "    model=\"gpt-3.5-turbo\",\n",
+    "#   response_format={ \"type\": \"json_object\" },\n",
+    "    messages=[\n",
+    "    {\"role\": \"user\", \"content\": prompt}\n",
+    "    ]\n",
+    "    )\n",
+    "    print(response.choices[0].message.content)\n",
+    "\n",
+    "getCFG(test_methods)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "['D:\\\\learn\\\\junit-test\\\\test\\\\EightQueens_1665290554002\\\\src\\\\test\\\\java\\\\net\\\\mooctest\\\\EightQueensTest.java']\n",
+      "find method count 1\n",
+      "find method: @Test(timeout = 4000)\n",
+      "\tpublic void test()\n",
+      "find: test @Test(timeout = 4000)\n",
+      "\tpublic void test() {\n",
+      "\t\tEightQueens board = new EightQueens();\n",
+      "\t\tQueen[] startBoard = board.generateBoard();\n",
+      "\t\t// 检查不攻击的女王触发\n",
+      "\t\tassertTrue(new Queen(1, 3).canAttack(new Queen(2, 2)));\n",
+      "\t\t// 检查同一行的女王触发\n",
+      "\t\tassertTrue(new Queen(1, 3).canAttack(new Queen(1, 5)));\n",
+      "\t\t// 检查同一列的女王触发\n",
+      "\t\tassertTrue(new Queen(3, 1).canAttack(new Queen(5, 1)));\n",
+      "\t\t// 检查同一对角线的女王触发\n",
+      "\t\tassertTrue(new Queen(1, 1).canAttack(new Queen(2, 2)));\n",
+      "\t\t// 2. movedown\n",
+      "\t\tstartBoard[0].setRow(0);\n",
+      "\t\tstartBoard[0].setColumn(1);\n",
+      "\t\tassertEquals(startBoard[0].getRow(), 0);\n",
+      "\t\tassertEquals(startBoard[0].getColumn(), 1);\n",
+      "\t\tfor(int i = 0; i < 30; i++) startBoard[0].moveDown(i);\n",
+      "\t\t// 3. Test HillClimbing  爬山法解八皇后问题\n",
+      "\t\tHillClimbing hcTest = new HillClimbing();\n",
+      "\t\tHillClimbing hc = new HillClimbing(startBoard);\n",
+      "\t\t// 4. 检查生成的Node\n",
+      "\t\tNode node = hc.hillClimbing();\n",
+      "\t\tNode nodeTest = hcTest.getStartNode();\n",
+      "\t\tassertNotNull(node);\n",
+      "\t\tassertNotNull(nodeTest);\n",
+      "\t\tassertNotNull(node.getRandomNeighbour(node));\n",
+      "\t\t// 5. 测试RandomRestart\n",
+      "\t\tRandomRestart rr = new RandomRestart(startBoard);\n",
+      "\t\tNode randomNode = rr.randomRestart();\n",
+      "\t\tassertNotNull(rr);\n",
+      "\t\tassertNotNull(randomNode);\n",
+      "\t\tNode now = rr.randomRestart();\n",
+      "\t\tassertNotNull(now);\n",
+      "\t\trr.setStartNode(now);\n",
+      "\t\tassertSame(rr.getStartNode(), now);\n",
+      "\t\t// 6. 测试SimulatedAnnealing    模拟退火解八皇后问题\n",
+      "\t\tSimulatedAnnealing sa = new SimulatedAnnealing(startBoard);\n",
+      "\t\tsa.startState();\n",
+      "\t\tassertNotNull(sa.getStartNode());\n",
+      "\t\tNode ans;\n",
+      "\t\tdouble T = 1000.0, delta = 0.7;    // 温度越高越好,速率0.8~0.99\n",
+      "\t\twhile(delta < 1) {\n",
+      "\t\t\tans = sa.simulatedAnneal(T, delta);\n",
+      "\t\t\tassertNotNull(ans);\n",
+      "\t\t\tdelta *= 1.1;\n",
+      "\t\t\tT *= 1.1;\n",
+      "\t\t}\n",
+      "\t\t\n",
+      "\t}\n",
+      "Method 'test' was successfully split into separate test units.\n",
+      "be replace test\n",
+      "old------------- @Test(timeout = 4000)\n",
+      "\tpublic void test() {\n",
+      "\t\tEightQueens board = new EightQueens();\n",
+      "\t\tQueen[] startBoard = board.generateBoard();\n",
+      "\t\t// 检查不攻击的女王触发\n",
+      "\t\tassertTrue(new Queen(1, 3).canAttack(new Queen(2, 2)));\n",
+      "\t\t// 检查同一行的女王触发\n",
+      "\t\tassertTrue(new Queen(1, 3).canAttack(new Queen(1, 5)));\n",
+      "\t\t// 检查同一列的女王触发\n",
+      "\t\tassertTrue(new Queen(3, 1).canAttack(new Queen(5, 1)));\n",
+      "\t\t// 检查同一对角线的女王触发\n",
+      "\t\tassertTrue(new Queen(1, 1).canAttack(new Queen(2, 2)));\n",
+      "\t\t// 2. movedown\n",
+      "\t\tstartBoard[0].setRow(0);\n",
+      "\t\tstartBoard[0].setColumn(1);\n",
+      "\t\tassertEquals(startBoard[0].getRow(), 0);\n",
+      "\t\tassertEquals(startBoard[0].getColumn(), 1);\n",
+      "\t\tfor(int i = 0; i < 30; i++) startBoard[0].moveDown(i);\n",
+      "\t\t// 3. Test HillClimbing  爬山法解八皇后问题\n",
+      "\t\tHillClimbing hcTest = new HillClimbing();\n",
+      "\t\tHillClimbing hc = new HillClimbing(startBoard);\n",
+      "\t\t// 4. 检查生成的Node\n",
+      "\t\tNode node = hc.hillClimbing();\n",
+      "\t\tNode nodeTest = hcTest.getStartNode();\n",
+      "\t\tassertNotNull(node);\n",
+      "\t\tassertNotNull(nodeTest);\n",
+      "\t\tassertNotNull(node.getRandomNeighbour(node));\n",
+      "\t\t// 5. 测试RandomRestart\n",
+      "\t\tRandomRestart rr = new RandomRestart(startBoard);\n",
+      "\t\tNode randomNode = rr.randomRestart();\n",
+      "\t\tassertNotNull(rr);\n",
+      "\t\tassertNotNull(randomNode);\n",
+      "\t\tNode now = rr.randomRestart();\n",
+      "\t\tassertNotNull(now);\n",
+      "\t\trr.setStartNode(now);\n",
+      "\t\tassertSame(rr.getStartNode(), now);\n",
+      "\t\t// 6. 测试SimulatedAnnealing    模拟退火解八皇后问题\n",
+      "\t\tSimulatedAnnealing sa = new SimulatedAnnealing(startBoard);\n",
+      "\t\tsa.startState();\n",
+      "\t\tassertNotNull(sa.getStartNode());\n",
+      "\t\tNode ans;\n",
+      "\t\tdouble T = 1000.0, delta = 0.7;    // 温度越高越好,速率0.8~0.99\n",
+      "\t\twhile(delta < 1) {\n",
+      "\t\t\tans = sa.simulatedAnneal(T, delta);\n",
+      "\t\t\tassertNotNull(ans);\n",
+      "\t\t\tdelta *= 1.1;\n",
+      "\t\t\tT *= 1.1;\n",
+      "\t\t}\n",
+      "\t\t\n",
+      "\t}\n",
+      "new------------- @Test(timeout = 4000)\n",
+      "\tpublic void testGenerateBoard() {\n",
+      "\t\tEightQueens board = new EightQueens();\n",
+      "\t\tQueen[] startBoard = board.generateBoard();\n",
+      "\t\tassertNotNull(startBoard);\n",
+      "\t}\n",
+      "\n",
+      "\t@Test\n",
+      "\tpublic void testCanAttack() {\n",
+      "\t\tassertTrue(new Queen(1, 3).canAttack(new Queen(2, 2)));\n",
+      "\t\tassertTrue(new Queen(1, 3).canAttack(new Queen(1, 5)));\n",
+      "\t\tassertTrue(new Queen(3, 1).canAttack(new Queen(5, 1)));\n",
+      "\t\tassertTrue(new Queen(1, 1).canAttack(new Queen(2, 2)));\n",
+      "\t}\n",
+      "\n",
+      "\t@Test\n",
+      "\tpublic void testMoveDown() {\n",
+      "\t\tQueen queen = new Queen(1, 3);\n",
+      "\t\tqueen.moveDown(5);\n",
+      "\t\tassertEquals(queen.getRow(), 6);\n",
+      "\t\tassertEquals(queen.getColumn(), 3);\n",
+      "\t}\n",
+      "\n",
+      "\t@Test\n",
+      "\tpublic void testHillClimbing() {\n",
+      "\t\tHillClimbing hc = new HillClimbing();\n",
+      "\t\thc.startState();\n",
+      "\t\tNode node = hc.hillClimbing();\n",
+      "\t\tassertNotNull(node);\n",
+      "\t}\n",
+      "\n",
+      "\t@Test\n",
+      "\tpublic void testRandomRestart() {\n",
+      "\t\tEightQueens board = new EightQueens();\n",
+      "\t\tQueen[] startBoard = board.generateBoard();\n",
+      "\t\tRandomRestart rr = new RandomRestart(startBoard);\n",
+      "\t\tNode node = rr.randomRestart();\n",
+      "\t\tassertNotNull(node);\n",
+      "\t\tNode startNode = rr.getStartNode();\n",
+      "\t\trr.setStartNode(startNode);\n",
+      "\t\tassertSame(rr.getStartNode(), startNode);\n",
+      "\t}\n",
+      "\n",
+      "\t@Test\n",
+      "\tpublic void testSimulatedAnnealing() {\n",
+      "\t\tEightQueens board = new EightQueens();\n",
+      "\t\tQueen[] startBoard = board.generateBoard();\n",
+      "\t\tSimulatedAnnealing sa = new SimulatedAnnealing(startBoard);\n",
+      "\t\tsa.startState();\n",
+      "\t\tNode startNode = sa.getStartNode();\n",
+      "\t\tassertNotNull(startNode);\n",
+      "\t\tdouble initialTemp = 1000.0;\n",
+      "\t\tdouble step = 0.7;\n",
+      "\t\tNode ans = sa.simulatedAnneal(initialTemp, step);\n",
+      "\t\tassertNotNull(ans);\n",
+      "\t}\n"
+     ]
+    }
+   ],
+   "source": [
+    "import glob\n",
+    "import re\n",
+    "import os\n",
+    "from openai import OpenAI\n",
+    "\n",
+    "api_key = 'sk-ZLMKmXkh5EAlsGE9431f6c690cE6498c847f48C7D7FbAfA6'\n",
+    "api_base = \"https://openkey.cloud/v1\"\n",
+    "client = OpenAI(api_key=api_key, base_url=api_base)\n",
+    "\n",
+    "def get_test_methods(file_path):\n",
+    "    with open(file_path, 'r', encoding='utf-8') as file:\n",
+    "        content = file.read()\n",
+    "    \n",
+    "    method_declarations = re.findall(r'(@Test\\s*(?:\\(.*?\\))?\\s*public void (\\w+)\\(\\))', content)\n",
+    "\n",
+    "    test_methods = []\n",
+    "    print(\"find method count\", len(method_declarations))\n",
+    "    for method_declaration in method_declarations:\n",
+    "        method_body = method_declaration[0]\n",
+    "        print(\"find method:\", method_body)\n",
+    "        origin_index = content.index(method_body)\n",
+    "        start_index = origin_index + len(method_body)\n",
+    "        # 继续向前查找,直到找到第一个 {\n",
+    "        while content[start_index] != '{':\n",
+    "            start_index += 1\n",
+    "        brace_count = 1  # 已经找到了一个 {\n",
+    "        for i in range(start_index + 1, len(content)):\n",
+    "            if content[i] == '{':\n",
+    "                brace_count += 1\n",
+    "            elif content[i] == '}':\n",
+    "                brace_count -= 1\n",
+    "            if brace_count == 0:\n",
+    "                # 找到了完整的方法体\n",
+    "                method_body = content[origin_index:i+1]\n",
+    "                test_methods.append((method_body, method_declaration[1]))\n",
+    "                break\n",
+    "\n",
+    "# 移除不包含断言的方法\n",
+    "    filtered_test_methods = [(method_name, method_body) for method_body, method_name in test_methods if re.search(r'\\b(?:assert\\w*|assertTrue|assertFalse)\\s*\\(', method_body)]\n",
+    "    for (name, body) in filtered_test_methods:\n",
+    "        print(\"find:\", name, body)\n",
+    "    return filtered_test_methods\n",
+    "\n",
+    "def split_assertions(test_methods):\n",
+    "    new_test_methods = []\n",
+    "    for method_name, method_body in test_methods:\n",
+    "        # 使用OpenAI对方法体进行拆分\n",
+    "        try:\n",
+    "            response = client.chat.completions.create(\n",
+    "                model=\"gpt-3.5-turbo\",\n",
+    "                messages=[\n",
+    "            {\"role\": \"user\",\n",
+    "            \"content\": f\"\"\"\n",
+    "        你是一个拆分代码的AI助手,你的任务是将一个junit代码方法拆分成若干个独立可运行的junit测试单元方法。要求:\n",
+    "        1.一个测试单元只能有一个断言\n",
+    "        2.如果原代码只有一个断言,不用拆分\n",
+    "        3.你的输入是一个完整的方法\n",
+    "        4.输出该方法被拆分后的若干个方法\n",
+    "        5.输出不需要其他提示词\n",
+    "        方法体:\n",
+    "        \\n\\n{method_body}\\n\\n\"\"\"}\n",
+    "        ],\n",
+    "                # response_format={ \"type\": \"json_object\" }\n",
+    "            )\n",
+    "            new_body = response.choices[0].message.content\n",
+    "            new_test_methods.append((method_name, new_body))\n",
+    "            print(f\"Method '{method_name}' was successfully split into separate test units.\")\n",
+    "        except Exception as e:\n",
+    "            print(f\"Failed to split method '{method_name}'. Error: {str(e)}\")\n",
+    "    return new_test_methods\n",
+    "\n",
+    "def write_new_file(file_path, origin_test_methods, new_test_methods):\n",
+    "    with open(file_path, 'r', encoding='utf-8') as file:\n",
+    "        content = file.read()\n",
+    "\n",
+    "    # 创建一个字典,将方法名映射到新的方法体\n",
+    "    new_methods_dict = {name: body for name, body in new_test_methods}\n",
+    "\n",
+    "    # 替换原始文件中的测试方法体\n",
+    "    for method_name, old_body in origin_test_methods:\n",
+    "        if method_name in new_methods_dict:\n",
+    "            print(\"be replace\", method_name)\n",
+    "            new_body = new_methods_dict[method_name]\n",
+    "            print(\"old-------------\", old_body)\n",
+    "            print(\"new-------------\", new_body)\n",
+    "            content = content.replace(old_body, new_body)\n",
+    "\n",
+    "    # 将更改后的内容写回文件\n",
+    "    with open(file_path, 'w', encoding='utf-8') as file:\n",
+    "        file.write(content)\n",
+    "\n",
+    "def process_directory(directory):\n",
+    "    test_files = glob.glob(os.path.join(directory, '**/src/test/**/*.java'), recursive=True)\n",
+    "    print(test_files)\n",
+    "    for file_path in test_files:\n",
+    "        test_methods = get_test_methods(file_path)\n",
+    "        if test_methods:\n",
+    "            new_test_methods = split_assertions(test_methods)\n",
+    "            write_new_file(file_path, test_methods, new_test_methods)\n",
+    "\n",
+    "# 指定要扫描的目录\n",
+    "directory_to_scan = 'D:\\\\learn\\junit-test\\\\test\\\\EightQueens_1665290554002'\n",
+    "process_directory(directory_to_scan)\n"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "dl",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.9.18"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}

+ 111 - 0
src/main/java/com/frk/AssertDependencyAnalyzer.java

@@ -0,0 +1,111 @@
+package com.frk;
+
+import soot.*;
+import soot.jimple.*;
+import soot.jimple.internal.JIfStmt;
+import soot.options.Options;
+import soot.toolkits.graph.*;
+import soot.toolkits.scalar.*;
+
+import java.util.*;
+
+public class AssertDependencyAnalyzer {
+    public static void main(String[] args) {
+        // 设置Soot环境
+        Options.v().set_prepend_classpath(true);
+        Options.v().set_whole_program(true);
+        Options.v().set_app(true);
+        Options.v().set_src_prec(Options.src_prec_java);
+        Options.v().set_process_dir(Collections.singletonList("D:\\learn\\junit-test\\test\\solve2\\EightQueens_1666011085487\\src\\test\\java\\net\\mooctest\\EightQueensTest.java"));
+//        "JavaParser"
+        // 设置主类(Main class)
+        Options.v().set_main_class("D:\\learn\\junit-test\\openclover\\src\\main\\java\\com\\frk\\AssertDependencyAnalyzer.java"); // 这里需要替换为你的主类名
+
+        // 设置入口点
+        List<SootMethod> entryPoints = new ArrayList<>();
+//        SootClass mainClass = Scene.v().loadClassAndSupport("D:\\learn\\junit-test\\openclover\\src\\main\\java\\com\\frk\\AssertDependencyAnalyzer.java");
+//        mainClass.setApplicationClass();
+//        SootMethod mainMethod = mainClass.getMethodByName("main");
+//        entryPoints.add(mainMethod);
+//        Scene.v().setEntryPoints(entryPoints);
+        // 注册一个Transform
+        PackManager.v().getPack("jtp").add(new Transform("jtp.myTransform", new BodyTransformer() {
+            @Override
+            protected void internalTransform(Body body, String phase, Map<String, String> options) {
+                analyzeMethod(body);
+            }
+        }));
+
+        // 启动Soot
+        System.out.println("Before launching Soot");
+
+        soot.Main.main(args);
+
+        System.out.println("Exiting main method");
+    }
+
+    private static void analyzeMethod(Body body) {
+        // 构建控制流图
+        UnitGraph cfg = new BriefUnitGraph(body);
+
+        // 查找assert语句
+        for (Unit unit : body.getUnits()) {
+            if (unit instanceof JIfStmt) {
+                JIfStmt ifStmt = (JIfStmt) unit;
+                if (isAssertStatement(ifStmt)) {
+                    // 分析assert语句的依赖
+                    analyzeDependencies(ifStmt, cfg);
+                }
+            }
+        }
+        System.out.println("Exiting analyzeMethod");
+    }
+
+    private static boolean isAssertStatement(JIfStmt ifStmt) {
+        // 假设assert语句是if语句中的条件为assert表达式的情况
+        // 可以根据实际情况调整判定逻辑
+        Value condition = ifStmt.getCondition();
+        return condition.toString().contains("assert");
+    }
+
+    private static void analyzeDependencies(Unit assertUnit, UnitGraph cfg) {
+        // 使用反向数据流分析
+        SimpleLocalDefs localDefs = new SimpleLocalDefs(cfg);
+        SimpleLiveLocals liveLocals = new SimpleLiveLocals(cfg);
+
+        for (Unit pred : cfg.getPredsOf(assertUnit)) {
+            List<Unit> defs = localDefs.getDefsOfAt((Local) ((JIfStmt) assertUnit).getCondition(), pred);
+            System.out.println("Assert statement at " + assertUnit + " depends on " + defs);
+        }
+
+        // 打印所有影响assert语句的语句
+        List<Unit> reachableUnits = getReachableUnits(assertUnit, cfg);
+        for (Unit unit : reachableUnits) {
+            System.out.println("Unit " + unit + " affects the assert statement.");
+        }
+    }
+
+    private static List<Unit> getReachableUnits(Unit target, UnitGraph cfg) {
+        List<Unit> reachableUnits = new ArrayList<>();
+        Queue<Unit> queue = new LinkedList<>();
+        Set<Unit> visited = new HashSet<>();
+
+        queue.add(target);
+        visited.add(target);
+
+        while (!queue.isEmpty()) {
+            Unit current = queue.poll();
+            reachableUnits.add(current);
+
+            for (Unit pred : cfg.getPredsOf(current)) {
+                if (!visited.contains(pred)) {
+                    visited.add(pred);
+                    queue.add(pred);
+                }
+            }
+        }
+
+        return reachableUnits;
+    }
+}
+

+ 22 - 0
src/main/java/com/frk/IntNumber.java

@@ -0,0 +1,22 @@
+package com.frk;
+
+/**
+ * @date 2024/3/19
+ */
+public class IntNumber {
+    private int a;
+    private int b;
+
+    public IntNumber(int a, int b) {
+        this.a = a;
+        this.b = b;
+    }
+
+    public int add () {
+        if (a == 1)
+            return a + b;
+        else if(a == 0)
+            return 0;
+        return -1;
+    }
+}

+ 74 - 0
src/main/java/com/frk/mycode/DBRead.java

@@ -0,0 +1,74 @@
+package com.frk.mycode;
+
+import com.atlassian.clover.CloverDatabase;
+import com.atlassian.clover.CodeType;
+import com.atlassian.clover.CoverageData;
+import com.atlassian.clover.CoverageDataSpec;
+import com.atlassian.clover.api.registry.*;
+import com.atlassian.clover.registry.entities.FullBranchInfo;
+import com.atlassian.clover.registry.entities.FullProjectInfo;
+import com.atlassian.clover.registry.entities.TestCaseInfo;
+
+import java.io.PrintStream;
+import java.util.BitSet;
+import java.util.Set;
+
+/**
+ * @date 2024/4/12
+ */
+public class DBRead {
+    public static void main(String[] args) throws Exception {
+//        String s = "D:\\learn\\junit-test\\test\\solve\\EightQueens_1664963256377\\target\\clover\\clover.db";
+        String s = "D:\\learn\\junit-test\\openclover\\target\\clover\\clover.db";
+        // read clover database together with coverage recording files, use time span=0 (latest build)
+        CloverDatabase db = CloverDatabase.loadWithCoverage(s, new CoverageDataSpec());
+        ProjectInfo projectInfo = db.getRegistry().getProject();
+        FullProjectInfo model = db.getModel(CodeType.ALL);
+        // print some project details
+        CoverageData cd= db.getCoverageData();
+        BitSet allHits = cd.getAllHits();
+        printProject(projectInfo, System.out, cd);
+
+
+    }
+
+    private static void printProject(ProjectInfo db, PrintStream out, CoverageData cd) {
+        for (PackageInfo packageInfo : db.getAllPackages()) {
+            out.println("package: " + packageInfo.getName());
+            for (FileInfo fileInfo : packageInfo.getFiles()) {
+                out.println("\tfile: " + fileInfo.getName());
+                for (ClassInfo classInfo : fileInfo.getClasses()) {
+                    out.println("\t\tclass: " + classInfo.getName());
+                    for (MethodInfo methodInfo : classInfo.getMethods()) {
+//                        int dataIndex = methodInfo.getDataIndex();
+//                        int dataLength = methodInfo.getDataLength();
+//                        BitSet methodCoverage = allHits.get(dataIndex, dataIndex + dataLength);
+                        System.out.println("\t\t\tMethod " + methodInfo.getName());
+                        for (BranchInfo branchInfo : methodInfo.getBranches()) {
+                            System.out.println("\t\t\t\tbrach: " + branchInfo.getContext());
+                            int dataIndex = branchInfo.getDataIndex();
+                            int dataLength = branchInfo.getDataLength();
+                            for (TestCaseInfo test : cd.getTests()) {
+                                // hitsFor表示 该测试方法命中了哪些 数据(语句、分支、方法)
+                                BitSet hitsFor = cd.getHitsFor(test);
+                                // 检查测试方法是否覆盖了这个分支
+                                BitSet branchHits = hitsFor.get(dataIndex, dataIndex + dataLength);
+                                if (!branchHits.isEmpty()) {
+                                    // System.out.println(hitsFor);
+                                    System.out.println("\t\t\t\t\tTest方法: " + test.getTestName() + " covers branch at " + branchInfo.getStartLine());
+                                }
+                            }
+//                            int startLine = branchInfo.getStartLine();
+//                            System.out.println("\t\t\t\t\tbranch Line: " + startLine);
+//                            FullBranchInfo fullBranchInfo = (FullBranchInfo) branchInfo;
+//                            Set<TestCaseInfo> testsCovering = cd.getTestsCovering(fullBranchInfo);
+//                            System.out.println("\t\t\t\t\tcoverage By: " + testsCovering);
+
+                        }
+                    }
+
+                }
+            }
+        }
+    }
+}

+ 157 - 0
src/main/java/com/frk/mycode/DecreaseTestCase.java

@@ -0,0 +1,157 @@
+package com.frk.mycode;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.atlassian.clover.registry.entities.TestCaseInfo;
+import com.frk.mycode.branch.BranchResult;
+import com.frk.mycode.mutation.Mutation;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+/**
+ * @date 2024/4/12
+ */
+public class DecreaseTestCase {
+    public static void main(String[] args) throws InterruptedException {
+        /**
+         * 跑一个试一下
+         */
+        if (false) {
+            testone();
+            return;
+        }
+        /**
+         * 项目一级路径,下一级目录应该是很多个子项目例如EightQueens_XXX
+         */
+        String sourcePath = "D:\\learn\\junit-test\\test\\EightQueens_N";
+        File sourceDir = new File(sourcePath);
+//        replaceAll(sourceDir);
+        int success = 0;
+        List<String> error = new ArrayList<>();
+        for (File tempFile : sourceDir.listFiles()) {
+            String path = tempFile.getPath();
+            if (tempFile.isDirectory()) {
+                        System.out.println("RUN " + path);
+                    if (!OpencloverRunUtil.FAILURE.equals(OpencloverRunUtil.execCMD(path))) {
+                        List<BranchResult> results = ReadCloverDB.readDB(path);
+                        if (results != null) {
+                            generateResultFile(results, tempFile.getAbsolutePath());
+                        }
+                    } else  {
+                        error.add(path);
+                    }
+            }
+        }
+        /**
+         * 分支覆盖统计
+         */
+        ReadCloverDB.printDecreaseInfo();
+        /**
+         * 打印编译不通过的信息
+         */
+        for (String s : error) {
+            System.out.println(s);
+        }
+        System.out.println(1.0 * success / sourceDir.listFiles().length);
+    }
+    public static void testone() {
+        String sourcePath = "D:\\learn\\junit-test\\test\\origin\\EightQueens_1665842723113";
+
+        File sourceDir = new File(sourcePath);
+        if (!OpencloverRunUtil.FAILURE.equals(OpencloverRunUtil.execCMD(sourcePath))) {
+            List<BranchResult> results = ReadCloverDB.readDB(sourcePath);
+            if (results != null) {
+                generateResultFile(results, sourceDir.getAbsolutePath());
+            }
+        } else  {
+        }
+    }
+    private static void generateResultFile(List<BranchResult> results, String absolutePath) {
+        JSONObject jsonObject = new JSONObject();
+        String jsonTarget = absolutePath + "//target//" + "myresult.json";
+        jsonObject.put("file", absolutePath);
+        JSONArray jsonArray = new JSONArray();
+        for (BranchResult branchResult : results) {
+            JSONObject tmp = new JSONObject();
+            tmp.put("branch", branchResult.getFilePath());
+            tmp.put("line", branchResult.getBranchStartLine());
+            tmp.put("isCover", branchResult.isCovered());
+            JSONArray coverArray = new JSONArray();
+            if (!Objects.isNull(branchResult.getTestCaseInfo()))
+                for (TestCaseInfo testCaseInfo : branchResult.getTestCaseInfo()) {
+                    coverArray.add(testCaseInfo.getClassName() + ":" + testCaseInfo.getTestName());
+                }
+            tmp.put("testCase", coverArray);
+            jsonArray.add(tmp);
+        }
+        jsonObject.put("coverMessage", jsonArray);
+        writeJSONString(jsonObject.toJSONString(), jsonTarget);
+
+    }
+    public static void writeJSONString(String jsonString, String outputFileName){
+        try {
+            BufferedWriter output = new BufferedWriter(new FileWriter(outputFileName));
+            output.write(jsonString);
+            output.close();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+    public static void  replaceAll(File sourceDir) {
+        File[] subProjects = sourceDir.listFiles(File::isDirectory);
+        String targetPath = "src\\main\\java\\net\\mooctest";
+        if (subProjects != null && subProjects.length > 0) {
+            // 获取第一个子项目的 "src\\main\\java\\net\\mooctest" 目录下的所有 Java 文件
+            File firstSubProject = subProjects[0];
+            File[] sourceFiles = getJavaFilesInDirectory(new File(firstSubProject, targetPath));
+
+            if (sourceFiles != null && sourceFiles.length > 0) {
+                // 遍历所有其他子项目
+                for (int i = 1; i < subProjects.length; i++) {
+                    // 替换每个子项目的 "src\\main\\java\\net\\mooctest" 目录下的 Java 文件
+                    replaceJavaFiles(subProjects[i].getPath(), sourceFiles);
+                }
+            } else {
+                System.out.println("未找到任何Java文件。");
+            }
+        } else {
+            System.out.println("未找到任何子项目。");
+            return;
+        }
+    }
+    public static File[] getJavaFilesInDirectory(File directory) {
+        if (!directory.exists() || !directory.isDirectory()) {
+            return null;
+        }
+        return directory.listFiles((dir, name) -> name.endsWith(".java"));
+    }
+
+    // 将目标目录下的所有 Java 文件替换为源文件
+    public static void replaceJavaFiles(String targetPath, File[] sourceFiles) {
+        for (File sourceFile : sourceFiles) {
+            String targetFilePath = targetPath + File.separator + "src\\main\\java\\net\\mooctest" + File.separator + sourceFile.getName();
+            Path target = Paths.get(targetFilePath);
+            if (Files.exists(target)) {
+                try {
+                    Files.copy(sourceFile.toPath(), target, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+                    System.out.println("替换文件:" + targetFilePath);
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            } else {
+                System.out.println("未找到目标文件:" + targetFilePath);
+            }
+        }
+    }
+
+}

+ 10 - 0
src/main/java/com/frk/mycode/Main.java

@@ -0,0 +1,10 @@
+package com.frk.mycode;
+
+/**
+ * @date 2024/3/31
+ */
+public class Main {
+    public static void main(String[] args) {
+        StringBuilder sb = new StringBuilder();
+    }
+}

+ 55 - 0
src/main/java/com/frk/mycode/MyThreadPool.java

@@ -0,0 +1,55 @@
+package com.frk.mycode;
+
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+/**
+ * @date 2024/5/17
+ */
+public class MyThreadPool {
+    private static ExecutorService executorService  =  createThreadPool();
+    /**
+     * 核心线程数
+     * 默认的核心线程数为1
+     *
+     */
+    private static final int CORE_POOL_SIZE = 17;
+    /**
+     * 最大线程数
+     * 默认的最大线程数是Integer.MAX_VALUE 即2<sup>31</sup>-1
+     */
+    private static final int MAX_POOL_SIZE = 17;
+    /**
+     * 缓冲队列数
+     * 默认的缓冲队列数是Integer.MAX_VALUE 即2<sup>31</sup>-1
+     */
+    private static final int QUEUE_CAPACITY = 100;
+
+    /**
+     * 允许线程空闲时间
+     * 默认的线程空闲时间为60
+     */
+    private static final int KEEP_ALIVE_SECONDS = 30;
+
+    /**
+     * 线程池前缀名
+     */
+    private static final String THREAD_NAME_PREFIX = "Task_Service_Async_";
+
+    /**
+     * allowCoreThreadTimeOut为true则线程池数量最后销毁到0
+     * allowCoreThreadTimeOut为false
+     * 销毁机制:超过核心线程数时,而且(超过最大值或者timeout过),就会销毁。
+     * 默认是false
+     */
+    private boolean allowCoreThreadTimeOut = false;
+
+    public static ExecutorService createThreadPool() {
+        ExecutorService executorService = Executors.newFixedThreadPool(10);
+        return executorService;
+    }
+    public static ExecutorService getThreadpoolInstance() {
+        return executorService;
+    }
+}

+ 309 - 0
src/main/java/com/frk/mycode/OpencloverRunUtil.java

@@ -0,0 +1,309 @@
+package com.frk.mycode;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+import org.dom4j.DocumentException;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+public class OpencloverRunUtil {
+	public static final String FAILURE = "FAILURE";
+
+	public static String execCMD(String filepath) {
+		String OpencloverRun = "";
+		try {
+			BufferedReader bufferedReader = null;
+			Process process = null;
+			OpencloverRun = "cmd /c mvn -file " + filepath + " clean clover:setup test clover:aggregate clover:clover";
+			process = Runtime.getRuntime().exec(OpencloverRun);
+			bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+			String line = null;
+			while ((line = bufferedReader.readLine()) != null) {
+				if (line.contains("BUILD FAILURE")) {
+					OpencloverRun = "FAILURE";
+				}
+//				System.out.println(line);
+			}
+			bufferedReader.close();
+			process.destroy();
+			process = null;
+		} catch (IOException e) {
+			// e.printStackTrace();
+			OpencloverRun = "FAILURE";
+		}
+		return OpencloverRun;
+	}
+	
+	@SuppressWarnings("static-access")
+	public static String execSSH(String filepath) {
+		Runtime runtime = Runtime.getRuntime();
+		String JcovRun = "";
+		try {
+			BufferedReader bufferedReader = null;
+			Process process = null;
+			JcovRun = "/usr/bin/env mvn -f " + filepath + " clean clover:setup test clover:aggregate clover:clover";
+			// System.out.println(jacocoRun);
+			process = runtime.getRuntime().exec(JcovRun);
+			bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+			String line = null;
+			while ((line = bufferedReader.readLine()) != null) {
+				// System.out.println(line);
+				if (line.contains("BUILD FAILURE")) {
+					JcovRun = "FAILURE";
+				}
+			}
+			bufferedReader.close();
+			process.destroy();
+			process = null;
+		} catch (IOException e) {
+			// e.printStackTrace();
+			JcovRun = "FAILURE";
+		}
+		return JcovRun;
+	}
+	
+	@SuppressWarnings("static-access")
+	public static String execSSH2(String filepath) {
+		Runtime runtime = Runtime.getRuntime();
+		String JcovRun = "";
+		try {
+			BufferedReader bufferedReader = null;
+			Process process = null;
+			JcovRun = "/usr/local/bin/mvn -f " + filepath + " clean clover:setup test clover:aggregate clover:clover";
+			// System.out.println(jacocoRun);
+			process = runtime.getRuntime().exec(JcovRun);
+			bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+			String line = null;
+			while ((line = bufferedReader.readLine()) != null) {
+				// System.out.println(line);
+				if (line.contains("BUILD FAILURE")) {
+					JcovRun = "FAILURE";
+				}
+			}
+			bufferedReader.close();
+			process.destroy();
+			process = null;
+		} catch (IOException e) {
+			// e.printStackTrace();
+			JcovRun = "FAILURE";
+		}
+		return JcovRun;
+	}
+
+	@SuppressWarnings("static-access")
+	public static String execSSH3(String filepath) {
+		Runtime runtime = Runtime.getRuntime();
+		String JcovRun = "";
+		try {
+			BufferedReader bufferedReader = null;
+			Process process = null;
+			JcovRun = "mvn -f " + filepath + " clean clover:setup test clover:aggregate clover:clover";
+			// System.out.println(jacocoRun);
+			process = runtime.getRuntime().exec(JcovRun);
+			bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+			String line = null;
+			while ((line = bufferedReader.readLine()) != null) {
+				// System.out.println(line);
+				if (line.contains("BUILD FAILURE")) {
+					JcovRun = "FAILURE";
+				}
+			}
+			bufferedReader.close();
+			process.destroy();
+			process = null;
+		} catch (IOException e) {
+			// e.printStackTrace();
+			JcovRun = "FAILURE";
+		}
+		return JcovRun;
+	}
+	
+	public static void parseXML(String filepath) throws DocumentException {
+		String resultpath = filepath + "/target/mcnode/result";
+		File resultDir = new File(resultpath);
+		if (!resultDir.exists())
+			resultDir.mkdirs();
+		String inputXMLFilePath = filepath + "/target/site/clover/clover.xml";
+		String outputCatchNodeFilePath = filepath + "/target/mcnode/result/coverage.json";
+		String outputNodeFilePath = filepath + "/target/mcnode/result/project.json";
+		String outputColorNodeFilePath = filepath + "/target/mcnode/result/color.json";
+
+		 String[] args= {inputXMLFilePath, outputCatchNodeFilePath,
+		 outputNodeFilePath, outputColorNodeFilePath};
+		 ParseXML.main(args);
+		 
+	}
+
+	public static JSONArray CatchJson(String path) {
+		String laststr = "";
+		JSONArray catchnode = new JSONArray();
+		File file = new File(path);
+		if (file.exists()) {
+			System.out.println("here is coverage");
+			BufferedReader reader = null;
+			try {
+				reader = new BufferedReader(new FileReader(file));
+				String tempString = null;
+				// int line=1;
+				while ((tempString = reader.readLine()) != null) {
+					// System.out.println("line"+line+":"+tempString);
+					laststr = laststr + tempString;
+					// line++;
+				}
+				catchnode = new JSONArray(laststr);
+				reader.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+				return catchnode;
+			} finally {
+				if (reader != null) {
+					try {
+						reader.close();
+					} catch (IOException el) {
+						return catchnode;
+					}
+				}
+			}
+			// System.out.println(catchnode);
+			return catchnode;
+		} else {
+			System.out.println("no coverage");
+			System.out.println(path);
+			return catchnode;
+		}
+
+	}
+
+	public static JSONObject CatchObject(String path) {
+
+		String laststr = "";
+		JSONObject catchnode = new JSONObject();
+		File file = new File(path);
+		if (file.exists()) {
+			System.out.println("here is coverage");
+			BufferedReader reader = null;
+			try {
+				reader = new BufferedReader(new FileReader(file));
+				String tempString = null;
+				// int line=1;
+				while ((tempString = reader.readLine()) != null) {
+					// System.out.println("line"+line+":"+tempString);
+					laststr = laststr + tempString;
+					// line++;
+				}
+				catchnode = new JSONObject(laststr);
+				reader.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+				return catchnode;
+			} finally {
+				if (reader != null) {
+					try {
+						reader.close();
+					} catch (IOException el) {
+						return catchnode;
+					}
+				}
+			}
+			return catchnode;
+		} else {
+			System.out.println("no coverage");
+			System.out.println(path);
+			return catchnode;
+		}
+	}
+
+	public static String[] CalculateNode(JSONArray catchNode, JSONObject templateNode) {
+		String[] score = new String[3];
+		double[] sum = { 0, 0, 0 };
+		double[] covered = { 0, 0, 0 };
+		JSONArray nodes = new JSONArray(templateNode.get("nodes").toString());
+		double weight = 0;
+		System.out.println(catchNode.length());
+		System.out.println(templateNode.length());
+		if (catchNode.length() > 0 && templateNode.length() > 0) {
+			Map<String, Double> NodeMap = new HashMap<String, Double>();
+			for (int j = 0; j < nodes.length(); j++) {
+				JSONObject tnode = new JSONObject(nodes.get(j).toString());
+				NodeMap.put(tnode.get("name").toString(),
+						(double) 1/* Double.parseDouble(tnode.get("weight").toString()) */);
+			}
+			for (int i = 0; i < catchNode.length(); i++) {
+				if (catchNode.get(i).toString().contains("statement")) {
+					JSONObject node = new JSONObject(catchNode.get(i).toString());
+					weight = NodeMap.get(node.get("nodeName").toString());
+					sum[0] = sum[0] + weight;
+					if (catchNode.get(i).toString().contains("\"ifCatch\":true"))
+						covered[0] = covered[0] + weight;
+				} else if (catchNode.get(i).toString().contains("branch")) {
+					JSONObject node = new JSONObject(catchNode.get(i).toString());
+					// catchNode中的NodeName 对应 Node里面的name 二者是一样的
+					weight = NodeMap.get(node.get("nodeName").toString());
+					sum[1] = sum[1] + weight;
+					if (catchNode.get(i).toString().contains("\"ifCatch\":true"))
+						covered[1] = covered[1] + weight;
+				} else if (catchNode.get(i).toString().contains("method")) {
+					JSONObject node = new JSONObject(catchNode.get(i).toString());
+					weight = NodeMap.get(node.get("nodeName").toString());
+					sum[2] = sum[2] + weight;
+					System.out.println(catchNode.get(i).toString());
+					if (catchNode.get(i).toString().contains("\"ifCatch\":true"))
+						covered[2] = covered[2] + weight;
+				}
+			}
+			DecimalFormat dcmFmt = new DecimalFormat("0.00");
+			String linescore = dcmFmt.format((covered[0] / sum[0]) * 100);
+			String branchscore = dcmFmt.format((covered[1] / sum[1]) * 100);
+			String conditionscore = dcmFmt.format((covered[2] / sum[2]) * 100);
+			score[0] = linescore;
+			score[1] = branchscore;
+			score[2] = conditionscore;
+			System.out.println(score[0] + "!!!" + score[1] + "???" + score[2]);
+		} else {
+			score[0] = "run failure";
+			score[1] = "run failure";
+			score[2] = "run failure";
+		}
+		return score;
+	}
+	
+	public static void main(String[] args) throws UnsupportedEncodingException, DocumentException {
+		System.out.println("start: "+System.currentTimeMillis());
+		Scanner in = new Scanner(System.in);
+		String path = in.next();
+		execCMD(path);
+		System.out.println("mvn end: "+System.currentTimeMillis());
+		parseXML(path); 
+		JSONArray catchNode = CatchJson(path + "/target/mcnode/result/coverage.json");
+		JSONObject templateNode = CatchObject(path + "/target/mcnode/result/project.json");
+		String[] score = CalculateNode(catchNode, templateNode);
+		System.out.println("local end: "+System.currentTimeMillis());
+		System.out.println("http end: "+System.currentTimeMillis());
+		System.out.println("Line Cov: " + score[0] + " Branch Cov: " + score[1] + " Condition Cov:" + score[2]);
+		System.out.println(System.currentTimeMillis());
+	}
+	
+//	public static void main(String[] args) throws UnsupportedEncodingException, DocumentException {
+//		  System.out.println("start: "+System.currentTimeMillis());
+//		  execSSH2("/Users/insomnialee/mooctest/projects/4214/8212/Nextday");
+//		  System.out.println("mvn end: "+System.currentTimeMillis());
+//		  parseXML("/Users/insomnialee/mooctest/projects/4214/8212/Nextday"); 
+//		  JSONArray catchNode = CatchJson("/Users/insomnialee/mooctest/projects/4214/8212/Nextday/target/mcnode/result/coverage.json");
+//		  JSONObject templateNode = CatchObject("/Users/insomnialee/mooctest/projects/4214/8212/Nextday/target/mcnode/result/project.json");
+//		  String[] score = CalculateNode(catchNode, templateNode);
+//		  System.out.println("local end: "+System.currentTimeMillis());
+//		  System.out.println("http end: "+System.currentTimeMillis());
+//		  System.out.println(score[0] + "!!!" + score[1] + "???" + score[2]);
+//		  System.out.println(System.currentTimeMillis());
+//		 }
+
+}

+ 76 - 0
src/main/java/com/frk/mycode/PITesrDecrease.java

@@ -0,0 +1,76 @@
+package com.frk.mycode;
+
+import com.atlassian.clover.registry.entities.TestCaseInfo;
+import com.frk.mycode.branch.MyBranchInfo;
+import com.frk.mycode.mutation.Mutation;
+import com.frk.mycode.mutation.MyTestCase;
+
+import java.io.File;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * @date 2024/5/17
+ */
+public class PITesrDecrease {
+    /**
+     * 被覆盖的分支-对应的覆盖该分支的测试用例
+     */
+    static HashMap<Mutation, MyTestCase> mutationMyTestCaseHashMap = new HashMap<>();
+    /**
+     * 所有的变异体信息
+     */
+    public static LinkedHashSet<Mutation> allMutationInfo = new LinkedHashSet<>();
+    /**
+     * 已经存储在约简库中的测试用例
+     */
+    static HashSet<MyTestCase> existTestCase = new HashSet<>();
+
+    /**
+     * 已经存储在约简库中的测试用例
+     */
+    static List<MyTestCase> allTestCases = new ArrayList<>();
+    public static void mutationDecrease(String path) {
+        ExecutorService executorService = MyThreadPool.getThreadpoolInstance();
+        List<Future<List<Mutation>>> futures = new ArrayList<>();
+        File projectFile = new File(path);
+        int count =0;
+        for (File file : projectFile.listFiles(File::isDirectory)) {
+//            if (count++ == 30)break;
+            Future<List<Mutation>> future =  executorService.submit(()-> PITestUtil.runAndParsePITest(file.getAbsolutePath()));
+            futures.add(future);
+        }
+        for (Future<List<Mutation>> future : futures) {
+            List<Mutation> mutationList = null;
+            try {
+                mutationList = future.get(60, TimeUnit.SECONDS);
+                if (mutationList == null) continue;
+                allMutationInfo.addAll(mutationList);
+                for (Mutation mutation : mutationList) {
+                    if (mutationMyTestCaseHashMap.get(mutation) == null) {
+                        if (!mutation.getKilledByTestCases().isEmpty()) {
+                            mutationMyTestCaseHashMap.put(mutation, mutation.getKilledByTestCases().get(0));
+                            existTestCase.add(mutation.getKilledByTestCases().get(0));
+                        }
+                    }
+                }
+            } catch (InterruptedException | ExecutionException | TimeoutException e) {
+                future.cancel(true);
+                e.printStackTrace();
+            }
+        }
+        System.out.println("TotalMutation: " + allMutationInfo.size());
+        System.out.println(allMutationInfo);
+        System.out.println("Killed Mutation: " + mutationMyTestCaseHashMap.size());
+        System.out.println("TotalTestCse: " + allTestCases.size());
+        System.out.println(allTestCases);
+        System.out.println("existTestCases: " + existTestCase.size());
+        System.out.println("Mutation Killed Percent: " + mutationMyTestCaseHashMap.size()*100.0 / allMutationInfo.size());
+        System.out.println("Decrease Ratio: " + ((allTestCases.size() - existTestCase.size()*1.0) / allTestCases.size())*100.0);
+        System.out.println(mutationMyTestCaseHashMap);
+    }
+
+    public static void main(String[] args) {
+
+    }
+}

+ 180 - 0
src/main/java/com/frk/mycode/PITestUtil.java

@@ -0,0 +1,180 @@
+package com.frk.mycode;
+
+import com.alibaba.fastjson.JSONObject;
+import com.frk.mycode.mutation.Mutation;
+import com.frk.mycode.mutation.MyTestCase;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * @date 2024/4/28
+ */
+public class PITestUtil {
+
+    public static List<Mutation> runAndParsePITest(String projectPath) {
+        String result = execCMD(projectPath);
+        if (result.equals("FAILURE")) {
+            return null;
+        }
+        String pitestPath = projectPath + File.separator + "target" + File.separator + "pit-reports";
+        File file = new File(pitestPath);
+        if (!file.exists()) {
+            return null;
+        }
+        ArrayList<Mutation> resultList = new ArrayList<>();
+        for (File singlePackageFile : file.listFiles(File::isDirectory)) {
+//            System.out.println(singlePackageFile);
+            List<Mutation> mutationList = parseSinglePackageXML(singlePackageFile.getAbsolutePath());
+            resultList.addAll(mutationList);
+        }
+        int killedCount = 0;
+        for (Mutation mutation : resultList) {
+            if (!mutation.getKilledByTestCases().isEmpty()) {
+                killedCount++;
+            }
+        }
+        System.out.println("Project: " + projectPath + "Total Mutation: " + resultList.size() + " Killed Mutation: " + killedCount + " percent: " + killedCount*100.0 / resultList.size() );
+        String jsonString = JSONObject.toJSONString(resultList);
+        File writeFile = new File(file.getAbsolutePath() + File.separator + "result.json");
+        try(Writer write = new OutputStreamWriter(new FileOutputStream(writeFile), StandardCharsets.UTF_8)) {
+            write.write(jsonString);
+            write.flush();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return resultList;
+    }
+    public static String execCMD(String filepath) {
+        String PITestRun = "";
+        try {
+            BufferedReader bufferedReader = null;
+            Process process = null;
+            PITestRun = "cmd /c mvn -file " + filepath + " clean test-compile org.pitest:pitest-maven:mutationCoverage";
+            process = Runtime.getRuntime().exec(PITestRun);
+            bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+            String line = null;
+            while ((line = bufferedReader.readLine()) != null) {
+                if (line.contains("BUILD FAILURE")) {
+                    PITestRun = "FAILURE";
+                }
+//                System.out.println(line);
+            }
+            bufferedReader.close();
+            process.destroy();
+            process = null;
+        } catch (IOException e) {
+            // e.printStackTrace();
+            PITestRun = "FAILURE";
+        }
+        return PITestRun;
+    }
+
+    /**
+     *
+     * @param xmlDirPath /项目/target/pit-reports/包的路径
+     * @return
+     * @throws IOException
+     */
+    public static List<Mutation> parseSinglePackageXML(String xmlDirPath) {
+        ArrayList<Mutation> mutations = new ArrayList<>();
+        File file = new File(xmlDirPath);
+        for (File listFile : file.listFiles()) {
+            if (listFile.isFile()) {
+                if (listFile.getName().endsWith(".java.html")) {
+                    List<Mutation> mutations1 = PITestUtil.parseXML(listFile.getAbsolutePath());
+                    mutations.addAll(mutations1);
+                }
+            } else if (listFile.isDirectory()) {
+                mutations.addAll(parseSinglePackageXML(listFile.getAbsolutePath()));
+            }
+
+        }
+//        System.out.println(mutations);
+        return mutations;
+    }
+    public static List<Mutation> parseXML(String xmlPath) {
+        File file = new File(xmlPath);
+        Document doc = null;
+        try {
+            doc = Jsoup.parse(file, "utf-8");
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        Elements testMethods = doc.select("ul li");
+        HashSet<MyTestCase> myTestCaseHashSet = new HashSet<>();
+        for (Element testMethod : testMethods) {
+            String methodName = testMethod.text();
+            if (!methodName.contains("("))continue;
+            String testMethodPath = methodName.substring(0, methodName.indexOf("("));
+            int index = testMethodPath.lastIndexOf(".");
+            MyTestCase myTestCase = new MyTestCase(xmlPath, testMethodPath.substring(0, index), testMethodPath.substring(index+1));
+            myTestCaseHashSet.add(myTestCase);
+//            System.out.println(myTestCase);
+        }
+//        System.out.println(myTestCaseHashSet);
+        PITesrDecrease.allTestCases.addAll(myTestCaseHashSet);
+        Elements mutations = doc.select("tr");
+        List<Mutation> mutationList = new ArrayList<>();
+        for (Element mutation : mutations) {
+            Elements mutationInfos = mutation.select("p");
+            if (mutationInfos.isEmpty()) {
+                continue;
+            }
+            Elements aTags = mutation.select("td a");
+            if (!aTags.isEmpty()) {
+                String href = aTags.first().attr("href");
+                String id = href.substring(href.lastIndexOf('_') + 1);
+//                System.out.println("Mutation ID: " + id);
+                for (Element mutationInfo : mutationInfos) {
+//                    System.out.println("Mutation Info: " + mutationInfo.text());
+                    Elements groudId = mutationInfo.select("span.pop");
+
+                    String infoText = mutationInfo.text();
+//                    System.out.println(groudId.text());
+                    int endIndex = groudId.text().indexOf('.');
+                    String type = groudId.text().substring(0, endIndex);
+                    String location = infoText.split(" ")[3];
+                    List<MyTestCase> killedByTestCases = new ArrayList<>();
+                    int end = infoText.indexOf("→");
+                    int begin = infoText.lastIndexOf(":");
+                    String mutationDeTail = infoText.substring(begin+1, end).trim();
+//                    type += " " + mutationDeTail;
+                    String mutationResult = infoText.contains("→") ? infoText.split("→")[1].trim() : "none";
+                    MyTestCase tesCase = null;
+                    Mutation mutationObj = new Mutation(file.getParentFile().getName(), Integer.parseInt(id), type, location, file.getName().substring(0, file.getName().lastIndexOf(".html")),killedByTestCases);
+                    if ((tesCase = findTestCases(myTestCaseHashSet, mutationInfo.text())) != null) {
+                        killedByTestCases.add(tesCase);
+                    }
+                    mutationList.add(mutationObj);
+                }
+            }
+        }
+        return mutationList;
+    }
+
+    private static MyTestCase findTestCases(HashSet<MyTestCase> myTestCaseHashSet, String text) {
+        for (MyTestCase myTestCase : myTestCaseHashSet) {
+            String s = myTestCase.getPackagePath() + "." + myTestCase.getMethodName();
+            if (text.contains(s)) {
+                return myTestCase;
+            }
+        }
+        return null;
+    }
+
+    public static void main(String[] args) throws IOException {
+//        String s = parseXML("D:\\learn\\junit-test\\openclover\\src\\main\\resources\\IntNumber.java.html").toString();
+//        System.out.println(s);
+        String s = "D:\\learn\\junit-test\\openclover";
+        runAndParsePITest(s);
+
+    }
+}

+ 340 - 0
src/main/java/com/frk/mycode/ParseXML.java

@@ -0,0 +1,340 @@
+package com.frk.mycode;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class ParseXML {
+
+    /**
+     * ��node�б�ת��Node������д��json�ļ�
+     * @param nodesList �б�����ÿ��node�ľ�����Ϣ�����ƣ�λ�ã����Ǵ�����
+     * @param edgesList �б�����ÿ������ߵ���Ϣ�������㣬�����㣬�ߵ�ֵ
+     * @return JSONObject����������JSONArray���ֱ��Ǹ����������ͣ�node������Ϣ������ߵľ�����Ϣ
+     */
+    public JSONObject getNode(List<List<String>> nodesList, List<List<String>> edgesList){
+        String[] categories = {"openclover-statement", "openclover-branch", "openclover-method"};
+        JSONObject result = new JSONObject(true);
+
+        JSONArray categoriesJson = new JSONArray();
+        JSONArray nodesJson = new JSONArray();
+        JSONArray edgesJson = new JSONArray();
+
+        //Category
+        for (String category : categories) {
+            JSONObject tmp = new JSONObject(true);
+            tmp.put("name", category);
+            categoriesJson.add(tmp);
+        }
+
+        //Node
+        for (List<String> nodeList : nodesList){
+            JSONObject node = new JSONObject(true);
+            node.put("name", nodeList.get(0));
+            node.put("category", nodeList.get(1));
+            node.put("location", nodeList.get(2));
+            nodesJson.add(node);
+        }
+
+        //Edge
+        for (List<String> edgeList : edgesList){
+            JSONObject node = new JSONObject(true);
+            node.put("source", edgeList.get(0));
+            node.put("target", edgeList.get(1));
+            node.put("value", "openclover-branch");
+            edgesJson.add(node);
+        }
+
+        result.put("categories", categoriesJson);
+        result.put("nodes", nodesJson);
+        result.put("edges", edgesJson);
+        return result;
+
+    }
+
+    /**
+     * ��node�б�ת��catchNode������д��json�ļ�
+     * @param nodesList �б�����ÿ��node�ľ�����Ϣ�����ƣ�λ�ã����Ǵ�����
+     * @return ת�����JSONArray������node���ƣ������Լ��Ƿ񱻸���
+     */
+    public JSONArray getCatchNode(List<List<String>> nodesList){
+
+        JSONArray result = new JSONArray();
+        for (List<String> nodeList : nodesList) {
+            JSONObject catchNode = new JSONObject(true);
+            catchNode.put("nodeName", nodeList.get(0));
+            catchNode.put("category", nodeList.get(1));
+            catchNode.put("ifCatch", nodeList.get(3).equals("0") ? false : true);
+
+            result.add(catchNode);
+        }
+
+        return result;
+    }
+
+    /**
+     * ��color�б�ת����color node��Ϣ����д��json�ļ�
+     * @param colorsList �б�����ÿ��node����ɫ��Ϣ
+     * @return ת�����JSONArray������nodeλ�ú�����ɫ
+     */
+    public JSONArray getColorNode(List<List<String>> colorsList){
+
+        JSONArray result = new JSONArray();
+
+//        for (List<String> colorList : colorsList) {
+//            JSONObject catchNode = new JSONObject(true);
+//            catchNode.put("location", colorList.get(0));
+//            catchNode.put("color", colorList.get(1));
+//
+//            result.add(catchNode);
+//        }
+
+        //2019-12-08 �޸�colorNode��ʽ
+        List<String> fileList = new ArrayList<>();
+        Map<String, String> map = new HashMap<>();
+        for (List<String> colorList : colorsList) {
+            String fileName = colorList.get(0).substring(0, colorList.get(0).indexOf(".java")+5);
+            if (!fileList.contains(fileName)) fileList.add(fileName);
+            String lineNum = colorList.get(0).substring(colorList.get(0).indexOf(".java")+6);
+
+            if (map.get(fileName) == null) {
+                map.put(fileName, lineNum + ":" + colorList.get(1));
+            }else {
+                String lineInfo = map.get(fileName);
+                map.put(fileName, lineInfo + " " +lineNum + ":" + colorList.get(1));
+            }
+
+        }
+
+        for (String fileName : fileList){
+            JSONObject jsonObject = new JSONObject();
+
+
+            JSONArray jsonArray_file = new JSONArray();
+            for (String lineInfo : map.get(fileName).split(" ")){
+                JSONArray jsonArray_line = new JSONArray();
+                jsonArray_line.add(Integer.parseInt(lineInfo.split(":")[0]));
+                jsonArray_line.add(Integer.parseInt(lineInfo.split(":")[1]));
+                jsonArray_file.add(jsonArray_line);
+            }
+            jsonObject.put("path", fileName);
+            jsonObject.put("color", jsonArray_file);
+
+
+            result.add(jsonObject);
+        }
+
+
+        return result;
+    }
+
+    /**
+     * ������Ϣ�ļ�������xml��ʽ
+     * @param fileName ��Ҫ������xml�ĵ�
+     * @return ���������б��ֱ���node��edge �� color�б�
+     */
+    public List<List<List<String>>>  parseXML(String fileName){
+
+        File inputXml = new File(fileName);
+        SAXReader saxReader = new SAXReader();
+        List<List<String>> nodesList = new ArrayList<>(); // element: name, type, location, count
+        List<List<String>> colorsList = new ArrayList<>(); // element: path, line, color(0,1,2)
+        List<List<String>> edgesList = new ArrayList<>(); // element: branch-true, branch-false
+        int numStatement = 0, numBranch = 0, numMethod = 0;
+
+        try {
+            Document document = saxReader.read(inputXml);
+            Element nodeRoot = document.getRootElement();
+            Element nodeProject = nodeRoot.element("project");
+            // 遍历一个 project下的 所有 package 元素
+            for (Iterator iteratorPackage = nodeProject.elementIterator("package"); iteratorPackage.hasNext();) {
+                Element nodePackage = (Element) iteratorPackage.next();
+                String namePackage = nodePackage.attributeValue("name").replace(".", File.separator);
+                // 遍历一个 package下所有的 file元素, 也就是所有的.java源码文件
+                for (Iterator iteratorFile = nodePackage.elementIterator("file"); iteratorFile.hasNext();) {
+                    Element nodeFile = (Element) iteratorFile.next();
+                    String nameFile = nodeFile.attributeValue("name");
+
+                    String methodInfo = null;
+                    // 遍历一个 file下所有的 line元素, 每行
+                    for (Iterator iteratorLine = nodeFile.elementIterator("line"); iteratorLine.hasNext();) {
+                        Element nodeLine = (Element) iteratorLine.next();
+
+                        String lineType = nodeLine.attributeValue("type");
+                        String lineIndex = namePackage + File.separator + nameFile + File.separator + nodeLine.attributeValue("num");
+                        List nodeList;
+                        List colorList;
+                        List edgeList;
+                        switch (lineType){
+                            case "stmt":
+                                String lineCount = nodeLine.attributeValue("count");
+                                String lineName = "statement-" + ++numStatement + "-" + methodInfo;
+
+                                //node
+                                nodeList= new ArrayList();
+                                nodeList.add(lineName);
+                                nodeList.add("openclover-"+"statement");
+                                nodeList.add(lineIndex);
+                                nodeList.add(lineCount);
+                                nodesList.add(nodeList);
+
+                                //color
+                                colorList= new ArrayList();
+                                colorList.add(lineIndex);
+                                colorList.add(lineCount.equals("0") ? "0" : "2");
+                                colorsList.add(colorList);
+
+                                break;
+                            case "cond":
+//                                branch�����Ƿ�Ҳ��һ����䣬������ȥ��֮ǰ����Ľڵ�
+                                // 分支覆盖branch统计
+//                                nodesList.remove(nodesList.size()-1);
+//                                colorsList.remove(colorsList.size()-1);
+                                String branchFalseCount = nodeLine.attributeValue("falsecount");
+                                String branchTrueCount = nodeLine.attributeValue("truecount");
+
+                                String branchTrueName = "branch-" + ++numBranch + "-" + methodInfo;
+                                String branchFalseName = "branch-" + ++numBranch + "-" + methodInfo;
+
+                                //node
+                                nodeList = new ArrayList();
+                                /*
+                                true nodeList包含:
+                                1.分支行号
+                                2.分支标识 “openclover-branch”
+                                3. 行索引 即哪个包下的哪个文件
+                                4. 覆盖条件true的次数
+                                 */
+                                nodeList.add(branchTrueName);
+                                nodeList.add("openclover-"+"branch");
+                                nodeList.add(lineIndex + "-true");
+                                nodeList.add(branchTrueCount);
+                                nodesList.add(nodeList);
+                                /*
+                                false nodeList包含:
+                                1.分支行号
+                                2.分支标识 “openclover-branch”
+                                3. 行索引 即哪个包下的哪个文件
+                                4. 覆盖条件false的次数
+                                 */
+                                nodeList = new ArrayList();
+                                nodeList.add(branchFalseName);
+                                nodeList.add("openclover-"+"branch");
+                                nodeList.add(lineIndex + "-false");
+                                nodeList.add(branchFalseCount);
+                                nodesList.add(nodeList);
+
+                                //color
+                                colorList= new ArrayList();
+                                colorList.add(lineIndex);
+                                colorList.add(branchTrueCount.equals("0") && branchFalseCount.equals("0") ? "0" : !branchTrueCount.equals("0") && !branchFalseCount.equals("0") ? "2" : "1");
+                                colorsList.add(colorList);
+
+                                //edge
+                                edgeList = new ArrayList();
+                                edgeList.add(branchTrueName);
+                                edgeList.add(branchFalseName);
+                                edgesList.add(edgeList);
+                                break;
+                            case "method":
+                                String methodCount = nodeLine.attributeValue("count");
+                                methodInfo = nodeLine.attributeValue("signature");
+                                String methodName = "method-" + ++numMethod + "-" + methodInfo;
+
+                                //node
+                                nodeList= new ArrayList();
+                                nodeList.add(methodName);
+                                nodeList.add("openclover-"+"method");
+                                nodeList.add(lineIndex);
+                                nodeList.add(methodCount);
+                                nodesList.add(nodeList);
+
+                                //color
+                                colorList= new ArrayList();
+                                colorList.add(lineIndex);
+                                colorList.add(methodCount.equals("0") ? "0" : "2");
+                                colorsList.add(colorList);
+                                break;
+                            default:
+                                break;
+                        }
+                    }
+
+                }
+            }
+
+        } catch (DocumentException e) {
+            System.out.println(e.getMessage());
+        }
+        List<List<List<String>>> xmlResult = new ArrayList<>();
+        xmlResult.add(nodesList);
+        xmlResult.add(colorsList);
+        xmlResult.add(edgesList);
+        return xmlResult;
+
+    }
+
+    /**
+     * д��json�ַ���
+     * @param jsonString ��Ҫд���node��Ϣ
+     * @param outputFileName ��Ҫд����ļ�
+     */
+    public void writeJSONString(String jsonString, String outputFileName){
+        try {
+            BufferedWriter output = new BufferedWriter(new FileWriter(outputFileName));
+            output.write(jsonString);
+            output.close();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+
+    public static void main(String[] args){
+
+        //��������
+        String inputXMLFilePath = args[0];//"clover.xml"
+        String outputCatchNodeFilePath = args[1];//"coverage.json"
+        String outputNodeFilePath = args[2];//"project.json"
+        String outputColorNodeFilePath = args[3];//"color.json"
+
+//        String inputXMLFilePath = "clover.xml";
+//        String outputCatchNodeFilePath = "coverage.json";
+//        String outputNodeFilePath = "project.json";
+//        String outputColorNodeFilePath = "color.json";
+
+        //����xml�����ĵ�
+        ParseXML parseXML = new ParseXML();
+        List<List<List<String>>> xmlResult = parseXML.parseXML(inputXMLFilePath);
+        List<List<String>> nodesList = xmlResult.get(0);
+        List<List<String>> colorsList = xmlResult.get(1);
+        List<List<String>> edgesList = xmlResult.get(2);
+
+        //���catchNode
+        JSONArray catchNodeJsonArray = parseXML.getCatchNode(nodesList);
+        parseXML.writeJSONString(catchNodeJsonArray.toString(), outputCatchNodeFilePath);
+
+        //���node
+        JSONObject nodeJsonObject = parseXML.getNode(nodesList, edgesList);
+        parseXML.writeJSONString(nodeJsonObject.toString(), outputNodeFilePath);
+
+        //���colorNode
+        JSONArray colorNodeJsonArray = parseXML.getColorNode(colorsList);
+        parseXML.writeJSONString(colorNodeJsonArray.toString(), outputColorNodeFilePath);
+
+    }
+}

+ 151 - 0
src/main/java/com/frk/mycode/ReadCloverDB.java

@@ -0,0 +1,151 @@
+package com.frk.mycode;
+
+import com.atlassian.clover.CloverDatabase;
+import com.atlassian.clover.CoverageData;
+import com.atlassian.clover.CoverageDataSpec;
+import com.atlassian.clover.api.registry.*;
+import com.atlassian.clover.registry.entities.FullFileInfo;
+import com.atlassian.clover.registry.entities.TestCaseInfo;
+import com.frk.mycode.branch.BranchResult;
+import com.frk.mycode.branch.MyBranchInfo;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * @date 2024/4/12
+ */
+public class ReadCloverDB {
+    static int totalCount;
+    /**
+     * 被覆盖的分支-对应的覆盖该分支的测试用例
+     */
+    static HashMap<MyBranchInfo, TestCaseInfo> branchInfoTestCaseInfoHashMap = new HashMap<>();
+    /**
+     * 所有的分支信息
+     */
+    static LinkedHashSet<MyBranchInfo> allBranchInfo = new LinkedHashSet<>();
+    /**
+     * 已经存储在约简库中的测试用例
+     */
+    static HashSet<TestCaseInfo> existTestCase = new HashSet<>();
+
+    /**
+     * 已经存储在约简库中的测试用例
+     */
+    static List<TestCaseInfo> allTestCases = new ArrayList<>();
+
+    static ArrayList<BranchResult> nowBranToTestCase;
+    public static void main(String[] args) throws Exception {
+        String s = "D:\\learn\\junit-test\\test\\solve\\EightQueens_1664963256377";
+        readDB(s);
+        System.out.println("总分支数量 " + allBranchInfo.size());
+        System.out.println("约简后的测试用例数量 " + existTestCase.size());
+        System.out.println("约简后的分支覆盖率 " + branchInfoTestCaseInfoHashMap.size()*1.0/allBranchInfo.size() * 100);
+    }
+
+    public static List<BranchResult> readDB(String s) {
+        String path = s + "\\target\\clover\\clover.db";
+        File file = new File(path);
+        if (!file.exists())
+            return null;
+        try {
+            nowBranToTestCase = new ArrayList<>();
+            CloverDatabase db = CloverDatabase.loadWithCoverage(path, new CoverageDataSpec());
+            ProjectInfo projectInfo = db.getRegistry().getProject();
+            CoverageData cd = db.getCoverageData();
+            allTestCases.addAll(cd.getTests());
+            parseProject(projectInfo, System.out, cd, path);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return nowBranToTestCase;
+    }
+    public static void printDecreaseInfo() {
+        System.out.println("===============================RESULT SHOW================================");
+        System.out.println("总分支数量: " + allBranchInfo.size());
+        System.out.println("约简前的测试用例数量: " + allTestCases.size());
+        System.out.println("约简后的测试用例数量: " + existTestCase.size());
+        System.out.println("约简后的分支覆盖率: " + branchInfoTestCaseInfoHashMap.size()*1.0/allBranchInfo.size() * 100.0);
+        System.out.println("===============================ALL Branch================================");
+        for (MyBranchInfo myBranchInfo : allBranchInfo) {
+            System.out.println(myBranchInfo);
+        }
+        System.out.println("===============================ALL Selected Test Case================================");
+        for (TestCaseInfo testCaseInfo: existTestCase) {
+            System.out.println(testCaseInfo.getTestName());
+        }
+    }
+
+    private static void parseProject(ProjectInfo projectInfo, PrintStream out, CoverageData cd, String path) {
+        for (PackageInfo packageInfo : projectInfo.getAllPackages()) {
+//            out.println("package: " + packageInfo.getName());
+            for (FileInfo fileInfo : packageInfo.getFiles()) {
+//                out.println("\tfile: " + fileInfo.getName());
+                if (fileInfo.getName().endsWith("Test.java"))continue;
+                for (ClassInfo classInfo : fileInfo.getClasses()) {
+//                    out.println("\t\tclass: " + classInfo.getName());
+                    for (MethodInfo methodInfo : classInfo.getMethods()) {
+//                        System.out.println("\t\t\tMethod " + methodInfo.getName());
+                        for (BranchInfo branchInfo : methodInfo.getBranches()) {
+                            totalCount++;
+//                            System.out.println("\t\t\t\tbranch: " + branchInfo.getContext());
+                            int dataIndex = branchInfo.getDataIndex();
+                            int dataLength = branchInfo.getDataLength();
+                            MyBranchInfo myBranchInfo = new MyBranchInfo(packageInfo, fileInfo, methodInfo, branchInfo, path);
+                            // 1.查看在不在所有的分支里面
+                            if (allBranchInfo.contains(myBranchInfo)) {
+//                                System.out.println(branchInfo + " " + branchInfo.getStartLine());
+//                                System.out.println(myBranchInfo);
+                            } else {
+                                allBranchInfo.add(myBranchInfo);
+                            }
+
+                            // 2. 统计每个项目的覆盖信息
+                            BranchResult branchResult = new BranchResult(fileInfo.getName(), branchInfo.getStartLine(), false);
+                            nowBranToTestCase.add(branchResult);
+                            for (TestCaseInfo test : cd.getTests()) {
+                                // hitsFor表示 该测试方法命中了哪些 数据(语句、分支、方法)
+                                BitSet hitsFor = cd.getHitsFor(test);
+                                // 检查测试方法是否覆盖了这个分支
+                                BitSet branchHits = hitsFor.get(dataIndex, dataIndex + dataLength);
+                                if (!branchHits.isEmpty()) {
+                                    branchResult.setCovered(true);
+                                    if (null == branchResult.getTestCaseInfo())
+                                        branchResult.setTestCaseInfo(new ArrayList<>());
+                                    branchResult.getTestCaseInfo().add(test);
+                                }
+                            }
+
+                            // 3. 统计全局的覆盖信息
+                            // 查看是否已经被覆盖了
+                            if (branchInfoTestCaseInfoHashMap.containsKey(myBranchInfo)) {
+                                continue;
+                            }
+                            TestCaseInfo addTestCase = null;
+                            for (TestCaseInfo test : cd.getTests()) {
+                                // hitsFor表示 该测试方法命中了哪些 数据(语句、分支、方法)
+                                BitSet hitsFor = cd.getHitsFor(test);
+                                // 检查测试方法是否覆盖了这个分支
+                                BitSet branchHits = hitsFor.get(dataIndex, dataIndex + dataLength);
+                                if (!branchHits.isEmpty()) {
+                                    if (existTestCase.contains(test)) {
+                                        branchInfoTestCaseInfoHashMap.put(myBranchInfo, test);
+                                        break;
+                                    } else {
+                                        addTestCase = test;
+                                    }
+//                                    System.out.println("\t\t\t\t\tTest方法: " + test.getTestName() + " covers branch at " + branchInfo.getStartLine());
+                                }
+                            }
+                            if (!branchInfoTestCaseInfoHashMap.containsKey(myBranchInfo) && addTestCase!=null) {
+                                branchInfoTestCaseInfoHashMap.put(myBranchInfo, addTestCase);
+                                existTestCase.add(addTestCase);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 55 - 0
src/main/java/com/frk/mycode/SootExample.java

@@ -0,0 +1,55 @@
+package com.frk.mycode;
+
+/**
+ * @date 2024/5/17
+ */
+import soot.*;
+import soot.options.Options;
+import soot.toolkits.graph.*;
+import soot.toolkits.scalar.*;
+
+import java.util.*;
+
+public class SootExample {
+    public static void main(String[] args) {
+        // 设置 Soot 的类路径
+        Options.v().set_prepend_classpath(true);
+        Options.v().set_soot_classpath(Scene.v().defaultClassPath());
+        Options.v().set_src_prec(Options.src_prec_java);
+        Options.v().set_output_format(Options.output_format_jimple);
+
+        // 加载要分析的类
+        SootClass sClass = Scene.v().loadClassAndSupport("com.frk.mycode.SootExample");
+        Scene.v().loadNecessaryClasses();
+
+        // 获取 main 方法
+        SootMethod method = sClass.getMethodByName("main");
+
+        // 生成 Jimple 中间表示
+        Body body = method.retrieveActiveBody();
+
+        // 构建控制流图
+        UnitGraph graph = new ExceptionalUnitGraph(body);
+
+        // 进行数据流分析
+        SimpleLocalDefs localDefs = new SimpleLocalDefs(graph);
+
+        // 遍历每个语句
+        for (Unit unit : graph) {
+            System.out.println("Statement: " + unit);
+
+            // 获取语句的定义
+            List<ValueBox> useBoxes = unit.getUseBoxes();
+            for (ValueBox vb : useBoxes) {
+                Value v = vb.getValue();
+                if (v instanceof Local) {
+                    List<Unit> defs = localDefs.getDefsOfAt((Local) v, unit);
+                    for (Unit def : defs) {
+                        System.out.println("  Depends on: " + def);
+                    }
+                }
+            }
+        }
+    }
+}
+

+ 72 - 0
src/main/java/com/frk/mycode/branch/BranchResult.java

@@ -0,0 +1,72 @@
+package com.frk.mycode.branch;
+
+import com.atlassian.clover.registry.entities.TestCaseInfo;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @date 2024/4/21
+ */
+public class BranchResult {
+    String filePath;
+    Integer branchStartLine;
+    boolean isCovered;
+    List<TestCaseInfo> testCaseInfo;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof BranchResult)) return false;
+
+        BranchResult that = (BranchResult) o;
+
+        if (!Objects.equals(filePath, that.filePath)) return false;
+        return Objects.equals(branchStartLine, that.branchStartLine);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = filePath != null ? filePath.hashCode() : 0;
+        result = 31 * result + (branchStartLine != null ? branchStartLine.hashCode() : 0);
+        return result;
+    }
+
+    public BranchResult(String filePath, Integer branchStartLine, boolean isCovered) {
+        this.filePath = filePath;
+        this.branchStartLine = branchStartLine;
+        this.isCovered = isCovered;
+    }
+
+    public String getFilePath() {
+        return filePath;
+    }
+
+    public void setFilePath(String filePath) {
+        this.filePath = filePath;
+    }
+
+    public Integer getBranchStartLine() {
+        return branchStartLine;
+    }
+
+    public void setBranchStartLine(Integer branchStartLine) {
+        this.branchStartLine = branchStartLine;
+    }
+
+    public boolean isCovered() {
+        return isCovered;
+    }
+
+    public void setCovered(boolean covered) {
+        isCovered = covered;
+    }
+
+    public List<TestCaseInfo> getTestCaseInfo() {
+        return testCaseInfo;
+    }
+
+    public void setTestCaseInfo(List<TestCaseInfo> testCaseInfo) {
+        this.testCaseInfo = testCaseInfo;
+    }
+}

+ 105 - 0
src/main/java/com/frk/mycode/branch/MyBranchInfo.java

@@ -0,0 +1,105 @@
+package com.frk.mycode.branch;
+
+import com.atlassian.clover.api.registry.*;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.Objects;
+
+/**
+ * @date 2024/4/12
+ */
+public class MyBranchInfo {
+    public BranchInfo branchInfo;
+    public FileInfo fileInfo;
+    public String packagePath;
+    public String filePath;
+    public String methodName;
+    public String startStatement;
+    public String endStatement;
+    public int branchStartLine;
+    public int branchStartColumn;
+
+    public int branchEndLine;
+    public int branchEndColumn;
+    public ContextSet contextSet;
+
+    public MyBranchInfo(PackageInfo packageInfo, FileInfo fileInfo, MethodInfo methodInfo, BranchInfo branchInfo, String path) {
+        this.packagePath = packageInfo.getName().replace(".", File.separator);
+        this.filePath = packagePath + File.separator + fileInfo.getName();
+        this.branchInfo = branchInfo;
+        this.methodName = methodInfo.getName();
+        this.branchStartLine = this.branchInfo.getStartLine();
+        this.branchStartColumn = this.branchInfo.getStartColumn();
+        this.branchEndLine = this.branchInfo.getEndLine();
+        this.branchEndColumn = this.branchInfo.getEndColumn();
+        this.fileInfo = fileInfo;
+        this.contextSet = branchInfo.getContext();
+        parseStatement(path);
+    }
+
+    private void parseStatement(String path) {
+        int startLine = branchInfo.getStartLine();
+        int endLine = branchInfo.getEndLine();
+//        System.out.println(startLine);
+//        System.out.println(endLine);
+        File file = new File(path);
+        file = file.getParentFile().getParentFile().getParentFile();
+        // 读取源代码文件
+        String sourceFilePath = Paths.get(file.getAbsolutePath() + "\\src\\main\\java", fileInfo.getContainingPackage().getName().replace(".", "/"), fileInfo.getName()).toString();
+//        System.out.println(sourceFilePath);
+
+        try (BufferedReader reader = new BufferedReader(new FileReader(sourceFilePath))) {
+            int lineNumber = 0;
+            String line;
+            while ((line = reader.readLine()) != null) {
+                lineNumber++;
+                if (lineNumber == startLine) {
+                    this.startStatement = line;
+                } else if(lineNumber == endLine) {
+                    this.endStatement = line;
+                    break;
+                }
+
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    @Override
+    public String toString() {
+        return "MyBranchInfo{" +
+                "filePath='" + filePath + '\'' +
+                ", methodName='" + methodName + '\'' +
+                ", startLine='" + branchStartLine + '\'' +
+                ", contextSet=" + contextSet +
+                '}';
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof MyBranchInfo)) {
+            return false;
+        }
+        return filePath.equals(((MyBranchInfo) obj).filePath) &&
+                Objects.equals(methodName, ((MyBranchInfo) obj).methodName) &&
+                Objects.equals(startStatement, ((MyBranchInfo) obj).startStatement) &&
+                Objects.equals(endStatement, ((MyBranchInfo) obj).endStatement) &&
+                Objects.equals(branchStartLine, ((MyBranchInfo) obj).branchStartLine);
+//        return filePath.equals(((MyBranchInfo) obj).filePath) &&
+//                Objects.equals(methodName, ((MyBranchInfo) obj).methodName) &&
+//                Objects.equals(contextSet, ((MyBranchInfo) obj).contextSet);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(filePath, methodName, startStatement, endStatement);
+//        return Objects.hash(filePath, methodName);
+    }
+
+}

+ 53 - 0
src/main/java/com/frk/mycode/mutation/Mutation.java

@@ -0,0 +1,53 @@
+package com.frk.mycode.mutation;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * @date 2024/5/14
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class Mutation {
+    private String packageName;
+    /**
+     * 变异体所在的行号
+     */
+    private Integer id;
+
+    private String type;
+    /**
+     * 变异体所在的方法名
+     */
+    private String location;
+    /**
+     * 变异体所在的java文件
+     */
+    private String javaFileName;
+    private List<MyTestCase> killedByTestCases;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof Mutation)) return false;
+
+        Mutation mutation = (Mutation) o;
+
+        if (!getPackageName().equals(mutation.getPackageName())) return false;
+        if (!getId().equals(mutation.getId())) return false;
+        if (!getType().equals(mutation.getType())) return false;
+        if (!getLocation().equals(mutation.getLocation())) return false;
+        return getJavaFileName().equals(mutation.getJavaFileName());
+    }
+
+    @Override
+    public int hashCode() {
+        int result = getId().hashCode();
+        result = 31 * result + getType().hashCode();
+        return result;
+    }
+}

+ 40 - 0
src/main/java/com/frk/mycode/mutation/MyTestCase.java

@@ -0,0 +1,40 @@
+package com.frk.mycode.mutation;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * @date 2024/5/14
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class MyTestCase {
+    private String xmlPath;
+    private String packagePath;
+    private String methodName;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof MyTestCase)) return false;
+
+        MyTestCase that = (MyTestCase) o;
+
+        if (getXmlPath() != null ? !getXmlPath().equals(that.getXmlPath()) : that.getXmlPath() != null) return false;
+        if (getPackagePath() != null ? !getPackagePath().equals(that.getPackagePath()) : that.getPackagePath() != null)
+            return false;
+        return getMethodName() != null ? getMethodName().equals(that.getMethodName()) : that.getMethodName() == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = getXmlPath() != null ? getXmlPath().hashCode() : 0;
+        result = 31 * result + (getPackagePath() != null ? getPackagePath().hashCode() : 0);
+        result = 31 * result + (getMethodName() != null ? getMethodName().hashCode() : 0);
+        return result;
+    }
+}

+ 42 - 0
src/main/java/com/frk/mycode/util/FileSolveUtil.java

@@ -0,0 +1,42 @@
+package com.frk.mycode.util;
+
+import org.apache.commons.io.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @date 2024/5/24
+ */
+public class FileSolveUtil {
+    public static void filterData(String targetPath, String templatePath) {
+        File templateFile = new File(templatePath);
+        String name = templateFile.getName();
+        File bigProjectDir = new File(targetPath);
+        int count = 0;
+        for (File subProjectFile : bigProjectDir.listFiles(File::isDirectory)) {
+            File mooctestPackageFile = new File(subProjectFile.getAbsolutePath() + File.separator + "src" + File.separator + "test" + File.separator + "java" + File.separator + "net" + File.separator + "mooctest");
+            File[] listFiles = mooctestPackageFile.listFiles();
+            if (listFiles != null && listFiles.length >= 2) continue;
+            try {
+                File file = new File(mooctestPackageFile, name);
+                boolean b = FileUtils.contentEquals(file, templateFile);
+                if (b) {
+                    count++;
+                    System.out.println(subProjectFile + " is null !!!");
+                    FileUtils.deleteDirectory(subProjectFile);
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        System.out.println(count);
+
+
+    }
+
+    public static void main(String[] args) {
+        filterData("D:\\learn\\junit-test\\test\\EightQueens", "D:\\learn\\junit-test\\EightQueensTest.java");
+    }
+
+}

+ 448 - 0
src/main/resources/IntNumber.java.html

@@ -0,0 +1,448 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html;charset=GBK">
+    <link rel="stylesheet" type="text/css" href="../style.css">
+</head>
+<body>
+
+
+<h1>IntNumber.java</h1>
+
+<table class="src">
+
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_1'/>
+1
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_1'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''>package com.frk;</span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_2'/>
+2
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_2'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''></span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_3'/>
+3
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_3'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''>/**</span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_4'/>
+4
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_4'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''> * @date 2024/3/19</span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_5'/>
+5
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_5'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''> */</span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_6'/>
+6
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_6'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''>public class IntNumber {</span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_7'/>
+7
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_7'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''>    private int a;</span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_8'/>
+8
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_8'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''>    private int b;</span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_9'/>
+9
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_9'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''></span></pre></td></tr>
+
+
+<tr>
+<td class='covered'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_10'/>
+10
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_10'></a>
+<span>
+</span>
+</span>
+</td>
+<td class='covered'><pre><span  class=''>    public IntNumber(int a, int b) {</span></pre></td></tr>
+
+
+<tr>
+<td class='covered'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_11'/>
+11
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_11'></a>
+<span>
+</span>
+</span>
+</td>
+<td class='covered'><pre><span  class=''>        this.a = a;</span></pre></td></tr>
+
+
+<tr>
+<td class='covered'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_12'/>
+12
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_12'></a>
+<span>
+</span>
+</span>
+</td>
+<td class='covered'><pre><span  class=''>        this.b = b;</span></pre></td></tr>
+
+
+<tr>
+<td class='covered'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_13'/>
+13
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_13'></a>
+<span>
+</span>
+</span>
+</td>
+<td class='covered'><pre><span  class=''>    }</span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_14'/>
+14
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_14'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''></span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_15'/>
+15
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_15'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''>    public int add () {</span></pre></td></tr>
+
+
+<tr>
+<td class='covered'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_16'/>
+16
+</td>
+<td class='killed'>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_16'>1</a>
+<span>
+
+1. add : negated conditional &rarr; KILLED<br/>
+
+</span>
+</span>
+</td>
+<td class='covered'><pre><span  class='killed'>        if (a == 1)</span></pre></td></tr>
+
+
+<tr>
+<td class='covered'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_17'/>
+17
+</td>
+<td class='killed'>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_17'>2</a>
+<span>
+
+1. add : replaced int return with 0 for com/frk/IntNumber::add &rarr; KILLED<br/>
+
+2. add : Replaced integer addition with subtraction &rarr; KILLED<br/>
+
+</span>
+</span>
+</td>
+<td class='covered'><pre><span  class='killed'>            return a + b;</span></pre></td></tr>
+
+
+<tr>
+<td class='covered'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_18'/>
+18
+</td>
+<td class='killed'>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_18'>1</a>
+<span>
+
+1. add : negated conditional &rarr; KILLED<br/>
+
+</span>
+</span>
+</td>
+<td class='covered'><pre><span  class='killed'>        else if(a == 0)</span></pre></td></tr>
+
+
+<tr>
+<td class='covered'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_19'/>
+19
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_19'></a>
+<span>
+</span>
+</span>
+</td>
+<td class='covered'><pre><span  class=''>            return 0;</span></pre></td></tr>
+
+
+<tr>
+<td class='uncovered'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_20'/>
+20
+</td>
+<td class='survived'>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_20'>1</a>
+<span>
+
+1. add : replaced int return with 0 for com/frk/IntNumber::add &rarr; NO_COVERAGE<br/>
+
+</span>
+</span>
+</td>
+<td class='uncovered'><pre><span  class='survived'>        return -1;</span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_21'/>
+21
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_21'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''>    }</span></pre></td></tr>
+
+
+<tr>
+<td class='na'>
+<a name='org.pitest.mutationtest.report.html.SourceFile@1283bef9_22'/>
+22
+</td>
+<td class=''>
+<span class='pop'>
+<a href='#grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_22'></a>
+<span>
+</span>
+</span>
+</td>
+<td class=''><pre><span  class=''>}</span></pre></td></tr>
+
+
+
+<tr><td></td><td></td><td><h2>Mutations</h2></td></tr>
+
+
+<tr>
+<td><a href='#org.pitest.mutationtest.report.html.SourceFile@1283bef9_16'>16</a></td> 
+<td></td>
+<td>
+
+<a name='grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_16'/> 
+
+<p class='KILLED'><span class='pop'>1.<span><b>1</b><br/><b>Location : </b>add<br/><b>Killed by : </b>com.frk.main.TestMain12.test2(com.frk.main.TestMain12)</span></span> negated conditional &rarr; KILLED</p> 
+</td>
+</tr>
+
+<tr>
+<td><a href='#org.pitest.mutationtest.report.html.SourceFile@1283bef9_17'>17</a></td> 
+<td></td>
+<td>
+
+<a name='grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_17'/> 
+
+<p class='KILLED'><span class='pop'>1.<span><b>1</b><br/><b>Location : </b>add<br/><b>Killed by : </b>com.frk.main.TestMain12.test1(com.frk.main.TestMain12)</span></span> replaced int return with 0 for com/frk/IntNumber::add &rarr; KILLED</p> <p class='KILLED'><span class='pop'>2.<span><b>2</b><br/><b>Location : </b>add<br/><b>Killed by : </b>com.frk.main.TestMain12.test1(com.frk.main.TestMain12)</span></span> Replaced integer addition with subtraction &rarr; KILLED</p> 
+</td>
+</tr>
+
+<tr>
+<td><a href='#org.pitest.mutationtest.report.html.SourceFile@1283bef9_18'>18</a></td> 
+<td></td>
+<td>
+
+<a name='grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_18'/> 
+
+<p class='KILLED'><span class='pop'>1.<span><b>1</b><br/><b>Location : </b>add<br/><b>Killed by : </b>com.frk.main.TestMain12.test2(com.frk.main.TestMain12)</span></span> negated conditional &rarr; KILLED</p> 
+</td>
+</tr>
+
+<tr>
+<td><a href='#org.pitest.mutationtest.report.html.SourceFile@1283bef9_20'>20</a></td> 
+<td></td>
+<td>
+
+<a name='grouporg.pitest.mutationtest.report.html.SourceFile@1283bef9_20'/> 
+
+<p class='NO_COVERAGE'><span class='pop'>1.<span><b>1</b><br/><b>Location : </b>add<br/><b>Killed by : </b>none</span></span> replaced int return with 0 for com/frk/IntNumber::add &rarr; NO_COVERAGE</p> 
+</td>
+</tr>
+
+</table>
+
+
+<h2>Active mutators</h2>
+<ul>
+
+<li class='mutator'>CONDITIONALS_BOUNDARY</li>
+
+<li class='mutator'>EMPTY_RETURNS</li>
+
+<li class='mutator'>FALSE_RETURNS</li>
+
+<li class='mutator'>INCREMENTS</li>
+
+<li class='mutator'>INVERT_NEGS</li>
+
+<li class='mutator'>MATH</li>
+
+<li class='mutator'>NEGATE_CONDITIONALS</li>
+
+<li class='mutator'>NULL_RETURNS</li>
+
+<li class='mutator'>PRIMITIVE_RETURNS</li>
+
+<li class='mutator'>TRUE_RETURNS</li>
+
+<li class='mutator'>VOID_METHOD_CALLS</li>
+
+</ul>
+
+<h2>Tests examined</h2>
+<ul>
+<li>com.frk.main.TestMain12.test1(com.frk.main.TestMain12) (16 ms)</li><li>com.frk.main.TestMain12.test2(com.frk.main.TestMain12) (0 ms)</li>
+</ul>
+
+<br/>
+
+Report generated by <a href='https://pitest.org'>PIT</a> 1.16.0
+
+</body>
+</html>

+ 73 - 0
src/test/java/com/frk/main/PITest.java

@@ -0,0 +1,73 @@
+package com.frk.main;
+
+import com.alibaba.fastjson.JSONObject;
+import com.frk.mycode.PITesrDecrease;
+import com.frk.mycode.PITestUtil;
+import com.frk.mycode.mutation.Mutation;
+import org.apache.commons.io.FileUtils;
+import org.junit.Test;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @date 2024/5/17
+ */
+public class PITest {
+    @Test
+    public void test() {
+        String source = "D:\\learn\\junit-test\\test\\EightQueens_N";
+        PITesrDecrease.mutationDecrease(source);
+        LinkedHashSet<Mutation> resultList = PITesrDecrease.allMutationInfo;
+        String jsonString = JSONObject.toJSONString(resultList);
+        File writeFile = new File(source + File.separator + "result.json");
+        try(Writer write = new OutputStreamWriter(new FileOutputStream(writeFile), StandardCharsets.UTF_8)) {
+            write.write(jsonString);
+            write.flush();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+    @Test
+    public void testSingle() {
+        PITestUtil.runAndParsePITest("D:\\learn\\junit-test\\test\\solve2\\EightQueens_1666011085487");
+    }
+    @Test
+    public void replace() {
+        String s = "D:\\learn\\junit-test\\test\\EightQueens_N";
+        String t = "D:\\learn\\junit-test\\test\\EightQueensTemplate";
+
+        replaceSourcetoTemplate(s, t);
+    }
+
+    public void  replaceSourcetoTemplate(String sourceDirPath, String templateDirPath) {
+        File sourceDir = new File(sourceDirPath);
+        File[] subProjects = sourceDir.listFiles(File::isDirectory);
+        File templateDir = new File(templateDirPath);
+        String targetPath = "src" + File.separator + "main" + File.separator + "java" + File.separator + "net" + File.separator + "mooctest";
+        if (subProjects != null && subProjects.length > 0) {
+                // 遍历所有其他子项目
+                for (int i = 0; i < subProjects.length; i++) {
+                    File sub = subProjects[i];
+                    // 替换每个子项目的 "src\\main\\java\\net\\mooctest" 目录下的 Java 文件
+                    File targetSrcDir = new File(sub, targetPath);
+                    if (targetSrcDir.exists() && targetSrcDir.isDirectory()) {
+                        try {
+                        FileUtils.deleteDirectory(targetSrcDir);
+                        for (File temp : templateDir.listFiles()) {
+                            FileUtils.copyFileToDirectory(temp, targetSrcDir);
+                        }
+                        } catch (IOException e) {
+                            e.printStackTrace();
+                        }
+                        System.out.println("Copy " + templateDirPath + " to " + sub.getAbsolutePath() + " success !!!" );
+                    }
+                }
+            } else {
+                System.out.println("未找到任何Java文件。");
+            }
+        }
+}

+ 126 - 0
src/test/java/com/frk/main/ReadCloverDb.java

@@ -0,0 +1,126 @@
+package com.frk.main;
+
+import com.atlassian.clover.CloverDatabase;
+import com.atlassian.clover.CodeType;
+import com.atlassian.clover.CoverageData;
+import com.atlassian.clover.CoverageDataSpec;
+import com.atlassian.clover.api.registry.*;
+import com.atlassian.clover.recorder.PerTestCoverage;
+import com.atlassian.clover.registry.entities.FullBranchInfo;
+import com.atlassian.clover.registry.entities.FullProjectInfo;
+import com.atlassian.clover.registry.entities.PackageFragment;
+import com.atlassian.clover.registry.entities.TestCaseInfo;
+
+import java.io.PrintStream;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @date 2024/4/11
+ */
+public class ReadCloverDb {
+    static BitSet bs;
+    static double totalBranches = 0.0;
+    static double coverageBranches = 0.0;
+    static int originTestCase = 0;
+    static HashMap<BranchInfo, TestCaseInfo> branchInfoTestCaseInfoHashMap = new HashMap<>();
+    static HashSet<BranchInfo> allBranchInfo = new HashSet<>();
+    static HashSet<TestCaseInfo> existTestCase = new HashSet<>();
+    public static void main(String[] args) throws Exception {
+        String s = "D:\\learn\\junit-test\\test\\solve\\EightQueens_1664963256377\\target\\clover\\clover.db";
+        //String s = "D:\\learn\\junit-test\\openclover\\target\\clover\\clover.db";
+        // read clover database together with coverage recording files, use time span=0 (latest build)
+        CloverDatabase db = CloverDatabase.loadWithCoverage(s, new CoverageDataSpec());
+        ProjectInfo projectInfo = db.getRegistry().getProject();
+        FullProjectInfo model = db.getModel(CodeType.ALL);
+        // print some project details
+        CoverageData cd= db.getCoverageData();
+        BitSet allHits = cd.getAllHits();
+        bs = allHits;
+        printProject(projectInfo, System.out, cd);
+        System.out.println(coverageBranches / totalBranches * 100);
+        System.out.println(allHits);
+        // 原来的测试用例数量
+        originTestCase = cd.getTests().size();
+        System.out.println("原来的测试用例数量 " + originTestCase);
+        // 约简后的测试用例数量:
+        System.out.println("约简后的测试用例数量 " + existTestCase.size());
+        System.out.println("约简后的分支覆盖率 " + branchInfoTestCaseInfoHashMap.size()/totalBranches * 100);
+//        Map<TestCaseInfo, BitSet> map = cd.mapTestsAndCoverageForFile();
+
+
+//        Set<TestCaseInfo> testsCovering = cd.getTestsCovering(model);
+//        for (TestCaseInfo testCaseInfo : testsCovering) {
+//            System.out.println();
+//        }
+
+//        System.out.println(allHits);
+//        Set<TestCaseInfo> tests = cd.getTests();
+//        for (TestCaseInfo test : tests) {
+//            BitSet hitsFor = cd.getHitsFor(test);
+//            System.out.println(test);
+//            System.out.println(hitsFor);
+//        }
+
+    }
+
+    private static void printProject(ProjectInfo db, PrintStream out, CoverageData cd) {
+        for (PackageInfo packageInfo : db.getAllPackages()) {
+            out.println("package: " + packageInfo.getName());
+            for (FileInfo fileInfo : packageInfo.getFiles()) {
+                out.println("\tfile: " + fileInfo.getName());
+                for (ClassInfo classInfo : fileInfo.getClasses()) {
+                    out.println("\t\tclass: " + classInfo.getName());
+                    for (MethodInfo methodInfo : classInfo.getMethods()) {
+                        out.println("\t\t\tmethod: " + methodInfo.getName());
+                        for (BranchInfo branchInfo: methodInfo.getBranches()) {
+                            allBranchInfo.add(branchInfo);
+                            totalBranches += 1.0;
+                            /*
+                            这些bitset代表了分支的编号
+                             */
+                            System.out.println("\t\t\t\tbrach: " + branchInfo.getContext());
+                            int startLine = branchInfo.getStartLine();
+                            System.out.println("\t\t\t\t\tbranch Line: " + startLine);
+                            FullBranchInfo fullBranchInfo = (FullBranchInfo) branchInfo;
+                            Set<TestCaseInfo> testsCovering = cd.getTestsCovering(fullBranchInfo);
+                            System.out.println("\t\t\t\t\tcoverage By: " + testsCovering);
+                            if (!branchInfoTestCaseInfoHashMap.containsKey(branchInfo)) {
+                                boolean hasTestCase = false;
+                                for (TestCaseInfo testCaseInfo : testsCovering) {
+                                    if (existTestCase.contains(testCaseInfo)) {
+                                        branchInfoTestCaseInfoHashMap.put(branchInfo, testCaseInfo);
+                                        hasTestCase = true;
+                                        break;
+                                    }
+                                }
+                                if (!hasTestCase && !testsCovering.isEmpty()) {
+                                    TestCaseInfo testCaseInfo = testsCovering.iterator().next();
+                                    branchInfoTestCaseInfoHashMap.put(branchInfo, testCaseInfo);
+                                    existTestCase.add(testCaseInfo);
+                                }
+                            }
+                            for (TestCaseInfo testCaseInfo : testsCovering) {
+                                // 该分支之前记录没有被覆盖
+                                BitSet hitsFor = cd.getHitsFor(testCaseInfo);
+                                System.out.println("\t\t\t\t\ttestCaseInfo " +testCaseInfo.getTestName() +": " + hitsFor);
+                            }
+
+                            if (branchInfo.getHitCount() > 0) {
+                                coverageBranches += 1.0;
+                            }
+//                            int dataIndex = branchInfo.getDataIndex();
+//                            int len = branchInfo.getDataLength();
+//                            System.out.println("\t\t\t\t\tcoverage: " +bs.get(dataIndex,dataIndex + len));
+
+
+                        }
+                    }
+
+                }
+            }
+        }
+    }
+}

+ 28 - 0
src/test/java/com/frk/main/TestMain12.java

@@ -0,0 +1,28 @@
+package com.frk.main;
+
+import com.frk.IntNumber;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @date 2024/3/19
+ */
+@RunWith(JUnit4.class)
+public class TestMain12 {
+    @Test
+    public void test1() {
+
+        IntNumber intNumber = new IntNumber(1, 2);
+        int result = intNumber.add();
+        assert result == 3;
+    }
+
+    @Test
+    public void test2() {
+
+        IntNumber intNumber = new IntNumber(0, 2);
+        int result = intNumber.add();
+        assert result == 0;
+    }
+}