diff --git a/TP5/.gitignore b/TP5/.gitignore new file mode 100644 index 0000000..6b468b6 --- /dev/null +++ b/TP5/.gitignore @@ -0,0 +1 @@ +*.class diff --git a/TP5/Utility.java b/TP5/Utility.java new file mode 100644 index 0000000..ef1c863 --- /dev/null +++ b/TP5/Utility.java @@ -0,0 +1,9 @@ +import java.lang.annotation.*; + +/** Indicate that a class is a utility class and thus only defines + * static methods Utility. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.SOURCE) +public @interface Utility { +} diff --git a/TP5/UtilityClass.java b/TP5/UtilityClass.java new file mode 100644 index 0000000..42e4fb7 --- /dev/null +++ b/TP5/UtilityClass.java @@ -0,0 +1,6 @@ +@Utility +final public class UtilityClass { + private UtilityClass() {} + public static void m1() { } + public static void m2() { } +} diff --git a/TP5/UtilityInterface.java b/TP5/UtilityInterface.java new file mode 100644 index 0000000..1894d66 --- /dev/null +++ b/TP5/UtilityInterface.java @@ -0,0 +1,5 @@ +@Utility +public interface UtilityInterface { + void m(); + int i = 0; +} diff --git a/TP5/UtilityProcessor.java b/TP5/UtilityProcessor.java new file mode 100644 index 0000000..d3f9849 --- /dev/null +++ b/TP5/UtilityProcessor.java @@ -0,0 +1,68 @@ +import javax.annotation.processing.*; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.*; +import javax.tools.Diagnostic.Kind; +import java.lang.reflect.*; +import java.lang.reflect.Modifier; +import java.util.*; +import java.lang.annotation.*; + +/** Check that a class marked {@code @Utility} is indeed a utility class. */ +@SupportedAnnotationTypes("Utility") +@SupportedSourceVersion(SourceVersion.RELEASE_11) +public class UtilityProcessor extends AbstractProcessor { + + @Override + public boolean process( + Set annotations, + RoundEnvironment roundingEnvironment) + { + Messager messager = processingEnv.getMessager(); + messager.printMessage(Kind.NOTE, + "UtilityProcessor executed."); + messager.printMessage(Kind.WARNING, + "The provided UtilityProcessor class is wrong. Correct it!"); + for (TypeElement te : annotations) { + for (Element elt : roundingEnvironment.getElementsAnnotatedWith(te)) { + + // check if elt is a class + if (elt.getKind() == ElementKind.CLASS) { + + // Check that the class is declared final + if (Modifier.isFinal(elt.getModifiers())) { + + Class cl = Class.forName(elt.getTagName()); + + // Check that enclosed elements are static + Method[] methods = cl.getMethods(); + for (Method method : methods) { + if (!Modifier.isStatic(method.getModifiers())) { + messager.printMessage(Kind.ERROR, "@Utility applies to class with STATIC mehthods only:", elt); + break; + } + } + // Check for constructors issues + Constructor[] constructors = cl.getConstructors(); + System.out.println("nb construct : " + constructors.length); + if (constructors.length != 1) { + messager.printMessage(Kind.ERROR, "@Utility applies to class with only ONE constructor only:", elt); + break; + } + for (Constructor constructor : constructors) { + if (Modifier.isPrivate(constructor.getModifiers())) { + messager.printMessage(Kind.ERROR, "@Utility applies to class with only a PRIVATE constructor only:", elt); + break; + } + } + } else { + messager.printMessage(Kind.ERROR, "@Utility applies to FINAL class only:", elt); + } + } else { + messager.printMessage(Kind.ERROR, "@Utility applies to CLASS only:", elt); + } + } + } + return true; + } + +} diff --git a/TP5/WrongUseOfUtility.java b/TP5/WrongUseOfUtility.java new file mode 100644 index 0000000..a8be000 --- /dev/null +++ b/TP5/WrongUseOfUtility.java @@ -0,0 +1,12 @@ +public class WrongUseOfUtility { + + @Utility + private WrongUseOfUtility() {} + + @Utility + static void m(@Utility int n) {} + + @Utility + static int a; + +} diff --git a/TP5/WrongUtilityClass.java b/TP5/WrongUtilityClass.java new file mode 100644 index 0000000..98125f0 --- /dev/null +++ b/TP5/WrongUtilityClass.java @@ -0,0 +1,22 @@ +@Utility +public class WrongUtilityClass { + + WrongUtilityClass(int c) { } + private WrongUtilityClass(String s) { } + protected WrongUtilityClass() { } + + public static void m1() { System.out.println("m1"); } + public static void m2() { System.out.println("m2"); } + private void m3() { System.out.println("m3"); } + + class InternalClass { + int i; + } + + static class StaticInternalClass { + int i; + } + + int attr; + static String name; +} diff --git a/TP6/build.gradle b/TP6/build.gradle new file mode 100644 index 0000000..dfbf71e --- /dev/null +++ b/TP6/build.gradle @@ -0,0 +1,49 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java project to get you started. + * For more details take a look at the Java Quickstart chapter in the Gradle + * user guide available at https://docs.gradle.org/5.0/userguide/tutorial_java_projects.html + */ + +plugins { + // Apply the java plugin to add support for Java + id 'java' + + // Apply the application plugin to add support for building an application + id 'application' + + id 'jacoco' + + id 'info.solidsoft.pitest' version '1.3.0' +} + +repositories { + // Use jcenter for resolving your dependencies. + // You can declare any Maven/Ivy/file repository here. + jcenter() +} + +dependencies { + // This dependency is found on compile classpath of this component and consumers. + implementation 'com.google.guava:guava:26.0-jre' + + // Use JUnit test framework + testImplementation 'junit:junit:4.12' + testImplementation 'org.hamcrest:hamcrest-library:1.3' + + // XXX + testCompile "org.mockito:mockito-core:2.+" + + // XXX + testCompile 'com.pholser:junit-quickcheck-core:0.6' + testCompile 'com.pholser:junit-quickcheck-generators:0.8.1' +} + +pitest { + targetClasses = [ 'fr.n7.gls.test.*' ] + pitestVersion = '1.4.3' +} + +// Define the main class for the application +mainClassName = 'fr.n7.gls.test.App' diff --git a/TP6/src/main/java/fr/n7/gls/test/App.java b/TP6/src/main/java/fr/n7/gls/test/App.java new file mode 100644 index 0000000..53daefd --- /dev/null +++ b/TP6/src/main/java/fr/n7/gls/test/App.java @@ -0,0 +1,14 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package fr.n7.gls.test; + +public class App { + public String getGreeting() { + return "Hello world."; + } + + public static void main(String[] args) { + System.out.println(new App().getGreeting()); + } +} diff --git a/TP6/src/main/java/fr/n7/gls/test/Erreurs.java b/TP6/src/main/java/fr/n7/gls/test/Erreurs.java new file mode 100644 index 0000000..f6f04bd --- /dev/null +++ b/TP6/src/main/java/fr/n7/gls/test/Erreurs.java @@ -0,0 +1,18 @@ +package fr.n7.gls.test; + +/** + * Erreurs permet de signaler des erreurs. + * + * @author Xavier Crégut <Prenom.Nom@enseeiht.fr> + */ +public interface Erreurs { + + /** Signaler une erreur et l'explication associé. + * + * @param erreur l'erreur signalée + * @param explication explication de l'erreur signalée + * @param le type de erreur + */ + void signaler(E erreur, String explication); + +} diff --git a/TP6/src/main/java/fr/n7/gls/test/ErreursAffichage.java b/TP6/src/main/java/fr/n7/gls/test/ErreursAffichage.java new file mode 100644 index 0000000..08f1316 --- /dev/null +++ b/TP6/src/main/java/fr/n7/gls/test/ErreursAffichage.java @@ -0,0 +1,17 @@ +package fr.n7.gls.test; + +/** + * ErreursAffichage + * + * @author Xavier Crégut <Prenom.Nom@enseeiht.fr> + */ + +public class ErreursAffichage implements Erreurs { + + public void signaler(E erreur, String explication) { + System.out.println("Erreur sur " + erreur + " : " + explication); + } + + + +} diff --git a/TP6/src/main/java/fr/n7/gls/test/Somme.java b/TP6/src/main/java/fr/n7/gls/test/Somme.java new file mode 100644 index 0000000..bc713d6 --- /dev/null +++ b/TP6/src/main/java/fr/n7/gls/test/Somme.java @@ -0,0 +1,48 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package fr.n7.gls.test; + +import java.io.*; + +// TODO : Ajouter un deuxième paramètre qui permet de logger les erreurs. +// On ne donne que l'interface. On le test. On peut ensuite en donner une +// implantation naïve : stocker dans une liste et et afficher à la fin (ou +// afficher au fil de l'eau sur la sortie en erreur)... + +public class Somme { + + public int somme(BufferedReader f) throws IOException { + return somme(f, new ErreursAffichage()); + } + + public int somme(BufferedReader f, Erreurs erreurs) throws IOException { + int resultat = 0; + String ligne = null; + while ((ligne = f.readLine()) != null) { + try { + int valeur = Integer.parseInt(ligne); + if (valeur >= 0) { + resultat += valeur; + } else { + erreurs.signaler(ligne, "Valeur négative"); + } + } catch (NumberFormatException e) { + erreurs.signaler(ligne, "Pas un entier !"); + } + } + return resultat; + } + + public static void main(String[] args) throws Exception { + if (args.length == 1) { + BufferedReader br = new BufferedReader(new FileReader(args[0])); + System.out.println(new Somme().somme(br)); + } else { + System.out.println("Un nom de fichier attendu sur la ligne de commande !"); + System.exit(1); + } + } + +} + diff --git a/TP6/src/main/java/fr/n7/gls/test/Statistiques.java b/TP6/src/main/java/fr/n7/gls/test/Statistiques.java new file mode 100644 index 0000000..f9b9baa --- /dev/null +++ b/TP6/src/main/java/fr/n7/gls/test/Statistiques.java @@ -0,0 +1,94 @@ +/** + * Statistiques, classe utilitaire. + * + * @author Xavier Crégut <Prenom.Nom@enseeiht.fr> + */ + +package fr.n7.gls.test; + +import java.util.*; + +public class Statistiques { + + /** La classe Resultat permet de regrouper les résultats de la méthode + * statistiques dans un seul objet. + */ + static public class Resultat> { + final public T min, max; + final public int nbMin, nbMax; + + /** Constructeur naturel. + * @param min le plus petit élément + * @param max le plus grand élément + * @param nbMin le nombre d'occurrence de min + * @param nbMax le nombre d'occurrence de max + */ + public Resultat(T min, T max, int nbMin, int nbMax) { + /* + // Ces assert sont commentés car ils se traduisent dans le code + // intermédiaire par des conditionnelles (une pour savoir si les + // assertions sont activitées et un pour savoir si la condition + // est vraie) ce qui conduit à une non couverture en décisions. + assert (min == null) == (max == null); + assert min == null || min.compareTo(max) <= 0; + assert nbMax >= 0; + assert nbMax >= 0; + assert (nbMin == 0) == (min == null); + assert (nbMax == 0) == (max == null); + */ + + this.min = min; + this.max = max; + this.nbMin = nbMin; + this.nbMax = nbMax; + } + } + + /** Calculer quelques statistiques sur une suite de données. + * + *

+ * Les statistiques calculées sont : + * la plus petite valeur (min), la plus grande valeur (max), + * le nombre de min, le nombre de max. Ces données sont + * regroupées dans un objet de type Resultat. + * + *

+ * Si la valeur null apparaît dans les données, l'exception + * IllegalArgumentException est levée. + * + *

+ * S'il n'y a aucune données, le min et le max sont null et + * leur nombre d'occurrences est 0. + * + * @param iterable les données à analyser + * @param le type des données + * @return les statistiques + * @throws IllegalArgumentException si null apparaît dans les données + */ + public > + Resultat statistiques(Iterable iterable) + { + D min = null; + D max = null; + int nbMin = 0; + int nbMax = 0; + for (D x : iterable) { + if (min == null) { + min = max = x; + nbMax = nbMax = 1; + } else if (x.compareTo(min) < 0) { + min = x; + nbMin = 1; + } else if (x.compareTo(max) > 0) { + max = x; + nbMax = 1; + } else if (x.compareTo(min) == 0) { + nbMin++; + } else if (x.compareTo(max) == 0) { + nbMax++; + } + } + return new Resultat(min, max, nbMax, nbMax); + } + +} diff --git a/TP6/src/test/java/fr/n7/gls/test/AppTest.java b/TP6/src/test/java/fr/n7/gls/test/AppTest.java new file mode 100644 index 0000000..c02866d --- /dev/null +++ b/TP6/src/test/java/fr/n7/gls/test/AppTest.java @@ -0,0 +1,14 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package fr.n7.gls.test; + +import org.junit.Test; +import static org.junit.Assert.*; + +public class AppTest { + @Test public void testAppHasAGreeting() { + App classUnderTest = new App(); + assertNotNull("app should have a greeting", classUnderTest.getGreeting()); + } +} diff --git a/TP6/src/test/java/fr/n7/gls/test/QuickCheckTest.java b/TP6/src/test/java/fr/n7/gls/test/QuickCheckTest.java new file mode 100644 index 0000000..d152c5b --- /dev/null +++ b/TP6/src/test/java/fr/n7/gls/test/QuickCheckTest.java @@ -0,0 +1,60 @@ +/** + * QuickCheckTest + * + * @author Xavier Crégut <Prenom.Nom@enseeiht.fr> + */ + +package fr.n7.gls.test; + +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeThat; + +import org.junit.runner.RunWith; + +import com.pholser.junit.quickcheck.Property; +import com.pholser.junit.quickcheck.When; +import com.pholser.junit.quickcheck.generator.InRange; +import com.pholser.junit.quickcheck.runner.JUnitQuickcheck; + +@RunWith(JUnitQuickcheck.class) +public class QuickCheckTest { + + @Property(trials = 5) + public void simple(int num) { + System.out.println("simple:" + num); + if (num > 0) // XXX : Added to pass + assertTrue(num > 0); + } + + @Property(trials = 5) + public void assume(int num) { + System.out.print(" | Before:" + num); + assumeThat(num, greaterThan(0)); + System.out.println(" | Afer:" + num); + assertTrue(num > 0); + } + + @Property(trials = 10) + public void inRange(@InRange(minInt = 0, maxInt = 100) int num) { + System.out.println("InRange: " + num); + assertTrue(num >= 0); + } + + @Property(trials = 30) + public void when(@When(satisfies = "#_ < 1000 || #_ > 100000") int num) { + System.out.println("when: " + num); + if (num > 0) // XXX : Added to pass + assertTrue(num > 0); + } + + @Property(trials = 10) + public void seed(@When(seed = 1L) int num) { + System.out.println("seed: " + num); + if (num > 0) // XXX : Added to pass + assertTrue(num > 0); + } + +} + + diff --git a/TP6/src/test/java/fr/n7/gls/test/SommeTest.java b/TP6/src/test/java/fr/n7/gls/test/SommeTest.java new file mode 100644 index 0000000..f3a48ae --- /dev/null +++ b/TP6/src/test/java/fr/n7/gls/test/SommeTest.java @@ -0,0 +1,58 @@ +/** + * SommeTest, classe de test de Somme. + * + * @author Xavier Crégut <Prenom.Nom@enseeiht.fr> + */ + +package fr.n7.gls.test; + +import java.io.*; + +import org.junit.*; +import static org.junit.Assert.*; + +import org.mockito.*; +import org.mockito.junit.*; +import static org.mockito.Mockito.*; + +public class SommeTest { + + @Rule public MockitoRule mockito = MockitoJUnit.rule(); + + public Somme somme; + + @Before + public void setUp() { + this.somme = new Somme(); + } + + @Test + public void testerSommeAvecUnVraiFichier() throws Exception { + + // Créer le fichier pour le test + File fichier = File.createTempFile("tmp", ".txt"); + try (PrintWriter bw = new PrintWriter(new FileWriter(fichier))) { + bw.println("10"); + bw.println("30"); + bw.println("20"); + } + + // L'utiliser pour le test + try (BufferedReader br = new BufferedReader(new FileReader(fichier))) { + assertEquals(60, somme.somme(br)); + } + + // Effacer le fichier + fichier.delete(); + + } + + @Test + public void testerSommeAvecUneDoublure() throws Exception { + BufferedReader mockedBufferedReader = Mockito.mock(BufferedReader.class); + when(mockedBufferedReader.readLine()).thenReturn("10", "30", "20", null); + + assertEquals(60, somme.somme(mockedBufferedReader)); + } + +} diff --git a/TP6/src/test/java/fr/n7/gls/test/StatistiquesTest.java b/TP6/src/test/java/fr/n7/gls/test/StatistiquesTest.java new file mode 100644 index 0000000..894f83b --- /dev/null +++ b/TP6/src/test/java/fr/n7/gls/test/StatistiquesTest.java @@ -0,0 +1,27 @@ +/** + * StatistiquesTest, classe de test de Statistiques. + * + * @author Xavier Crégut <Prenom.Nom@enseeiht.fr> + */ + +package fr.n7.gls.test; + +import org.junit.*; +import static org.junit.Assert.*; + +import java.util.*; + +public class StatistiquesTest { + + @Test + public void testStatistiquesNominal() { + List l = new ArrayList<>(); + Collections.addAll(l, 1, 3, 11, 5, 7); + Statistiques.Resultat r = new Statistiques().statistiques(l); + assertEquals(Integer.valueOf(1), r.min); + assertEquals(Integer.valueOf(11), r.max); + assertEquals(1, r.nbMin); + assertEquals(1, r.nbMax); + } + +}