diff --git a/.gitignore b/.gitignore
index 6e7d9a3..465560c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -108,3 +108,5 @@ gen### VisualStudioCode template
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
+.scannerwork/
+.attach_pid*
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..5179b05
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,19 @@
+language: java
+
+jdk: oraclejdk8
+
+addons:
+ sonarcloud:
+ organization: istic-m2-ila-gm
+ token:
+ secure: e/yARBIuHIJXfRySzbSLWAeIu652kaZ8ElWZyavAB5XBZlpJX4AneV5jXBGRtlAnka77KaR1uL9f/pE3Itnchvdz1P12VFWTxFWkNFe2c4Ms0zkieAdAF//4k8p81G6mfKP8y4U0Jf2dqjj3+SNc4Dn2aoYZvL2mcpT0hPQiY4wjlE6qI12A72IfnUDgR6zr28qw7IkPho6LLwac8Qk3lL8qNJ2n6gP2OX05YsmSSv+XRAxZ5EpTwEg4HCsiB8ziqixFhaih4UcIfJ2q6OS/y1j3cdpwL11EgSrvvz104a8jj77hcKx/IAPRUFGYnb8N3DGm9fNgMviZdR8hgWBFWbRc7CHNo9L0PJVHUe/T8TTSeisKz/Id67KLw8nBS9eQUE3/ljuEN9HcvQLB2uwNWYIodLYgjougax9VyVft/0zlcLaKjYUhFpGkpmsEToST8/++CbB8UeYGZX8G7Dn6gtib0iD+Cl1Lcz0ZcAn+nvWXbL8Ix+WXSRqkhJk9gmR5RCUpPI3cFspS9t82ey0DYrzEbH9mh+1o8sVvkRp+xExU5PuAdKdCY7pz+a4/f2ulsktpfbH5cxUly+NQHDtVt654xj/rfW6UhEmD5DFJR7OrAlnuYAIzsjQkeI4e3X131kOWJ+BiLb0ZuHZ4b0v7RiboVEwo5/zcyymUZZcsMq8=
+
+cache:
+ directories:
+ - "$HOME/.m2/repository"
+ - "$HOME/.sonar/cache"
+
+jobs:
+ include:
+ - script: cd fake && mvn test && cd .. && mvn -B org.jacoco:jacoco-maven-plugin:prepare-agent verify && sonar-scanner
+ name: Unit & Quality
\ No newline at end of file
diff --git a/README.md b/README.md
index c0ae0bb..f5226c4 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,47 @@
-# WeAssert
\ No newline at end of file
+# WeAssert
+
+## Project Status
+
+[![Build Status](https://travis-ci.org/ISTIC-M2-ILa-GM/WeAssert.svg?branch=dev)](https://travis-ci.org/ISTIC-M2-ILa-GM/WeAssert)
+[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=fr.istic.gm.weassert&metric=code_smells)](https://sonarcloud.io/dashboard?id=fr.istic.gm.weassert)
+[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=fr.istic.gm.weassert&metric=coverage)](https://sonarcloud.io/dashboard?id=fr.istic.gm.weassert)
+
+## Links
+
+* Subject: https://github.com/Software-Testing/Projects-2018-2019
+* Project: https://github.com/ISTIC-M2-ILa-GM/WeAssert/projects/1
+* Issues and Features TODO: https://github.com/ISTIC-M2-ILa-GM/WeAssert/issues
+* Continuous integration - Travis CI: https://travis-ci.org/ISTIC-M2-ILa-GM/WeAssert
+* Quality - Sonarcloud: https://sonarcloud.io/dashboard?id=fr.istic.gm.weassert
+
+## Build
+```
+mvn compile
+```
+This project needs to be installed to can be used:
+```
+mvn install
+```
+For a quicker install you can skip tests:
+```
+mvn install -DskipTests
+```
+
+## Execute the jar
+```
+java -jar weassert.jar
+```
+
+## How to use the project
+
+* Start the application,
+* On the GUI:
+ * Select maven executable,
+ * Select the project,
+ * Click on generate button,
+ * Click on run tests,
+ * Select test and see modified code.
+
+## Tested projects
+
+* we-assert-fake-test
\ No newline at end of file
diff --git a/fake/pom.xml b/fake/pom.xml
new file mode 100644
index 0000000..490a508
--- /dev/null
+++ b/fake/pom.xml
@@ -0,0 +1,135 @@
+
+
+
+ fr.istic.gm
+ we-assert-fake-test
+ 1.0
+ 4.0.0
+ FakeProject
+
+ 2018
+
+
+ GM
+ https://github.com/ISTIC-M2-ILa-GM
+
+
+
+
+ mlh
+ Gwenole LE HENAFF
+
+
+ grl
+ Gautier Rouleau
+
+
+
+
+ 1.8
+ 1.8
+ 3.1
+ 3.1.0
+ 3.1.0
+ 2.4
+ 2.19
+ 3.0.0
+ 0.8.2
+
+ 1.7.25
+ 1.18.2
+
+ 4.12
+ 1.3
+ 2.22.0
+ 7.2.0.RELEASE
+
+
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+
+
+ junit
+ junit
+ ${junit4.version}
+
+
+
+
+ org.hamcrest
+ hamcrest-all
+ ${hamcrest.version}
+ test
+
+
+ org.mockito
+ mockito-core
+ ${mockito.core.version}
+ test
+
+
+ uk.co.jemos.podam
+ podam
+ ${podam.version}
+ test
+
+
+
+
+
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+ maven-compiler-plugin
+ ${maven-compiler.version}
+
+
+ ${java.version.target}
+ true
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ ${jacoco.version}
+
+
+ **/config/**
+ **/*Exception.java
+ **/*Configuration.java
+
+
+
+
+
+ prepare-agent
+
+
+
+ report
+ prepare-package
+
+ report
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/fake/src/main/java/fr/istic/gm/weassert/fake/Person.java b/fake/src/main/java/fr/istic/gm/weassert/fake/Person.java
new file mode 100644
index 0000000..61ff6da
--- /dev/null
+++ b/fake/src/main/java/fr/istic/gm/weassert/fake/Person.java
@@ -0,0 +1,17 @@
+package fr.istic.gm.weassert.fake;
+
+import lombok.Data;
+
+/**
+ * A fake class Person to test the projet
+ */
+@Data
+public class Person {
+
+ private String name;
+ private int age;
+
+ public boolean isAdult() {
+ return age >= 18;
+ }
+}
\ No newline at end of file
diff --git a/fake/src/test/java/fr/istic/gm/weassert/fake/PersonTest.java b/fake/src/test/java/fr/istic/gm/weassert/fake/PersonTest.java
new file mode 100644
index 0000000..d8ab65c
--- /dev/null
+++ b/fake/src/test/java/fr/istic/gm/weassert/fake/PersonTest.java
@@ -0,0 +1,21 @@
+package fr.istic.gm.weassert.fake;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+
+/**
+ * A fake Test class to try to generate assert
+ */
+public class PersonTest {
+
+ @Test
+ public void testAge() {
+
+ Person p = new Person();
+ p.setAge(13);
+ p.setName("name");
+
+ assertFalse(p.isAdult());
+ }
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 0a81743..6c37b72 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,10 +5,10 @@
fr.istic.gm
we-assert
- 1.0-SNAPSHOT
+ 1.0
WeAssert
- 2018
+ 2019
GM
@@ -45,93 +45,118 @@
1.7.25
1.18.2
+ 3.24.0-GA
+ 5.2
+
4.12
1.3
2.22.0
7.2.0.RELEASE
-
-
-
- org.projectlombok
- lombok
- ${lombok.version}
-
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+ org.slf4j
+ slf4j-simple
+ ${slf4j.version}
+
+
+
+
+ org.javassist
+ javassist
+ ${javassist.version}
+
-
-
- org.slf4j
- slf4j-api
- ${slf4j.version}
-
+
+
+ org.ow2.asm
+ asm-debug-all
+ ${asm.version}
+
-
-
- junit
- junit
- ${junit4.version}
- test
-
+
+
+ junit
+ junit
+ ${junit4.version}
+
-
-
- org.hamcrest
- hamcrest-all
- ${hamcrest.version}
- test
-
-
- org.mockito
- mockito-core
- ${mockito.core.version}
- test
-
-
- uk.co.jemos.podam
- podam
- ${podam.version}
- test
-
-
+
+
+ org.hamcrest
+ hamcrest-all
+ ${hamcrest.version}
+ test
+
+
+ org.mockito
+ mockito-core
+ ${mockito.core.version}
+ test
+
+
+ uk.co.jemos.podam
+ podam
+ ${podam.version}
+ test
+
+
-
-
-
- maven-surefire-plugin
- ${maven-surefire-plugin.version}
-
-
- maven-compiler-plugin
- ${maven-compiler.version}
-
-
- org.jacoco
- jacoco-maven-plugin
- ${jacoco.version}
-
-
- **/config/**
- **/*Exception.java
- **/*Configuration.java
-
-
-
-
-
- prepare-agent
-
-
-
- report
- prepare-package
-
- report
-
-
-
-
-
-
+
+
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+ maven-compiler-plugin
+ ${maven-compiler.version}
+
+
+ ${java.version.target}
+ true
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ ${jacoco.version}
+
+
+ src/main/java/fr/istic/gm/weassert/test/model/*
+ **/config/**
+ **/*Exception.java
+ **/*Configuration.java
+
+
+
+
+
+ prepare-agent
+
+
+
+ report
+ prepare-package
+
+ report
+
+
+
+
+
\ No newline at end of file
diff --git a/sonar-project.properties b/sonar-project.properties
new file mode 100644
index 0000000..3562da2
--- /dev/null
+++ b/sonar-project.properties
@@ -0,0 +1,14 @@
+sonar.host.url=https://sonarcloud.io
+sonar.projectKey=fr.istic.gm.weassert
+sonar.projectName=WeAssert
+sonar.organization=istic-m2-ila-gm
+sonar.sources=src/main/java
+sonar.projectVersion=1.0.0
+sonar.language=java
+sonar.coverage.exclusions=**/config/**,**/*Exception.java, **/*Configuration.java,src/main/java/fr/istic/gm/weassert/test/model/*
+sonar.java.source=1.8
+sonar.java.binaries=.
+sonar.java.libraries=/home/travis/.m2
+sonar.links.homepage=https://github.com/ISTIC-M2-ILa-GM/WeAssert
+sonar.links.ci=https://travis-ci.org/ISTIC-M2-ILa-GM/WeAssert
+sonar.links.scm=git@github.com:ISTIC-M2-ILa-GM/WeAssert.git
\ No newline at end of file
diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..0100d39
--- /dev/null
+++ b/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: fr.istic.gm.weassert.TestRunnerApp
+
diff --git a/src/main/java/fr/istic/gm/weassert/App.java b/src/main/java/fr/istic/gm/weassert/App.java
deleted file mode 100644
index 9a05f9b..0000000
--- a/src/main/java/fr/istic/gm/weassert/App.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package fr.istic.gm.weassert;
-
-public class App {
-
- public static void main(String... args) {
-
- }
-}
diff --git a/src/main/java/fr/istic/gm/weassert/TestRunnerApp.java b/src/main/java/fr/istic/gm/weassert/TestRunnerApp.java
new file mode 100644
index 0000000..08ed748
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/TestRunnerApp.java
@@ -0,0 +1,23 @@
+package fr.istic.gm.weassert;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+
+public class TestRunnerApp extends Application {
+ public static void main(String... args) {
+ launch(args);
+ }
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/rootPane.fxml"));
+ Parent root = loader.load();
+
+ primaryStage.setTitle("WeAssert");
+ primaryStage.setScene(new Scene(root, 800, 600));
+ primaryStage.show();
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/controller/MainController.java b/src/main/java/fr/istic/gm/weassert/controller/MainController.java
new file mode 100644
index 0000000..5ed1968
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/controller/MainController.java
@@ -0,0 +1,163 @@
+package fr.istic.gm.weassert.controller;
+
+import com.sun.javafx.collections.ObservableListWrapper;
+import fr.istic.gm.weassert.test.application.WeAssertRunner;
+import fr.istic.gm.weassert.test.application.impl.WeAssertRunnerImpl;
+import fr.istic.gm.weassert.test.runner.TestRunnerListener;
+import fr.istic.gm.weassert.test.utils.FileUtils;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.chart.PieChart;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.MultipleSelectionModel;
+import javafx.scene.control.TreeItem;
+import javafx.scene.control.TreeView;
+import javafx.scene.web.WebEngine;
+import javafx.scene.web.WebView;
+import javafx.stage.DirectoryChooser;
+import javafx.stage.FileChooser;
+import lombok.AccessLevel;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.runner.Result;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static javafx.scene.chart.PieChart.Data;
+
+@Slf4j
+public class MainController {
+ @FXML
+ public PieChart testResultsChart;
+
+ @FXML
+ public Label selectedMaven;
+
+ @FXML
+ public Label selectedFile;
+
+ @FXML
+ public Button browseButton;
+
+ @FXML
+ public WebView webView;
+
+ @FXML
+ public TreeView treeView;
+
+ private File projectDirectory;
+
+ private File mavenBinary;
+
+ private int passedTest = 0;
+
+ private int failedTests = 0;
+
+ private WebEngine webEngine;
+
+ @Setter(AccessLevel.PACKAGE)
+ private WeAssertRunner weAssertRunner;
+
+ public void initialize() {
+ this.webEngine = this.webView.getEngine();
+ TreeItem rootItem = new TreeItem<>("[No project selected]");
+ rootItem.setExpanded(true);
+ treeView.setRoot(rootItem);
+
+ this.testResultsChart.setStartAngle(45);
+
+ ObservableList observableList = new ObservableListWrapper<>(Arrays.asList(new Data("Passed tests", this.passedTest), new Data("Failed tests", this.failedTests)));
+ this.testResultsChart.setData(observableList);
+ }
+
+ public void browseAction() {
+ DirectoryChooser directoryChooser = new DirectoryChooser();
+ this.projectDirectory = directoryChooser.showDialog(null);
+ if (this.projectDirectory == null) {
+ this.selectedFile.setText("[No project selected]");
+ } else {
+ if (this.projectDirectory.isDirectory()) {
+ this.selectedFile.setText(this.projectDirectory.getPath());
+
+ this.weAssertRunner = new WeAssertRunnerImpl(
+ projectDirectory.getAbsolutePath(),
+ this.mavenBinary != null ? this.mavenBinary.getAbsolutePath() : "/usr/bin/mvn",
+ new TestRunnerListener() {
+ @Override
+ public void testRunFinished(Result result) throws Exception {
+ passedTest += result.getRunCount() - result.getFailureCount();
+ failedTests += result.getFailureCount();
+ Data passedTestData = new Data("Passed tests", passedTest);
+
+ Data failedTestData = new Data("Failed tests", failedTests);
+
+ ObservableList observableList = new ObservableListWrapper<>(Arrays.asList(passedTestData, failedTestData));
+ testResultsChart.setData(observableList);
+ }
+ }
+ );
+
+ showTestFiles(this.projectDirectory);
+ }
+ }
+ }
+
+ public void selectMavenAction() {
+ FileChooser fileChooser = new FileChooser();
+ this.mavenBinary = fileChooser.showOpenDialog(null);
+ if (this.mavenBinary == null) {
+ this.selectedMaven.setText("[System default]");
+ } else {
+ this.selectedMaven.setText(this.projectDirectory.getPath());
+ }
+ }
+
+ public void generateAction() {
+ this.weAssertRunner.generate();
+ }
+
+ public void testAction() {
+ passedTest = 0;
+ failedTests = 0;
+ this.weAssertRunner.runTests();
+ }
+
+ public void itemClickedAction() {
+ MultipleSelectionModel selectionModel = this.treeView.getSelectionModel();
+ ObservableList selectedItems = selectionModel.getSelectedItems();
+ this.displaySourceCode(selectedItems.get(0).getValue().toString());
+ }
+
+ private void displaySourceCode(String s) {
+ File sourceFile = new File(s);
+ if (sourceFile.isFile() && !sourceFile.isDirectory()) {
+ try {
+ String sourceCode = new String(Files.readAllBytes(sourceFile.toPath()));
+
+ this.webEngine.loadContent(String.format("\n" +
+ "%s\n" +
+ "
", sourceCode));
+ } catch (IOException e) {
+ log.error("Can't read a source file", e);
+ }
+ }
+ }
+
+ private void showTestFiles(File directory) {
+ this.treeView.getRoot().setValue(directory.getName());
+ this.treeView.getRoot().getChildren().clear();
+
+ List> collect = FileUtils.findFilesFromFolder(directory)
+ .stream().filter(f -> f.getName().endsWith("Test.java"))
+ .map(f -> new TreeItem<>(f.getAbsolutePath()))
+ .collect(Collectors.toList());
+
+ this.treeView.getRoot().getChildren().addAll(collect);
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/analyser/CodeVisitor.java b/src/main/java/fr/istic/gm/weassert/test/analyser/CodeVisitor.java
new file mode 100644
index 0000000..dd286a2
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/analyser/CodeVisitor.java
@@ -0,0 +1,14 @@
+package fr.istic.gm.weassert.test.analyser;
+
+import fr.istic.gm.weassert.test.model.VariableDefinition;
+
+import java.util.Map;
+
+public interface CodeVisitor {
+
+ Map getVariableValues();
+
+ void initVariableValues();
+
+ void visit(Class clazz, String methodName, String methodDefinition, String variableName, Object variableValue);
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/analyser/LocalVariableParser.java b/src/main/java/fr/istic/gm/weassert/test/analyser/LocalVariableParser.java
new file mode 100644
index 0000000..cad7053
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/analyser/LocalVariableParser.java
@@ -0,0 +1,13 @@
+package fr.istic.gm.weassert.test.analyser;
+
+import fr.istic.gm.weassert.test.model.LocalVariableParsed;
+
+import java.util.List;
+
+public interface LocalVariableParser {
+
+ Class getClazz();
+
+ List parse();
+
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/analyser/TestAnalyser.java b/src/main/java/fr/istic/gm/weassert/test/analyser/TestAnalyser.java
new file mode 100644
index 0000000..2b6cdfe
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/analyser/TestAnalyser.java
@@ -0,0 +1,9 @@
+package fr.istic.gm.weassert.test.analyser;
+
+import fr.istic.gm.weassert.test.model.TestAnalysed;
+
+import java.util.List;
+
+public interface TestAnalyser {
+ List analyse();
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/analyser/impl/CodeVisitorImpl.java b/src/main/java/fr/istic/gm/weassert/test/analyser/impl/CodeVisitorImpl.java
new file mode 100644
index 0000000..0cac664
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/analyser/impl/CodeVisitorImpl.java
@@ -0,0 +1,41 @@
+package fr.istic.gm.weassert.test.analyser.impl;
+
+import fr.istic.gm.weassert.test.analyser.CodeVisitor;
+import fr.istic.gm.weassert.test.model.VariableDefinition;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+public class CodeVisitorImpl implements CodeVisitor {
+
+ public static final CodeVisitor INSTANCE = new CodeVisitorImpl();
+
+ private Map variableValues;
+
+ @Override
+ public Map getVariableValues() {
+ if (variableValues == null) {
+ variableValues = new HashMap<>();
+ }
+ return variableValues;
+ }
+
+ @Override
+ public void initVariableValues() {
+ variableValues = new HashMap<>();
+ }
+
+ @Override
+ public void visit(Class clazz, String methodName, String methodDesc, String variableName, Object variableValue) {
+
+ VariableDefinition variableDefinition = VariableDefinition.builder()
+ .clazz(clazz)
+ .methodName(methodName)
+ .methodDesc(methodDesc)
+ .variableName(variableName)
+ .build();
+ getVariableValues().put(variableDefinition, variableValue);
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/analyser/impl/LocalVariableParserImpl.java b/src/main/java/fr/istic/gm/weassert/test/analyser/impl/LocalVariableParserImpl.java
new file mode 100644
index 0000000..ccd4e16
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/analyser/impl/LocalVariableParserImpl.java
@@ -0,0 +1,112 @@
+package fr.istic.gm.weassert.test.analyser.impl;
+
+import fr.istic.gm.weassert.test.analyser.LocalVariableParser;
+import fr.istic.gm.weassert.test.model.LocalVariableParsed;
+import fr.istic.gm.weassert.test.utils.ClassReaderFactory;
+import fr.istic.gm.weassert.test.utils.UrlClassLoaderWrapper;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.LocalVariableNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static java.util.Arrays.asList;
+
+@Slf4j
+public class LocalVariableParserImpl implements LocalVariableParser {
+
+ private static final List PRIMITIVE_TYPE = asList(Type.BOOLEAN, Type.DOUBLE, Type.FLOAT, Type.INT, Type.LONG, Type.CHAR, Type.SHORT);
+
+ private ClassReader classReader;
+
+ private ClassNode classNode;
+
+ private UrlClassLoaderWrapper urlClassLoaderWrapper;
+
+ @Getter
+ private Class clazz;
+
+ public LocalVariableParserImpl(ClassReaderFactory classReaderFactory, Class clazz, ClassNode classNode, UrlClassLoaderWrapper urlClassLoaderWrapper) {
+ this.classReader = classReaderFactory.create(clazz);
+ this.clazz = clazz;
+ this.classNode = classNode;
+ this.urlClassLoaderWrapper = urlClassLoaderWrapper;
+ }
+
+ public List parse() {
+
+ log.info("LOCAL VARIABLE PARSE...");
+ classReader.accept(classNode, 0);
+ List variableParseds = mapMethodsToLocalVariableParsed(classNode.methods);
+ log.info("LOCAL VARIABLE PARSED: " + variableParseds);
+
+ return variableParseds;
+ }
+
+ private List mapMethodsToLocalVariableParsed(List methods) {
+ return methods.stream()
+ .filter(m -> !"".equals(m.name))
+ .map(m -> LocalVariableParsed.builder()
+ .name(m.name)
+ .desc(m.desc)
+ .localVariables(retrieveLocalVariables(m))
+ .build())
+ .collect(Collectors.toList());
+ }
+
+ private List retrieveLocalVariables(MethodNode methodNode) {
+ return methodNode.localVariables.stream()
+ .filter(v -> !"this".equals(v.name))
+ .map(this::retrieveVariableName)
+ .filter(Objects::nonNull)
+ .flatMap(Collection::stream)
+ .collect(Collectors.toList());
+ }
+
+ private List retrieveVariableName(LocalVariableNode localVariable) {
+ List variables = new ArrayList<>();
+ Type t = Type.getType(localVariable.desc);
+ if (t.getSort() == Type.OBJECT) {
+ variables.addAll(retrieveGetters(localVariable, t));
+ } else if (PRIMITIVE_TYPE.contains(t.getSort())) {
+ variables.add(localVariable.name);
+ }
+ return variables;
+ }
+
+ private List retrieveGetters(LocalVariableNode localVariable, Type type) {
+ List variables = new ArrayList<>();
+ Class> c = urlClassLoaderWrapper.getClassList().stream().filter(cl -> cl.getName().equals(type.getClassName())).findFirst().orElse(null);
+ if (c != null) {
+ for (Field f : c.getDeclaredFields()) {
+ if (f.getName() == null || f.getName().isEmpty()) {
+ continue;
+ }
+ String methodName = String.format("get%s%s", f.getName().substring(0, 1).toUpperCase(), f.getName().substring(1));
+ if (contains(c.getDeclaredMethods(), methodName)) {
+ variables.add(String.format("%s.%s()", localVariable.name, methodName));
+ }
+ }
+ }
+ return variables;
+ }
+
+ private boolean contains(Method[] declaredMethods, String methodName) {
+ for (Method m : declaredMethods) {
+ if (methodName.equals(m.getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/analyser/impl/TestAnalyserImpl.java b/src/main/java/fr/istic/gm/weassert/test/analyser/impl/TestAnalyserImpl.java
new file mode 100644
index 0000000..101b828
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/analyser/impl/TestAnalyserImpl.java
@@ -0,0 +1,99 @@
+package fr.istic.gm.weassert.test.analyser.impl;
+
+import fr.istic.gm.weassert.test.generator.CodeWriter;
+import fr.istic.gm.weassert.test.analyser.CodeVisitor;
+import fr.istic.gm.weassert.test.analyser.LocalVariableParser;
+import fr.istic.gm.weassert.test.analyser.TestAnalyser;
+import fr.istic.gm.weassert.test.compiler.SourceCodeCompiler;
+import fr.istic.gm.weassert.test.exception.WeAssertException;
+import fr.istic.gm.weassert.test.model.LocalVariableParsed;
+import fr.istic.gm.weassert.test.model.MethodDefinition;
+import fr.istic.gm.weassert.test.model.TestAnalysed;
+import fr.istic.gm.weassert.test.model.VariableDefinition;
+import fr.istic.gm.weassert.test.runner.TestRunner;
+import fr.istic.gm.weassert.test.utils.UrlClassLoaderWrapper;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static fr.istic.gm.weassert.test.utils.ClassResolverUtil.mapClassToClassPath;
+
+@Slf4j
+@AllArgsConstructor
+public class TestAnalyserImpl implements TestAnalyser {
+
+ private static final String VISITOR_CODE = "%s.INSTANCE.visit(getClass(), \"%s\", \"%s\", \"%s\", %s); // GENERATED VISITOR";
+
+ private LocalVariableParser localVariableParser;
+
+ private CodeWriter codeWriter;
+
+ private CodeVisitor codeVisitor;
+
+ private SourceCodeCompiler sourceCodeCompiler;
+
+ private UrlClassLoaderWrapper urlClassLoaderWrapper;
+
+ private TestRunner testRunner;
+
+ @Override
+ public List analyse() {
+
+ log.info("ANALYSE...");
+ addVisitorToTests();
+ Class> refreshedClass = retrieveClass();
+ Map firstVariableValues = runTestsAndRetrieveFistVariableValues(refreshedClass);
+ List result = createAnalyseResult(firstVariableValues, codeVisitor.getVariableValues());
+
+ log.info(String.format("ANALYSED: %s", result));
+ return result;
+ }
+
+ private Class> retrieveClass() {
+ return urlClassLoaderWrapper.getClassList().stream()
+ .filter(c -> mapClassToClassPath(c).equals(mapClassToClassPath(localVariableParser.getClazz())))
+ .findFirst()
+ .orElseThrow(() -> new WeAssertException("Can't reload refreshed class"));
+ }
+
+ private void addVisitorToTests() {
+ List parse = localVariableParser.parse();
+ parse.forEach(p ->
+ p.getLocalVariables().forEach(v ->
+ {
+ String visitor = String.format(VISITOR_CODE, codeVisitor.getClass().getName(), p.getName(), p.getDesc(), v, v);
+ codeWriter.insertOne(p.getName(), p.getDesc(), visitor);
+ }
+ ));
+ codeWriter.writeAndCloseFile();
+ sourceCodeCompiler.compileAndWait();
+ }
+
+ private Map runTestsAndRetrieveFistVariableValues(Class clazz) {
+ testRunner.startTest(clazz);
+ Map firstVariableValues = codeVisitor.getVariableValues();
+ codeVisitor.initVariableValues();
+ testRunner.startTest(clazz);
+ return firstVariableValues;
+ }
+
+ private List createAnalyseResult(Map firstVariableValues, Map secondsVariableValues) {
+ Map testAnalyseds = new HashMap<>();
+ firstVariableValues.keySet().stream().filter(k -> secondsVariableValues.containsKey(k) && secondsVariableValues.get(k).equals(firstVariableValues.get(k))).forEach(k -> {
+ MethodDefinition methodDefinition = MethodDefinition.builder().clazz(k.getClazz()).methodName(k.getMethodName()).methodDesc(k.getMethodDesc()).build();
+ TestAnalysed testAnalysed;
+ if (testAnalyseds.containsKey(methodDefinition)) {
+ testAnalysed = testAnalyseds.get(methodDefinition);
+ } else {
+ testAnalysed = TestAnalysed.builder().clazz(k.getClazz()).methodName(k.getMethodName()).methodDesc(k.getMethodDesc()).build();
+ testAnalyseds.put(methodDefinition, testAnalysed);
+ }
+ testAnalysed.getVariableValues().put(k.getVariableName(), firstVariableValues.get(k));
+ });
+ return new ArrayList<>(testAnalyseds.values());
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/application/WeAssertRunner.java b/src/main/java/fr/istic/gm/weassert/test/application/WeAssertRunner.java
new file mode 100644
index 0000000..2e98aa5
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/application/WeAssertRunner.java
@@ -0,0 +1,6 @@
+package fr.istic.gm.weassert.test.application;
+
+public interface WeAssertRunner {
+ void generate();
+ void runTests();
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/application/impl/WeAssertRunnerImpl.java b/src/main/java/fr/istic/gm/weassert/test/application/impl/WeAssertRunnerImpl.java
new file mode 100644
index 0000000..775225a
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/application/impl/WeAssertRunnerImpl.java
@@ -0,0 +1,80 @@
+package fr.istic.gm.weassert.test.application.impl;
+
+import fr.istic.gm.weassert.test.generator.AssertionGenerator;
+import fr.istic.gm.weassert.test.analyser.LocalVariableParser;
+import fr.istic.gm.weassert.test.analyser.TestAnalyser;
+import fr.istic.gm.weassert.test.analyser.impl.CodeVisitorImpl;
+import fr.istic.gm.weassert.test.analyser.impl.LocalVariableParserImpl;
+import fr.istic.gm.weassert.test.analyser.impl.TestAnalyserImpl;
+import fr.istic.gm.weassert.test.application.WeAssertRunner;
+import fr.istic.gm.weassert.test.compiler.SourceCodeCompiler;
+import fr.istic.gm.weassert.test.compiler.impl.SourceCodeCompilerImpl;
+import fr.istic.gm.weassert.test.generator.impl.AssertionGeneratorImpl;
+import fr.istic.gm.weassert.test.generator.impl.SourceCodeWriter;
+import fr.istic.gm.weassert.test.model.TestAnalysed;
+import fr.istic.gm.weassert.test.runner.TestRunner;
+import fr.istic.gm.weassert.test.runner.TestRunnerListener;
+import fr.istic.gm.weassert.test.runner.impl.TestRunnerImpl;
+import fr.istic.gm.weassert.test.utils.BackupUtils;
+import fr.istic.gm.weassert.test.utils.UrlClassLoaderWrapper;
+import fr.istic.gm.weassert.test.utils.impl.BackupUtilsImpl;
+import fr.istic.gm.weassert.test.utils.impl.ClassReaderFactoryImpl;
+import fr.istic.gm.weassert.test.utils.impl.ProcessBuilderFactoryImpl;
+import fr.istic.gm.weassert.test.utils.impl.UrlClassLoaderWrapperImpl;
+import org.junit.runner.JUnitCore;
+import org.objectweb.asm.tree.ClassNode;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static fr.istic.gm.weassert.test.utils.ClassResolverUtil.mapClassToSourcePath;
+import static java.util.Arrays.asList;
+
+public class WeAssertRunnerImpl implements WeAssertRunner {
+
+ private static final String TEST_END_FILENAME = "Test";
+ private static final List DEFAULT_MAVEN_FILE_PATH = asList("%s/target/classes/", "%s/target/test-classes/");
+
+ private String mavenProjectPath;
+
+ private String mavenCommand;
+
+ private TestRunnerListener testRunnerListener;
+
+ public WeAssertRunnerImpl(String mavenProjectPath, String mavenCommand, TestRunnerListener testRunnerListener) {
+ this.mavenProjectPath = mavenProjectPath;
+ this.mavenCommand = mavenCommand;
+ this.testRunnerListener = testRunnerListener;
+ }
+
+ @Override
+ public void generate() {
+ List filePaths = getMavenFilePath();
+ UrlClassLoaderWrapper urlClassLoaderWrapper = new UrlClassLoaderWrapperImpl(filePaths);
+ urlClassLoaderWrapper.getClassList().stream().filter(c -> c.getName().endsWith(TEST_END_FILENAME)).forEach(c -> {
+ LocalVariableParser localVariableParser = new LocalVariableParserImpl(new ClassReaderFactoryImpl(), c, new ClassNode(), urlClassLoaderWrapper);
+ SourceCodeCompiler codeCompiler = new SourceCodeCompilerImpl(mavenProjectPath, mavenCommand, new ProcessBuilderFactoryImpl(), urlClassLoaderWrapper);
+ String sourcePath = mapClassToSourcePath(c);
+ BackupUtils backupUtils = new BackupUtilsImpl(sourcePath);
+ TestAnalyser testAnalyser = new TestAnalyserImpl(localVariableParser, new SourceCodeWriter(sourcePath), CodeVisitorImpl.INSTANCE, codeCompiler, urlClassLoaderWrapper, new TestRunnerImpl(new JUnitCore(), testRunnerListener));
+ List testAnalyseds = testAnalyser.analyse();
+ backupUtils.restore();
+ AssertionGenerator assertionGenerator = new AssertionGeneratorImpl(new SourceCodeWriter(sourcePath));
+ assertionGenerator.generate(testAnalyseds);
+ });
+ }
+
+ @Override
+ public void runTests() {
+ List filePaths = getMavenFilePath();
+ UrlClassLoaderWrapper urlClassLoaderWrapper = new UrlClassLoaderWrapperImpl(filePaths);
+ urlClassLoaderWrapper.getClassList().stream().filter(c -> c.getName().endsWith(TEST_END_FILENAME)).forEach(c -> {
+ TestRunner testRunner = new TestRunnerImpl(new JUnitCore(), testRunnerListener);
+ testRunner.startTest(c);
+ });
+ }
+
+ private List getMavenFilePath() {
+ return DEFAULT_MAVEN_FILE_PATH.stream().map(s -> String.format(s, mavenProjectPath)).collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/compiler/SourceCodeCompiler.java b/src/main/java/fr/istic/gm/weassert/test/compiler/SourceCodeCompiler.java
new file mode 100644
index 0000000..2305296
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/compiler/SourceCodeCompiler.java
@@ -0,0 +1,5 @@
+package fr.istic.gm.weassert.test.compiler;
+
+public interface SourceCodeCompiler {
+ void compileAndWait();
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/compiler/impl/SourceCodeCompilerImpl.java b/src/main/java/fr/istic/gm/weassert/test/compiler/impl/SourceCodeCompilerImpl.java
new file mode 100644
index 0000000..c22562b
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/compiler/impl/SourceCodeCompilerImpl.java
@@ -0,0 +1,103 @@
+package fr.istic.gm.weassert.test.compiler.impl;
+
+import fr.istic.gm.weassert.test.compiler.SourceCodeCompiler;
+import fr.istic.gm.weassert.test.exception.WeAssertException;
+import fr.istic.gm.weassert.test.utils.BackupUtils;
+import fr.istic.gm.weassert.test.utils.ProcessBuilderFactory;
+import fr.istic.gm.weassert.test.utils.ProcessBuilderWrapper;
+import fr.istic.gm.weassert.test.utils.UrlClassLoaderWrapper;
+import fr.istic.gm.weassert.test.utils.impl.BackupUtilsImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStreamReader;
+import java.nio.file.Paths;
+
+@Slf4j
+public class SourceCodeCompilerImpl implements SourceCodeCompiler {
+
+ private static final String POM_FILE = "/pom.xml";
+ private static final String ERROR_NO_POM = "SourceCodeCompilerImpl: No pom file on the maven project %s";
+
+ private String mavenProjectPath;
+
+ private ProcessBuilderWrapper processBuilder;
+
+ private UrlClassLoaderWrapper urlClassLoaderWrapper;
+
+ public SourceCodeCompilerImpl(String mavenProjectPath, String mavenCommand, ProcessBuilderFactory processBuilderFactory, UrlClassLoaderWrapper urlClassLoaderWrapper) {
+ this.mavenProjectPath = mavenProjectPath + POM_FILE;
+ this.urlClassLoaderWrapper = urlClassLoaderWrapper;
+ if (!Paths.get(mavenProjectPath).toFile().exists()) {
+ throw new WeAssertException(String.format(ERROR_NO_POM, this.mavenProjectPath));
+ }
+ processBuilder = processBuilderFactory.create(mavenProjectPath, mavenCommand, "clean", "test", "-DskipTests");
+ }
+
+ @Override
+ public void compileAndWait() {
+ try {
+ BackupUtils backupUtils = insertDeps();
+ Process start = processBuilder.start();
+ BufferedReader buff = new BufferedReader(new InputStreamReader(start.getInputStream()));
+ while (start.isAlive()) {
+ String line;
+ while ((line = buff.readLine()) != null) {
+ log.info(line);
+ }
+ }
+ urlClassLoaderWrapper.refresh();
+ backupUtils.restore();
+ } catch (Exception e) {
+ throw new WeAssertException("SourceCodeCompilerImpl: Compile error", e);
+ }
+ }
+
+ private BackupUtils insertDeps() {
+ try {
+ BackupUtils backupUtils = new BackupUtilsImpl(mavenProjectPath);
+ DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
+ domFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ DocumentBuilder builder = domFactory.newDocumentBuilder();
+ Document doc = builder.parse(new File(mavenProjectPath));
+ NodeList nodes = doc.getElementsByTagName("dependencies");
+ Element dependency = doc.createElement("dependency");
+ Element groupId = doc.createElement("groupId");
+ Element artifactId = doc.createElement("artifactId");
+ Element version = doc.createElement("version");
+ Text groupIdText = doc.createTextNode("fr.istic.gm");
+ Text artifactIdText = doc.createTextNode("we-assert");
+ Text versionText = doc.createTextNode("1.0");
+ groupId.appendChild(groupIdText);
+ artifactId.appendChild(artifactIdText);
+ version.appendChild(versionText);
+ dependency.appendChild(groupId);
+ dependency.appendChild(artifactId);
+ dependency.appendChild(version);
+ nodes.item(0).insertBefore(dependency, nodes.item(0).getChildNodes().item(0).getNextSibling());
+ TransformerFactory factory = TransformerFactory.newInstance();
+ factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ Transformer transformer = factory.newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ DOMSource domSource = new DOMSource(doc);
+ StreamResult streamResult = new StreamResult(new File(mavenProjectPath));
+ transformer.transform(domSource, streamResult);
+ return backupUtils;
+ } catch (Exception e) {
+ throw new WeAssertException("Can't insert deps", e);
+ }
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/exception/WeAssertException.java b/src/main/java/fr/istic/gm/weassert/test/exception/WeAssertException.java
new file mode 100644
index 0000000..89d4a56
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/exception/WeAssertException.java
@@ -0,0 +1,17 @@
+package fr.istic.gm.weassert.test.exception;
+
+/**
+ * The main application exception
+ */
+public class WeAssertException extends RuntimeException {
+
+ public static final String WRONG_CLASS_PATH = "The class path is wrong.";
+
+ public WeAssertException(String message) {
+ super(message);
+ }
+
+ public WeAssertException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/generator/AssertionGenerator.java b/src/main/java/fr/istic/gm/weassert/test/generator/AssertionGenerator.java
new file mode 100644
index 0000000..a324080
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/generator/AssertionGenerator.java
@@ -0,0 +1,9 @@
+package fr.istic.gm.weassert.test.generator;
+
+import fr.istic.gm.weassert.test.model.TestAnalysed;
+
+import java.util.List;
+
+public interface AssertionGenerator {
+ void generate(List testsAnalysed);
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/generator/CodeWriter.java b/src/main/java/fr/istic/gm/weassert/test/generator/CodeWriter.java
new file mode 100644
index 0000000..653b5a7
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/generator/CodeWriter.java
@@ -0,0 +1,9 @@
+package fr.istic.gm.weassert.test.generator;
+
+import java.util.List;
+
+public interface CodeWriter {
+ void insertOne(String methodName, String desc, String code);
+ void insertMany(String methodName, String desc, List codes);
+ void writeAndCloseFile();
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/generator/impl/AssertionGeneratorImpl.java b/src/main/java/fr/istic/gm/weassert/test/generator/impl/AssertionGeneratorImpl.java
new file mode 100644
index 0000000..1b4164a
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/generator/impl/AssertionGeneratorImpl.java
@@ -0,0 +1,39 @@
+package fr.istic.gm.weassert.test.generator.impl;
+
+import fr.istic.gm.weassert.test.generator.AssertionGenerator;
+import fr.istic.gm.weassert.test.generator.CodeWriter;
+import fr.istic.gm.weassert.test.model.TestAnalysed;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class AssertionGeneratorImpl implements AssertionGenerator {
+
+ private static final List PRIMITIVES = Arrays.asList(Integer.class, Long.class, Float.class, Double.class, Boolean.class);
+ private CodeWriter codeWriter;
+
+ public AssertionGeneratorImpl(CodeWriter codeWriter) {
+ this.codeWriter = codeWriter;
+ }
+
+ @Override
+ public void generate(List testsAnalysed) {
+ testsAnalysed.forEach(testAnalysed -> {
+ List generatedCodes = new ArrayList<>();
+
+ testAnalysed.getVariableValues().keySet().forEach(key -> {
+ Object o = testAnalysed.getVariableValues().get(key);
+ if (PRIMITIVES.contains(o.getClass())) {
+ generatedCodes.add("org.junit.Assert.assertEquals(" + key + "," + o.toString() + "); // GENERATED ASSERT");
+ } else if (o.getClass() == String.class) {
+ generatedCodes.add("org.junit.Assert.assertEquals(" + key + ",\"" + o.toString() + "\"); // GENERATED ASSERT");
+ }
+ });
+
+ this.codeWriter.insertMany(testAnalysed.getMethodName(), testAnalysed.getMethodDesc(), generatedCodes);
+ });
+
+ this.codeWriter.writeAndCloseFile();
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/generator/impl/JavassitCodeWriter.java b/src/main/java/fr/istic/gm/weassert/test/generator/impl/JavassitCodeWriter.java
new file mode 100644
index 0000000..83bda8f
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/generator/impl/JavassitCodeWriter.java
@@ -0,0 +1,59 @@
+package fr.istic.gm.weassert.test.generator.impl;
+
+import fr.istic.gm.weassert.test.generator.CodeWriter;
+import fr.istic.gm.weassert.test.exception.WeAssertException;
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.NotFoundException;
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+public class JavassitCodeWriter implements CodeWriter {
+ private String className;
+
+ private CtClass classContainer;
+
+ public JavassitCodeWriter(Class clazz) {
+ ClassPool pool = ClassPool.getDefault();
+
+ try {
+ this.classContainer = pool.get(clazz.getName());
+ this.className = clazz.getName();
+ } catch (NotFoundException e) {
+ throw new WeAssertException(
+ String.format("CodeWriter: could not find class named %s", clazz.getName()), e
+ );
+ }
+ }
+
+ public void insertOne(String methodName, String desc, String code) {
+ try {
+ CtMethod method = this.classContainer.getMethod(methodName, desc);
+ method.insertAfter(code);
+ } catch (CannotCompileException e) {
+ throw new WeAssertException("JavassitCodeWriter: could not insert code", e);
+ } catch (NotFoundException e) {
+ throw new WeAssertException(
+ String.format("JavassitCodeWriter: could not find method named %s", methodName), e
+ );
+ }
+ }
+
+ @Override
+ public void insertMany(String methodName, String desc, List codes) {
+ codes.forEach(src -> this.insertOne(methodName, desc, src));
+ }
+
+ @Override
+ public void writeAndCloseFile() {
+ try {
+ this.classContainer.writeFile();
+ } catch (Exception e) {
+ throw new WeAssertException("JavassitCodeWriter: could not write file", e);
+ }
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/generator/impl/SourceCodeWriter.java b/src/main/java/fr/istic/gm/weassert/test/generator/impl/SourceCodeWriter.java
new file mode 100644
index 0000000..8a5d7b7
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/generator/impl/SourceCodeWriter.java
@@ -0,0 +1,124 @@
+package fr.istic.gm.weassert.test.generator.impl;
+
+import fr.istic.gm.weassert.test.generator.CodeWriter;
+import fr.istic.gm.weassert.test.exception.WeAssertException;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Slf4j
+@Getter
+public class SourceCodeWriter implements CodeWriter {
+ public static final String CLASSNAME_REGEX = "^(private |public |protected |)(static |)class (\\w+)( \\{|)$";
+
+ public static final String METHODNAME_REGEX = "^.*(@Test)(\\r|\\n)*\\s*(private |public |protected |)(static |)(void |)(\\w+)\\s*\\(\\)\\s+\\{$";
+
+ private File sourceFile;
+
+ private String sourceCode;
+
+ private String className;
+
+ public SourceCodeWriter(String classPath) {
+ this.sourceFile = new File(classPath);
+
+ if (!sourceFile.exists()) {
+ throw new WeAssertException(String.format("SourceCodeWriter: no such source file at: '%s'", classPath));
+ }
+
+ try {
+ this.sourceCode = new String(Files.readAllBytes(sourceFile.toPath()));
+ } catch (IOException e) {
+ throw new WeAssertException("SourceCodeWriter: could not read source code !");
+ }
+
+ findClassName();
+ }
+
+ private void findClassName() {
+ Pattern pattern = Pattern.compile(CLASSNAME_REGEX, Pattern.MULTILINE);
+ Matcher matcher = pattern.matcher(this.sourceCode);
+
+ if (matcher.find()) {
+ if (matcher.group(3) != null) {
+ this.className = matcher.group(3);
+ } else {
+ throw new WeAssertException(getClassName() + ": could not find class name!");
+ }
+ } else {
+ throw new WeAssertException(getClassName() + ": given file is not a Java class source file!");
+ }
+ }
+
+ public void insertOne(String methodName, String desc, String code) {
+ Pattern pattern = Pattern.compile(METHODNAME_REGEX, Pattern.MULTILINE);
+ Matcher matcher = pattern.matcher(this.sourceCode);
+
+ int firstCurlyBraceIndex = 0;
+ while (matcher.find()) {
+ if (matcher.group(6).equals(methodName)) {
+ firstCurlyBraceIndex = matcher.end();
+ break;
+ }
+ }
+
+ if (firstCurlyBraceIndex == 0) {
+ throw new WeAssertException(String.format("%s: could not find method named \"%s\" !", getClassName(), methodName));
+ }
+
+ int lastCurlyBraceIndex = findLastCurlyBraceIndex(firstCurlyBraceIndex);
+
+ StringBuilder str = new StringBuilder(this.sourceCode);
+ str.insert(lastCurlyBraceIndex, code + "\n");
+
+ // CODE INSERTION HERE
+ this.sourceCode = str.toString();
+ }
+
+ private int findLastCurlyBraceIndex(int firstCurlyIndex) {
+ int curlyBracesCounter = 1;
+ int lastCurlyBrace = firstCurlyIndex;
+
+ for (;lastCurlyBrace < this.sourceCode.length(); lastCurlyBrace++) {
+ if (this.sourceCode.charAt(lastCurlyBrace) == '{') {
+ curlyBracesCounter++;
+ } else if (this.sourceCode.charAt(lastCurlyBrace) == '}') {
+ curlyBracesCounter--;
+ }
+
+ if (curlyBracesCounter == 0) {
+ break;
+ }
+ }
+
+ if(lastCurlyBrace == 0) {
+ throw new WeAssertException(getClassName() + ": parse error, could not find end of method!");
+ }
+
+ return lastCurlyBrace;
+ }
+
+ @Override
+ public void insertMany(String methodName, String desc, List codes) {
+ codes.forEach(src -> this.insertOne(methodName, desc, src));
+ }
+
+ @Override
+ public void writeAndCloseFile() {
+ try {
+ PrintWriter writer = new PrintWriter(this.sourceFile);
+ writer.write(this.sourceCode);
+ writer.close();
+ } catch (FileNotFoundException e) {
+ log.error("Can't find the file to write", e);
+ }
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/model/LocalVariableParsed.java b/src/main/java/fr/istic/gm/weassert/test/model/LocalVariableParsed.java
new file mode 100644
index 0000000..fe6086e
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/model/LocalVariableParsed.java
@@ -0,0 +1,19 @@
+package fr.istic.gm.weassert.test.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class LocalVariableParsed implements MethodSignature {
+
+ private String name;
+ private String desc;
+ private List localVariables;
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/model/MethodDefinition.java b/src/main/java/fr/istic/gm/weassert/test/model/MethodDefinition.java
new file mode 100644
index 0000000..5197631
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/model/MethodDefinition.java
@@ -0,0 +1,19 @@
+package fr.istic.gm.weassert.test.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class MethodDefinition {
+
+ private Class clazz;
+
+ private String methodName;
+
+ private String methodDesc;
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/model/MethodSignature.java b/src/main/java/fr/istic/gm/weassert/test/model/MethodSignature.java
new file mode 100644
index 0000000..a8fb979
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/model/MethodSignature.java
@@ -0,0 +1,6 @@
+package fr.istic.gm.weassert.test.model;
+
+public interface MethodSignature {
+ String getName();
+ String getDesc();
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/model/TestAnalysed.java b/src/main/java/fr/istic/gm/weassert/test/model/TestAnalysed.java
new file mode 100644
index 0000000..5a6b326
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/model/TestAnalysed.java
@@ -0,0 +1,33 @@
+package fr.istic.gm.weassert.test.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(exclude = "variableValues")
+public class TestAnalysed {
+
+ private Class clazz;
+
+ private String methodName;
+
+ private String methodDesc;
+
+ Map variableValues = new HashMap<>();
+
+ public Map getVariableValues() {
+ if (variableValues == null) {
+ variableValues = new HashMap<>();
+ }
+ return variableValues;
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/model/VariableDefinition.java b/src/main/java/fr/istic/gm/weassert/test/model/VariableDefinition.java
new file mode 100644
index 0000000..274e34a
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/model/VariableDefinition.java
@@ -0,0 +1,21 @@
+package fr.istic.gm.weassert.test.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class VariableDefinition {
+
+ private Class clazz;
+
+ private String methodName;
+
+ private String methodDesc;
+
+ private String variableName;
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/runner/TestRunner.java b/src/main/java/fr/istic/gm/weassert/test/runner/TestRunner.java
new file mode 100644
index 0000000..c18a4f7
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/runner/TestRunner.java
@@ -0,0 +1,23 @@
+package fr.istic.gm.weassert.test.runner;
+
+import java.util.List;
+
+/**
+ * The test runner
+ */
+public interface TestRunner {
+
+ /**
+ * Start all tests from the classes
+ *
+ * @param classes the classes to start test
+ */
+ void startTests(List> classes);
+
+ /**
+ * Start all tests from the class
+ *
+ * @param clazz the class to start test
+ */
+ void startTest(Class> clazz);
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/runner/TestRunnerListener.java b/src/main/java/fr/istic/gm/weassert/test/runner/TestRunnerListener.java
new file mode 100644
index 0000000..58efcf8
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/runner/TestRunnerListener.java
@@ -0,0 +1,6 @@
+package fr.istic.gm.weassert.test.runner;
+
+import org.junit.runner.notification.RunListener;
+
+public class TestRunnerListener extends RunListener {
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/runner/impl/TestRunnerImpl.java b/src/main/java/fr/istic/gm/weassert/test/runner/impl/TestRunnerImpl.java
new file mode 100644
index 0000000..1752c5a
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/runner/impl/TestRunnerImpl.java
@@ -0,0 +1,31 @@
+package fr.istic.gm.weassert.test.runner.impl;
+
+import fr.istic.gm.weassert.test.runner.TestRunner;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.notification.RunListener;
+
+import java.util.List;
+
+@Slf4j
+public class TestRunnerImpl implements TestRunner {
+
+ private JUnitCore jUnitCore;
+
+ public TestRunnerImpl(JUnitCore jUnitCore, RunListener runListener) {
+ this.jUnitCore = jUnitCore;
+ this.jUnitCore.addListener(runListener);
+ }
+
+ @Override
+ public void startTests(List> classes) {
+ classes.forEach(this::startTest);
+ log.info("TESTS RUNNED: " + classes);
+ }
+
+ @Override
+ public void startTest(Class> clazz) {
+ jUnitCore.run(clazz);
+ log.info("TESTS RUNNED: " + clazz);
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/BackupUtils.java b/src/main/java/fr/istic/gm/weassert/test/utils/BackupUtils.java
new file mode 100644
index 0000000..7587aa3
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/BackupUtils.java
@@ -0,0 +1,5 @@
+package fr.istic.gm.weassert.test.utils;
+
+public interface BackupUtils {
+ void restore();
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/ClassReaderFactory.java b/src/main/java/fr/istic/gm/weassert/test/utils/ClassReaderFactory.java
new file mode 100644
index 0000000..40b5657
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/ClassReaderFactory.java
@@ -0,0 +1,7 @@
+package fr.istic.gm.weassert.test.utils;
+
+import org.objectweb.asm.ClassReader;
+
+public interface ClassReaderFactory {
+ ClassReader create(Class clazz);
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/ClassResolverUtil.java b/src/main/java/fr/istic/gm/weassert/test/utils/ClassResolverUtil.java
new file mode 100644
index 0000000..7128605
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/ClassResolverUtil.java
@@ -0,0 +1,15 @@
+package fr.istic.gm.weassert.test.utils;
+
+public class ClassResolverUtil {
+
+ private ClassResolverUtil() {
+ }
+
+ public static String mapClassToClassPath(Class clazz) {
+ return String.format("%s%s.class", clazz.getProtectionDomain().getCodeSource().getLocation().getPath(), clazz.getName().replace(".", "/"));
+ }
+
+ public static String mapClassToSourcePath(Class clazz) {
+ return String.format("%s%s.java", clazz.getProtectionDomain().getCodeSource().getLocation().getPath().replace("/target/classes/", "/src/main/java/").replace("/target/test-classes/", "/src/test/java/"), clazz.getName().replace(".", "/"));
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/FileUtils.java b/src/main/java/fr/istic/gm/weassert/test/utils/FileUtils.java
new file mode 100644
index 0000000..ecf0a13
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/FileUtils.java
@@ -0,0 +1,27 @@
+package fr.istic.gm.weassert.test.utils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FileUtils {
+
+ private FileUtils() {
+ }
+
+ public static List findFilesFromFolder(File folder) {
+ List files = new ArrayList<>();
+ File[] listFiles = folder.listFiles();
+ if (listFiles == null) {
+ return files;
+ }
+ for (File file : listFiles) {
+ if (file.isDirectory()) {
+ files.addAll(findFilesFromFolder(file));
+ } else {
+ files.add(file);
+ }
+ }
+ return files;
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/ProcessBuilderFactory.java b/src/main/java/fr/istic/gm/weassert/test/utils/ProcessBuilderFactory.java
new file mode 100644
index 0000000..7b0a3e2
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/ProcessBuilderFactory.java
@@ -0,0 +1,6 @@
+package fr.istic.gm.weassert.test.utils;
+
+public interface ProcessBuilderFactory {
+
+ ProcessBuilderWrapper create(String directory, String... command);
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/ProcessBuilderWrapper.java b/src/main/java/fr/istic/gm/weassert/test/utils/ProcessBuilderWrapper.java
new file mode 100644
index 0000000..2ccc2bb
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/ProcessBuilderWrapper.java
@@ -0,0 +1,11 @@
+package fr.istic.gm.weassert.test.utils;
+
+import java.io.File;
+import java.util.List;
+
+public interface ProcessBuilderWrapper {
+ Process start();
+ File directory();
+ List command();
+ ProcessBuilderWrapper directory(String filePath);
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/UrlClassLoaderWrapper.java b/src/main/java/fr/istic/gm/weassert/test/utils/UrlClassLoaderWrapper.java
new file mode 100644
index 0000000..11c4ea1
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/UrlClassLoaderWrapper.java
@@ -0,0 +1,18 @@
+package fr.istic.gm.weassert.test.utils;
+
+import java.util.List;
+
+/**
+ * A Url Class Loader wrapper to retrieve classes
+ */
+public interface UrlClassLoaderWrapper {
+
+ /**
+ * Retrieve classes
+ *
+ * @return the classes
+ */
+ List> getClassList();
+
+ void refresh();
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/impl/BackupUtilsImpl.java b/src/main/java/fr/istic/gm/weassert/test/utils/impl/BackupUtilsImpl.java
new file mode 100644
index 0000000..3f6eb19
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/impl/BackupUtilsImpl.java
@@ -0,0 +1,37 @@
+package fr.istic.gm.weassert.test.utils.impl;
+
+import fr.istic.gm.weassert.test.exception.WeAssertException;
+import fr.istic.gm.weassert.test.utils.BackupUtils;
+import lombok.Getter;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+public class BackupUtilsImpl implements BackupUtils {
+
+ private String fileName;
+
+ @Getter
+ private byte[] content;
+
+ public BackupUtilsImpl(String fileName) {
+ this.fileName = fileName;
+ File file = new File(fileName);
+ try {
+ content = Files.readAllBytes(file.toPath());
+ } catch (IOException e) {
+ throw new WeAssertException("Can't store file: " + fileName, e);
+ }
+ }
+
+ @Override
+ public void restore() {
+ File file = new File(fileName);
+ try {
+ Files.write(file.toPath(), content);
+ } catch (IOException e) {
+ throw new WeAssertException("Can't restore file: " + fileName, e);
+ }
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/impl/ClassReaderFactoryImpl.java b/src/main/java/fr/istic/gm/weassert/test/utils/impl/ClassReaderFactoryImpl.java
new file mode 100644
index 0000000..f5f9e3c
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/impl/ClassReaderFactoryImpl.java
@@ -0,0 +1,26 @@
+package fr.istic.gm.weassert.test.utils.impl;
+
+import fr.istic.gm.weassert.test.exception.WeAssertException;
+import fr.istic.gm.weassert.test.utils.ClassReaderFactory;
+import org.objectweb.asm.ClassReader;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+
+import static fr.istic.gm.weassert.test.exception.WeAssertException.WRONG_CLASS_PATH;
+import static fr.istic.gm.weassert.test.utils.ClassResolverUtil.mapClassToClassPath;
+
+public class ClassReaderFactoryImpl implements ClassReaderFactory {
+
+ @Override
+ public ClassReader create(Class clazz) {
+ try {
+ String classPath = mapClassToClassPath(clazz);
+ InputStream classInputStream = new FileInputStream(new File(classPath));
+ return new ClassReader(classInputStream);
+ } catch (Exception e) {
+ throw new WeAssertException(WRONG_CLASS_PATH, e);
+ }
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/impl/ProcessBuilderFactoryImpl.java b/src/main/java/fr/istic/gm/weassert/test/utils/impl/ProcessBuilderFactoryImpl.java
new file mode 100644
index 0000000..7f1d652
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/impl/ProcessBuilderFactoryImpl.java
@@ -0,0 +1,27 @@
+package fr.istic.gm.weassert.test.utils.impl;
+
+import fr.istic.gm.weassert.test.exception.WeAssertException;
+import fr.istic.gm.weassert.test.utils.ProcessBuilderFactory;
+import fr.istic.gm.weassert.test.utils.ProcessBuilderWrapper;
+import lombok.AllArgsConstructor;
+
+import java.nio.file.Paths;
+
+@AllArgsConstructor
+public class ProcessBuilderFactoryImpl implements ProcessBuilderFactory {
+
+ private static final String ERROR_DIRECTORY = "ProcessBuilderFactoryImpl: The directory needs to exists %s";
+ private static final String ERROR_COMMAND = "ProcessBuilderFactoryImpl: No command";
+
+ @Override
+ public ProcessBuilderWrapper create(String directory, String... command) {
+ if (directory == null || !Paths.get(directory).toFile().isDirectory()) {
+ throw new WeAssertException(String.format(ERROR_DIRECTORY, directory));
+ }
+ if (command == null || command.length == 0 || command[0].isEmpty()) {
+ throw new WeAssertException(ERROR_COMMAND);
+ }
+ return new ProcessBuilderWrapperImpl(command)
+ .directory(directory);
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/impl/ProcessBuilderWrapperImpl.java b/src/main/java/fr/istic/gm/weassert/test/utils/impl/ProcessBuilderWrapperImpl.java
new file mode 100644
index 0000000..840ef66
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/impl/ProcessBuilderWrapperImpl.java
@@ -0,0 +1,42 @@
+package fr.istic.gm.weassert.test.utils.impl;
+
+import fr.istic.gm.weassert.test.exception.WeAssertException;
+import fr.istic.gm.weassert.test.utils.ProcessBuilderWrapper;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+public class ProcessBuilderWrapperImpl implements ProcessBuilderWrapper {
+
+ private ProcessBuilder processBuilder;
+
+ ProcessBuilderWrapperImpl(String... command) {
+ processBuilder = new ProcessBuilder(command);
+ }
+
+ @Override
+ public Process start() {
+ try {
+ return processBuilder.start();
+ } catch (IOException e) {
+ throw new WeAssertException("ProcessBuilderWrapperImpl: Process start failed", e);
+ }
+ }
+
+ @Override
+ public File directory() {
+ return processBuilder.directory();
+ }
+
+ @Override
+ public List command() {
+ return processBuilder.command();
+ }
+
+ @Override
+ public ProcessBuilderWrapper directory(String filePath) {
+ processBuilder.directory(new File(filePath));
+ return this;
+ }
+}
diff --git a/src/main/java/fr/istic/gm/weassert/test/utils/impl/UrlClassLoaderWrapperImpl.java b/src/main/java/fr/istic/gm/weassert/test/utils/impl/UrlClassLoaderWrapperImpl.java
new file mode 100644
index 0000000..796f6f6
--- /dev/null
+++ b/src/main/java/fr/istic/gm/weassert/test/utils/impl/UrlClassLoaderWrapperImpl.java
@@ -0,0 +1,91 @@
+package fr.istic.gm.weassert.test.utils.impl;
+
+import fr.istic.gm.weassert.test.exception.WeAssertException;
+import fr.istic.gm.weassert.test.utils.FileUtils;
+import fr.istic.gm.weassert.test.utils.UrlClassLoaderWrapper;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class UrlClassLoaderWrapperImpl implements UrlClassLoaderWrapper {
+
+ private static final String LOAD_CLASS_ERROR = "Can't load class: ";
+ private static final String PARSED_ERROR = "Url can't be parsed: ";
+
+ private List paths;
+
+ @Getter
+ private List> classList;
+
+ private URLClassLoader urlClassLoader;
+
+ public UrlClassLoaderWrapperImpl(List paths) {
+ this.paths = paths;
+ refresh();
+ }
+
+ @Override
+ public void refresh() {
+ log.info("LOADING CLASS...");
+ URL[] urls = paths.stream().map(this::mapToUrl).toArray(URL[]::new);
+ urlClassLoader = URLClassLoader.newInstance(urls, getClass().getClassLoader());
+ classList = mapPathsToClass(paths);
+ log.info("CLASSLOADED: " + paths);
+ }
+
+ private List> mapPathsToClass(List paths) {
+ List fileNames = mapPathsToFileNames(paths);
+ List classNames = new ArrayList<>();
+ fileNames.forEach(f -> {
+ for (String p : paths) {
+ if (f.startsWith(p)) {
+ String className = f.replaceAll(String.format("^%s", p), "")
+ .replaceAll("\\.class$", "")
+ .replaceAll("^/", "")
+ .replace("/", ".");
+ classNames.add(className);
+ break;
+ }
+ }
+ });
+ return classNames.stream().map(this::mapToClass).collect(Collectors.toList());
+ }
+
+ private List mapPathsToFileNames(List paths) {
+ return paths.stream()
+ .map(File::new)
+ .map(FileUtils::findFilesFromFolder)
+ .flatMap(Collection::stream)
+ .map(File::getPath)
+ .filter(f -> f.endsWith(".class")).collect(Collectors.toList());
+ }
+
+ private URL mapToUrl(String a) {
+ try {
+ return new URL(String.format("file://%s/", a));
+ } catch (MalformedURLException e) {
+ String message = PARSED_ERROR + e.getCause();
+ log.info(message);
+ throw new WeAssertException(message, e);
+ }
+ }
+
+ private Class> mapToClass(String className) {
+ try {
+ return urlClassLoader.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ String message = LOAD_CLASS_ERROR + e.getCause();
+ log.info(message);
+ throw new WeAssertException(message, e);
+ }
+ }
+}
diff --git a/src/main/resources/rootPane.fxml b/src/main/resources/rootPane.fxml
new file mode 100644
index 0000000..24e34e3
--- /dev/null
+++ b/src/main/resources/rootPane.fxml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/fr/istic/gm/weassert/AppTest.java b/src/test/java/fr/istic/gm/weassert/AppTest.java
deleted file mode 100644
index eee4c1b..0000000
--- a/src/test/java/fr/istic/gm/weassert/AppTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package fr.istic.gm.weassert;
-
-import org.junit.Test;
-
-public class AppTest {
-
- @Test
- public void shouldStartTheApplication() {
- App.main();
- }
-}
diff --git a/src/test/java/fr/istic/gm/weassert/TestData.java b/src/test/java/fr/istic/gm/weassert/TestData.java
new file mode 100644
index 0000000..4736f34
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/TestData.java
@@ -0,0 +1,21 @@
+package fr.istic.gm.weassert;
+
+import uk.co.jemos.podam.api.PodamFactory;
+import uk.co.jemos.podam.api.PodamFactoryImpl;
+
+public class TestData {
+
+ private static final PodamFactory FACTORY = new PodamFactoryImpl();
+
+ /**
+ * Generate an object
+ * usage: some(YourObject.class)
+ *
+ * @param clazz the class
+ * @param the return type
+ * @return a new object with all data
+ */
+ public static final T some(Class clazz) {
+ return FACTORY.manufacturePojoWithFullData(clazz);
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/TestUtils.java b/src/test/java/fr/istic/gm/weassert/TestUtils.java
new file mode 100644
index 0000000..fea30d7
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/TestUtils.java
@@ -0,0 +1,10 @@
+package fr.istic.gm.weassert;
+
+import java.nio.file.Paths;
+
+public class TestUtils {
+
+ public static String getAbsolutePath(String relativePath) {
+ return Paths.get(relativePath).toAbsolutePath().toString();
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/controller/MainControllerTest.java b/src/test/java/fr/istic/gm/weassert/controller/MainControllerTest.java
new file mode 100644
index 0000000..e46e7f4
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/controller/MainControllerTest.java
@@ -0,0 +1,40 @@
+package fr.istic.gm.weassert.controller;
+
+import fr.istic.gm.weassert.test.application.WeAssertRunner;
+import javafx.scene.layout.VBox;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.mockito.Mockito.verify;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MainControllerTest {
+
+ @Mock
+ private VBox mainVBox;
+
+ @Mock
+ private WeAssertRunner mockWeAssertRunner;
+
+ @InjectMocks
+ private MainController mainController;
+
+ @Test
+ public void shouldRunTests() {
+
+ mainController.testAction();
+
+ verify(mockWeAssertRunner).runTests();
+ }
+
+ @Test
+ public void shouldRunGeneration() {
+
+ mainController.generateAction();
+
+ verify(mockWeAssertRunner).generate();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/fr/istic/gm/weassert/test/analyser/CodeVisitorImplTest.java b/src/test/java/fr/istic/gm/weassert/test/analyser/CodeVisitorImplTest.java
new file mode 100644
index 0000000..5ad862a
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/analyser/CodeVisitorImplTest.java
@@ -0,0 +1,54 @@
+package fr.istic.gm.weassert.test.analyser;
+
+import fr.istic.gm.weassert.test.analyser.impl.CodeVisitorImpl;
+import fr.istic.gm.weassert.test.model.VariableDefinition;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNull.notNullValue;
+
+public class CodeVisitorImplTest {
+
+ private CodeVisitor codeVisitor;
+
+ @Before
+ public void setUp() {
+ codeVisitor = new CodeVisitorImpl();
+ }
+
+ @Test
+ public void shouldGetValue() {
+
+ assertThat(codeVisitor.getVariableValues(), notNullValue());
+ }
+
+ @Test
+ public void shouldResetValueWhenInit() {
+
+ VariableDefinition key = new VariableDefinition();
+ codeVisitor.getVariableValues().put(key, "a-string");
+
+ codeVisitor.initVariableValues();
+
+ assertThat(codeVisitor.getVariableValues().containsKey(key), equalTo(false));
+ }
+
+ @Test
+ public void shouldVisit() {
+
+ codeVisitor.visit(getClass(), "a-method", "a-def", "a-var", 10);
+
+ VariableDefinition expectedVariableDefinition = VariableDefinition.builder()
+ .clazz(getClass())
+ .methodName("a-method")
+ .methodDesc("a-def")
+ .variableName("a-var")
+ .build();
+
+ assertThat(codeVisitor.getVariableValues(), notNullValue());
+ assertThat(codeVisitor.getVariableValues().containsKey(expectedVariableDefinition), equalTo(true));
+ assertThat(codeVisitor.getVariableValues().get(expectedVariableDefinition), equalTo(10));
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/test/analyser/LocalVariableParserTest.java b/src/test/java/fr/istic/gm/weassert/test/analyser/LocalVariableParserTest.java
new file mode 100644
index 0000000..770e765
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/analyser/LocalVariableParserTest.java
@@ -0,0 +1,71 @@
+package fr.istic.gm.weassert.test.analyser;
+
+import fr.istic.gm.weassert.test.analyser.impl.LocalVariableParserImpl;
+import fr.istic.gm.weassert.test.model.LocalVariableParsed;
+import fr.istic.gm.weassert.test.model.VariableDefinition;
+import fr.istic.gm.weassert.test.utils.ClassReaderFactory;
+import fr.istic.gm.weassert.test.utils.UrlClassLoaderWrapper;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.tree.ClassNode;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LocalVariableParserTest {
+
+ private LocalVariableParser localVariableParser;
+
+ @Mock
+ private ClassReaderFactory mockClassReaderFactory;
+
+ @Mock
+ private UrlClassLoaderWrapper mockUrlClassLoaderWrapper;
+
+ @Before
+ public void setUp() throws Exception {
+ when(mockClassReaderFactory.create(any())).thenReturn(new ClassReader(TestAnalyserTest.class.getName()));
+
+ localVariableParser = new LocalVariableParserImpl(mockClassReaderFactory, TestAnalyserTest.class, new ClassNode(), mockUrlClassLoaderWrapper);
+ }
+
+ @Test
+ public void shouldInstanceClassReader() {
+
+ verify(mockClassReaderFactory).create(TestAnalyserTest.class);
+ }
+
+ @Test
+ public void shouldParseClassReader() {
+
+ when(mockUrlClassLoaderWrapper.getClassList()).thenReturn(Collections.singletonList(VariableDefinition.class));
+
+ List result = localVariableParser.parse();
+
+ verify(mockUrlClassLoaderWrapper, atLeastOnce()).getClassList();
+
+ assertThat(result, notNullValue());
+ assertThat(result, hasSize(3));
+ assertThat(result.get(0).getName(), equalTo("setUp"));
+ assertThat(result.get(1).getName(), equalTo("shouldCallAllNeedMethodsWhenAnalyse"));
+ assertThat(result.get(2).getName(), equalTo("shouldReturnAGoodResponseWhenAnalyse"));
+ assertThat(result.get(2).getLocalVariables(), hasItem("var0.getMethodName()"));
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/test/analyser/TestAnalyserTest.java b/src/test/java/fr/istic/gm/weassert/test/analyser/TestAnalyserTest.java
new file mode 100644
index 0000000..2855c70
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/analyser/TestAnalyserTest.java
@@ -0,0 +1,132 @@
+package fr.istic.gm.weassert.test.analyser;
+
+import fr.istic.gm.weassert.test.generator.CodeWriter;
+import fr.istic.gm.weassert.test.analyser.impl.TestAnalyserImpl;
+import fr.istic.gm.weassert.test.compiler.SourceCodeCompiler;
+import fr.istic.gm.weassert.test.model.LocalVariableParsed;
+import fr.istic.gm.weassert.test.model.TestAnalysed;
+import fr.istic.gm.weassert.test.model.VariableDefinition;
+import fr.istic.gm.weassert.test.runner.TestRunner;
+import fr.istic.gm.weassert.test.utils.UrlClassLoaderWrapper;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.Arrays.asList;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestAnalyserTest {
+
+ private TestAnalyser testAnalyser;
+
+ @Mock
+ private LocalVariableParser mockLocalVariableParser;
+
+ @Mock
+ private CodeWriter mockCodeWriter;
+
+ @Mock
+ private CodeVisitor mockCodeVisitor;
+
+ @Mock
+ private SourceCodeCompiler mockSourceCodeCompiler;
+
+ @Mock
+ private TestRunner mockTestRunner;
+
+ @Mock
+ private UrlClassLoaderWrapper mockUrlClassLoaderWrapper;
+
+ private LocalVariableParsed fakeLocalVariableParsed;
+
+ private LocalVariableParsed fakeLocalVariableParsed1;
+
+ @Before
+ public void setUp() {
+ testAnalyser = new TestAnalyserImpl(mockLocalVariableParser, mockCodeWriter, mockCodeVisitor, mockSourceCodeCompiler, mockUrlClassLoaderWrapper, mockTestRunner);
+
+ fakeLocalVariableParsed = LocalVariableParsed.builder()
+ .desc("a-desc")
+ .name("a-name")
+ .localVariables(asList("a-var", "a-var1"))
+ .build();
+
+ fakeLocalVariableParsed1 = LocalVariableParsed.builder()
+ .desc("a-desc1")
+ .name("a-name1")
+ .localVariables(asList("a-var1", "a-var2"))
+ .build();
+ }
+
+ @Test
+ public void shouldCallAllNeedMethodsWhenAnalyse() {
+
+ when(mockLocalVariableParser.parse()).thenReturn(asList(fakeLocalVariableParsed, fakeLocalVariableParsed1));
+ when(mockLocalVariableParser.getClazz()).thenReturn(getClass());
+ when(mockUrlClassLoaderWrapper.getClassList()).thenReturn(Collections.singletonList(getClass()));
+
+ testAnalyser.analyse();
+
+ verify(mockLocalVariableParser).parse();
+ verify(mockLocalVariableParser).getClazz();
+ verify(mockCodeWriter).insertOne("a-name", "a-desc", mockCodeVisitor.getClass().getName() + ".INSTANCE.visit(getClass(), \"a-name\", \"a-desc\", \"a-var\", a-var); // GENERATED VISITOR");
+ verify(mockCodeWriter).insertOne("a-name", "a-desc", mockCodeVisitor.getClass().getName() + ".INSTANCE.visit(getClass(), \"a-name\", \"a-desc\", \"a-var1\", a-var1); // GENERATED VISITOR");
+ verify(mockCodeWriter).writeAndCloseFile();
+ verify(mockSourceCodeCompiler).compileAndWait();
+ verify(mockUrlClassLoaderWrapper).getClassList();
+ verify(mockTestRunner, times(2)).startTest(getClass());
+ verify(mockCodeVisitor, times(2)).getVariableValues();
+ verify(mockCodeVisitor).initVariableValues();
+ }
+
+
+
+ @Test
+ public void shouldReturnAGoodResponseWhenAnalyse() {
+
+ VariableDefinition var0 = VariableDefinition.builder().clazz(getClass()).methodName("a-name").methodDesc("a-desc").variableName("var0").build();
+ VariableDefinition var1 = VariableDefinition.builder().clazz(getClass()).methodName("a-name").methodDesc("a-desc").variableName("var1").build();
+ VariableDefinition var2 = VariableDefinition.builder().clazz(getClass()).methodName("a-name").methodDesc("a-desc").variableName("var2").build();
+ VariableDefinition var3 = VariableDefinition.builder().clazz(getClass()).methodName("a-name").methodDesc("a-desc").variableName("var3").build();
+ VariableDefinition var4 = VariableDefinition.builder().clazz(getClass()).methodName("a-name").methodDesc("a-desc").variableName("var4").build();
+ Map firstCall = new HashMap<>();
+ firstCall.put(var0, 0);
+ firstCall.put(var1, 1);
+ firstCall.put(var2, 2);
+ firstCall.put(var3, 3);
+ Map secondCall = new HashMap<>();
+ secondCall.put(var0, 0);
+ secondCall.put(var1, 4);
+ secondCall.put(var2, 2);
+ secondCall.put(var3, 5);
+ secondCall.put(var4, 6);
+
+ when(mockLocalVariableParser.parse()).thenReturn(asList(fakeLocalVariableParsed, fakeLocalVariableParsed1));
+ when(mockLocalVariableParser.getClazz()).thenReturn(getClass());
+ when(mockCodeVisitor.getVariableValues()).thenReturn(firstCall, secondCall);
+ when(mockUrlClassLoaderWrapper.getClassList()).thenReturn(Collections.singletonList(getClass()));
+
+ List result = testAnalyser.analyse();
+
+ Map variableValues = new HashMap<>();
+ variableValues.put("var0", 0);
+ variableValues.put("var2", 2);
+ List expectedTestAnalyseds = Collections.singletonList(
+ TestAnalysed.builder().clazz(getClass()).methodName("a-name").methodDesc("a-desc").variableValues(variableValues).build()
+ );
+
+ assertThat(result, notNullValue());
+ assertThat(result, equalTo(expectedTestAnalyseds));
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/test/application/WeAssertRunnerTest.java b/src/test/java/fr/istic/gm/weassert/test/application/WeAssertRunnerTest.java
new file mode 100644
index 0000000..612568d
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/application/WeAssertRunnerTest.java
@@ -0,0 +1,67 @@
+package fr.istic.gm.weassert.test.application;
+
+import fr.istic.gm.weassert.test.application.impl.WeAssertRunnerImpl;
+import fr.istic.gm.weassert.test.runner.TestRunnerListener;
+import fr.istic.gm.weassert.test.utils.BackupUtils;
+import fr.istic.gm.weassert.test.utils.impl.BackupUtilsImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.Result;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.List;
+
+import static fr.istic.gm.weassert.TestUtils.getAbsolutePath;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasItem;
+
+@Slf4j
+public class WeAssertRunnerTest {
+
+ private WeAssertRunner weAssertRunner;
+
+ private BackupUtils backupUtils;
+
+ private boolean testRunned;
+
+ @Before
+ public void setUp() {
+ testRunned = false;
+ backupUtils = new BackupUtilsImpl(getAbsolutePath("fake/src/test/java/fr/istic/gm/weassert/fake/PersonTest.java"));
+ weAssertRunner = new WeAssertRunnerImpl(getAbsolutePath("fake"), "mvn", new TestRunnerListener() {
+ @Override
+ public void testRunFinished(Result result) {
+ testRunned = true;
+ }
+ });
+ }
+
+ @After
+ public void tearDown() {
+ backupUtils.restore();
+ }
+
+ @Test
+ public void shouldGenerate() throws IOException {
+
+ weAssertRunner.generate();
+
+ List lines = Files.readAllLines(new File(getAbsolutePath("fake/src/test/java/fr/istic/gm/weassert/fake/PersonTest.java")).toPath());
+ assertThat(lines, hasItem(" org.junit.Assert.assertEquals(p.getName(),\"name\"); // GENERATED ASSERT"));
+ assertThat(lines, hasItem("org.junit.Assert.assertEquals(p.getAge(),13); // GENERATED ASSERT"));
+ }
+
+ @Test
+ public void shouldRunTests() {
+
+ weAssertRunner.runTests();
+
+ assertThat(testRunned, equalTo(true));
+
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/test/compiler/SourceCodeCompilerITest.java b/src/test/java/fr/istic/gm/weassert/test/compiler/SourceCodeCompilerITest.java
new file mode 100644
index 0000000..fa512bb
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/compiler/SourceCodeCompilerITest.java
@@ -0,0 +1,44 @@
+package fr.istic.gm.weassert.test.compiler;
+
+import fr.istic.gm.weassert.test.compiler.impl.SourceCodeCompilerImpl;
+import fr.istic.gm.weassert.test.utils.ProcessBuilderFactory;
+import fr.istic.gm.weassert.test.utils.UrlClassLoaderWrapper;
+import fr.istic.gm.weassert.test.utils.impl.ProcessBuilderFactoryImpl;
+import fr.istic.gm.weassert.test.utils.impl.UrlClassLoaderWrapperImpl;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class SourceCodeCompilerITest {
+
+ private SourceCodeCompiler sourceCodeCompiler;
+
+ private ProcessBuilderFactory processBuilderFactory;
+
+ private UrlClassLoaderWrapper urlClassLoaderWrapper;
+
+ @Before
+ public void setUp() {
+ processBuilderFactory = new ProcessBuilderFactoryImpl();
+ urlClassLoaderWrapper = new UrlClassLoaderWrapperImpl(new ArrayList<>());
+ sourceCodeCompiler = new SourceCodeCompilerImpl("fake", "mvn", processBuilderFactory, urlClassLoaderWrapper);
+ }
+
+ @Test
+ public void shouldCompile() throws InterruptedException {
+
+ processBuilderFactory.create("fake", "rm", "-rf", "target/classes").start().waitFor();
+
+ assertThat(Files.exists(Paths.get("fake/target/classes")), equalTo(false));
+
+ sourceCodeCompiler.compileAndWait();
+
+ assertThat(Files.exists(Paths.get("fake/target/classes")), equalTo(true));
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/test/compiler/SourceCodeCompilerTest.java b/src/test/java/fr/istic/gm/weassert/test/compiler/SourceCodeCompilerTest.java
new file mode 100644
index 0000000..2272d66
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/compiler/SourceCodeCompilerTest.java
@@ -0,0 +1,75 @@
+package fr.istic.gm.weassert.test.compiler;
+
+import fr.istic.gm.weassert.test.compiler.impl.SourceCodeCompilerImpl;
+import fr.istic.gm.weassert.test.exception.WeAssertException;
+import fr.istic.gm.weassert.test.utils.ProcessBuilderFactory;
+import fr.istic.gm.weassert.test.utils.ProcessBuilderWrapper;
+import fr.istic.gm.weassert.test.utils.UrlClassLoaderWrapper;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SourceCodeCompilerTest {
+
+ private SourceCodeCompiler sourceCodeCompiler;
+
+ @Mock
+ private ProcessBuilderFactory mockProcessBuilderFactory;
+
+ @Mock
+ private ProcessBuilderWrapper mockProcessBuilderWrapper;
+
+ @Mock
+ private UrlClassLoaderWrapper mockUrlClassLoaderWrapper;
+
+ @Mock
+ private Process mockProcess;
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Before
+ public void setUp() {
+
+ when(mockProcessBuilderFactory.create(any(), any())).thenReturn(mockProcessBuilderWrapper);
+
+ sourceCodeCompiler = new SourceCodeCompilerImpl("fake", "mvn", mockProcessBuilderFactory, mockUrlClassLoaderWrapper);
+ }
+
+ @Test
+ public void shouldThrownAnExceptionWhenInstanciateCompilerWithWrongPath() {
+
+ thrown.expect(WeAssertException.class);
+ new SourceCodeCompilerImpl("not_a_path", "mvn", mockProcessBuilderFactory, mockUrlClassLoaderWrapper);
+ }
+
+ @Test
+ public void shouldCreateProcessBuilder() {
+ verify(mockProcessBuilderFactory).create("fake", "mvn", "clean", "test", "-DskipTests");
+ }
+
+ @Test
+ public void shouldCompile() throws FileNotFoundException {
+
+ when(mockProcessBuilderWrapper.start()).thenReturn(mockProcess);
+ when(mockProcess.getInputStream()).thenReturn(new FileInputStream(".gitignore"));
+
+ sourceCodeCompiler.compileAndWait();
+
+ verify(mockProcessBuilderWrapper).start();
+ verify(mockProcess).getInputStream();
+ verify(mockUrlClassLoaderWrapper).refresh();
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/test/generator/AssertionGeneratorTest.java b/src/test/java/fr/istic/gm/weassert/test/generator/AssertionGeneratorTest.java
new file mode 100644
index 0000000..0f06b46
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/generator/AssertionGeneratorTest.java
@@ -0,0 +1,108 @@
+package fr.istic.gm.weassert.test.generator;
+
+import fr.istic.gm.weassert.test.generator.impl.AssertionGeneratorImpl;
+import fr.istic.gm.weassert.test.model.TestAnalysed;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AssertionGeneratorTest {
+ private AssertionGenerator assertionGenerator;
+
+ @Mock
+ private CodeWriter codeWriterMock;
+
+
+ @Before
+ public void setUp() {
+ this.assertionGenerator = new AssertionGeneratorImpl(this.codeWriterMock);
+ }
+
+ @Test
+ public void generate() {
+ Map variableValues = new HashMap<>();
+
+ variableValues.put("maVariable1", new Object());
+
+ TestAnalysed testAnalysed = TestAnalysed.builder()
+ .clazz(getClass())
+ .methodName("generate")
+ .methodDesc("V()")
+ .variableValues(variableValues)
+ .build();
+
+ this.assertionGenerator.generate(Collections.singletonList(testAnalysed));
+
+ Mockito.verify(this.codeWriterMock).insertMany(testAnalysed.getMethodName(), testAnalysed.getMethodDesc(), new ArrayList<>());
+ }
+
+ @Test
+ public void generateWithStrings() {
+ Map variableValues = new HashMap<>();
+
+ variableValues.put("maVariable2", "Hey there !");
+
+ TestAnalysed testAnalysed = TestAnalysed.builder()
+ .clazz(getClass())
+ .methodName("generateWithStrings")
+ .methodDesc("V()")
+ .variableValues(variableValues)
+ .build();
+
+ this.assertionGenerator.generate(Collections.singletonList(testAnalysed));
+
+ List generatedCodes = new ArrayList<>();
+ generatedCodes.add("org.junit.Assert.assertEquals(maVariable2,\"Hey there !\"); // GENERATED ASSERT");
+ Mockito.verify(this.codeWriterMock).insertMany(testAnalysed.getMethodName(), testAnalysed.getMethodDesc(), generatedCodes);
+ }
+
+ @Test
+ public void generateWithIntegers() {
+ Map variableValues = new HashMap<>();
+
+ variableValues.put("maVariable3", 123);
+
+ TestAnalysed testAnalysed = TestAnalysed.builder()
+ .clazz(getClass())
+ .methodName("generateWithIntegers")
+ .methodDesc("V()")
+ .variableValues(variableValues)
+ .build();
+
+ this.assertionGenerator.generate(Collections.singletonList(testAnalysed));
+
+ List generatedCodes = new ArrayList<>();
+ generatedCodes.add("org.junit.Assert.assertEquals(maVariable3,123); // GENERATED ASSERT");
+ Mockito.verify(this.codeWriterMock).insertMany(testAnalysed.getMethodName(), testAnalysed.getMethodDesc(), generatedCodes);
+ }
+
+ @Test
+ public void generateWithFloats() {
+ Map variableValues = new HashMap<>();
+
+ variableValues.put("maVariable4", 123.0);
+
+ TestAnalysed testAnalysed = TestAnalysed.builder()
+ .clazz(getClass())
+ .methodName("generateWithFloats")
+ .methodDesc("V()")
+ .variableValues(variableValues)
+ .build();
+
+ this.assertionGenerator.generate(Collections.singletonList(testAnalysed));
+
+ List generatedCodes = new ArrayList<>();
+ generatedCodes.add("org.junit.Assert.assertEquals(maVariable4,123.0); // GENERATED ASSERT");
+ Mockito.verify(this.codeWriterMock).insertMany(testAnalysed.getMethodName(), testAnalysed.getMethodDesc(), generatedCodes);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/fr/istic/gm/weassert/test/generator/JavassistCodeWriterITest.java b/src/test/java/fr/istic/gm/weassert/test/generator/JavassistCodeWriterITest.java
new file mode 100644
index 0000000..223865f
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/generator/JavassistCodeWriterITest.java
@@ -0,0 +1,35 @@
+package fr.istic.gm.weassert.test.generator;
+
+import fr.istic.gm.weassert.test.generator.impl.JavassitCodeWriter;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class JavassistCodeWriterITest {
+ private JavassitCodeWriter codeWriter;
+
+ @Before
+ public void setUp() {
+ this.codeWriter = new JavassitCodeWriter(getClass());
+
+ assertEquals(this.codeWriter.getClassName(), getClass().getName());
+ }
+
+ @Test
+ public void insertMany() {
+ List sourceCode = Arrays.asList(
+ "System.out.println(\"Hello world\");",
+ "System.out.println(\"Leonard de Vinci\");"
+ );
+
+ this.codeWriter.insertMany("insertMany", "()V", sourceCode);
+ this.codeWriter.writeAndCloseFile();
+
+ assertTrue(this.codeWriter.getClassContainer().isFrozen());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/fr/istic/gm/weassert/test/generator/SourceCodeWriterTest.java b/src/test/java/fr/istic/gm/weassert/test/generator/SourceCodeWriterTest.java
new file mode 100644
index 0000000..017c430
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/generator/SourceCodeWriterTest.java
@@ -0,0 +1,65 @@
+package fr.istic.gm.weassert.test.generator;
+
+import fr.istic.gm.weassert.test.generator.impl.SourceCodeWriter;
+import fr.istic.gm.weassert.test.utils.BackupUtils;
+import fr.istic.gm.weassert.test.utils.impl.BackupUtilsImpl;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import static fr.istic.gm.weassert.TestUtils.getAbsolutePath;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+
+public class SourceCodeWriterTest {
+ private SourceCodeWriter sourceCodeWriter;
+ private String classPath;
+ private BackupUtils backupUtils;
+
+ @Before
+ public void setUp() {
+ this.classPath = getAbsolutePath("fake/src/test/java/fr/istic/gm/weassert/fake/PersonTest.java");
+
+ backupUtils = new BackupUtilsImpl(classPath);
+ this.sourceCodeWriter = new SourceCodeWriter(this.classPath);
+ }
+
+ @After
+ public void tearDown() {
+ backupUtils.restore();
+ }
+
+ @Test
+ public void shouldConstruct() {
+ assertNotNull(this.sourceCodeWriter.getClassName());
+ }
+
+ @Test
+ public void insertOne() {
+ String code = "System.out.println(\"Hello World !\");";
+ this.sourceCodeWriter.insertOne("testAge", "()V", code);
+
+
+ assertTrue(this.sourceCodeWriter.getSourceCode().contains(code));
+ }
+
+ @Test
+ public void writeAndCloseFile() {
+ String code = "System.out.println(\"Hello World !\");";
+ this.sourceCodeWriter.insertOne("testAge", "()V", code);
+ this.sourceCodeWriter.writeAndCloseFile();
+
+ try {
+ String readFile = new String(Files.readAllBytes(Paths.get(this.classPath)));
+ assertEquals(this.sourceCodeWriter.getSourceCode(), readFile);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/fr/istic/gm/weassert/test/runner/TestRunnerTest.java b/src/test/java/fr/istic/gm/weassert/test/runner/TestRunnerTest.java
new file mode 100644
index 0000000..cf8aea2
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/runner/TestRunnerTest.java
@@ -0,0 +1,50 @@
+package fr.istic.gm.weassert.test.runner;
+
+import fr.istic.gm.weassert.TestRunnerApp;
+import fr.istic.gm.weassert.test.runner.impl.TestRunnerImpl;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.RunWith;
+import org.junit.runner.notification.RunListener;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static java.util.Arrays.asList;
+import static org.mockito.Mockito.verify;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestRunnerTest {
+
+ private TestRunner testRunner;
+
+ @Mock
+ private JUnitCore mockJUnitCore;
+
+ @Mock
+ private RunListener mockRunListener;
+
+ @Before
+ public void setUp() {
+ testRunner = new TestRunnerImpl(mockJUnitCore, mockRunListener);
+ }
+
+ @Test
+ public void shouldAStartTestClass() {
+
+ testRunner.startTest(getClass());
+
+ verify(mockJUnitCore).addListener(mockRunListener);
+ verify(mockJUnitCore).run(getClass());
+ }
+
+ @Test
+ public void shouldAStartTestsClass() {
+
+ testRunner.startTests(asList(getClass(), TestRunnerApp.class));
+
+ verify(mockJUnitCore).addListener(mockRunListener);
+ verify(mockJUnitCore).run(getClass());
+ verify(mockJUnitCore).run(TestRunnerApp.class);
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/test/utils/BackupUtilsTest.java b/src/test/java/fr/istic/gm/weassert/test/utils/BackupUtilsTest.java
new file mode 100644
index 0000000..32b0cc0
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/utils/BackupUtilsTest.java
@@ -0,0 +1,33 @@
+package fr.istic.gm.weassert.test.utils;
+
+import fr.istic.gm.weassert.test.utils.impl.BackupUtilsImpl;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import static fr.istic.gm.weassert.TestUtils.getAbsolutePath;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsEqual.equalTo;
+
+public class BackupUtilsTest {
+
+ private String absolutePath;
+ private BackupUtilsImpl backupUtils;
+
+ @Before
+ public void setUp() {
+ absolutePath = getAbsolutePath("fake/src/test/java/fr/istic/gm/weassert/fake/PersonTest.java");
+ backupUtils = new BackupUtilsImpl(absolutePath);
+ }
+
+ @Test
+ public void shouldStoreData() throws IOException {
+
+ byte[] content = Files.readAllBytes(new File(absolutePath).toPath());
+
+ assertThat(backupUtils.getContent(), equalTo(content));
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/test/utils/ClassReaderFactoryTest.java b/src/test/java/fr/istic/gm/weassert/test/utils/ClassReaderFactoryTest.java
new file mode 100644
index 0000000..dc97428
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/utils/ClassReaderFactoryTest.java
@@ -0,0 +1,27 @@
+package fr.istic.gm.weassert.test.utils;
+
+import fr.istic.gm.weassert.test.utils.impl.ClassReaderFactoryImpl;
+import org.junit.Before;
+import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNull.notNullValue;
+
+public class ClassReaderFactoryTest {
+
+ private ClassReaderFactory factory;
+
+ @Before
+ public void setUp() {
+ factory = new ClassReaderFactoryImpl();
+ }
+
+ @Test
+ public void shouldCreateClassReader() {
+
+ ClassReader result = factory.create(getClass());
+
+ assertThat(result, notNullValue());
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/test/utils/ProcessBuilderFactoryTest.java b/src/test/java/fr/istic/gm/weassert/test/utils/ProcessBuilderFactoryTest.java
new file mode 100644
index 0000000..f7b21b9
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/utils/ProcessBuilderFactoryTest.java
@@ -0,0 +1,68 @@
+package fr.istic.gm.weassert.test.utils;
+
+import fr.istic.gm.weassert.test.exception.WeAssertException;
+import fr.istic.gm.weassert.test.utils.impl.ProcessBuilderFactoryImpl;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.core.IsNull.notNullValue;
+
+public class ProcessBuilderFactoryTest {
+
+ private ProcessBuilderFactory processBuilderFactory;
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Before
+ public void setUp() {
+ processBuilderFactory = new ProcessBuilderFactoryImpl();
+ }
+
+ @Test
+ public void shouldThrowExceptionWhenCreateAProcessBuilderWithNullDirectory() {
+
+ thrown.expect(WeAssertException.class);
+
+ processBuilderFactory.create(null, "a-command");
+ }
+
+ @Test
+ public void shouldThrowExceptionWhenCreateAProcessBuilderWithAWongDirectory() {
+
+ thrown.expect(WeAssertException.class);
+
+ processBuilderFactory.create("not-a-directory", "a-command");
+ }
+
+ @Test
+ public void shouldThrowExceptionWhenCreateAProcessBuilderWithNullCommand() {
+
+ thrown.expect(WeAssertException.class);
+
+ processBuilderFactory.create("/tmp", null);
+ }
+
+ @Test
+ public void shouldThrowExceptionWhenCreateAProcessBuilderWithEmptyCommand() {
+
+ thrown.expect(WeAssertException.class);
+
+ processBuilderFactory.create("/tmp", "");
+ }
+
+ @Test
+ public void shouldCreateAProcessBuilder() {
+
+ ProcessBuilderWrapper processBuilder = processBuilderFactory.create("/tmp", "ls", "test");
+
+ assertThat(processBuilder, notNullValue());
+ assertThat(processBuilder.directory().getPath(), equalTo("/tmp"));
+ assertThat(processBuilder.command().get(0), equalTo("ls"));
+ assertThat(processBuilder.command().get(1), equalTo("test"));
+ }
+}
diff --git a/src/test/java/fr/istic/gm/weassert/test/utils/UrlClassLoaderWrapperTest.java b/src/test/java/fr/istic/gm/weassert/test/utils/UrlClassLoaderWrapperTest.java
new file mode 100644
index 0000000..6449bb5
--- /dev/null
+++ b/src/test/java/fr/istic/gm/weassert/test/utils/UrlClassLoaderWrapperTest.java
@@ -0,0 +1,36 @@
+package fr.istic.gm.weassert.test.utils;
+
+import fr.istic.gm.weassert.test.utils.impl.UrlClassLoaderWrapperImpl;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.List;
+
+import static fr.istic.gm.weassert.TestUtils.getAbsolutePath;
+import static java.util.Arrays.asList;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+import static org.hamcrest.core.IsNull.notNullValue;
+
+@RunWith(MockitoJUnitRunner.class)
+public class UrlClassLoaderWrapperTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void shouldReturnAllClassOfAnExternalProject() {
+ List paths = asList(getAbsolutePath("fake/target/classes"), getAbsolutePath("fake/target/test-classes"));
+
+ UrlClassLoaderWrapper urlClassLoaderWrapper = new UrlClassLoaderWrapperImpl(paths);
+
+ assertThat(urlClassLoaderWrapper.getClassList(), notNullValue());
+ assertThat(urlClassLoaderWrapper.getClassList(), hasSize(2));
+ assertThat(urlClassLoaderWrapper.getClassList().get(0).getSimpleName(), equalTo("Person"));
+ assertThat(urlClassLoaderWrapper.getClassList().get(1).getSimpleName(), equalTo("PersonTest"));
+ }
+}