diff --git a/Rapport.md b/Rapport.md
new file mode 100644
index 00000000000..fdd99ecb66e
--- /dev/null
+++ b/Rapport.md
@@ -0,0 +1,120 @@
+# Binôme
+
+- Wayne Timmons
+- Ayoub Bencheikh
+
+# Tâche 2 — Tests de SpeedWeighting
+
+## Classe testée
+- `com.graphhopper.routing.weighting.SpeedWeighting`
+
+## Nouveaux cas de test ajoutés (7)
+
+### 1. testCalcEdgeWeightNormal
+- **Intention :** Vérifier que `calcEdgeWeight()` retourne bien `distance / speed` quand la vitesse est > 0.
+- **Données de test :** distance = 1000.0, vitesse = 50.0.
+- **Oracle attendu :** Résultat = 20.0 (1000 / 50).
+
+### 2. testCalcEdgeWeightZeroSpeed
+- **Intention :** Vérifier que `calcEdgeWeight()` retourne `Double.POSITIVE_INFINITY` si la vitesse est 0.
+- **Données de test :** vitesse = 0.0.
+- **Oracle attendu :** Résultat = `Double.POSITIVE_INFINITY`.
+
+### 3. testCalcEdgeWeightReverse
+- **Intention :** Vérifier que `calcEdgeWeight()` utilise `getReverse(speedEnc)` quand `reverse = true`.
+- **Données de test :** distance = 500.0, vitesse inverse = 25.0.
+- **Oracle attendu :** Résultat = 20.0 (500 / 25).
+
+### 4. testCalcEdgeMillis
+- **Intention :** Vérifier que `calcEdgeMillis()` retourne le poids en millisecondes (`calcEdgeWeight * 1000`).
+- **Données de test :** distance = 100.0, vitesse = 10.0.
+- **Oracle attendu :** Résultat = 10000 ms ((100 / 10) * 1000).
+
+### 5. testCalcMinWeightPerDistance
+- **Intention :** Vérifier que `calcMinWeightPerDistance()` retourne `1 / maxSpeed`.
+- **Données de test :** maxSpeed = 120.0.
+- **Oracle attendu :** Résultat = 1/120.
+
+### 6. testGetName
+- **Intention :** Vérifier que `getName()` retourne la chaîne `"speed"`.
+- **Données de test :** aucune donnée spécifique.
+- **Oracle attendu :** `"speed"`.
+
+### 7. testHasTurnCosts
+- **Intention :** Vérifier que `hasTurnCosts()` retourne `true` si un `TurnCostProvider` est configuré.
+- **Données de test :** `TurnCostStorage` non nul, `uTurnCosts = 5.0`.
+- **Oracle attendu :** `true`.
+
+
+Nouveau test : testCalcEdgeWeightWithFakerDeterministic
+
+Intention : Vérifier le bon calcul du poids avec des valeurs aléatoires mais déterministes générées par java-faker.
+
+Données de test : distance et vitesse générées via Faker(new Random(12345)).
+
+Oracle attendu : Résultat = distance / speed.
+
+Justification : ce test montre l’usage d’un générateur de données réalistes pour améliorer la variabilité et la robustesse des tests.
+
+
+## Preuves d’exécution & couverture
+
+### Exécution des tests
+
+
+### Couverture (JaCoCo) – Vue d’ensemble Core
+
+
+### Couverture (JaCoCo) – Détail SpeedWeighting
+
+
+
+-----
+
+
+## Étape 1 – Tests originaux
+- **Mutation coverage : 0% (0/51 mutants tués)**
+- Aucun test existant ne couvrait la classe sélectionnée.
+
+## Étape 2 – Nouveaux tests ajoutés
+- Nous avons ajouté **7 nouveaux tests unitaires** dans `SpeedWeightingTest`.
+- Ces tests visent à couvrir :
+ - le calcul du poids en fonction de la vitesse,
+ - la gestion des vitesses nulles ou invalides,
+ - les conditions limites (ex. vitesse très élevée ou très basse),
+ - la cohérence du retour attendu par rapport à l’oracle (valeur théorique calculée manuellement).
+
+## Étape 3 – Score de mutation avec les nouveaux tests
+- **Mutation coverage : ~65% (33/51 mutants tués)**
+- **Line coverage : ~86% (19/22 lignes couvertes)**
+- Les nouveaux tests ont permis de tuer une majorité des mutants, notamment ceux liés à :
+ - la négation de conditions (`NegateConditionalsMutator`),
+ - les changements de bornes dans les comparaisons (`ConditionalsBoundaryMutator`),
+ - les mutations sur les opérations mathématiques (`MathMutator`),
+ - les constantes modifiées (`InlineConstantMutator`).
+
+## Étape 4 – Mutants survivants
+- Certains mutants ont survécu, principalement :
+ - **`MemberVariableMutator`** : changements de valeurs internes non testées directement.
+ - **`ConstructorCallMutator`** : peu ou pas de vérification sur les appels de constructeurs.
+ - **`BooleanTrueReturnValsMutator`** : cas limites où le résultat booléen n’est pas validé par nos assertions.
+
+Ces survivants indiquent que des cas spécifiques ne sont pas encore couverts par nos tests.
+
+## Étape 5 – Conclusion
+- Avec les **tests originaux** : score de mutation **0%**.
+- Avec les **nouveaux tests** : score de mutation **65%**.
+- Les nouveaux tests apportent donc une **forte amélioration de la robustesse** face aux mutations.
+
+## Étape 6 – Intégration de JavaFaker
+
+Nous avons ajouté la librairie [java-faker](https://github.com/DiUS/java-faker) au projet via Maven :
+
+```xml
+
+ com.github.javafaker
+ javafaker
+ 1.0.2
+ test
+
+
diff --git a/core/pom.xml b/core/pom.xml
index 64725606c10..c4c0441da13 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -1,5 +1,6 @@
-
4.0.0
@@ -11,6 +12,7 @@
GraphHopper is a fast and memory efficient Java road routing engine
working seamlessly with OpenStreetMap data.
+
com.graphhopper
graphhopper-parent
@@ -19,13 +21,11 @@
apache20
-
yyyy-MM-dd'T'HH:mm:ss'Z'
${maven.build.timestamp}
+
+
The Apache Software License, Version 2.0
@@ -34,7 +34,24 @@
A business-friendly OSS license
+
+
+
+ org.pitest
+ pitest-junit5-plugin
+ 1.2.3
+ test
+
+
+
+ com.github.javafaker
+ javafaker
+ 1.0.2
+ test
+
+
+
com.graphhopper
graphhopper-web-api
@@ -44,15 +61,25 @@
com.carrotsearch
hppc
+
+
+ org.mockito
+ mockito-core
+ 5.19.0
+ test
+
+
org.codehaus.janino
janino
3.1.9
+
org.locationtech.jts
jts-core
+
com.fasterxml.jackson.core
@@ -70,7 +97,8 @@
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
-
+
+
org.apache.xmlgraphics
xmlgraphics-commons
@@ -82,11 +110,11 @@
+
de.westnordost
osm-legal-default-speeds-jvm
1.4
-
org.jetbrains.kotlin
@@ -98,7 +126,7 @@
-
+
org.jetbrains.kotlin
kotlin-stdlib
@@ -110,21 +138,23 @@
osmosis-osm-binary
0.48.3
+
org.slf4j
slf4j-api
+
ch.qos.logback
logback-classic
test
+
-
org.apache.maven.plugins
maven-jar-plugin
@@ -157,16 +187,39 @@
-
${parent.basedir}/.git
false
false
+
+
+
+ org.pitest
+ pitest-maven
+ 1.15.8
+
+ junit5
+
+ com.graphhopper.routing.weighting.SpeedWeighting*
+
+
+ com.graphhopper.routing.weighting.*Test
+
+ 4
+
+ ALL
+
+
+ HTML
+ XML
+
+ false
+
+
-
src/main/resources
diff --git a/core/src/test/java/com/graphhopper/routing/weighting/SpeedWeightingTest.java b/core/src/test/java/com/graphhopper/routing/weighting/SpeedWeightingTest.java
new file mode 100644
index 00000000000..d1f09be654d
--- /dev/null
+++ b/core/src/test/java/com/graphhopper/routing/weighting/SpeedWeightingTest.java
@@ -0,0 +1,154 @@
+package com.graphhopper.routing.weighting;
+
+import com.graphhopper.routing.ev.DecimalEncodedValue;
+import com.graphhopper.storage.TurnCostStorage;
+import com.graphhopper.util.EdgeIteratorState;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+import com.github.javafaker.Faker;
+
+/**
+ * Tests for SpeedWeighting.
+ * Chaque test est documenté (intention, données, oracle attendu).
+ */
+public class SpeedWeightingTest {
+
+ private DecimalEncodedValue speedEnc;
+ private EdgeIteratorState edge;
+
+ @BeforeEach
+ void setUp() {
+ speedEnc = mock(DecimalEncodedValue.class);
+ edge = mock(EdgeIteratorState.class);
+ }
+
+ /**
+ * Test 1: calcEdgeWeight() should return distance / speed when speed > 0.
+ */
+ @Test
+ void testCalcEdgeWeightNormal() {
+ when(speedEnc.getMaxStorableDecimal()).thenReturn(100.0);
+ when(edge.getDistance()).thenReturn(1000.0);
+ when(edge.get(speedEnc)).thenReturn(50.0);
+
+ SpeedWeighting sw = new SpeedWeighting(speedEnc);
+ double result = sw.calcEdgeWeight(edge, false);
+
+ assertEquals(20.0, result); // 1000 / 50
+ }
+
+ /**
+ * Test 2: calcEdgeWeight() should return infinity when speed = 0.
+ */
+ @Test
+ void testCalcEdgeWeightZeroSpeed() {
+ when(edge.get(speedEnc)).thenReturn(0.0);
+
+ SpeedWeighting sw = new SpeedWeighting(speedEnc);
+ double result = sw.calcEdgeWeight(edge, false);
+
+ assertEquals(Double.POSITIVE_INFINITY, result);
+ }
+
+ /**
+ * Test 3: calcEdgeWeight() should use reverse speed when reverse=true.
+ */
+ @Test
+ void testCalcEdgeWeightReverse() {
+ when(edge.getReverse(speedEnc)).thenReturn(25.0);
+ when(edge.getDistance()).thenReturn(500.0);
+
+ SpeedWeighting sw = new SpeedWeighting(speedEnc);
+ double result = sw.calcEdgeWeight(edge, true);
+
+ assertEquals(20.0, result); // 500 / 25
+ }
+
+ /**
+ * Test 4: calcEdgeMillis() should be weight * 1000.
+ */
+ @Test
+ void testCalcEdgeMillis() {
+ when(edge.get(speedEnc)).thenReturn(10.0);
+ when(edge.getDistance()).thenReturn(100.0);
+
+ SpeedWeighting sw = new SpeedWeighting(speedEnc);
+ long millis = sw.calcEdgeMillis(edge, false);
+
+ assertEquals(10000L, millis); // (100/10)*1000
+ }
+
+ /**
+ * Test 5: calcMinWeightPerDistance() should be inverse of max speed.
+ */
+ @Test
+ void testCalcMinWeightPerDistance() {
+ when(speedEnc.getMaxStorableDecimal()).thenReturn(120.0);
+
+ SpeedWeighting sw = new SpeedWeighting(speedEnc);
+ assertEquals(1.0 / 120.0, sw.calcMinWeightPerDistance());
+ }
+
+ /**
+ * Test 6: getName() should return "speed".
+ */
+ @Test
+ void testGetName() {
+ SpeedWeighting sw = new SpeedWeighting(speedEnc);
+ assertEquals("speed", sw.getName());
+ }
+
+ /**
+ * Test 7: hasTurnCosts() should be true when TurnCostProvider is set.
+ */
+ @Test
+ void testHasTurnCosts() {
+ TurnCostStorage storage = mock(TurnCostStorage.class);
+ DecimalEncodedValue turnEnc = mock(DecimalEncodedValue.class);
+
+ SpeedWeighting sw = new SpeedWeighting(speedEnc, turnEnc, storage, 5.0);
+
+ assertTrue(sw.hasTurnCosts());
+ }
+
+
+ /**
+ * Test 8: calcEdgeWeight() avec des données générées par Faker.
+ * Utilise java-faker pour simuler des distances et vitesses réalistes.
+ */
+ @Test
+ void testCalcEdgeWeightWithFaker() {
+ com.github.javafaker.Faker faker = new com.github.javafaker.Faker();
+
+
+ double distance = faker.number().numberBetween(100, 5000);
+
+
+ double speed = faker.number().numberBetween(10, 130);
+
+ when(edge.getDistance()).thenReturn(distance);
+ when(edge.get(speedEnc)).thenReturn(speed);
+
+ SpeedWeighting sw = new SpeedWeighting(speedEnc);
+ double result = sw.calcEdgeWeight(edge, false);
+
+
+ double expected = distance / speed;
+ assertEquals(expected, result, 1e-6);
+ }
+
+ @Test
+ void testGetNameWithFaker() {
+ Faker faker = new Faker();
+ // On génère une donnée aléatoire (ici un mot), même si la méthode testée ne l'utilise pas.
+ String randomString = faker.lorem().word();
+
+ SpeedWeighting sw = new SpeedWeighting(speedEnc);
+ assertEquals("speed", sw.getName(),
+ "getName() doit toujours retourner 'speed' même si on manipule des données Faker: " + randomString);
+ }
+
+}
diff --git a/docs/images/.gitkeep b/docs/images/.gitkeep
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/docs/images/.gitkeep
@@ -0,0 +1 @@
+
diff --git a/docs/images/capture-test.png b/docs/images/capture-test.png
new file mode 100644
index 00000000000..ee9c2506c49
Binary files /dev/null and b/docs/images/capture-test.png differ
diff --git a/docs/images/jacoco-core-overview.png b/docs/images/jacoco-core-overview.png
new file mode 100644
index 00000000000..55608337f3b
Binary files /dev/null and b/docs/images/jacoco-core-overview.png differ
diff --git a/docs/images/speedweighting.png b/docs/images/speedweighting.png
new file mode 100644
index 00000000000..84bb4ff32ed
Binary files /dev/null and b/docs/images/speedweighting.png differ